fix!: dispatch only tools the tools list declares - #30
Merged
Martin Bens (SpiGAndromeda) merged 1 commit intoOct 1, 2026
Merged
Conversation
handle_tools_call decided that a tool existed by checking for a shell function named tool_<name> with `type`, and validate_tool_arguments returned success for a name it found no tools-list entry for. A sourced function the server never declared was therefore dispatched with its arguments unchecked, and every tool_<name>_cancel hook answered as tool <name>_cancel. A consumer that sources shared tool libraries into several servers had to unset the undeclared functions at startup to close this (#29). The new internal _mcp_tool_schema reads the tools list once per call and returns the declared entry's schema. _mcp_validate_against_schema, the validator body moved out of validate_tool_arguments, checks the arguments against that schema. An undeclared name answers -32601 before any function lookup. An unreadable list, a duplicate entry, or an entry with no inputSchema answers isError. Tool and cancel-hook lookups use declare -F, so a PATH executable named tool_x no longer runs. tests/cancellation.bats now declares the five tools its in-process cases dispatch. BREAKING CHANGE: an undeclared tool_<name> function, including a cancel hook called as a tool, answers -32601 instead of running. A declared entry with no or a null inputSchema answers isError instead of dispatching unvalidated. validate_tool_arguments returns 1 for an undeclared name. Declare every tool a client calls in tools.json with an inputSchema before bumping the pin. A tool function may still call another tool_* function directly in shell. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Martin Bens (SpiGAndromeda)
deleted the
fix/tools-call-declared-tools-only
branch
October 1, 2026 18:44
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.
Closes #29.
Problem
handle_tools_calldecided that a tool existed by checking for a shell functiontool_<name>withtype.validate_tool_argumentsreturned success for a name with no tools-list entry. A sourced function the server never declared was therefore dispatched with its arguments unchecked. Everytool_<name>_cancelhook also answered as tool<name>_cancel.typealso matches executables, so atool_xonPATHran as a tool or as a cancel hook.Behavior
The tools list decides which tools exist.
handle_tools_callchecks in this order:paramsobject gate →-32602(unchanged)-32602 Invalid tool name(unchanged)_mcp_tool_schemareads the tools list once:-32601 Tool not found: <name>nullinputSchema→isErrorresultdeclare -F tool_<name>→-32601when no function exists_mcp_validate_against_schemachecks the arguments against the schema from step 3 →isErroron violationThe lookup uses the same
.tools[]?iteration as before, so the declaration check and the validation read the list the same way._run_cancel_hookalso resolves hooks withdeclare -F. A tool function can still call anothertool_*function directly in shell. A nestedhandle_tools_callfollows the declaration rule.Compatibility
tool_<name>function, including a cancel hook called as a tool, answers-32601instead of running.nullinputSchemaanswersisErrorinstead of dispatching unvalidated. README previously documented the unvalidated dispatch.validate_tool_argumentskeeps its signature and returns 1 for an undeclared name, where it returned 0.they could not be evaluated against its schema.AGENTS.md§Compatibility contract classifies tightening the validator as major. The[Unreleased]CHANGELOG entry carries no version marker, so the bump is decided at release. Consumers should declare every tool their clients call intools.jsonwith aninputSchemabefore bumping the pin.