MCP 2026-07-28 Dual-Version Migration

AppTheory serves the final MCP 2026-07-28 stateless transport alongside the established 2025-11-25 session-ful transport on the same MCP handler. This is an additive server change; there is no server-wide mode flag and no second route or deployment construct.

Existing session-ful clients: no change

Clients that use 2025-11-25 keep the same behavior:

  • call initialize
  • retain the returned Mcp-Session-Id
  • use that session id for later POST/GET/DELETE requests
  • receive the existing response bodies without resultType
  • use SSE streaming, replay, tasks, and the existing session error contract as before

Do not add modern routing headers to a session-ful client unless it is intentionally sending a 2026-07-28 request. All pre-existing session-ful contract fixtures remain byte-identical.

Modern stateless clients: migration checklist

For a client that opts into 2026-07-28:

  1. Keep using POST /mcp on the existing AppTheory handler.
  2. Do not call initialize and do not send or expect Mcp-Session-Id.
  3. Call server/discover to read supported protocol versions, capabilities, and server identity.
  4. Send Content-Type: application/json and Accept: application/json, text/event-stream.
  5. Identify the protocol with Mcp-Protocol-Version: 2026-07-28 or params._meta["io.modelcontextprotocol/protocolVersion"].
  6. When both protocol values are present, make them identical.
  7. Send Mcp-Method equal to the JSON-RPC method on every request or notification.
  8. Send Mcp-Name for the methods below, using the exact body value:

    Method Mcp-Name value
    tools/call params.name
    prompts/get params.name
    resources/read params.uri
  9. Advertise per-request client capabilities under params._meta["io.modelcontextprotocol/clientCapabilities"].
  10. Branch on every successful result’s resultType.

The 2026-07-28 shape is POST-only in this milestone. It does not route initialize, sessions, GET/listen, DELETE, task methods, task-augmented tool calls, resource subscriptions, or subscriptions/listen. A GET or DELETE carrying Mcp-Protocol-Version: 2026-07-28 returns HTTP 405 before legacy session validation.

Discover before calling methods

Example:

curl -sS \
  -X POST "https://YOUR_ENDPOINT/mcp" \
  -H 'content-type: application/json' \
  -H 'accept: application/json, text/event-stream' \
  -H 'mcp-protocol-version: 2026-07-28' \
  -H 'mcp-method: server/discover' \
  -d '{
    "jsonrpc":"2.0",
    "id":"discover",
    "method":"server/discover",
    "params":{
      "_meta":{
        "io.modelcontextprotocol/protocolVersion":"2026-07-28",
        "io.modelcontextprotocol/clientCapabilities":{}
      }
    }
  }'

AppTheory advertises, in preference order:

  1. 2026-07-28
  2. 2025-11-25
  3. 2025-06-18
  4. 2025-03-26

The result derives capabilities from the server’s configured registries and hooks and returns the server constructor’s name/version under _meta["io.modelcontextprotocol/serverInfo"]. A task-enabled server advertises its task capability because discovery describes the server across all supported versions; task calls still require a 2025-11-25 session. A subscriptions capability is intentionally absent.

Handle resultType

Every successful modern result has one of:

  • resultType: "complete": processing is finished
  • resultType: "input_required": fulfill the returned input requests and retry the original request

For input_required, preserve requestState, collect a response for each named entry in inputRequests, and send those values as inputResponses on the retry. The input request method determines the required client capability. For example, this request metadata advertises elicitation:

{
  "_meta": {
    "io.modelcontextprotocol/protocolVersion": "2026-07-28",
    "io.modelcontextprotocol/clientCapabilities": {
      "elicitation": {}
    }
  }
}

Do not synthesize resultType for a 2025-11-25 response. AppTheory deliberately preserves the old wire shape.

Handle the modern validation errors

AppTheory exports and returns these 2026-07-28 error codes:

Code Name Action
-32020 Header mismatch Make protocol metadata and routing headers match the JSON-RPC body
-32021 Missing required client capability Advertise every capability needed by the returned input requests
-32022 Unsupported protocol version Choose a value from error.data.supported

These errors return a JSON-RPC error body with HTTP 400. -32021 includes error.data.requiredCapabilities; -32022 includes error.data.supported and error.data.requested.

In particular, a sessionless request with an unknown or future protocol header now receives -32022 instead of first failing as a missing legacy session.

Rollout

  1. Deploy the upgraded AppTheory runtime without changing existing clients.
  2. Verify a session-ful canary still initializes, calls tools, streams/replays if used, and deletes its session.
  3. Add one stateless canary that calls server/discover.
  4. Verify its routing headers at the HTTP edge before enabling tool calls.
  5. Verify the client handles both result types and all three modern validation codes.
  6. Expand the stateless canary only after capability and multi-round input handling is ready.

For the complete runtime surface, see docs/integrations/mcp.md. For the Remote MCP deployment shape, see docs/integrations/remote-mcp.md.