agent-capmap
Find out what your AI agents can actually do,
and which combinations of their tools an attacker could abuse.
Install · Quickstart · How it works · Policy · GitHub Action · Docs
Why
AI assistants such as Claude Desktop, Cursor, VS Code and Claude Code get their powers from MCP servers: read files, browse the web, send email, run shell commands. Each tool can look harmless on its own. The danger is usually the combination: an agent that can
| 1. Read private data | 2. Read attacker-written content | 3. Send data out |
|---|---|---|
| files, repos, email, databases | a web page, an issue, an email | email, HTTP requests, git push |
can be talked into leaking that data by a single poisoned page. That is the "lethal trifecta", and no single tool shows it.
agent-capmap inventories every MCP server and tool reachable by each agent, classifies what each tool can do, and applies policy-as-code rules to the combination of tools per agent. Findings come with evidence and can gate CI through SARIF and exit codes.
Status: alpha. All features below work. The classifier's accuracy has not been benchmarked yet, and the bundled labels are AI-reviewed; see Accuracy.
Highlights
| 🔎 Inventory | Claude Desktop, Cursor, VS Code, Claude Code and generic mcp.json. Secrets are redacted everywhere. |
| 🧰 Tools, prompts and resources | Listed read-only, never called, read or fetched. Poisoned descriptions are flagged. |
| 🏷️ Six-axis classification | An LLM only tags capabilities; every risk decision is deterministic code. |
| 📜 Policy as code | Eleven built-in rules, your own rules in YAML, and expiring waivers for accepted risks. |
| 🏃 Runtime discovery | Finds MCP servers that are running but declared in no config file. |
| 🧾 Rug-pull detection | Pin definitions in a baseline; see what a pull request changed in a PR comment. |
| 🛡️ CI-ready | Evidence for every finding, SARIF for code scanning, and exit codes for gating. |
| 🔌 Works without a key | 381 tools from 28 well-known servers are classified from bundled labels. |
Contents
- Install
- Quickstart
- Example output
- How it works
- Capability taxonomy · Policy
- CI and GitHub code scanning
- Accuracy · Limitations · Safety
- Documentation
Install
Requires Python 3.11+.
pipx install agent-capmap # or: uv tool install agent-capmap
Releases are built and published by GitHub Actions with PyPI trusted publishing, so each file on PyPI carries an attestation linking it to the workflow run that built it.
For a fully hash-pinned install, with the exact dependency versions CI tests, install from a clone instead:
git clone https://github.com/NKwolv/agent-capmap
cd agent-capmap
python -m venv .venv
. .venv/bin/activate # Windows PowerShell: .venv\Scripts\Activate.ps1
pip install --require-hashes -r requirements/runtime.lock
pip install --no-deps .
Locked-down Windows machines: if your organization's policy (Device Guard, AppLocker, Smart App Control) blocks
agentcapmap.exeorpipx.exe, run the tool through Python instead, which is the same program. If you installed withpip install agent-capmap, runpython -m agentcapmap scan --user. If you installed with pipx, the package lives in pipx's own environment, so plainpythonwill not find it: use that environment's interpreter (python -m pipx environment --value PIPX_LOCAL_VENVSshows the folder):<venvs>\agent-capmap\Scripts\python.exe -m agentcapmap scan --user. Do not try to bypass the policy; ask your administrator to allow the launcher if you want it.
Windows: if
pip installfails with "No such file or directory" deep insidesite-packages, the path is too long for Windows' 260-character limit. Clone to a short path (for exampleC:\src\agent-capmap) or enable long path support.
Quickstart (5 minutes, no API key)
# 1. See findings on a ready-made inventory of five example agents
# (from a clone, use examples/demo/inventory.json directly)
curl -fsSLO https://raw.githubusercontent.com/NKwolv/agent-capmap/main/examples/demo/inventory.json
agentcapmap evaluate inventory.json --format markdown
# 2. List the MCP servers configured on your own machine (reads files only)
agentcapmap scan --user
On Windows PowerShell, use curl.exe instead of curl.
Step 1 should report 2 critical, 2 high and 1 medium finding. Step 2 lists your servers with every secret redacted, without starting anything.
Example output
### 1. `CAP-001` | Critical
`Lethal trifecta: the agent can read private data, ingest attacker-controlled content,
and send data externally, so injected instructions can exfiltrate data.`
- **Agent:** `generic:fixtures/trifecta/mcp.json` at `fixtures/trifecta/mcp.json:3`
- **Tools:** `github/get_file_contents`, `github/list_issues`, `mailer/send_email`
| Server | Tool | Matched | Evidence |
|---|---|---|---|
| `github` | `get_file_contents` | `data_access=private_read` | `contents of a file from a private or public repository` |
| `github` | `list_issues` | `untrusted_input=true` | `including issues opened by anyone` |
| `mailer` | `send_email` | `egress=external` | `Send an email to any recipient address` |
(Abridged from the real output of step 1.)
How it works
config files ──► discover ──► enumerate ──► classify ──► policy ──► report
(read only) (initialize + (LLM tags (YAML (JSON, Markdown,
list calls) 6 axes) rules) SARIF, exit code)
- Discover MCP configs: Claude Desktop, Cursor, VS Code (
.vscode/mcp.json,settings.json), Claude Code (.mcp.json, and with--useryour~/.claude.jsonuser and per-project servers, including permission rules) and genericmcp.json. Secrets are redacted everywhere. - Enumerate (
--enumerate): start each server and ask only for what it offers: its tools, and its prompts and resources if it has them. Nothing is called, read or fetched. - Classify (
--classify): an LLM tags each tool on six axes and flags descriptions that try to manipulate the model. Results are cached and validated against a JSON schema. - Evaluate (
--evaluate): deterministic rules decide what is dangerous. The LLM never makes risk decisions. - Report: JSON, Markdown, or SARIF for GitHub code scanning;
--fail-onsets the exit code.
Full scan of your own setup (needs an API key)
export ANTHROPIC_API_KEY=<YOUR_API_KEY> # PowerShell: $env:ANTHROPIC_API_KEY = "..."
agentcapmap scan --user --enumerate --classify --evaluate --format markdown -o report.md
--enumerate runs the server commands in your configs: only use it on configs you
trust. To try the whole pipeline on two known servers first, see
examples/live-trifecta.
Prompts and resources
MCP servers also offer prompts and resources, and their descriptions are another place a
poisoned instruction can hide. When a server advertises them, --enumerate lists
them (prompts/list, resources/list, resources/templates/list): it never reads a
resource or gets a prompt. With --classify, each one that has any text is checked for
instructions aimed at the model (rule CAP-008), and baseline create pins them so a
later change is a rug pull (CAP-006). They add no capabilities: they are not tools.
Items with no description are skipped, at most 200 per server are sent to the classifier,
and anything not checked is reported under "not assessed".
Accept a finding on purpose (waivers)
When you have reviewed a finding and accept the risk, record that decision instead of
ignoring the finding. Copy its fingerprint from the JSON output into a waivers file
(example):
version: 1
waivers:
- fingerprint: 3f2a9c0b7d1e4a5c8b6d0e2f1a3c5b7d # from the finding
rule: CAP-001 # optional check
owner: platform-security
reason: Filesystem server limited to the sandbox directory; reviewed in SEC-1234.
expires: 2027-03-31 # at most a year ahead
agentcapmap evaluate inventory.json --waivers waivers.yaml --fail-on high
Waivers are deliberately strict: they match one finding exactly (no wildcards), need an owner, a reason and an end date, and stop applying after that date (the finding comes back and the waiver is reported). Waived findings leave the exit status and the counts but stay listed with their reason; a waiver that matches nothing is reported as stale. A broken waivers file is an error, never silently ignored.
A pull request can edit the waivers file, so keep it under CODEOWNERS. In the GitHub
Action, the PR comment compares against the base branch's waivers and lists any waiver the
PR adds under Newly waived, so a reviewer sees what was accepted.
Find servers that are running right now
Config files only show what is declared. --running also reads the process table and
reports MCP servers that are actually running, including ones that are in no config file:
pip install "agent-capmap[runtime]" # adds psutil, needed only for this
agentcapmap scan --user --running --evaluate --format markdown
A running server that matches a configured one is marked with its process id. One that
matches no scanned config is added under a runtime:<client> agent and reported by
CAP-010; one listening on a non-loopback address is reported by CAP-011. Use
--user so your per-user client configs count as "declared".
It only reads the current user's process list and listening sockets. It never starts,
connects to or probes anything, and servers found this way are never enumerated (that
would re-run a command taken from the process table). Detection is heuristic: it
recognizes common launch styles (npx, uvx, python -m, docker run, MCP-named
programs), so a custom server with an unrelated name can be missed.
Capability taxonomy
| Axis | Values | Question |
|---|---|---|
data_access |
none, private_read, secrets_read | What non-public data can it read? |
untrusted_input |
false, true | Does it return content strangers can write? |
egress |
none, internal, external | Can it send data somewhere an outsider can read? |
mutation |
none, reversible_write, destructive | What can it change or delete? |
execution |
none, sandboxed, host | Does it run code, and where? |
privilege |
none, identity_admin | Does it manage users or permissions? |
Definitions and edge-case rulings: docs/taxonomy.md.
Policy
The built-in policies/default.yaml has eleven rules:
| ID | Severity | Fires when an agent has |
|---|---|---|
| CAP-001 | 🔴 critical | private data + untrusted input + external egress (lethal trifecta) |
| CAP-002 | 🔴 critical | untrusted input + host code execution |
| CAP-003 | 🟠 high | a destructive or host-execution tool with no approval gate |
| CAP-004 | 🟠 high | secrets access + external egress |
| CAP-005 | 🟠 high | a remote server with no authentication exposing capabilities |
| CAP-006 | 🟠 high | tool, prompt or resource definitions that changed since the baseline (rug pull) |
| CAP-007 | 🟡 medium | a server not pinned to an exact version, or from an unvetted source |
| CAP-008 | 🟠 high | a tool, prompt or resource description that tries to instruct the model (poisoning) |
| CAP-009 | 🟡 medium | the same tool name on two servers (shadowing) |
| CAP-010 | 🟡 medium | an MCP server is running but is in no scanned config (scan --running) |
| CAP-011 | 🟠 high | an MCP server is listening on a non-loopback address (scan --running) |
Write your own rules in the same format and pass --policy my-policy.yaml:
- id: ACME-001
severity: high
when_server: {remote: true}
when_agent_has_any:
- privilege: identity_admin
message: Remote servers must not manage identities.
Conditions: when_agent_has_all, when_agent_has_any, when_server,
when_hash_changed, when_tool_name_shadowed. The format is defined by
schemas/policy.schema.json. Rug-pull detection:
agentcapmap baseline create inventory.json -o baseline.json # once, after review
agentcapmap evaluate new-inventory.json --baseline baseline.json
To see what changed between two runs (for example main versus a pull request), save
each evaluate output and compare them:
agentcapmap diff before.json after.json --format markdown
agentcapmap diff before.json after.json --fail-on high --fail-on-new-capability
diff lists new and resolved findings and capabilities an agent gained or lost.
--fail-on looks at new findings only, so existing, already-accepted findings do not
fail the build; --fail-on-new-capability fails when an agent gains any capability.
CI and GitHub code scanning
agentcapmap evaluate inventory.json --format sarif -o agentcapmap.sarif --fail-on high
Exit codes: 0 passed, 1 findings at or above --fail-on, 2 usage or input error.
On pull requests the action can also post one comment that shows only what the PR
changed (comment: "true"; see the action docs).
The repository is also a GitHub Action: see docs/github-action.md
and the example workflow. By default the Action reads
configs only, which is safe for pull requests from forks.
Accuracy
The classifier is evaluated against hand-labeled tools from real MCP servers (see
eval/). No accuracy numbers are published yet. The 381 labels
(28 servers) were drafted by one AI model and then reviewed by another AI model at the
maintainer's request. A person has so far reviewed only some of the files
(python eval/review.py list shows which); the rest are still AI-reviewed. A model grading
a model can overstate accuracy, so numbers will be quoted here only after a person has
reviewed the labels and the run is frozen (python eval/run_eval.py). The same labels
also power classification without an API key for these known tools; see
Limitations.
Limitations
- Descriptions, not behavior. Tools are classified by what their definitions say. A tool that lies about itself will be mis-tagged; agent-capmap never calls tools.
- Classifier errors. Tags can be wrong, especially for vague descriptions. Every tag carries a confidence and an evidence phrase; phrases not found in the definition are marked unverified.
- Approval gates are mostly invisible. Claude Code's permission settings are read (so its default "ask before each MCP call" counts as a gate), but most other clients do not record this, and CAP-003 treats "unknown" as "no gate" by default.
- Enumeration runs code. Starting servers executes the configured commands. A started server can also read its parent's environment on Linux.
- Coverage. Config formats evolve; Windsurf is not read yet. MCP servers that do not live in config files (Claude Code plugins, claude.ai connectors, IDE built-in servers, managed settings) are not seen. WebSocket servers are listed but not enumerated. Token scopes are not visible.
- Reference labels are AI-reviewed. For 381 tools from 28 well-known servers, the classifier answers from bundled labels (matched by exact definition hash) instead of calling a model, so no API key is needed. Those labels were reviewed by an AI model, and only some files by a person so far, and a wrong label is returned with full confidence; any change to a tool's definition falls back to the cache or the LLM. Treat them as a convenience.
- Runtime discovery is heuristic.
--runningrecognizes servers by their command line and misses ones with unrelated names; a process can also be named to look like a declared server. It lists what it sees and is not proof of absence. - Not assessed is not safe. Servers that could not be enumerated and tools that
could not be classified are listed under
not_assessed, never assumed safe.
Safety
Secrets from configs are redacted in all output and logs. Enumeration sends only
initialize and the read-only listings of tools, prompts and resources (never calling,
reading or fetching anything), with a minimal environment for launched servers, no
credential-forwarding redirects, and size limits on everything a server returns.
Reports render untrusted text inertly. See SECURITY.md and the
threat model.
Documentation
- Capability taxonomy
- Threat model: attacks covered, OWASP / MITRE ATLAS mapping
- GitHub Action
- Comparison with Snyk Agent Scan (mcp-scan)
- Examples · Evaluation · POC checklist
- Contributing · Security policy · Changelog
License
MIT. See LICENSE.
Metadata
Release files for agent-capmap 0.3.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| agent_capmap-0.3.1.tar.gz | 778.2 kB | With provenance | Details for agent_capmap-0.3.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| agent_capmap-0.3.1-py3-none-any.whl | Python 3 | none | any | Details for agent_capmap-0.3.1-py3-none-any.whl |
Total release size: 916.0 kB
Release files / agent_capmap-0.3.1.tar.gz
| Download URL | agent_capmap-0.3.1.tar.gz |
|---|---|
| Size | 778.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
924eed7d810e0ab4dd49f866fce9ba4a1db13aab3f4fa1c4d049d863cf87b23a
|
|
BLAKE2b-256 checksum How to use checksums |
31941869a302957a98a75ab36215d7eaf3fea28b3d3371c2816abbf3abbff633
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 10, 2026.
Transparency logRelease files / agent_capmap-0.3.1-py3-none-any.whl
| Download URL | agent_capmap-0.3.1-py3-none-any.whl |
|---|---|
| Size | 137.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d8ee02a25467d57779bc05e9826ed112d4ba8c033d11ef4babd7433b0bb64648
|
|
BLAKE2b-256 checksum How to use checksums |
43c462fab51e47ecae9bb143ee92a6c88d266d59ada6a97074ee12b9f78e377f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 10, 2026.
Transparency logSecurity for agent-capmap 0.3.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for agent_capmap-0.3.1.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 10, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.