Merge pull request #487 from koic/stamp_result_type_on_modern_results
Stamp the required `resultType` on modern results per SEP-2322
This commit is contained in:
commit
29647deb0e
3 changed files with 61 additions and 1 deletions
|
|
@ -2851,6 +2851,10 @@ The Ruby client recognizes such results and raises `MCP::Client::InputRequiredEr
|
||||||
and the raw `result`; automatic resumption is not implemented yet, so callers respond manually if they opt into the draft flow. `MCP::ResultType::COMPLETE` and `MCP::ResultType::INPUT_REQUIRED`
|
and the raw `result`; automatic resumption is not implemented yet, so callers respond manually if they opt into the draft flow. `MCP::ResultType::COMPLETE` and `MCP::ResultType::INPUT_REQUIRED`
|
||||||
are provided for forward compatibility. Servers on stable protocol versions never send `resultType`, so existing behavior is unchanged.
|
are provided for forward compatibility. Servers on stable protocol versions never send `resultType`, so existing behavior is unchanged.
|
||||||
|
|
||||||
|
SEP-2322 also makes `resultType` a required member of every result a 2026-07-28 server returns. The server stamps `resultType: "complete"` on all results of requests carrying
|
||||||
|
the modern `_meta` envelope (and on `server/discover` results), while results that already carry a discriminator (`"input_required"`, the tasks extension's `"task"`) keep it.
|
||||||
|
Legacy results stay unstamped, and clients treat an absent `resultType` as `"complete"` per the spec.
|
||||||
|
|
||||||
## Conformance Testing
|
## Conformance Testing
|
||||||
|
|
||||||
The `conformance/` directory contains a test server and runner that validate the SDK against the MCP specification using [`@modelcontextprotocol/conformance`](https://github.com/modelcontextprotocol/conformance).
|
The `conformance/` directory contains a test server and runner that validate the SDK against the MCP specification using [`@modelcontextprotocol/conformance`](https://github.com/modelcontextprotocol/conformance).
|
||||||
|
|
|
||||||
|
|
@ -621,6 +621,14 @@ module MCP
|
||||||
result = serialize_input_required_result(result, envelope: envelope, request: params)
|
result = serialize_input_required_result(result, envelope: envelope, request: params)
|
||||||
end
|
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
|
result
|
||||||
rescue CancelledError => e
|
rescue CancelledError => e
|
||||||
add_instrumentation_data(cancelled: true, cancellation_reason: e.reason)
|
add_instrumentation_data(cancelled: true, cancellation_reason: e.reason)
|
||||||
|
|
@ -837,7 +845,13 @@ module MCP
|
||||||
capabilities: capabilities,
|
capabilities: capabilities,
|
||||||
instructions: instructions,
|
instructions: instructions,
|
||||||
_meta: { RequestEnvelope::SERVER_INFO_META_KEY => server_info },
|
_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
|
end
|
||||||
|
|
||||||
def configure_logging_level(request, session: nil)
|
def configure_logging_level(request, session: nil)
|
||||||
|
|
|
||||||
|
|
@ -4142,6 +4142,42 @@ module MCP
|
||||||
refute Apps.client_supports?(server.client_capabilities)
|
refute Apps.client_supports?(server.client_capabilities)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# SEP-2322 makes `resultType` REQUIRED on every result of a 2026-07-28 server;
|
||||||
|
# `"complete"` is the standard shape, and legacy results stay unstamped.
|
||||||
|
test "modern results carry resultType complete" do
|
||||||
|
server = Server.new(name: "result_type_test", tools: [result_type_tool])
|
||||||
|
|
||||||
|
[
|
||||||
|
modern_request(Methods::TOOLS_LIST, {}),
|
||||||
|
modern_request(Methods::PING, {}),
|
||||||
|
modern_request(Methods::TOOLS_CALL, { name: "result_type_tool", arguments: {} }),
|
||||||
|
].each do |request|
|
||||||
|
response = server.handle(request)
|
||||||
|
assert_equal "complete", response.dig(:result, :resultType), "expected stamp for #{request[:method]}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
test "legacy results carry no resultType" do
|
||||||
|
server = Server.new(name: "result_type_test", tools: [result_type_tool])
|
||||||
|
|
||||||
|
[
|
||||||
|
{ jsonrpc: "2.0", method: Methods::TOOLS_LIST, id: 1 },
|
||||||
|
{ jsonrpc: "2.0", method: Methods::PING, id: 2 },
|
||||||
|
{ jsonrpc: "2.0", method: Methods::TOOLS_CALL, id: 3, params: { name: "result_type_tool", arguments: {} } },
|
||||||
|
].each do |request|
|
||||||
|
response = server.handle(request)
|
||||||
|
refute response[:result].key?(:resultType), "expected no stamp for #{request[:method]}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
test "server/discover carries resultType complete" do
|
||||||
|
server = Server.new(name: "result_type_test", tools: [result_type_tool])
|
||||||
|
|
||||||
|
response = server.handle({ jsonrpc: "2.0", method: Methods::SERVER_DISCOVER, id: 1 })
|
||||||
|
|
||||||
|
assert_equal "complete", response.dig(:result, :resultType)
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
# Builds a request carrying the SEP-2575 modern `_meta` envelope.
|
# Builds a request carrying the SEP-2575 modern `_meta` envelope.
|
||||||
|
|
@ -4159,5 +4195,11 @@ module MCP
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def result_type_tool
|
||||||
|
@result_type_tool ||= Tool.define(name: "result_type_tool") do |**|
|
||||||
|
Tool::Response.new([{ type: "text", text: "ok" }])
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue