Endpoints
A request’s payload begins with one tag byte designating the endpoint; thirteen endpoints are defined, and a request the server cannot read is answered by a bare response finish.
A request opens a scope for exactly one endpoint. The request’s payload begins with a single tag byte designating the endpoint; the remainder of the payload is the endpoint’s request content, in the form the endpoint defines.
The tag values are normative as tabulated. Each endpoint has its own section. Every section of this layer states requirements of the server only: a sentence describing what the client sends states the input the server serves, and imposes no requirement on the client.
- An unreadable request is answered, not dropped. A request whose payload the server cannot read — a tag the server does not define, or content that does not conform to the endpoint’s form — is answered by a response finish with no response preceding it. The scope opens and closes; the client observes an unanswered request.
- Growth is new tag values. A future endpoint is a new tag value in this table. The frame types of the Frames layer are unaffected by the addition of endpoints.
Notation#
The JSON payloads of this layer are defined by type declarations, written as Rust with serde attributes. The declarations are normative for the JSON they describe — the protocol is not Rust, and the notation binds no implementation language — under the following reading:
- A
structis a JSON object. A field is a member of the same name, unless#[serde(rename = "…")]states the wire name;r#typeis the membertype. - A field marked
#[serde(default, skip_serializing_if = …)]may be absent, and absence has the marked default’s meaning. AnOptionfield without that marking is present, and may benull. - An enum marked
#[serde(untagged)]is exactly one of its variants’ shapes, with no wrapper naming the variant. - An enum of unit variants is a string: each variant’s
#[serde(rename = "…")]value, or its name insnake_casewhere#[serde(rename_all = "snake_case")]is stated. A one-variant enum is thereby a constant. - A field marked
#[serde(flatten)]contributes its members to the containing object; the field’s own name never appears. Stringis a string;boolis a boolean;u64andi64are integers;f64andDecimalare numbers;Vec<T>is an array;Vec<u8>is an array of integers; a map is an object;serde_json::Valueis any JSON value.- Types named from
rmcp::modelare the types of the Model Context Protocol specification, serialized as MCP defines them; they are incorporated by reference and not restated. Wherever a declaration references one, its definition in rmcp 3.1.2 — the MCP implementation this revision builds against — is linked beneath the declaration.
The binary payloads of this layer that a page marks as postcard are defined by the same type declarations, under the following reading, which is the postcard wire format:
- A
structis its fields, in declaration order, with no delimiter between them and no name before them. u16,u32,u64andusizeare unsigned LEB128 varints: seven bits of the value per byte, least significant first, the high bit of every byte but the last set. Au64occupies at most 10 bytes.u8is one byte.boolis one byte,0or1.Stringis a varint byte length followed by that many bytes of UTF-8.Vec<T>is a varint count followed by that many elements, each encoded asT.- An enum is a varint discriminant, the index of the variant in
declaration order counted from
0, followed by the variant’s fields in declaration order. Option<T>is the byte0, or the byte1followed byT.