Repository navigation
Streamable HTTP accepts direct 2026 requests without required request _meta #1086
Description
Summary
rmcp 3.0.1's Streamable HTTP server accepts direct MCP 2026-07-28 requests whose HTTP headers select the modern protocol version but whose JSON-RPC body omits the required per-request _meta.
Both tools/list and tools/call return HTTP 200, and the tool call executes. There was no preceding initialize or server/discover exchange.
This is distinct from #1083: that PR rejects _meta.protocolVersion when the corresponding HTTP header is absent. This issue is the inverse—the MCP-Protocol-Version header is present, but the required body _meta is absent.
Environment
- Tag:
rmcp-v3.0.1 - Commit:
3bb3c8dbce8ff4c1f8c9e91ebe03ca5cd42f3e81 - Server: repository
mcp-conformanceserver withSTATELESS=1 - Protocol version:
2026-07-28
Reproduction
Build and start the reference server:
cargo build -p mcp-conformance
STATELESS=1 PORT=8002 ./target/debug/conformance-serverSend tools/list without params._meta:
curl --include --http1.1 http://127.0.0.1:8002/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-H 'MCP-Protocol-Version: 2026-07-28' \
-H 'Mcp-Method: tools/list' \
--data '{"jsonrpc":"2.0","id":31,"method":"tools/list","params":{}}'Send tools/call without params._meta:
curl --include --http1.1 http://127.0.0.1:8002/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-H 'MCP-Protocol-Version: 2026-07-28' \
-H 'Mcp-Method: tools/call' \
-H 'Mcp-Name: test_simple_text' \
--data '{"jsonrpc":"2.0","id":32,"method":"tools/call","params":{"name":"test_simple_text","arguments":{}}}'Actual behavior
Both requests return HTTP 200 with a successful resultType: "complete" response. test_simple_text executes and returns its normal text result.
The server log also shows synthetic peer information with meta: None, while treating the request as protocol version 2026-07-28.
Expected behavior
For the final 2026-07-28 stateless lifecycle, each request is self-contained and MUST carry the required request metadata: io.modelcontextprotocol/protocolVersion and io.modelcontextprotocol/clientCapabilities. The HTTP protocol-version header mirrors the body field and does not make an otherwise incomplete request valid.
io.modelcontextprotocol/clientInfo is optional. Clients SHOULD include it on every request unless specifically configured not to do so, but servers must not reject a request solely because clientInfo is absent.
Because the requests above omit both required fields, they MUST return HTTP 400 with JSON-RPC -32602 Invalid params, identifying the missing or malformed required _meta fields.
Specification references: 2026-07-28 per-request protocol fields and transport request metadata.
Likely validation gap
validate_request_protocol_version_meta rejects an absent metadata protocol version only for server/discover; other methods return Ok(()).
The later requires_request_metadata check activates for discovery, previously marked peers, or requests whose _meta already declares a modern version. A direct request whose modern version appears only in the HTTP header therefore does not activate required-field validation.
Conformance coverage gap
The current 2026 server suite passes against the reference server because it checks missing metadata on server/discover and sends later requests after a valid discovery exchange. It does not send a direct non-discover request with a 2026 HTTP version header and missing _meta.
Suggested regression coverage
Add Streamable HTTP tests for:
- Direct
tools/listwith a 2026 version header and no_meta. - Direct
tools/callwith valid routing headers and no_meta. _metamissing onlyio.modelcontextprotocol/protocolVersion(must be rejected)._metamissing onlyio.modelcontextprotocol/clientInfo(must be accepted; this field is optional)._metamissing onlyio.modelcontextprotocol/clientCapabilities(must be rejected).
The first two cases would also be useful additions to the upstream conformance suite.
Activity