pathhound-mcp

pathhound-mcp

An MCP server that enables LLMs to query and reason over Active Directory attack graphs collected by BloodHound, providing attack paths, blast radius analysis, choke points, and defender remediation advice.

Category
访问服务器

README

pathhound-mcp

An MCP (Model Context Protocol) server that lets an LLM reason over an Active Directory attack graph already collected by BloodHound — shortest paths to Tier 0, blast radius from a principal, the highest-leverage choke points to remediate, and defender-facing remediation text — with every action scoped to an authorized engagement and logged.

Authorized penetration-testing use only. This server never touches a live domain, never collects data, and never runs attacks. Collection is done separately (SharpHound / bloodhound-python); this tool only reads and reasons over the resulting graph in Neo4j. See SECURITY.md for the full intended-use boundary.

What it does

  • Turns a collected graph into explainable answers. Ask "what are the shortest paths to Domain Admins," "if I own this account what becomes reachable," or "which edges should we fix first" and get structured results.
  • Read-only and scoped by design. It refuses to start without an engagement scope, refuses to query domains outside that scope, rejects write/destructive Cypher, and appends every call to an audit log.
  • Defender-facing output. explain_edge and remediation_for_path produce report-ready remediation, not exploit commands.

Tools

Tool What it returns
list_domains() Domains/forests in the graph, with node counts and an in-scope flag.
run_cypher(query, params) Rows from a read-only Cypher query. Write clauses are rejected unless allow_writes is set; destructive/external ops are always refused. Results are row-capped with a truncation flag.
shortest_paths_to_tier0(start, max_paths) Shortest attack paths to Tier 0 / high-value targets — from start (an in-scope principal) or from every owned principal. Each path is an ordered list of start —[edge]→ end hops.
reachable_from(principal, max_hops) Blast radius from a principal, summarized by node type, highlighting any Tier 0 reachability.
find_choke_points(top_n) The edges appearing in the most distinct shortest paths to Tier 0, each with the number of paths removing it would break.
explain_edge(edge_type) Plain-language reason a BloodHound edge (e.g. GenericAll, AddKeyCredentialLink, DCSync) is abusable, the technique name, a defender remediation, and reference pointers.
remediation_for_path(path_id_or_cypher) For a path (given as a read-only Cypher query returning a path p), the specific ACE / delegation / membership change that breaks each hop, phrased for a report.
engagement_summary() Headline counts for reporting: principals, owned, high-value, distinct paths to Tier 0, and the top choke points.

Resources

Resource Contents
pathhound://engagement-scope The active scope (engagement id, authorization reference, allowed domains, write flag) and the Neo4j target with the password masked.
pathhound://cypher-library A curated, versioned set of named read-only Cypher queries (Kerberoastable, unconstrained delegation, AS-REP roastable, paths to Domain Admins, ACL abuse from a principal, …), each validated read-only on load.

Optional write tools (off by default)

Two tools — mark_owned(principal, confirm) and set_high_value(principal, confirm) — set BloodHound's owned / Tier 0 markers (and nothing else) so the path tools treat those nodes accordingly. They only exist when allow_writes: true is set in scope.yaml; each call also requires an explicit confirm=true, an in-scope principal, and is audited. They never delete or drop. Leave allow_writes: false (the default) for a strictly read-only deployment.

Requirements

  • Python 3.11+
  • A BloodHound CE Neo4j instance reachable over Bolt (the graph is collected and ingested separately — see the quickstart below)

Install

# With uv (preferred):
uv venv && uv pip install -e ".[dev]"

# Or with pip:
python -m venv .venv && . .venv/bin/activate
pip install -r requirements.txt && pip install -e .

Configure

Two pieces of configuration: the engagement scope (a file) and the Neo4j connection (environment variables — credentials are never hardcoded).

1. Engagement scope — copy the example and edit it:

cp scope.example.yaml scope.yaml
# scope.yaml
engagement_id: "ENG-0001"                      # names the audit log file
authorization_ref: "SoW-2026-ACME-001 / JIRA-1234"
allowed_domains:                               # only these may be queried
  - "CORP.LOCAL"
  - "CHILD.CORP.LOCAL"
allow_writes: false                            # keep false unless you need the write-flag tools
max_rows: 500                                  # run_cypher row cap

The server refuses to start if scope.yaml is missing or allowed_domains is empty — this is intentional; there are no unscoped queries. Domain names are matched case-insensitively against BloodHound's uppercase FQDNs.

2. Neo4j connection — via environment variables (or a .env; see .env.example):

