Raw HTTP API (curl)
Call Pact's MCP server with plain HTTP — the Streamable HTTP handshake, JSON-RPC framing, and copy-paste curl examples.
Pact's MCP server speaks Streamable HTTP — MCP's standard remote transport: JSON-RPC 2.0 messages POSTed to a single endpoint, with responses returned as JSON or as a short SSE stream. This page is for anyone building a custom client or debugging with curl. If you just want a working client, the TypeScript and Python SDKs handle everything below.
Endpoint https://api.pact.place/mcp/ (keep the trailing slash)
Auth Authorization: Bearer <pact_live_* key or OAuth access token>
Framing JSON-RPC 2.0 over POST
Accept application/json, text/event-stream (both, on every request)
Session mcp-session-id header, issued by initialize
Note
There is no WebSocket transport — Streamable HTTP is the remote transport MCP standardizes on.
Clients that can only launch stdio servers can bridge with
mcp-remote.
1. Initialize a session
The first request is initialize. The response carries the server's
capabilities — and, in the mcp-session-id response header, your session
id. Capture it:
curl -isS https://api.pact.place/mcp/ \
-H "Authorization: Bearer pact_live_xxx" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{
"jsonrpc": "2.0", "id": 1, "method": "initialize",
"params": {
"protocolVersion": "2025-03-26",
"capabilities": {},
"clientInfo": { "name": "curl", "version": "0.0.0" }
}
}' | grep -i "^mcp-session-id"
2. Confirm initialization
Send the notifications/initialized notification (no id — it's a
notification, and the server replies 202 Accepted with no body):
SESSION="<value from step 1>"
curl -sS https://api.pact.place/mcp/ \
-H "Authorization: Bearer pact_live_xxx" \
-H "mcp-session-id: $SESSION" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc": "2.0", "method": "notifications/initialized"}'
3. List tools
curl -sS https://api.pact.place/mcp/ \
-H "Authorization: Bearer pact_live_xxx" \
-H "mcp-session-id: $SESSION" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc": "2.0", "id": 2, "method": "tools/list"}'
Each tool comes back with its inputSchema, so you can build requests — or
forms — mechanically. (That's exactly what the in-app
tool sandbox does.)
4. Call a tool
curl -sS https://api.pact.place/mcp/ \
-H "Authorization: Bearer pact_live_xxx" \
-H "mcp-session-id: $SESSION" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{
"jsonrpc": "2.0", "id": 3, "method": "tools/call",
"params": {
"name": "query_accounts",
"arguments": { "search": "Acme" }
}
}'
Responses may arrive as plain JSON or SSE-framed (event: message lines with
data: payloads) — parse whichever Content-Type the response declares.
Results report Pact's guarantees inline: consent_filtered (records hidden
because the subject withdrew consent), cost_cents on AI-powered tools, and
every call writes one tenant-scoped audit row.
Gotchas
- Trailing slash.
/mcpredirects to/mcp/, and most HTTP clients drop theAuthorizationheader across the redirect — which surfaces as a 401. - Both Accept types. Omitting
text/event-streamfromAcceptis a406 Not Acceptable. - Session reuse. Reuse one
mcp-session-idfor a conversation; sessions are cheap but not free. A404on a previously-good session means it expired — initialize again. - Scopes. A key without a tool's scope gets a scope error, not an empty result. Scopes per tool are in the tool reference.