anomalyco / anomalyco/opencode
[FEATURE]: Model-agnostic MCP tool search / deferred schema loading (works on OpenAI-style backends)
@jlongster is already working on this.
Since Sep 18, 2026.
- Dominant language
- TypeScript
- Stars
- 209k
- Forks
- 27.5k
- PR merge metrics
- PR metrics pending
Description
Enhancement
Add a config option (e.g. mcp.tool_search) that keeps MCP tool schemas out of the system-prompt prefix and exposes them through a single lightweight opencode-native search tool instead. When the model calls the search tool, opencode returns matching tool names/descriptions; on first real call to a discovered tool, its full schema is registered for the rest of the session.
Prior art / related issues
This has been requested before but is not implemented:
- #34873 proposed
mcp.tool_search(closed automatically for a missing title prefix, not because it shipped) - #23298 proposed Anthropic
defer_loadingpassthrough (closed as completed; the feature is absent ondev) - #45527 documents that absence and proposes wiring Anthropic's
defer_loading+tool_search_tool_* - #8625, #9461, #10090 (adjacent)
I am opening this separately because the previously proposed mechanism is Anthropic-specific and does not reach a large class of deployments (details below). This request is for a model-agnostic version.
Why the Anthropic defer_loading / tool_search_tool path is not sufficient
#45527 proposes surfacing Anthropic's defer_loading flag and the tool_search_tool_bm25_20251119 provider-defined tool. That works only when the backend speaks the Anthropic tool protocol natively. Many setups route Anthropic-format requests through a gateway that translates to an OpenAI-style responses API (e.g. a Fireworks-backed model behind a multi-protocol LLM gateway).
I verified this against a live gateway that accepts Anthropic requests on /anthropic/v1/messages but translates to an OpenAI responses call for a non-Anthropic model:
- Declaring
{"type": "tool_search_tool_bm25_20251119", ...}→400: tools[0].type must be 'function', 'web_search_preview' or 'code_interpreter'. The provider-defined search tool is rejected; the downstream API has no equivalent primitive. - A plain tool with
defer_loading: truealongside a non-deferred tool →200, works. Sodefer_loadingis accepted/passed through, but there is no search tool for the model to discover deferred tools with.
Net: for any model served via an OpenAI-style backend, defer_loading is accepted but useless without a search tool, and the Anthropic search tool cannot be declared. A mechanism that lives entirely inside opencode avoids this dependency.
Proposed design (model-agnostic)
- New config:
mcp.tool_search: "auto" | "always" | "off"(defaultofffor back-compat)."auto"could enable it when the configured MCP surface exceeds a size threshold. - When enabled, MCP tools are partitioned out of the visible tool set in
ToolRegistry.toolsand replaced by one ordinaryfunction-typed tool, e.g.search_tools({ query }). Because it is a normal function tool, every provider/backend accepts it, no provider-defined tool required. - The search index is already available in-process (
McpCatalog,Permission.visibleTools), so lookup is cheap and needs no new infrastructure. - On the first real call to a discovered MCP tool, opencode registers that tool's full schema into the active request path for the remainder of the session (and emits a plugin event like
mcp.tool.resolvedfor observability, as #34873 suggested). - The model is told the tool exists via the search tool's own description; newly-resolved tools can be surfaced back to the model through a tool result or a short system note.
This keeps the per-turn prefix small for sessions that touch only a handful of MCP tools, regardless of model or gateway, and preserves prompt-cache reuse.
Benefits
- Users with many/rarely-used MCP servers pay a large token tax on every request today; this removes it for the common case.
- Works uniformly across Anthropic, OpenAI-style, and gateway-translated backends, unlike the Anthropic-only
defer_loadingpath. - Backward compatible (opt-in, default
off).
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.