Skip to content

fix: invalidate tool schema cache on ToolListChangedNotification; paginate all pages in _validate_tool_result#2441

Open
atishay2 wants to merge 2 commits intomodelcontextprotocol:mainfrom
atishay2:fix/tool-schema-cache-invalidation
Open

fix: invalidate tool schema cache on ToolListChangedNotification; paginate all pages in _validate_tool_result#2441
atishay2 wants to merge 2 commits intomodelcontextprotocol:mainfrom
atishay2:fix/tool-schema-cache-invalidation

Conversation

@atishay2
Copy link
Copy Markdown

Summary

Two correctness bugs in ClientSession that cause tool output schema validation to silently use stale or missing schemas.

Bug 1: ToolListChangedNotification does not clear the tool schema cache

_received_notification had no handler for ToolListChangedNotification, so _tool_output_schemas was never invalidated when the server signalled a tool list change. The next call_tool invocation would validate structured_content against the old (stale) schema:

  • False negative: a tool whose schema changed from {integer} to {string} would have valid string output rejected against the cached integer schema.
  • Silent acceptance: a tool whose schema became stricter would still pass validation because the old looser schema was still in the cache.

Fix: handle ToolListChangedNotification in _received_notification by clearing _tool_output_schemas. The cache is repopulated lazily on the next call_tool.

Bug 2: _validate_tool_result only fetches the first page of list_tools()

When a tool name was not in _tool_output_schemas, a single await self.list_tools() call was made (no arguments → first page only). If the tool lived on page 2 or later, it was never found in the cache, the schema lookup fell through to the warning path, and validation was silently skipped — invalid structured_content was returned to the caller without any error.

Fix: add a pagination loop in _validate_tool_result that continues fetching pages until the tool is found or all pages are exhausted.

Changed files

  • src/mcp/client/session.py — two targeted fixes (4 new lines each)
  • tests/client/test_output_schema_validation.py — two new test cases that fail without the fix and pass with it

Test plan

  • uv run --frozen pytest tests/client/test_output_schema_validation.py -v — all 7 tests pass
  • uv run --frozen pytest tests/client/ -v — 190 passed, 1 xfailed, no regressions
  • uv run --frozen pyright src/mcp/client/session.py — 0 errors
  • uv run --frozen ruff check src/mcp/client/session.py tests/client/test_output_schema_validation.py — all checks passed

🤖 Generated with Claude Code

Atishay Tiwari and others added 2 commits April 13, 2026 21:33
…paginate all pages

Two related bugs in ClientSession._validate_tool_result:

1. ToolListChangedNotification was not handled in _received_notification,
   leaving _tool_output_schemas stale after the server updates its tool list.
   Subsequent call_tool invocations would validate structured content against
   the old schema, causing false negatives (valid responses rejected) or
   silently accepting responses that no longer match the current schema.
   Fix: clear _tool_output_schemas when ToolListChangedNotification arrives.

2. When a tool was not found in the schema cache, only the first page of
   list_tools() was fetched. Tools on page 2+ were never cached, so their
   output schema was silently skipped — invalid structured_content was
   accepted without raising a RuntimeError.
   Fix: paginate through all pages until the tool is found or the list ends.

Tests added for both cases in test_output_schema_validation.py.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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