Concepts

Transport & endpoints

The Cortex MCP server speaks Streamable HTTP (the post-2025-03-26 standard) over a single endpoint, with optional SSE for server-initiated messages during active sessions. Push dispatch and callbacks are out-of-band HTTPS webhooks (not MCP — the spec deprecated server-initiated push). No stdio — this is a remote service.

Endpoints

MethodPathPurpose
POST/mcpSend client-to-server JSON-RPC messages. The body is one JSON-RPC request (or batch).
GET/mcpOpen an SSE stream for server-initiated notifications during an active session (per the 2026-07-28 MCP spec). Server-initiated requests outside an active session are not supported by the protocol — push dispatch uses out-of-band webhooks (below).
DELETE/mcpTerminate a session (matched by mcp-session-id header).
POST/v1/triggers/{trigger_id}/completeCallback endpoint — your handler reports successful execution. See Dispatch · Callbacks.
POST/v1/triggers/{trigger_id}/reverseCallback endpoint — your handler reports a reversal. Demotes trust if user intent.
GETPOST/healthUnauthenticated health probe. 200 when the process is up.

Base URLs

EnvironmentURLStatus
Local devhttp://localhost:3002/mcp available
Productionhttps://mcp.cortex.jakeselby.com/mcp July 20, 2026

Required headers

http
Authorization: Bearer <YOUR_TOKEN>
Content-Type: application/json
MCP-Protocol-Version: 2025-03-26
  • Authorization — required on every request. See Authentication.
  • Content-Type application/json for POSTs.
  • MCP-Protocol-Version — informational; server speaks 2025-03-26.
  • mcp-session-id — echo the value the server returned in response to initialize. Omit on the first request; the server assigns one.

Session lifecycle

The Streamable HTTP transport is stateful by default. A normal lifecycle:

  1. Client POST /mcp with an initialize JSON-RPC request and no mcp-session-id header.
  2. Server responds 200 with the initialize result and a new mcp-session-id header (exposed via Access-Control-Expose-Headers).
  3. Client sends every subsequent request (tools/list, tools/call, notifications) with the mcp-session-id echoed back.
  4. Client optionally opens a long-lived GET /mcp SSE stream with the same mcp-session-id for server-initiated messages.
  5. Client DELETE /mcp with the session id when finished (best-effort cleanup).

Stateless mode

Clients that don't need server-initiated notifications can omit the mcp-session-id header on every call. The server creates a fresh session per request, executes, and discards. This is the right mode for short-lived agents (a CI tool making one call) or workloads behind their own retry logic.

CORS

The server is configured permissively for local development:

text
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, DELETE, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization, mcp-session-id, MCP-Protocol-Version
Access-Control-Expose-Headers: Content-Type, mcp-session-id

Production CORS will scope Allow-Origin per (user × client) once OAuth ships. Until then, treat the public URL as bearer-token-only and store tokens server-side.

Initialize result

The server advertises a minimal capability set: tools only. No resources, no prompts, no sampling, no logging level negotiation.

jsoninitialize result
{
  "protocolVersion": "2025-03-26",
  "serverInfo": {
    "name": "cortex-mcp-server",
    "version": "0.1.0"
  },
  "capabilities": {
    "tools": {}
  }
}

Server-initiated messages (SSE)

Server-initiated MCP messages are restricted by the protocol. Per the MCP 2026-07-28 release candidate (SEP-2260, SEP-2322), servers may only send messages during the processing of a client-initiated request; long-lived server-pushed work is out-of-spec. Cortex stays inside the spec:

  • notifications/tools/list_changed — standard MCP notification fired when the tool surface re-registers (rare; typically only on server restart with a different version).
  • notifications/decisions/created — fired during an active session when a new pending_approval decision lands in your queue, so a client polling action.pending can wake immediately.

Outbound webhooks (server → your handler)

When the substrate decides an action should happen, Cortex HMAC-SHA256 signs a JSON envelope and POSTs it to the customer-registered handler URL. The full transport-level contract:

PropertyValue
MethodPOST
URLThe url you registered via handler.register (must be HTTPS, must respond ≤30s).
BodyJSON TriggerEnvelope — see Envelope & headers.
SigningX-Cortex-Signature: sha256=hex(hmac_sha256(secret, ts + "." + body)) with the handler's webhook_secret. 5-minute replay window. See Dispatch.
IdempotencyX-Cortex-Idempotency-Key — dedupe on this header. Repeated dispatches share the same key.
Retry policyExponential backoff (1s, 5s, 30s, 2m, 10m, 1h, 6h, 24h). Up to 8 attempts before DLQ.
Success criteria2xx response within 30 seconds, OR an explicit trigger.complete callback (async confirmation).
Dead-letterQueryable via trigger.history; replayable via trigger.replay.

Out-of-band webhooks are the industry standard for this pattern: Stripe Radar, Twilio Engage, Anthropic Managed Agent webhooks, Armalo agent webhooks, OpenAI Standard Webhooks all use the same shape. The MCP spec deprecation of in-protocol server push (SEP-2260) forecloses any MCP-native alternative; this is fine because the webhook pattern is better-understood operationally.

Callback endpoints (your handler → server)

Two REST endpoints on the Cortex MCP host. Both authenticate via your principal bearer token (the same token you use for inbound MCP calls). Full schema in Dispatch · Callbacks.

http
POST https://mcp.cortex.jakeselby.com/v1/triggers/{trigger_id}/complete
POST https://mcp.cortex.jakeselby.com/v1/triggers/{trigger_id}/reverse

Authorization: Bearer <YOUR_PRINCIPAL_TOKEN>
Content-Type: application/json
Idempotency-Key: <unique-key-per-callback>