fix(fastmcp): refuse an undeclared tool argument instead of dropping it - #106
Merged
Merged
Conversation
Upstream to_fastmcp builds its validation model from tool_call_schema's fields alone, and ArgModelBase sets no extra policy — so pydantic's default applies and an argument the tool does not declare is discarded before the tool is called, with nothing said to anyone. Mark that model extra="forbid", and stamp additionalProperties: false on the published input schema so a client is told the rule rather than surprised by it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SqYYX2DusBMsnR58iDro1Y
ciaransweet
force-pushed
the
fix/forbid-undeclared-tool-arguments
branch
from
August 26, 2026 12:55
99b87c8 to
510431a
Compare
ciaransweet
pushed a commit
that referenced
this pull request
Aug 26, 2026
🤖 I have created a release *beep* *boop* --- ## [0.8.1](mcp-toolsets-runtime-v0.8.0...mcp-toolsets-runtime-v0.8.1) (2026-08-26) ### Bug Fixes * **fastmcp:** refuse an undeclared tool argument instead of dropping it ([#106](#106)) ([82e6bf7](82e6bf7)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: ds-release-bot[bot] <116609932+ds-release-bot[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
An argument a tool does not declare is currently accepted, discarded, and never
mentioned. The tool then runs as though it had never been asked for.
langchain_mcp_adapters.to_fastmcppublishes the input schema fromtool_call_schema, but validates against a separate model built from thatschema's fields alone:
ArgModelBasesets no extra policy, so pydantic's default applies and theextras are stripped before the tool is called.
That is a silent wrong answer rather than a loud failure: the call succeeds, the
result looks ordinary, and the one thing that would explain it — that an
argument went missing — is the one thing nobody is told. It is easy to hit
wherever a tool renames or reshapes a parameter that a model has seen named
another way somewhere else; the model sends the name it saw, and gets a
confident answer to a question it did not ask.
Two lines, both needed:
extra="forbid"onfn_metadata.arg_model— the enforcement.additionalProperties: falseon the published schema — what tells a clientthe rule exists. Upstream publishes no extra policy at all, so enforcing on
its own would refuse calls the advertised schema allowed.
./scripts/test375 passed,./scripts/lintclean.Behaviour change worth a look before merging: any caller that has been
sending a stray argument starts getting an error rather than being quietly
tolerated. That is the point, but it will surface wherever it has been
happening. It surfaces as a tool-call error result, not a raised exception —
the same path an argument with a wrong type already takes today — so the model
gets a
ToolMessageit can act on and retries, and the thread stayswell-formed.
🤖 Generated with Claude Code
https://claude.ai/code/session_01SqYYX2DusBMsnR58iDro1Y