Stamp the required resultType on modern results per SEP-2322

## Motivation and Context

SEP-2322 (merged for the 2026-07-28 spec release) makes `resultType` a REQUIRED member of every result
a 2026-07-28 server returns: "Servers implementing this protocol version MUST include this field",
with absence tolerated only when the result comes FROM an earlier protocol version.
The client-side vocabulary landed earlier (`MCP::ResultType`, treating an absent value as `"complete"`),
but every ordinary modern result the server returns is unstamped, which violates the MUST for `tools/list`,
`tools/call`, `ping`, and every other standard result on the modern wire.
The conformance suite's 2026-07-28 requirements fail each of those scenarios on wire-schema validation
(`CallToolResult: must have required property 'resultType'`).

The dispatch path now stamps `resultType: "complete"` centrally: any Hash result of a request carrying
the SEP-2575 `_meta` envelope that does not already carry a `resultType` gets the standard value merged in.
Results that already carry a discriminator keep it, notifications and cancellation-suppressed responses
are untouched, and legacy results stay unstamped because pre-2026 clients do not know the field.
`server/discover`, which is exempt from the `_meta` envelope (pre-version discovery),
stamps its `DiscoverResult` at its construction site instead.

## How Has This Been Tested?

`bundle exec rake test` passes with zero failures. New tests in `test/mcp/server_test.rb`: `tools/list`,
`ping`, and `tools/call` results carry `resultType: "complete"` on modern requests and no `resultType`
on legacy requests; `server/discover` carries the stamp. The conformance scenarios previously failing
on the missing property (`tools-call-simple-text`, `prompts-get-simple`, `completion-complete`, and
the other tools/prompts scenarios) pass at `--spec-version 2026-07-28` against the conformance fixture server.

## Breaking Changes

None. The stamp applies only to results of requests carrying the SEP-2575 modern `_meta` envelope;
results on stable protocol versions through 2025-11-25 are byte-for-byte unchanged.
This commit is contained in:
Koichi ITO 2026-07-05 02:24:20 +09:00
commit 14bf3a7091

View file

@ -621,6 +621,14 @@ module MCP
result = serialize_input_required_result(result, envelope: envelope, request: params)
end
# SEP-2322 makes `resultType` REQUIRED on every result a 2026-07-28 server returns;
# a missing value is only tolerated FROM earlier protocol versions. Results that already carry
# a discriminator keep it; everything else on the modern wire is the standard shape,
# `"complete"`. Legacy results stay unstamped: pre-2026 clients do not know the field.
if envelope && result.is_a?(Hash) && !result.key?(:resultType)
result = result.merge(resultType: ResultType::COMPLETE)
end
result
rescue CancelledError => e
add_instrumentation_data(cancelled: true, cancellation_reason: e.reason)
@ -837,7 +845,13 @@ module MCP
capabilities: capabilities,
instructions: instructions,
_meta: { RequestEnvelope::SERVER_INFO_META_KEY => server_info },
}.compact.merge(ttlMs: ttl_ms || 0, cacheScope: cache_scope || "private")
}.compact.merge(
ttlMs: ttl_ms || 0,
cacheScope: cache_scope || "private",
# `server/discover` is exempt from the `_meta` envelope, so the central modern-result stamping does not see it;
# `DiscoverResult` is still a 2026-07-28 result and carries the REQUIRED `resultType` directly.
resultType: ResultType::COMPLETE,
)
end
def configure_logging_level(request, session: nil)