Skip to content

MCP Server Integration (@invariant/mcp)

Expose Invariant durable workflows to Model Context Protocol (MCP) clients (such as Claude Desktop, Cursor, and external MCP agents) using stable runtime tools and dynamic RuntimeProjection tool results.

"MCP tools stay stable. Runtime Projection changes with execution state."
"The MCP client does not need to reconstruct workflow progress from conversation history; Invariant returns the next execution boundary after every action."


Domain MCP vs. Invariant MCP

Generic workflow control tools do not replace domain-specific MCP tools:


5-Minute Quick Setup

Expose your Invariant app via MCP to Claude Desktop or Cursor:

ts
import { mcpServer } from "@invariant/mcp";
import { app } from "./runtime";

// Mount Invariant MCP tools on your stdio or HTTP server
const server = mcpServer({
  app,
  name: "support-agent-mcp",
  version: "1.0.0",
});

await server.start();

The Architectural Contrast


Shared Continuation Pattern (Realtime Live & MCP)

Both Persistent Realtime Models (Gemini Live WebSocket) and MCP Clients (Claude Desktop / Cursor) share the exact same continuation pattern:

The runtime continuation semantics are the same; the transport and model-session lifecycle differ.


Stable Tool Surface

An @invariant/mcp server exposes 4 generic, stable runtime tools:

MCP Tool NamePurposeInput PayloadReturn Value
invariant.get_stateRetrieves current AgentContextProjection (context + runtime) for the session.{ sessionId: string }{ status: "accepted", context: AgentContextProjection }
invariant.start_workflowInitiates a new durable workflow run within session.{ sessionId: string, workflowId: string, input: object }{ status: "accepted", next: RuntimeProjection }
invariant.submit_inputSubmits input payload to active .wait() boundary.{ sessionId: string, payload: object }{ status: "accepted", next: RuntimeProjection }
invariant.cancel_workflowCancels active workflow run.{ sessionId: string, reason?: string }{ status: "accepted", next: RuntimeProjection }

Tool Execution Result Example

When an MCP client invokes invariant.submit_input({ sessionId: "sess_100", payload: { locationId: "loc_downtown" } }), Invariant commits the durable transition and returns the updated RuntimeProjection in the tool result:

json
{
  "status": "accepted",
  "next": {
    "revision": 18,
    "activeExecution": {
      "runId": "run_booking_991",
      "workflowId": "boulevard-booking",
      "currentNodeId": "select-service",
      "status": "waiting"
    },
    "expectedInput": {
      "schema": {
        "type": "object",
        "properties": {
          "serviceId": {
            "type": "string",
            "description": "ID of selected salon service"
          }
        },
        "required": ["serviceId"]
      }
    },
    "validActions": [
      {
        "name": "submit_input",
        "description": "Submit service selection to active execution"
      },
      { "name": "cancel_workflow", "description": "Cancel active booking" }
    ]
  }
}

The tool result tells the MCP client:

"The location selection was committed. The execution is now waiting at select-service and expects serviceId."

The MCP client can make its next decision from the fresh execution boundary, while Invariant deterministically validates and commits the resulting runtime action.

Invariant Durable Execution Engine.