export NEO4J_URI="bolt://127.0.0.1:7687"
export NEO4J_USER="neo4j"
export NEO4J_PASSWORD="…"
export NEO4J_DATABASE="neo4j"        # optional, defaults to neo4j
# export PATHHOUND_SCOPE="/abs/path/scope.yaml"   # optional; defaults to ./scope.yaml

Run

As a standalone stdio MCP server:

pathhound-mcp          # or:  python -m pathhound_mcp.server

Register with an MCP client

Point your client at the console script (use the absolute path from your venv, e.g. /path/to/pathhound-mcp/.venv/bin/pathhound-mcp) and pass the connection + scope through its environment. Example (Claude Desktop claude_desktop_config.json):

{
  "mcpServers": {
    "pathhound": {
      "command": "/path/to/pathhound-mcp/.venv/bin/pathhound-mcp",
      "env": {
        "NEO4J_URI": "bolt://127.0.0.1:7687",
        "NEO4J_USER": "neo4j",
        "NEO4J_PASSWORD": "…",
        "PATHHOUND_SCOPE": "/path/to/pathhound-mcp/scope.yaml"
      }
    }
  }
}

Example questions to ask the LLM

Once connected, an operator can ask things like:

  • "List the domains in the graph and how big each is." → list_domains
  • "Which accounts are Kerberoastable?" → run_cypher with the kerberoastable_users library query
  • "Show the shortest attack paths to Tier 0." → shortest_paths_to_tier0
  • "If I compromise alice@corp.local, what becomes reachable?" → reachable_from
  • "What are the top 10 choke points we should fix first?" → find_choke_points
  • "Why is AddKeyCredentialLink dangerous, and how do we fix it?" → explain_edge
  • "Give me remediation steps for this attack path." → remediation_for_path
  • "Summarize the engagement for the report." → engagement_summary

Quickstart: collect into BloodHound, then point this at Neo4j

This server only reads an already-collected graph; collection happens separately and outside this tool.

  1. Collect the domain with SharpHound or bloodhound-python during your authorized engagement. You get a set of JSON files (or a zip) — from a lab like GOAD (GOAD-Light ~16 GB, full GOAD ~32 GB) or a real engagement.

  2. Stand up BloodHound CE and ingest the data. The official compose stack runs Neo4j (Bolt on 127.0.0.1:7687), Postgres, and the BloodHound UI on :8080:

    docker compose -f /path/to/docker-compose.yml up -d
    # open http://localhost:8080, log in, and upload the collection zip
    # (Administration → File Ingest). Wait for ingest + post-processing.
    

    If the Neo4j volume is already ingested, you can start just the graph: docker compose -f /path/to/docker-compose.yml up -d graph-db.

  3. Point pathhound-mcp at that Neo4j (see Configure) and run it. Your allowed_domains in scope.yaml should match the domains in the collection (e.g. CORP.LOCAL).

BloodHound schema compatibility

Newer BloodHound CE tags Tier 0 with the Tag_Tier_Zero node label and owned principals with Tag_Owned, while older versions used the highvalue / owned properties (and CE also sets system_tags: admin_tier_0). pathhound recognizes all of these, so Tier 0 / owned reasoning works across versions.

Tests

pytest        # unit tests — guardrails, scope, audit, Cypher guard, tool logic

The suite is fully database-free: the read-only guardrail, scope enforcement, audit logging, row-capping, and path/reporting logic are all exercised against stubs, so pytest runs in a fraction of a second with no Neo4j. (The tools have also been validated end-to-end against a real BloodHound CE graph.)

Project layout

src/pathhound_mcp/
├── server.py          # FastMCP app: tool/resource registration + startup guard
├── config.py          # loads/validates scope.yaml (pydantic); Neo4j from env
├── guardrails.py      # read-only Cypher guard + scope enforcement
├── audit.py           # append-only JSONL audit logger (@audited decorator)
├── graph.py           # Neo4j connection + read helpers (the only DB access)
├── schema.py          # attack-edge set + Tier 0 / owned predicates
├── models.py          # pydantic result models
├── cypher_library.json / edge_library.json   # curated read-only queries + edge KB
└── tools/             # inventory, query, paths, reporting, edges

audit/, scope.yaml, and .env are gitignored — treat the audit log and the collected graph as engagement-sensitive.

Safety model

See SECURITY.md for the intended-use boundary and the guarantees: scope-at-startup, read-only by default, scope enforcement, append-only audit log, and no live-domain capability.

License

MIT — see LICENSE.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选