Install
$ agentstack add skill-arasz-ai-badger-mcp-index ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
MCP Tool Index
Prerequisites
The index itself is JSON — no dependency needed to read, tag, intent, or list it. PyYAML is only needed to read a project's not-yet-migrated legacy mcp-tools.yaml:
python3 -m pip install pyyaml # also in $AI_BADGER/engine/requirements.txt
Without it, a legacy-YAML-only project falls back to a stricter built-in parser and, if that can't safely read the file, refuses with a hint rather than a traceback (see migrate below).
Manage .ai-badger/mcp-tools.json — a machine-readable index that maps every MCP server tool to tags (for filtering) and intent (for semantic matching). The index feeds the ai_badger_hooks.py plugin's pre_llm_call hook, which injects relevant tool recommendations into every LLM turn.
Overview
MCP servers expose 40+ tools per server. Agents scan ALL tool definitions in the system prompt, wasting tokens and sometimes picking the wrong tool (e.g., search_text when search_in_files_by_text is faster). The index solves this by:
- Tagging each tool with category labels (
[build],[database, sql],[diagnostic]) - Intent description for semantic disambiguation ("Compile the solution" vs "List project run configs")
- Hook-driven recommendation — the
pre_llm_callhook loads the index, extracts domain keywords from the user's message, and injects top-N matching tools as a context hint
Tags and intents come from three places, in descending authority — and each entry records which one spoke, in an origin field:
| origin | source | survives update? | |---|---|---| | manual | you, via mcp-index tag / mcp-index intent | yes — a human outranks both | | catalog | features//mcp//tools.json in the framework | refreshed from the catalog | | heuristic | _auto_tags guessing from the tool name | replaced as soon as the catalog covers the tool |
The catalog is a curation library, not a completeness claim: it applies to a server however that server arrived (project .mcp.json, user-global config, a plugin, a cloud connector), and the heuristics are the last resort for the servers it does not know.
When to Use
- After
hermes mcp add— runmcp-index updateto index new tools - Before complex multi-tool tasks — run
mcp-index validateto ensure the index is complete - When the agent picks the wrong tool — run
mcp-index tagto fix tagging - After removing MCP servers — run
mcp-index updateto mark stale tools
When NOT to Use
- A one-off tool lookup — read the index JSON (
.ai-badger/mcp-tools.json) directly - Writing a brand-new MCP server — use
hermes-mcp-setup - No MCP servers in the project — there is nothing to index
- A wrong-tool call that is a one-off — tag it, don't re-architect
Tag Taxonomy
Tags come from a closed set in features/common/mcp-tags.json:
| Category | Tags | |---|---| | Language | csharp, typescript, javascript, python, sql, css, html | | Action | navigation, diagnostic, build, run, refactoring, search, read, write, terminal | | Domain | database, tracing, opentelemetry, browser, dotnet, semantic, files | | Meta | batch, slow, unsafe |
Tools auto-tagged as [general] need manual curation.
Commands
init — create the index
python3 .ai-badger/skills/mcp-index/scripts/mcp_index.py init --target
python3 .ai-badger/skills/mcp-index/scripts/mcp_index.py init --target --host hermes
Asks the host CLIs for their MCP servers (see Where the server list comes from below), describes each tool from the catalog where it can and by name heuristics otherwise, seeds a server the listing named without tool detail from the catalog (see update), records each server's status, and writes .ai-badger/mcp-tools.json. Prints which listing answered and which sources were skipped, then how many tools were tagged as general and which servers reported no tools.
Completion criterion: .ai-badger/mcp-tools.json exists with all current MCP tools indexed.
update — sync index with current MCP state
python3 .ai-badger/skills/mcp-index/scripts/mcp_index.py update --target
Adds new tools, marks vanished ones with status: removed (preserving their curation), adds new MCP servers, and restates every server's status. Preserves manually-set tags and intents on existing tools; a tool the catalog describes is re-described from it unless origin is manual, and the tools that changed are printed by name. Takes --host like init.
A listing that carries no tool detail at all (every source but hermes mcp list --json) cannot tell "this server is gone" from "this is another host's listing", so a source it does not name is left untouched — same status, same tools — and named in the output. Only a listing that carries tools can move a source to absent and its tools to removed.
A server such a listing does name is seeded from the mcp catalog: the catalog stands in for a host that declined to enumerate, so a curated server is not stranded with tools: {}. The seed is a floor, never an override — an existing entry wins whatever its origin, a removed tool stays removed, an uncatalogued server stays empty, and a listing that carries tool detail is taken as the whole truth even when it reports none.
Completion criterion: All current MCP tools appear in the index; removed tools have status: removed.
validate — check index quality
python3 .ai-badger/skills/mcp-index/scripts/mcp_index.py validate --target
Fails (exit code 1) if any tool has [general] tags, empty tags, missing intent, or invalid tags.
Completion criterion: Exit 0 with "OK: N tool(s) validated".
tag — set tags for a tool
python3 .ai-badger/skills/mcp-index/scripts/mcp_index.py tag rider:search_symbol semantic search --target
Validates tags against the taxonomy. Rejects unknown tags.
Completion criterion: mcp-index list shows the tool with the new tags.
intent — set intent for a tool
python3 .ai-badger/skills/mcp-index/scripts/mcp_index.py intent rider:get_file_problems "Check a file for Rider code analysis errors and warnings" --target
Requires ≥10 characters. Use a concise one-sentence description that would help an agent pick this tool from a list of candidates.
Completion criterion: mcp-index list shows the tool with the new intent.
list — display tools
python3 .ai-badger/skills/mcp-index/scripts/mcp_index.py list --target
python3 .ai-badger/skills/mcp-index/scripts/mcp_index.py list --tag diagnostic --target
python3 .ai-badger/skills/mcp-index/scripts/mcp_index.py list --untagged --target
Completion criterion: All matching tools are displayed with server, tags, and intent.
migrate — one-shot legacy YAML to JSON conversion
python3 .ai-badger/skills/mcp-index/scripts/mcp_index.py migrate --target
Converts a legacy .ai-badger/mcp-tools.yaml to .ai-badger/mcp-tools.json, preserving every curated tag and intent. A no-op (exit 0) if the project already has mcp-tools.json. Any other write command (init/update/tag/intent) migrates a legacy file the same way as a side effect — migrate exists for a project that only wants the conversion, without also running init/update against a live MCP source. The old file is renamed to mcp-tools.yaml.migrated, never deleted.
If PyYAML is absent and the legacy file falls outside the built-in parser's verified subset, migrate refuses rather than risk a silently wrong conversion, and prints two remedies: install PyYAML and re-run, or regenerate via mcp-index init --from-json (which loses curated tags and intents — stated so the cost is explicit before choosing it).
Completion criterion: .ai-badger/mcp-tools.json exists with the same tools, tags, and intents the legacy file had; .ai-badger/mcp-tools.yaml.migrated exists.
Where the server list comes from
hermes mcp list --json — the source this skill was built on — no longer exists: the installed hermes answers error: unrecognized arguments: --json (measured 2026-07, issue #188). init and update therefore ask three sources in order and take the first that lists a server:
| order | source | what it carries | |---|---|---| | 1 | hermes mcp list --json | server names and their tools — the only listing that can | | 2 | claude mcp list | every server, plus a reachability phrase per server; no tools. Health-checks each server first (~14s for 17) | | 3 | hermes mcp list | server names and an enabled flag, from the text table; no tools |
--host hermes or --host claude restricts the chain to one CLI — use it when the other is slow, noisy, or listing the wrong project's servers. --from-json skips the hosts entirely and reads a saved hermes mcp list --json document.
--discover — ask each server for its own tools
No remaining listing carries tool names, but hermes mcp test does. Pass --discover to init or update and every server the listing left unenumerated is asked directly:
python3 .ai-badger/skills/mcp-index/scripts/mcp_index.py init --target --discover
It is opt-in because it costs one connection per server (measured: 11 servers, ~20s, 128 tools recovered from a listing that carried none). A server hermes does not have in its own config — a plugin- or connector-provided one — cannot be tested; it keeps tools_known False, is named in the output, and falls back to the catalog seed. hermes mcp test exits 0 even when it fails, so only its printed Tools discovered block is treated as an answer.
If no source answers, both commands refuse and print what each one said — a missing CLI, a non-zero exit with its error line, or an empty listing. They never write a half-index.
> Status meanings: read references/status.md if update reports a status other than ok (or when a silent server needs explaining).
> Auto-tagging rules: read references/heuristics.md when a tool came back [general] and you are deciding whether to curate it or extend the catalog.
Gotchas
- Auto-tagging covers only ~60% of tools. Expect 10-20 tools tagged as
[general]afterinit. Curate them withmcp-index tag, or — better, if the server is worth describing for every project — add itstools.jsonto the framework's mcp catalog. - The first
updateafter upgrading rewrites heuristic tags. Any tool the catalog describes gets the curated tags and intent, because an entry with noorigincannot be told apart from a guess. Tools curated withmcp-index tag/intentfrom now on are markedmanualand left alone. - Index goes stale after adding MCP servers. Run
mcp-index updateafter everyhermes mcp addorhermes mcp remove. - Tags aren't free-form. Use only tags from the taxonomy.
mcp-index tagrejects unknown tags. - Intent field is for disambiguation, not documentation. A 10-30 word sentence beats a paragraph. Write it to answer: "why would I pick this tool over a sibling with the same tags?"
- The
listfilter uses substring matching on tool names. Avoid naming tools with names that are substrings of each other in tests. --targetis required. The script does not default to.— always pass--target.- The two hosts name the same server differently.
claude mcp listdecorates a server with
where it routes it from — plugin:: for a plugin-provided server, claude.ai for a connector — where hermes mcp list prints the bare name. A source keeps whatever the host called it, so switching --host adds sources rather than renaming them, and the sources the new listing cannot speak for are left untouched rather than removed. The mcp catalog does reach through the decoration: a listing name is matched against the decorated name first and the undecorated server second, so plugin:ai-badger:code-review-graph picks up features/common/mcp/code-review-graph/tools.json. Curating a specific plugin's copy is possible — set "server": "plugin::" in its tools.json and the exact key wins — because two plugins may ship same-named servers, which is also why the bare name is never rewritten.
Verification Checklist
- [ ]
mcp-index initproduces.ai-badger/mcp-tools.jsonwith all current MCP servers - [ ]
mcp-index validateexits 0 - [ ] No tools are tagged
[general](all manually curated) - [ ] Every tool has a meaningful intent (≥10 chars, describes what it does)
- [ ]
mcp-index listshows all expected tools - [ ] All tests pass:
python3 -m pytest tests/test_mcp_index.py -q
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: Arasz
- Source: Arasz/ai-badger
- License: MIT
- Homepage: https://github.com/Arasz/ai-badger
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.