Conventions
Errors, idempotency, pagination, and the one visible difference between the two transports.
Read this once and the rest of the reference reads itself.
The two transports refuse differently
Same cause, two shapes — and this trips up anyone who reads the MCP guide and then writes REST.
| MCP | REST | |
|---|---|---|
| Transport-level refusal | 401 with WWW-Authenticate | 401 with WWW-Authenticate |
| Capability-level refusal | 200 with a JSON-RPC error envelope | Real HTTP status code |
Past the transport guard, the MCP layer wraps every error in a 200 JSON-RPC response — that is the
protocol, not a choice. Do not branch on the HTTP status alone when speaking MCP: read the envelope.
One deliberate exception: a capability outside your granted scope is refused before the transport,
as a real 403 insufficient_scope with a WWW-Authenticate challenge. It has to be, because a
refusal buried in a 200 is one no client can read as an invitation to re-authorise.
Refusals are typed
A refusal tells you which of four things went wrong: the capability does not exist, your credential may not use it, the request is malformed, or a precondition failed. Refusals are stable and enumerable — the full list is generated from the registry itself, so it cannot drift from what the server does.
Identifiers
Capability identifiers are dotted, lowercase, and stable: audit.overview.get,
content.items.list, brand-voice.define. The last segment is the verb. Resource identifiers are
UUIDs. Neither is ever recycled.
Timestamps
Every timestamp is UTC, ISO 8601, with an explicit offset. There are no naive timestamps in the API surface.
Rate limits
Requests are bounded per credential and per project. We publish no numbers here — a limit written in
documentation becomes a promise, and we only promise what the code enforces. When limits are
enforced at the edge you will see them announced in standard RateLimit-* response headers, and
this page will say so.
One project per connection
Not a convention — an invariant. A session carries exactly one project, resolved from the credential. No parameter can change it, and passing a project identifier in the body of a call is refused rather than ignored. An agency opens one connection per client.