Skip to content

feat(unstable-v2): disallow null request IDs - #2499

Merged
benbrandt merged 2 commits into
mainfrom
feat/v2-non-null-request-ids
Oct 26, 2026
Merged

benbrandt merged 2 commits into
mainfrom
feat/v2-non-null-request-ids

Conversation

@benbrandt

@benbrandt benbrandt commented Oct 26, 2026 •

Copy link
Copy Markdown
Member

Base JSON-RPC allows null request IDs but discourages them, because null is also the ID of an error response to a request whose ID couldn't be read. MCP disallows them (RequestId = string | number). This does the same for v2.

  • v2 gets its own RequestId (string | integer), Request and Response types in v2/rpc.rs. v1 keeps the shared JSON-RPC types unchanged.
  • The v1 RequestId, Request and Response move from crate::rpc into v1/rpc.rs to match. crate::rpc re-exports them, so existing paths keep working until the next breaking release of the crate; it otherwise keeps only the version-independent Notification, JsonRpcMessage and JsonRpcBatch.
  • Every v2 use of a request ID is now non-null: request envelopes, successful responses, $/cancel_request and request-scoped elicitations.
  • Error responses keep JSON-RPC's id: null for when the request ID could not be determined (parse errors, invalid requests). The key stays required, so the existing batch and parse-error rules in transports.mdx still hold. MCP makes the ID optional instead; keeping null stays compatible with generic JSON-RPC libraries.

The overview (main and draft) and the migration guide state the rule.

Following MCP, v2 request IDs must be a string or an integer, never null.
v2 gets its own RequestId, Request and Response types; v1 keeps the
shared JSON-RPC types unchanged.

Error responses keep JSON-RPC's `id: null` for when the request ID could
not be determined, such as a parse error or an invalid request.
@benbrandt
benbrandt requested a review from a team as a code owner October 26, 2026 21:40
RequestId, Request and Response now live in v1/rpc.rs, mirroring v2.
crate::rpc re-exports them so existing paths keep working, and keeps
only the version-independent Notification, JsonRpcMessage and
JsonRpcBatch types. Response gains a default Error = v1::Error parameter
so v1::Response<T> and rpc::Response<T, E> both still resolve.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant