anomalyco / anomalyco/opencode

[FEATURE]: Model-agnostic MCP tool search / deferred schema loading (works on OpenAI-style backends)

Open
#49,645 2 comments 2 reactions 1 assignee View on GitHub

@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_loading passthrough (closed as completed; the feature is absent on dev)
  • #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: true alongside a non-deferred tool → 200, works. So defer_loading is 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" (default off for 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.tools and replaced by one ordinary function-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.resolved for 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_loading path.
  • Backward compatible (opt-in, default off).

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.