Skip to content

Streamable HTTP accepts direct 2026 requests without required request _meta #1086

Description

@DaleSeo

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-conformance server with STATELESS=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-server

Send 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:

  1. Direct tools/list with a 2026 version header and no _meta.
  2. Direct tools/call with valid routing headers and no _meta.
  3. _meta missing only io.modelcontextprotocol/protocolVersion (must be rejected).
  4. _meta missing only io.modelcontextprotocol/clientInfo (must be accepted; this field is optional).
  5. _meta missing only io.modelcontextprotocol/clientCapabilities (must be rejected).

The first two cases would also be useful additions to the upstream conformance suite.

Metadata

Metadata

Assignees

Labels

T-bugBug fixes and error correctionsT-coreCore library changesT-transportTransport layer changes

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions