fix(http-base): return valid empty results for unhandled list methods - #476
Open
JosephDoUrden wants to merge 1 commit into
Open
Conversation
The BaseHttpScenario generic fallback answered any unrouted request
with only the required draft result fields, so a standard list method
a scenario does not route came back without its required list member.
http-standard-headers advertises resources but has no
resources/templates/list route; the reply's missing resourceTemplates
fails schema validation (draft and 2025-11-25 both require it), and
strictly-validating clients drop the connection before the scenario's
header checks run.
Merge schema-valid empty results for the six list-shaped methods
(tools, resources, resource templates, prompts, roots, tasks) into
the fallback, keyed by a ReadonlyMap so method names that collide
with Object.prototype ("constructor", "toString", ...) miss instead
of poisoning the reply with a prototype function. tasks/list has a
typed result only at 2025-11-25; the empty member is harmless on the
draft wire. Non-list results (tools/call, resources/read,
prompts/get, ...) have no meaningful empty default and keep the bare
stamped fallback, so a route a scenario forgot surfaces instead of
being masked.
Tests pin the fixed behaviour on all three http scenario classes,
the prototype-name lookups, and the spec schema's rejection of the
pre-fix payload.
Fixes modelcontextprotocol#474
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.
Fixes #474.
The http scenarios advertise capabilities they don't fully route.
http-standard-headersadvertises resources but has no route forresources/templates/list, so the request falls through tosendGenericResult, which returned only the stamped draft fields with noresourceTemplates. Both schema versions require that member, so an eager-discovery client schema-rejects the reply and drops the connection before the checks the scenario is actually about get to run. That's the failure cloudflare/agents baselines, and it reproduces with the plain TS SDK client too:listResourceTemplates()throws a zod error on the pre-fix referee and completes on this branch.The fix is a small map in http-base: when a list-shaped method reaches the generic fallback, return a schema-valid empty result (
resourceTemplates: []and friends) instead of a bare stamp. Six list methods are covered, includingroots/listandtasks/list(that one exists only at 2025-11-25, the draft schema has no ListTasksResult, noted in a comment).tools/listcan't currently reach the fallback since every scenario routes it, the entry is there for symmetry.Why the base class and not a route in each scenario: a server advertising resources must serve
resources/templates/list, so the invariant belongs where the fallback lives, otherwise every future scenario that advertises a capability re-creates the bug. And http-base is the only place in the repo with a success-shaped fallback at all, the other mock servers return -32601 for unrouted methods, so this can't live in the shared helper either.Deliberately not covered:
completion/complete,prompts/get,resources/read. Those have no meaningful empty default and faking one would mask real scenario-authoring bugs. They still return the bare stamp.One extra thing the tests pin: the lookup is a ReadonlyMap rather than an object literal, because
request.methodcomes off the wire and an object lookup walks the prototype chain. A client posting method"constructor"would get a function back, and the response serialises to an envelope with neither result nor error. There's a regression test posting prototype names to all three scenario classes.Tested per CONTRIBUTING: fail and pass both proven (the new tests fail on main), full suite green (532), and an end-to-end run of the http-standard-headers scenario through the runner with
@modelcontextprotocol/sdk1.29 doing eager discovery, pre-fix it dies atlistResourceTemplates, post-fix all 12 checks emit real verdicts.AI disclosure per AI_POLICY.md: this PR was built with AI assistance (investigation and code generation). I verified the defect and the fix against the schema files and a real SDK client myself, and the numbers above are from local runs.