anomalyco / anomalyco/opencode
[FEATURE]: Let tool.definition omit a tool from the request, so plugins can self-manage their own schema cost per session
@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
permissiondenies. - It's incremental on infrastructure that's already there:
tool.definitionalready 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
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.