Discovers Claude Code capabilities — skills, agents, plugins, MCP servers, hooks — into typed Pydantic catalogs and an environment report.
uv add claude-code-capabilities
# or
pip install claude-code-capabilitiescapdisc # scan this machine, write discovery-report.json + .html
capdisc --oauth # also allow the interactive OAuth flow for HTTP MCP servers
# with a pre-registered client (forces a fresh MCP harvest)Both files are written to ~/.claude/capdisc/ by default. Configure paths and MCP auth via env
vars (CAPDISC_ prefix), a .env file, or ~/.claude/capdisc/config.json/config.yaml — see
DiscoverySettings in settings.py for every field.
Scan the machine into a typed catalog:
from pathlib import Path
from capdisc.discovery import scan_environment
from capdisc.scope import ScopeRoots
roots = ScopeRoots.discover(start=Path.cwd(), home_dir=Path.home())
catalog = scan_environment(roots)
for entry in catalog.entries:
... # CatalogSkill | CatalogTool | CatalogMcpServer | CatalogPluginBuild and persist the full environment report (what the CLI does):
from capdisc.report import build_report, write_report
report = build_report(oauth=False)
write_report(report) # -> ~/.claude/capdisc/discovery-report.{json,html}Inspect the on-disk scope inventory directly — every skill/agent/command/hook found, its precedence, and which ones actually win a collision:
from capdisc.scope import ScopeInventory, ScopeRoots
inventory = ScopeInventory.scan(ScopeRoots.discover(start=Path.cwd(), home_dir=Path.home()))
print(len(inventory.artifacts), "captured,", len(inventory.effective), "in effect")
for hooks in inventory.hook_configs:
... # HookConfig, unified from settings.json and component frontmatterRead the last harvested tool inventory (fast, no network — served from a 12h cache):
from capdisc.mcp_harvest import read_mcp_cache, cache_is_stale
servers = read_mcp_cache() # [] if there's no cache yet
if cache_is_stale():
... # trigger a refresh (below) before trusting thisForce a fresh harvest — connects to every configured server concurrently (bounded) and lists their real tool schemas:
from capdisc.mcp_harvest import refresh_mcp_cache
servers = refresh_mcp_cache(oauth=False) # also (re)writes the cache
for server in servers:
print(server.ref, [t.name for t in server.tools])Bearer/OAuth auth for HTTP servers is opt-in via settings, bound to an exact hostname so a same-named server elsewhere can never receive a credential meant for another:
export CAPDISC_MCP_BEARER_ENV='{"github": {"env": "GH_TOKEN", "host": "api.githubcopilot.com"}}'report.EnvironmentReport captures the full discovery harvest (scan roots, on-disk inventory, skills,
builtin tools, plugins with per-component token cost, MCP servers). mcp_harvest and mcp_catalog
enumerate connected MCP servers; plugin_catalog reads installed plugins; scope resolves which
roots to scan.
The package ships py.typed.
uv run pytest
uv run mypy src
uv run ruff check .