Repository navigation
fix(mcp): deep-copy cached tools before returning them - #4525
Conversation
list_tools and cached_tools only shallow-copied the tools list, so callers could mutate nested input schemas and bypass required-parameter validation.
seratch
left a comment
There was a problem hiding this comment.
Thanks for the contribution. The deep-copy direction is correct, but the ownership boundary is still incomplete. list_tools() passes cached MCPTool objects into a callable tool_filter before _snapshot_tools() runs, so a filter that mutates input_schema["required"] can still corrupt _tools_list and bypass later call-time validation.
Please ensure callable filters receive detached tool objects before invocation, while no-filter/static-filter results and cached_tools remain deeply isolated. Add a regression test where a dynamic filter mutates a nested schema and verify that subsequent listings and call_tool() still use the original required fields. Please also extend the cached_tools snapshot test to mutate a returned tool or nested schema, rather than only the outer list.
With those focused changes and green CI, this should be ready for another review.
Callable tool_filter still received live cache objects, so mutating nested schemas could bypass call-time validation. Inspect detached copies and keep returned listings and cached_tools isolated from the cache.
Summary
This pull request finishes cache isolation for MCP tool listings.
#4424 returned a new list from
list_tools()/cached_tools, but theToolobjects and nestedinput_schemadicts remained shared with the server cache. Mutating a returned tool's schema could clearrequiredfields and bypass_validate_required_parameterson latercall_tool()invocations.Returned tools are now deep-copied so callers cannot corrupt the cache or required-parameter checks. Callable
tool_filterfunctions receive detached copies before invocation, so a filter that mutates nested schemas cannot rewrite_tools_list. No-filter and static-filter results stay isolated by the same return-path snapshot.Test plan
uv run pytest -q tests/mcp/test_caching.py tests/mcp/test_tool_filtering.pymake format && make lint && make typecheckinput_schema["required"]still fails call-time validationrequiredcannot change later listings orcall_tool()validationcached_toolsnested schema mutation does not leak into later snapshotsIssue number
N/A
Checks
.agents/skills/code-change-verification/scripts/run.shtests/sandbox/test_run_cwd.py::test_python_skill_uses_absolute_root_from_nested_workdiron this host/reviewbefore submitting this PR