The problem
Until revision 2025-11-25, an MCP (Model Context Protocol) connection began with a handshake: client and server exchanged protocol versions and capabilities, and the server then remembered them. Since revision 2026-07-28 there is no handshake: the protocol is stateless. Every request carries its protocol version and the client's capabilities in its params._meta field, and the server checks them on every request.
You will write that check, as a function that returns None if the request may proceed, or the JSON-RPC error response to send back.
The keys
In params._meta, all keys start with io.modelcontextprotocol/:
protocolVersion(a string, required), for example"2026-07-28";clientCapabilities(an object, required);clientInfo(an object with the client's name and version, recommended).
The constants PROTOCOL_VERSION, CLIENT_CAPABILITIES and CLIENT_INFO in the starter hold the full keys.
The check
check_meta(request, supported): request is a valid JSON-RPC request dict and supported the list of protocol versions the server implements.
params._metamust be an object containing the two required keys, with the right types. If either is missing or of the wrong type, return error-32602(invalid params) with the message"Missing required _meta field: <key>", with the full key, naming the first problem in the order above (version, then capabilities).- If the protocol version is not in
supported, return error-32022with message"Unsupported protocol version"anddataequal to{"supported": supported, "requested": <version>}, so that the client can retry with a version they have in common.
The error response is {"jsonrpc": "2.0", "id": <the request's id>, "error": {"code": ..., "message": ..., "data": ...}}, with "data" only for -32022.
Example. The server supports
["2026-07-28"]. Three requests with id 7:
_metawithprotocolVersion"2026-07-28"andclientCapabilities{}:None, the request may proceed._metawith onlyprotocolVersion: an error response with code-32602, and the message "Missing required _meta field: " followed by the full key ofclientCapabilities._metawithprotocolVersion"2025-01-01"and capabilities: code-32022, message "Unsupported protocol version", anddatawithsupported["2026-07-28"]andrequested"2025-01-01".
The client's name
client_info(request) returns the clientInfo object from _meta (full key in CLIENT_INFO), or None if it is absent or not an object: it is recommended, not required.
Example. For the first request, with
clientInfo{"name": "my-app", "version": "1.0"}in_meta:{"name": "my-app", "version": "1.0"}. Without that key:None.
What to implement
check_meta(request, supported)andclient_info(request).
Requirements
- A request without
params, or withparamsbut no_meta, is missing its required fields.