Send an MCP message to an upstream MCP server through the Gate
const url = 'http://127.0.0.1:8080/mcp/example';const options = { method: 'POST', headers: { 'Deedglass-Version': '2026-10-01', Authorization: 'Bearer <token>', 'Content-Type': 'application/json' }, body: '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url http://127.0.0.1:8080/mcp/example \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --header 'Deedglass-Version: 2026-10-01' \ --data '{ "jsonrpc": "2.0", "id": 1, "method": "tools/list" }'The MCP Streamable HTTP gateway (S15) for one upstream MCP server configured under mcp.upstreams.<connector> in deedglass.yaml. Deedglass runs every allowed tools/call itself (gateway mode) and holds the upstream’s credentials. A POST-only JSON-RPC endpoint, sessionless and dual-era: 2026-07-28 requests carry _meta io.modelcontextprotocol/protocolVersion and the MCP-Protocol-Version, Mcp-Method and (for tools/call, resources/read, prompts/get) Mcp-Name headers, and any Mcp-Param-* a tool’s x-mcp-header declares; a missing or different header is 400 with JSON-RPC -32020, an unsupported version 400 with -32022 and data.supported. Legacy clients (2025-11-25, 2025-06-18, 2025-03-26) open with initialize; no Mcp-Session-Id is minted, and one sent is ignored. Notifications get 202 with no body. An unknown method is 404 (modern) or 200 (legacy) with -32601. Responses are application/json with Cache-Control: no-store; an Accept without application/json is 406. Errors before the message is read are JSON-RPC errors without an id whose data names the Deedglass error code, doc_url and request_id: 401 with WWW-Authenticate: Bearer realm="deedglass", resource_metadata="<base>/.well-known/oauth-protected-resource/mcp/<connector>", scope="actions:execute", 413 over 4 MiB, 415 for another Content-Type, 429 beyond 32 requests in flight per agent. A browser Origin other than the server’s own or one in mcp.allowed_origins gets 403. A stopped or suspended agent’s tools/call is recorded and sealed, and answered as an isError tool result. GET and DELETE get 405 with Allow: POST. Idempotency-Key is ignored. An agent key with actions:execute. JSON-RPC is not modelled here; see docs/MCP.md.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”The upstream’s connector name (mcp.upstreams.<name>), or a connector id (con_…) from S16.
Header Parameters
Section titled “Header Parameters”The API version (YYYY-MM-DD). Leave it out to use your org’s pinned version (public routes use the latest). An unknown version is 400 api_version_invalid.
Request Bodyrequired
Section titled “Request Bodyrequired”A JSON-RPC 2.0 message.
object
Example
{ "jsonrpc": "2.0", "id": 1, "method": "tools/list"}Responses
Section titled “Responses”One JSON-RPC response (a result, or an error such as -32601 for a legacy unknown method).
object
Example
{ "jsonrpc": "2.0", "id": 3, "result": { "resultType": "complete", "content": [ { "type": "text", "text": "Echo: hello" } ], "isError": false, "_meta": { "com.deedglass/action": "act_01k6w4a3d5f7h9k1n3q5s7v9x1", "com.deedglass/deed": "deed_01k6w4a3d5f7h9k1n3q5s7v9x2" } }}Headers
Section titled “Headers”This request’s id. Quote it to support; it matches error.request_id.
A notification was accepted. No body.
A header that doesn’t match the body (-32020 HeaderMismatch), an unsupported protocol version (-32022 with data.supported and data.requested), a batch or a response (-32600), or JSON that can’t be parsed (-32700).
A JSON-RPC 2.0 error response.
object
object
Example
{ "jsonrpc": "2.0", "id": 3, "error": { "code": -32020, "message": "Header mismatch: Mcp-Name is \"echo\" but the body names \"delete_all\". Send the same tool name in both." }}Headers
Section titled “Headers”This request’s id. Quote it to support; it matches error.request_id.
A browser Origin other than the server’s own: a JSON-RPC error without an id (DNS-rebinding protection). A key without actions:execute, or a stopped or suspended agent, also gets 403, with the error envelope.
A JSON-RPC 2.0 error response.
object
object
Example
{ "jsonrpc": "2.0"}Headers
Section titled “Headers”This request’s id. Quote it to support; it matches error.request_id.
default
Section titled “default”An error. Every error has this envelope; doc_url explains the code.
object
object
One or more calm sentences with the next step.
The request field, query parameter or header the error is about.
On policy_invalid only. Each problem with its line, code and hint.
One finding about a policy file, with its position and the next step. Codes are stable and listed in docs/POLICY_ERRORS.md. In the policy_invalid error envelope each diagnostic also carries object: policy_diagnostic. The full PolicyDiagnostic schema is in openapi.yaml.
object
One agent action. Its sections mirror the deed’s. status is the one field an agent needs; state is the exact lifecycle state (docs/GATE.md). The Gate’s own responses (POST /v1/actions and its result report) add execution.result and witness.reasons; lists leave both out. The full Action schema is in openapi.yaml.
object
On undo_unavailable only. Every check of the undo, each with its fix. Additive (S23).
One of the twelve safety checks (S23 §3.3). Available means no check failed. The full UndoCheck schema is in openapi.yaml.
object
Example
{ "error": { "type": "invalid_request_error", "code": "not_found", "message": "There's no endpoint at GET /v1/helth. Did you mean /v1/health?", "param": null, "request_id": "req_01j9zr3m5k8q2w7x4t6v0b1c9d", "doc_url": "https://docs.deedglass.com/errors/not_found" }}Headers
Section titled “Headers”This request’s id. Quote it to support; it matches error.request_id.
The API version this response follows.