Developers · MCP server
Protocol
Transport, the MCP revisions PorchQ speaks, the headers and fields each needs, and how results are shaped.
Transport
PorchQ serves MCP over Streamable HTTP at https://porchq.com/mcp.
- Send every request as
POSTwith a JSON-RPC 2.0 body andContent-Type: application/json. PorchQ answers with a single JSON response, never a stream. GETandDELETEanswer405 Method Not AllowedwithAllow: POST. PorchQ opens no server-sent event stream and keeps no sessions, so there is noMcp-Session-Id.- A notification (no
id) is accepted with202 Acceptedand no body. - Batches (a JSON array) are refused with
-32600. - Every request needs an access token; see Sign-in and tokens.
Revisions
| Revision | How a client talks to the server |
|---|---|
2026-07-28 |
Stateless: each request carries its version and client capabilities in params._meta; no initialize. |
2025-11-25 |
Opens with initialize, then notifications/initialized. |
2025-06-18 |
Opens with initialize, then notifications/initialized. |
2025-03-26 |
Opens with initialize, then notifications/initialized. |
A request that carries io.modelcontextprotocol/protocolVersion in params._meta is served as 2026-07-28. Anything else is served as one of the earlier revisions.
Revision 2026-07-28
Each request stands alone: there is no initialize. It names its protocol version and declares the client’s capabilities in params._meta, and three HTTP headers repeat what the body says.
POST /mcp
Authorization: Bearer kV3n…
Content-Type: application/json
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: community_overview
{
"jsonrpc": "2.0",
"id": 7,
"method": "tools/call",
"params": {
"name": "community_overview",
"arguments": { "property_id": "prop_web4k2m9q7x1v8c3n5b6z0a2s4d" },
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": { "name": "ExampleClient", "version": "1.0.0" },
"io.modelcontextprotocol/clientCapabilities": {}
}
}
}
MCP-Protocol-VersionandMcp-Methodare required on every request,Mcp-Nameontools/call. Each must equal the body’s value, or PorchQ answers400with-32020. A header may be sent as=?base64?…?=when the value isn’t plain ASCII.io.modelcontextprotocol/clientCapabilitiesis required (an empty object is fine), or PorchQ answers400with-32602.- An unsupported version is answered
400with-32022and the supported versions inerror.data.supported. initializeandpingdon’t exist in this revision and answer404with-32601.
server/discover
server/discover tells a client what PorchQ supports before it does anything else:
{
"jsonrpc": "2.0",
"id": 7,
"result": {
"supportedVersions": ["2026-07-28", "2025-11-25", "2025-06-18", "2025-03-26"],
"capabilities": { "tools": {} },
"ttlMs": 3600000,
"cacheScope": "public",
"resultType": "complete",
"_meta": { "io.modelcontextprotocol/serverInfo": { "name": "PorchQ MCP Server", "version": "1.5.0" } }
}
}
Every result says "resultType": "complete" and, in this revision, carries the server’s name and version in _meta.
Revisions 2025-03-26 to 2025-11-25
Open with initialize, then send notifications/initialized:
{ "jsonrpc": "2.0", "id": 1, "method": "initialize", "params": { "protocolVersion": "2025-06-18", "capabilities": {}, "clientInfo": { "name": "ExampleClient", "version": "1.0.0" } } }
PorchQ answers with your protocolVersion if it supports it, otherwise with 2025-11-25, and with capabilities: { "tools": {} } and its serverInfo. From 2025-06-18 on, send the negotiated version in the MCP-Protocol-Version header on later requests. An unsupported value there is answered 400 with -32022.
ping answers an empty result. server/discover works in these revisions too.
Tools
PorchQ offers tools only: no resources, prompts or sampling yet. tools/list returns all 14 with their input and output schemas, annotations and securitySchemes, and may be cached for 60 minutes (ttlMs, cacheScope: "public"): the list is the same for everyone, and each call is checked on its own.
tools/call answers with:
content: a short sentence for the person;structuredContent: the data, described on each tool’s page;isError: truewhen the tool couldn’t do what was asked, with the reason incontent.
An unknown tool name is a protocol error, -32602.
Errors
| Code | HTTP | When |
|---|---|---|
-32700 |
200 | The body isn’t valid JSON. |
-32600 |
200 | Not a JSON-RPC 2.0 request, or a batch. |
-32601 |
404 (2026-07-28), 200 (earlier) |
Unknown method. |
-32602 |
400 or 200 | Missing _meta fields, or an unknown tool. |
-32020 |
400 | A header doesn’t match the body. |
-32022 |
400 | Unsupported protocol version. |
-32000 |
401 | No token, or a token that isn’t valid. |
Sign-in and permission answers (401, 403) carry a WWW-Authenticate header; see Sign-in and tokens. Rate limits answer 429; see Errors and limits.
Browser origins
A request from a web page (one with an Origin header) is accepted only from PorchQ, https://chatgpt.com, https://claude.ai or a loopback address; anything else gets 403. This protects people against DNS-rebinding attacks. Requests from servers carry no Origin and are unaffected.
This page as Markdown: /developers/mcp/protocol.md