Skip to content

fix(client): keep tool metadata intact when a listTools() refresh fails (v1.x) - #2618

Open
harshasiddartha wants to merge 1 commit into
modelcontextprotocol:v1.xfrom
harshasiddartha:fix/2614-atomic-tool-metadata-cache
Open

fix(client): keep tool metadata intact when a listTools() refresh fails (v1.x)#2618
harshasiddartha wants to merge 1 commit into
modelcontextprotocol:v1.xfrom
harshasiddartha:fix/2614-atomic-tool-metadata-cache

Conversation

@harshasiddartha

Copy link
Copy Markdown

Fixes #2614.

What's broken

cacheToolMetadata() clears _cachedToolOutputValidators, _cachedKnownTaskTools and _cachedRequiredTaskTools before it starts compiling the replacement catalog. If a later tool's outputSchema fails to compile, listTools() rejects as expected — but the caches have already been wiped or partially overwritten.

The client is then left in a worse state than before the refresh: callTool() finds no validator for tools that previously had one and silently skips output validation, and tools marked taskSupport: "required" are no longer recognised as such.

Change

Build the replacement Map/Set locally and assign them only after every tool has been processed. A failed refresh now leaves the metadata from the last successful listTools() in effect.

Test

Added a regression test to test/client/index.test.ts under outputSchema validation: it lists a catalog containing a tool with an output schema and a taskSupport: "required" tool, then serves a second catalog whose output schema fails to compile, and asserts both pieces of metadata are still enforced afterwards.

Without the source change it fails with:

AssertionError: promise resolved "{ content: [], …(1) }" instead of rejecting

npm test (1640 tests), npm run typecheck, npm run lint and npm run build all pass.

Scope

This is deliberately limited to the failure-atomicity of the cache write. The separate validator-lookup ordering issue in #2612 (callTool() resolving the validator after awaiting the response) is untouched — the two changes are in different methods and don't conflict.

Targeting v1.x since the reported behaviour is in the v1 client; main no longer has this code path.

cacheToolMetadata() cleared the output-validator and task-support caches
before compiling the replacement catalog. If a later output schema failed
to compile, listTools() rejected but the client was left with empty or
partially replaced metadata, so subsequent callTool() invocations skipped
output validation and lost task-support information.

Build the replacement Map/Set locally and publish them only once every
tool has been processed, so a failed refresh leaves the metadata from the
last successful listTools() in effect.
@harshasiddartha
harshasiddartha requested a review from a team as a code owner August 6, 2026 08:45
@pkg-pr-new

pkg-pr-new Bot commented Aug 6, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@modelcontextprotocol/sdk@2618

commit: a0350ac

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