Skip to content

dart mcp

Juwon1405 edited this page Apr 30, 2026 · 8 revisions

dart-mcp — the typed surface

dart-mcp is the security boundary of the project. Everything else is convenience.

What it is

A custom MCP (Model Context Protocol) server, implemented in Python, that exposes exactly 35 typed forensic functions to the agent. It runs over stdio and speaks JSON-RPC 2.0.

What it is NOT

It is not a wrapper that translates LLM intent into shell commands. There is no execute_shell. There is no query_evidence(sql). There is no escape hatch.

The 35 functions

Grouped by category:

Windows execution & traces (4)

  • get_amcache(path) — AmCache.hve enumeration
  • parse_prefetch(target) — Prefetch artifact parser
  • parse_shimcache(host) — Application Compatibility cache
  • get_process_tree(host) — process tree from snapshot

Windows user activity (3)

  • analyze_usb_history(host, time_window)
  • parse_shellbags(host) — shellbags reader
  • extract_mft_timeline(host, start, end) — MFT $SI vs $FN

Windows system state (3)

  • list_scheduled_tasks(host)
  • detect_persistence(host) — registry/service/scheduled-task aggregation
  • analyze_event_logs(host, event_ids, time_window)

macOS (3)

  • parse_unified_log(host, subsystem, time_window)
  • parse_knowledgec(host) — KnowledgeC.db reader
  • parse_fsevents(host) — FSEvents CSV reader

Browser & exfiltration (4)

  • parse_browser_history(host, browser)
  • analyze_downloads(host) — MOTW handling
  • correlate_download_to_execution(host)
  • detect_exfiltration(host, time_window)

Authentication & lateral movement (5)

  • analyze_windows_logons(host)
  • detect_lateral_movement(host) — PsExec, WMIExec
  • analyze_kerberos_events(host) — Kerberoasting / AS-REP roasting
  • analyze_unix_auth(host, time_window)
  • detect_privilege_escalation(host)

Web/WAS + RDP brute (3)

  • analyze_web_access_log(path, rules) — 16 attack patterns
  • detect_webshell(path) — 3 high-confidence indicators, 0 FP target
  • detect_brute_force_rdp(host) — credential stuffing vs spray vs single-account

MITRE gap fillers (4)

  • detect_credential_access(host) — T1003 (Mimikatz, SAM, NTDS, comsvcs.dll LOLBin)
  • detect_ransomware_behavior(host) — T1486/T1489/T1490
  • detect_defense_evasion(host) — T1070 (event log clearing, timestomp, MFT $SI vs $FN)
  • detect_discovery(host) — T1033/T1057/T1082/T1016/T1018/T1049/T1069/T1087/T1482

Cross-artifact (2)

  • correlate_events(hypothesis_id) — delegate to dart-corr
  • correlate_timeline(start, end, sources) — DuckDB join

The schema

Every function has a JSON schema declared in dart_mcp/src/dart_mcp/__init__.py. The schema is enforced at the MCP layer:

  • Required arguments are required. Missing them raises InvalidArguments.
  • Argument types are validated. Passing a string where the schema requires an integer raises before the handler is called.
  • Path arguments go through _safe_resolve, which:
    • Refuses ..
    • Refuses absolute paths outside EVIDENCE_ROOT
    • Refuses paths containing NUL bytes
    • Returns the resolved absolute path inside EVIDENCE_ROOT if and only if the resolution stayed inside the read-only mount

The bypass tests

tests/test_mcp_bypass.py asserts that:

Attack Expected result
Call an unregistered function (execute_shell, eval, etc.) ToolNotFound
Pass .. in a path argument rejected by _safe_resolve
Pass an absolute path outside EVIDENCE_ROOT rejected
Pass a NUL-byte-truncated path rejected
Surface drift — function appears that wasn't declared test fails
Handler attempts to write outside EVIDENCE_ROOT filesystem refuses (read-only mount)

All 6 tests pass on main. Any change that breaks one is a release blocker.

Pagination

Every function returns cursor-paginated JSON. There is no "return everything" mode. This is for context-window safety: a 5M-row MFT export does not fit in any current LLM context window. The agent receives a page, decides if it needs more, and explicitly requests the next page.

Audit side-tap

Every call into dart-mcp is side-tapped into dart-audit. There is no path to call the MCP layer that does not produce an audit entry. This is enforced by the dispatch table itself, not by convention.

Adding a function

The contribution checklist for adding a new function is in Contributing. The short version:

  1. Read-only by construction (no write paths in the implementation)
  2. Use _safe_resolve for any path argument
  3. Pydantic / JSON schema declared
  4. Cursor-paginated output
  5. Bypass test added (call an unregistered variant — must ToolNotFound)
  6. Sample evidence added under examples/sample-evidence/
  7. README and accuracy-report updated

PRs that miss any of these will be sent back.


← Back to Home

Agentic-DART

Concepts

The 5 packages

Reference

Running it

Case studies

Project


Project links

Clone this wiki locally