Skip to content

Let an mcp block name the arguments the model may write - #106

Open
haruotsu wants to merge 3 commits into
mcp-paramsfrom
mcp-only
Open

haruotsu wants to merge 3 commits into
mcp-paramsfrom
mcp-only

Conversation

@haruotsu

@haruotsu haruotsu commented Nov 10, 2026 •

Copy link
Copy Markdown
Collaborator

Stacked on #105; review that one first.

Why

params fixes one argument, but the tool keeps every other argument it takes, and some of them can widen what the fixed one bounds. A server's schemas are also listed while the agent runs, not packed, so an argument the server adds later would reach the model without anyone declaring it.

An openapi: block answers this with only, which names what the model may write so that the description growing fails safe. This brings the same to mcp: blocks.

What changes

  • only on an mcp: block, keyed by tool name, listing the arguments the model may write:

    params:
      search:
        scope: {value: team-handbook}
    only:
      search: [query]
  • Every other argument is taken out of the inputSchema the model is shown (properties and required) and dropped from each call even when the model writes it. A params value still rides.

  • Names are top-level arguments, taken literally. openapi:'s dotted paths into a body are not carried over; nothing has needed them for MCP tools.

  • validate refuses an only tool name outside allow, only without allow (same reasoning as params), and an argument that is both listed in only and fixed by params, as for openapi:.

  • Drift. An argument only lists that the listed schema does not declare is logged, and the tool is still offered: the miss opens nothing up, the model just cannot write what the declaration meant it to. A fixed argument the schema does not declare still keeps the tool away, as in the previous PR. So does an argument the schema requires that only does not list and params does not fix: every call would go out without it and be refused. An openapi: block refuses the same declaration in validate.

  • The previous PR's PinnedMcpTool becomes NarrowedMcpTool, holding both the fixed values and the list.

  • README explains why fixing one argument is not enough on its own, and how only relates to params.

Compatibility

Additive. Blocks without only behave as before.

Testing

  • Runtime: unlisted arguments are gone from the declaration's properties and required list; a listed argument the server does not declare is logged once and the tool still offered; a tool whose required argument is neither listed nor fixed is not offered, and one whose required argument is fixed is; the build refuses an only name outside allow.
  • End to end, against the test MCP server: an argument only leaves out is not sent even when the model writes it (the server answers with its own default), and a params value is sent although only does not list it.
  • Validate: only names outside allow, only without allow, and an argument both listed and fixed are refused.
  • Schema: a list of names passes; an empty list, a bare string, an empty name and a repeated name are refused.
  • pytest, ruff check, ruff format --check and mypy pass locally.

params fixes one argument, but a tool keeps every other argument it takes,
and some of them can widen what the fixed one bounds. A server's schemas
are listed while the agent runs, so an argument it adds later would reach
the model without anyone declaring it.

only names the arguments the model may write, by tool out of allow, as it
does for an openapi block. The rest are taken out of the schema the model
is shown and dropped from each call even when the model writes them; a
params value still rides. validate refuses an argument that is both
listed and fixed, and only, like params, needs allow to hold its tool
names against.

A listed argument the server does not declare is logged and the tool is
still offered, since the miss opens nothing up. A fixed one it does not
declare still keeps the tool away.

🤖 Generated with Claude Code
# Conflicts:
#	src/gete/runtime/mcp.py
When only left out an argument the server's schema requires, and params
did not fix it, the tool was offered with the argument dropped from its
schema. Every call then went out without it, and the server refused each
one, while the model kept being shown a tool it could never use. An
openapi block refuses the same declaration in validate; an mcp block can
only see the schema once the tools are listed, so that is where the tool
is now kept away, with a warning that names the tool and the argument.

The warning that only names an argument the server does not declare now
goes through the same once-per-toolset path as the others, since it would
otherwise repeat on every turn as well.

🤖 Generated with Claude Code
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant