Inventory discovers which MCP servers are configured on your local machine by reading client config files (Cursor, Claude Desktop, VS Code, Windsurf). It answers: what servers are installed, how are they launched, and do any tool names collide?
Want to scan a specific server? Use
mcts scaninstead. Inventory is for auditing your local setup.
If you use Cursor, Claude Desktop, or VS Code with MCP servers, those apps store config files listing which servers are installed and how to launch them. MCTS reads these configs and shows you:
- Which MCP servers are configured
- How each server is launched (command, args, environment)
- Whether any tool names appear on multiple servers (called tool shadowing — a common agent confusion risk)
With --scan, MCTS also runs a lightweight security scan on each server's entrypoint.
With --skills, MCTS discovers SKILL.md files under well-known agent skill directories (for example .cursor/skills) and project-local paths such as skills/ and agent/skills.
# Include repo-local skills/ without symlinks
mcts inventory --skills
# Additional skills tree
mcts inventory --skills --skills-dir ./skills --skills-dir ./custom-skillsFor full prompt/instruction analysis on markdown in your repository (not only MCP prompts/list):
mcts scan . --surfaces prompt,instruction
mcts scan ./skills --surfaces prompt,instruction
mcts scan . --instruction-file src/agent/system_prompt.md
mcts scan . --instruction-glob 'skills/**/SKILL.md'# List configured servers (terminal output)
mcts inventory
# Static-scan each entrypoint + export JSON
mcts inventory --scan -o inventory.json
# Scan agent SKILL.md files for injection/exfil patterns
mcts inventory --skills -o inventory.json
# Full security scan on every discovered server (GAP-008)
mcts inventory --scan-all -o inventory-scan-all.json
# Toxic flow analysis W015–W020 across servers
mcts inventory --full-toxic-flows
# Theme for saved-notice styling only
mcts inventory --theme minimal -o inventory.json| Code | When |
|---|---|
| 0 | Success; no critical/high shadow findings |
| 1 | Cross-server shadow findings with critical or high severity |
| 2 | Theme/usage error |
Platform-specific paths are defined in CLIENT_PATHS (inventory/discoverers.py). Only existing files are read.
| Client | Config path |
|---|---|
| Cursor | ~/.cursor/mcp.json |
| VS Code | ~/.vscode/mcp.json, ~/Library/Application Support/Code/User/settings.json |
| Claude Desktop | ~/Library/Application Support/Claude/claude_desktop_config.json |
| Windsurf | ~/.codeium/windsurf/mcp_config.json |
| Client | Config path |
|---|---|
| Cursor | ~/.cursor/mcp.json |
| VS Code | ~/.vscode/mcp.json, ~/.config/Code/User/settings.json |
| Windsurf | ~/.codeium/windsurf/mcp_config.json |
| Client | Config path |
|---|---|
| Cursor | ~/.cursor/mcp.json |
| VS Code | ~/.vscode/mcp.json, ~/AppData/Roaming/Code/User/settings.json |
| Claude Desktop | ~/AppData/Roaming/Claude/claude_desktop_config.json |
| Windsurf | ~/.codeium/windsurf/mcp_config.json |
Client name is inferred from the path string (cursor, claude, vscode, windsurf).
MCTS reads JSON config files and extracts mcpServers entries:
{
"mcpServers": {
"my-server": {
"command": "uv",
"args": ["run", "server.py"],
"env": { "API_KEY": "..." }
}
}
}For VS Code, it also supports mcp.servers nested under settings JSON when the mcp key is present.
Each entry becomes an InventoryEntry:
| Field | Description |
|---|---|
client |
cursor, claude, vscode, windsurf |
server_name |
Key in mcpServers |
command |
Launch binary |
args |
Argument list |
env_keys |
Environment variable names only (values not exported) |
config_path |
Absolute path to source file |
tools |
Populated when --scan is used |
MCP inventory — 2 config file(s)
• cursor
• claude
[cursor] my-server (12 tools) — /Users/you/.cursor/mcp.json
[claude] filesystem — /Users/you/Library/.../claude_desktop_config.json
Cross-server shadowing: 1 finding(s)
• Tool name collision: read_file
{
"clients_scanned": ["cursor", "claude"],
"config_files_found": 2,
"entries": [
{
"client": "cursor",
"server_name": "my-server",
"command": "uv",
"args": ["run", "server.py"],
"config_path": "/Users/you/.cursor/mcp.json",
"env_keys": ["API_KEY"],
"tools": ["read_file", "write_file", "delete_all_users"]
}
],
"shadow_findings": [
{
"title": "Tool name collision: read_file",
"severity": "high",
"technique_id": "MCTS-T-1008"
}
]
}When --scan is set, inventory/runner.py resolves each entrypoint (preferring .py paths from args) and runs a lightweight static Scanner to collect tool names. This does not run the full analyzer suite — it is optimized for inventory breadth.
Non-Python entrypoints (Node, Go binaries) may not resolve automatically. Use explicit mcts scan with --command for those servers.
CrossServerAnalyzer.analyze_inventory() builds a map of tool name → list of (client, server_name) pairs. When the same name appears on different servers:
- Finding severity scales with collision count and client diversity
- Technique ID: MCTS-T-1008 (Cross-Server Tool Shadowing)
- Mitigations reference agent routing and namespacing guidance
Why it matters: LLM agents often select tools by name only. Two servers both exposing read_file may cause the agent to invoke the wrong handler — potentially crossing trust boundaries.
During mcts scan, the same analyzer can run when inventory context is wired into Scanner (future: automatic inventory hook).
After inventory, run a full security scan:
# Static scan from config
mcts scan . --config ~/.cursor/mcp.json --server my-server
# Live probe from config
mcts scan . --config ~/.cursor/mcp.json --server my-server \
--live --i-understand-live-riskSee Live Scanning.
| Limitation | Detail |
|---|---|
| Local configs only | No remote fleet or enterprise MDM discovery |
| Heuristic entrypoint resolution | --scan may miss non-Python launch patterns |
| Four clients in original inventory | Expanded to 12+ agent clients — see inventory.md |
| No secret values in export | Only env_keys names — not values |
| Ephemeral CI runners | GitHub-hosted runners typically have no user MCP configs |
Planned inventory and discovery gaps (GAP-095–105, GAP-218–231):
| Capability | Status | Phase | GAP |
|---|---|---|---|
| 12+ agent clients (Gemini, Codex, OpenClaw, Amazon Q…) | Shipped | 3 | GAP-095 |
VS Code workspaceStorage / profiles |
Missing | 3 | GAP-096 |
| Claude Code plugin + project-level globs | Missing | 3 | GAP-097 |
Skills dirs (.cursor/skills, etc.) |
Shipped | 2 | GAP-099 |
mcts inventory --skills |
Shipped | 2 | GAP-029 |
mcts inventory --scan-all |
Shipped | 2 | GAP-008 |
| Machine-wide scan without explicit target | Shipped | 2 | GAP-006 |
--scan-all-users multi-home |
Missing | 3 | GAP-021 |
| macOS codesign trust on stdio binaries | Missing | 3 | GAP-101 |
| WSL profile merge | Missing | 3 | GAP-102 |
| Shadow MCP discovery + allowlist | Missing | 2 | GAP-231 |
| CycloneDX AI-BOM export | Missing | 2–3 | GAP-106 |
| Fleet asset prefix / enterprise merge | Missing | 4 | GAP-116 |
Full list: Feature Expansion Plan — Discovery.
Inventory reads configuration files that may reference secrets via environment variables. MCTS does not print env values in inventory output. Treat exported JSON like any config audit artifact.