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:
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 Name | Purpose | Input Payload | Return Value |
|---|---|---|---|
invariant.get_state | Retrieves current AgentContextProjection (context + runtime) for the session. | { sessionId: string } | { status: "accepted", context: AgentContextProjection } |
invariant.start_workflow | Initiates a new durable workflow run within session. | { sessionId: string, workflowId: string, input: object } | { status: "accepted", next: RuntimeProjection } |
invariant.submit_input | Submits input payload to active .wait() boundary. | { sessionId: string, payload: object } | { status: "accepted", next: RuntimeProjection } |
invariant.cancel_workflow | Cancels 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:
{
"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-serviceand expectsserviceId."
The MCP client can make its next decision from the fresh execution boundary, while Invariant deterministically validates and commits the resulting runtime action.