feat(mcp): adaptive tool retrieval (relevance-gated MCP)#50
Conversation
Design for replacing all-MCP-tools-every-request (~95 tools, 41k tokens, proven cause of empty-array tool calls) with relevance-gated injection: local MiniLM embedding, per-session base set (cap K + threshold tau), on-demand find_tools(query) meta-tool, native tools always-on.
Generic 'retry with complete response' let the model repeat an empty required array; the message now explicitly names the empty-array mistake and instructs to re-issue with the value populated.
There was a problem hiding this comment.
Pull request overview
Replaces the "send all ~95 MCP tool schemas every request" behavior with relevance-gated injection. MCP tool specs now carry a contextRequirements gate keyed off a session-scoped ActiveMcpToolSet, which is seeded on task start/resume from the first user prompt via a local MiniLM embedder (transformers.js) and grown on demand via a new always-on find_tools native tool. Includes fail-safe degradation, on-disk vector cache, CLI tuning flags, and a sharper missing-parameter error message.
Changes:
- New
src/core/mcp/retrieval/module:cosine,Embedder,ToolVectorIndex,ActiveMcpToolSet,config,sessionplus unit tests. - New
find_toolsnative tool (spec + handler + enum + registration);mcpToolToSpecgated viactx.activeMcpTools; seed/clear hooks inTask.startTask/resumeTaskFromHistory/abortTask; subagent + ApiRequestHandler propagate the snapshot. - Pinned
@huggingface/transformers@3.3.3(with onnxruntime/sharp transitive deps), new--mcp-top-k/--mcp-thresholdCLI flags, esbuild externals for native bindings, sharpermissingToolParameterError, and design/plan docs.
Reviewed changes
Copilot reviewed 34 out of 35 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| src/core/mcp/retrieval/* | New retrieval module (cosine, embedder, index, active set, config, session) + tests |
| src/core/mcp/bootstrap.ts | Adds contextRequirements gate on MCP specs and bootstraps embedder/index/active-set with fail-safe |
| src/core/task/index.ts | Seeds active set on start/resume; clears on abort; first-user-text extraction helper |
| src/core/task/ApiRequestHandler.ts | Threads activeMcpTools snapshot into SystemPromptContext |
| src/core/task/tools/subagent/SubagentRunner.ts | Subagent inherits parent's active set snapshot |
| src/core/task/tools/handlers/FindToolsToolHandler.ts (+test) | New handler invoking expand and reporting activated tools |
| src/core/task/tools/ToolExecutorCoordinator.ts | Registers FindToolsToolHandler |
| src/core/prompts/system-prompt/{types.ts,tools/find_tools.ts,tools/init.ts} | Adds context field, new spec, registration |
| src/core/prompts/system-prompt/tests/snapshots/*.snap | Snapshot updates for find_tools across providers |
| src/core/prompts/responses.ts | Sharper missing/empty-required-param message + minor formatting |
| src/shared/tools.ts | Adds FIND_TOOLS enum member |
| cli/src/index.ts | New --mcp-top-k / --mcp-threshold flags on both commands |
| cli/esbuild.mts | Marks @huggingface/transformers and onnxruntime-node as externals |
| package.json / package-lock.json | Pin @huggingface/transformers@3.3.3 (+ transitive sharp/onnxruntime) |
| docs/superpowers/{specs,plans}/2026-06-01-mcp-adaptive-retrieval-*.md | Design + implementation plan |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Tech-debt (c) — sharp/libvips duplicate: investigated, deferred to the dependency-mirroring stepUpdate to the caveat in the description (the earlier "consider
|
Follow-up on the two merge gates (2026-06-02)(2) Worker "roles must alternate" 400 — diagnosed + validated.
(1) Supply-chain mirror — prepared for HITL (per policy, not auto-executed).
Both gates now have a clear, low-risk path to closure. |
Mirror Ailiance-fr/all-MiniLM-L6-v2 created from upstream Xenova snapshot (sha 751bff37 -> mirror 5cbc3683). npm transformers@3.3.3 pin-only per org strategy (no vendor). Embedder verified loading from the mirror.
Problem
ISAAC sends every registered tool schema on every request. With the default plugin MCP set loaded that is ~95 tools (~41k tokens/turn). Measured: at 95 tools the worker (Qwen3-Coder-30B Q4) intermittently streams a well-formed but empty required array (
read_file {"paths":[]}) → validation fails → retry loop. At ~25 tools: 0 empty-array events. Tool-list bloat is the proven primary cause (and the dominant per-turn latency driver).Approach
Replace "inject all ~70 MCP tools every request" with relevance-gated injection, reusing the registry's existing
contextRequirements(ctx)=>booleanfilter (no new mechanism):contextRequirements: ctx => ctx.activeMcpTools === undefined || ctx.activeMcpTools.has(name).ActiveMcpToolSetis seeded from the first user prompt (cosine top-K over local MiniLM embeddings —@huggingface/transformers, all-MiniLM-L6-v2 ONNX — cap K=8, threshold τ=0.3; the base set may be empty) and grown on demand by a new always-onfind_tools(query)native tool.~/.dirac/mcp-tool-vectors.json).--no-mcpstays fully off;--mcp a,bscopes the candidate pool; new--mcp-top-k/--mcp-thresholdtuning flags.Also includes a sharper corrective message on missing/empty required params (independent guard).
Evidence
@huggingface/transformers@3.3.3(pinned) + the all-MiniLM-L6-v2 ONNX weights must be mirrored into theailianceorg before merge per policy. Runtime must load from the vendored/cached path, not the public HF CDN.transformers.jspulls its own@img/sharp-libvips(~25 MB native; duplicate-lib warning, benign for text feature-extraction — considernpm dedupe).Spec:
docs/superpowers/specs/2026-06-01-mcp-adaptive-retrieval-design.md· Plan:docs/superpowers/plans/2026-06-01-mcp-adaptive-retrieval.md🤖 Generated with Claude Code