anomalyco / anomalyco/opencode

[FEATURE]: Let tool.definition omit a tool from the request, so plugins can self-manage their own schema cost per session

Open
#42,869 2 comments 0 reactions 1 assignee View on GitHub

@jlongster is already working on this.

Since Aug 16, 2026.

Dominant language
TypeScript
Stars
209k
Forks
27.5k
PR merge metrics
PR metrics pending

Description

Title: [FEATURE]: Let tool.definition omit a tool from the request, so plugins can self-manage their own schema cost per session

Type

Performance Optimization / Token Efficiency (plugin-registered tools, not MCP)

Description

There's a long history of MCP tool-schema-bloat requests here (#17482, #8277, #9350, #16206, #8625, #35376). All of them are about MCP servers. This is the same underlying problem — every registered tool's full schema goes into the request on every turn, whether or not it's used that turn — but on the plugin side, where there's a specific, small API gap blocking any fix.

Measured on my own setup: 178 of 214 registered tools (built-in + MCP + plugin) had zero invocations across 404 sessions, while still costing schema tokens on every request. Scoping the dead ones out per-agent (permission: deny) cut one agent's measured input tokens by 37.6% (126,643 → 78,983) with no loss of capability, since it's per-agent, not global, and doesn't cascade to subagents. That's a config-side workaround, though — it required knowing in advance which tools are unused, and any plugin author who wanted to make their own toolkit self-managing has no way to do it today.

Current API surface

Two hooks are relevant, and neither can express "don't send this tool this turn":

// dist/index.d.ts ~203 — receives no tool list at all
"chat.params"?: (input: {
    sessionID: string; agent: string; model: Model;
    provider: ProviderContext; message: UserMessage;
}, output: {
    temperature: number; topP: number; topK: number;
    maxOutputTokens: number | undefined; options: Record<string, any>;
}) => Promise<void>;

// dist/index.d.ts ~316 — can only REWRITE a tool's schema, not omit it,
// and per the source comment it's a v1 plugin-surface limitation:
// tool descriptions are registered once per process, so any preset routing
// (e.g. per-model) can't apply here either.
"tool.definition"?: (input: {
    toolID: string;
}, output: {
    description: string; parameters: any;
}) => Promise<void>;

@cortexkit/opencode-magic-context already builds a prompt_surface: "light" preset on top of tool.definition — it shrinks its own 5 tools' descriptions ~70% when enabled — but it's explicitly bounded to rewriting, and the plugin's own docs note the once-per-process registration as a known limitation. A toolkit plugin that registers dozens of tools (which is common — several plugins in an average install register 20-100+) has no equivalent lever at all today; the only escape hatch is the consuming user's config (permission/tools denies), not anything the plugin itself can decide.

Proposed change

Minimal, backward compatible: let tool.definition's output accept an omit: boolean (or equivalent) that drops the tool from that request's tools array entirely, decided per-call. That's enough for a plugin to implement its own "only expose what's relevant this turn" logic — using whatever heuristic it wants (recent tool history, input.toolID prefix grouping, a companion chat.params-visible signal, etc.) — without needing the user to hand-maintain a deny list, and without needing chat.params to carry the full tool list (a heavier change).

Why this is worth a fix, distinct from the MCP asks
  • It doesn't require solving MCP's protocol-level constraints — this is 100% opencode-side API surface, on hooks that already exist.
  • It benefits every large toolkit plugin at once, not just power users who know to hand-tune permission denies.
  • It's incremental on infrastructure that's already there: tool.definition already runs per-tool per-request; it just can't say "no."

Happy to test against a draft PR — I have a working reproduction setup (211 registered tools across ~15 plugins) I've been using to measure this.

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.