mcp server
artblood
A fast and smart analyzer for BloodHound data with TUI and MCP.
Set up
Runs on your computer. Pick your agent and operating system.
This project does not publish an install method we can turn into a config. Follow the README instead.
README
synced Oct 25, 2026ArtBlood
ArtBlood is a fast, offline command-line analyzer for BloodHound data. It imports SharpHound JSON files, directories, or ZIP archives into a local indexed cache and provides search, pathfinding, security-focused reports, exports, and an interactive terminal interface without requiring Neo4j or a running BloodHound server.
ArtBlood also has an MCP server on board that enables AI agents to efficiently retrieve information about Active Directory.
[!IMPORTANT] ArtBlood is intended for authorized security assessment, defensive analysis, and lab use. BloodHound collections and ArtBlood reports can contain highly sensitive identity and infrastructure data. Keep them out of source control and protect them according to your organization's data-handling requirements.
Highlights
- Import one or more SharpHound JSON directories or ZIP archives.
- Inspect nodes, relationships, properties, and shortest attack paths.
- Find paths from owned principals to tier-zero targets.
- Report dangerous ACLs, Kerberoastable and AS-REP roastable users, sessions, local administrators, and AD CS ESC findings.
- Explore results in a keyboard- and mouse-driven terminal UI.
- Use AI to query data via MCP
- Run a native graph query DSL or a practical subset of Cypher.
- Generate Markdown assessment reports and BloodHound-style text reports.
- Merge new collections into an existing cache with
--append. - Search objects by name, SID, distinguished name, or object ID.
- Compare caches and export table, JSON, JSONL, CSV, Markdown, DOT, GraphML, or OpenGraph data where supported.
- Redact names or other identifying data from supported reports and exports.
Build and install
Download or clone the repository, then build the workspace:
cd ArtBlood
cargo build --workspace
Build an optimized binary:
cargo build --release --workspace
The resulting executable is:
- Linux/macOS:
target/release/abh - Windows:
target\release\abh.exe(not tested)
You can also install it into Cargo's binary directory:
cargo install --path crates/abh-cli
Quick start
Ingest SharpHound data into per-user cache at ~/.abh/cache:
abh ingest 20260725153725_bloodhound.zip
Inspect and analyze the imported graph:
abh doctor
abh stats --by-kind --by-edge-kind
abh search alice
abh path --from "ALICE@CORP.LOCAL" --to tier0
abh owned-to-tier0
abh dangerous-acls --format markdown
abh ui
Most commands use ~/.abh/cache when no cache path is provided. This gives every invocation by the same user one shared cache, regardless of the current working directory. Run abh --help or abh <command> --help for the complete option set.
Importing data
Import multiple inputs in one operation:
abh ingest first.zip second.zip --progress
Add new collections to an existing cache:
abh ingest latest.zip --append
Replace an existing cache without an interactive prompt:
abh ingest latest.zip --force
If the output cache already exists and neither --append nor --force is used, ArtBlood asks whether to append, rewrite, or quit when attached to an interactive terminal. Non-interactive callers must choose --append or --force explicitly. Pass --output <path> during ingestion, or a cache argument to commands that accept one, to override the shared cache.
Codex and MCP
ArtBlood includes a local STDIO MCP server so Codex can inspect and update one cache through structured tools. Register the default cache:
codex mcp add artblood -- abh mcp
Or bind the server to an explicit cache:
codex mcp add artblood -- abh mcp --cache /absolute/path/to/corp-cache
The equivalent user or trusted-project config.toml entry is:
[mcp_servers.artblood]
command = "abh"
args = ["mcp", "--cache", "/absolute/path/to/corp-cache"]
Run codex mcp list to verify the registration. Inside Codex, use /mcp to inspect the connected server and its tools.
The server exposes graph_stats, search_nodes, get_node, get_edge, query_graph, shortest_paths, reload_cache, and ingest. For example, ask Codex to search for a principal, run a native DSL or Cypher query, explain an attack path, or ingest several SharpHound directories with an explicit create, append, or replace mode. If another abh process changes the cache, ask Codex to call reload_cache.
Commands
| Command | Purpose |
|---|---|
ingest | Import BloodHound JSON/ZIP data into an indexed cache |
stats | Show graph totals and optional node/edge breakdowns |
search | Find objects by identity or name |
node | Show node details, properties, and relationships |
edge | Show relationship details and properties |
path | Find shortest paths between objects or selectors |
owned-to-tier0 | Find attack paths from owned objects to tier zero |
dangerous-acls | List high-risk ACL relationships |
kerberoast | List enabled Kerberoastable users |
asrep-roast | List enabled AS-REP roastable users |
sessions | List and filter user-session relationships |
local-admins | List and filter local-administrator relationships |
cert-esc | Report Active Directory Certificate Services ESC findings |
query | Run the native DSL or supported Cypher subset |
export | Export graph objects or queried paths |
diff | Compare two ArtBlood caches |
report | Generate a Markdown assessment report |
blood | Generate a BloodHound-style plain-text report |
mcp | Serve one cache to Codex and other local MCP clients |
ui | Open the interactive terminal interface |
doctor | Validate cache structure and integrity |
Querying
The native DSL provides concise selectors for nodes, relationships, and paths:
abh query 'nodes(kind=User, enabled=true, hasspn=true, limit=25)'
abh query 'nodes(kind=Computer, domaincontroller=true)'
abh query 'nodes(kind in [User,Computer], owned=true)'
abh query 'nodes(kind=User, description~="service account")'
abh query 'nodes(kind=User, logoncount>=10)'
abh query 'edges(kind in [GenericAll, WriteDacl, WriteOwner], limit=50)'
abh query 'edges(kind=MemberOf, from="ALICE@CORP.LOCAL")'
abh query 'path(from=owned(), to=tier0(), edges=attack, max_depth=8, limit=10)'
Native node predicates accept = for case-sensitive exact scalar matching, ~= for a case-insensitive substring match, and in [...] for node or relationship kind lists. The operators >, <, >=, and <= compare typed numbers and finite numeric strings numerically. Property names may refer to built-in identity fields, node flags, or any scalar attribute stored on the object. Path queries accept the all, attack, acl, membership, session, admin, cert, and azure relationship profiles.
tierzero and highvalue are effective classifications: recursive members of privileged groups are included, and Tier Zero principals are considered high value. The interactive object's corresponding detail fields and clickable filters use the same classification.
Domain Controller classification is likewise effective: ArtBlood recognizes the imported flag/property and membership in the built-in Domain Controllers groups, and uses that result consistently in queries, reports, and UI details.
ArtBlood also supports a focused Cypher subset for common graph-analysis tasks:
abh query --format table \
'MATCH (u:User) WHERE u.enabled = true RETURN u LIMIT 25'
abh query --format table \
'MATCH (c:Computer) WHERE c.smbsigning = false RETURN c LIMIT 100'
abh query --format table \
'MATCH (u:User) WHERE u.enabled = true AND (u.hasspn = true OR u.dontreqpreauth = true) RETURN u LIMIT 50'
abh query --format table \
'MATCH (u:User) WHERE u.description IS NOT NULL RETURN u.name, u.description'
abh query --format table \
'MATCH (u:User)-[r:MemberOf]->(g:Group) WHERE g.name CONTAINS "DOMAIN ADMINS" RETURN r'
abh query --format table \
'MATCH p=shortestPath((u:User)-[*1..5]->(g:Group)) WHERE u.name CONTAINS "ALICE" AND g.name CONTAINS "DOMAIN ADMINS" RETURN p LIMIT 5'
abh query --format table \
'MATCH p=(g:Group)-[r:Owns|WriteDacl|GenericAll]->(c:Computer) WHERE g.name STARTS WITH "DOMAIN ADMINS" RETURN p'
Supported Cypher functionality includes node-kind matching, fixed and variable-length relationships, shortestPath, typed node and relationship properties, IS NULL/IS NOT NULL, parenthesized AND/OR/NOT expressions, property projections, RETURN, and LIMIT. Exact string equality is case-sensitive; CONTAINS, STARTS WITH, and ENDS WITH are case-insensitive.
Interactive-UI custom queries are saved per user in ~/.abh/custom_queries.json. On first launch after upgrading, ArtBlood copies queries from the previous platform config location when the new file does not yet exist.
Reports and exports
Examples:
abh cert-esc --format markdown -o cert-report.md
abh report -o assessment.md --redact names
abh blood -o blood-report.txt
abh diff old.bhx new.bhx --format markdown --redact names
abh export --nodes --edges --format graphml -o graph.graphml
abh export --format opengraph -o graph.json
abh export accepts these formats:
table— a human-readable Markdown graph report.json— one JSON document containingnodesandedgesarrays.jsonl— one typed node or edge record per line.csv— node rows by default; use--edgesfor relationship rows.markdown(ormd) — a Markdown graph report.dot— Graphviz DOT.graphml— GraphML.opengraph(oropen-graph) — BloodHound OpenGraph JSON.
Without --nodes or --edges, graph exports include both, except CSV, which emits nodes because it has a single table schema. CSV rejects --nodes --edges.
Not every output format applies to every command. The command help identifies the accepted options, and ArtBlood reports an error for unsupported combinations.
In the Blood report, potential RBCD configuration findings are limited to computer targets and classified as direct attribute write, broad computer control, or indirect ACL takeover. The classification distinguishes an immediate property-write capability from permissions that require additional ACL or ownership changes.
Interactive terminal UI
Run abh with no subcommand or use ui like:
abh
abh ui
When the Query field is focused, searchable attribute labels in the right-hand object-information column are highlighted. Click a label to insert an exact filter containing that object's current raw value at the query cursor. Native nodes(...) queries receive comma-separated predicates; supported Cypher queries receive a variable-qualified WHERE predicate.
The UI provides clickable query, search, and path fields; autocomplete; pre-built searches; object and relationship details; directory mapping; and report rendering.
Pre-built searches that require graph-derived or alias-aware logic place a pb "Search title" command in the Query field. Re-running that command always executes the same search. Simpler searches expose their complete native query.
- Use the mouse wheel over a column to scroll it.
- Use PageUp and PageDown to scroll the center column by one visible page.
- Press
hfor in-application help. - Press
Ctrl+Zto return to the previous view. - Press
qto quit when no input field is focused.
Development
Run the same core checks used by CI:
cargo fmt --all -- --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace --locked
cargo build --release --workspace --locked
python scripts/check_sensitive_files.py --all
Workspace layout:
crates/
abh-schema Shared graph schema and object/relationship types
abh-graph In-memory graph model and indexing
abh-ingest SharpHound and OpenGraph ingestion
abh-cache Persistent indexed cache format
abh-algorithms Pathfinding and graph-analysis algorithms
abh-query Native DSL and supported Cypher parser/executor
abh-output Output formatters
abh-cli The abh command-line and terminal UI
License
ArtBlood is licensed under the GNU General Public License v3.0 only (GPL-3.0-only). See LICENSE.
Generated relationship-help content includes material adapted from BloodHound under the Apache License 2.0. See THIRD_PARTY_NOTICES.md for attribution.