Stately
Packages

Stately MCP

Use Stately's machine tools from an MCP compatible agent.

Use Stately's machine tools from an MCP-compatible agent.

Connect

Choose your client and add Stately MCP using one of these methods.

Codex

codex mcp add stately --url https://stately.ai/mcp
codex mcp login stately

Claude Code

claude mcp add --transport http stately https://stately.ai/mcp

Then open Claude Code, run /mcp, and complete Stately sign-in.

Cursor

Open Cursor Settings → MCP → Add new global MCP server, then add:

{
  "mcpServers": {
    "stately": {
      "url": "https://stately.ai/mcp"
    }
  }
}

Save the configuration and complete Stately sign-in when Cursor connects. To share the server with a project, put the same configuration in .cursor/mcp.json at the project root.

VS Code with GitHub Copilot

Create .vscode/mcp.json in your project:

{
  "servers": {
    "stately": {
      "type": "http",
      "url": "https://stately.ai/mcp"
    }
  }
}

Open the Command Palette and run MCP: List Servers, start stately, then complete Stately sign-in. For a personal configuration available in every workspace, run MCP: Open User Configuration instead.

Other MCP clients

Add a remote server using the Streamable HTTP transport and this URL:

https://stately.ai/mcp

Complete Stately sign-in when the client connects.

Machine input

Most tools accept a machine config object or a source document. Conversion supports XState, SCXML, XGraph, and D2. Validation also supports JSON, YAML, and Mermaid.

create_state_machine

Creates a new XState v5 machine from a natural-language request. The connected agent authors the XState source, then Stately normalizes it and returns the source. Visualization defaults on and returns native PNG image blocks because a diagram usually makes generated behavior easier to verify. Set visualization to false only for code-only requests, clients that cannot display images, or machines where a diagram adds no useful information.

Summary: create and visualize a machine
Make a state machine representing an order checkout flow.

The agent calls Stately with complete XState v5 source. Omit visualization to render PNG diagrams, customize it with direction or parentNodeIds, or set it to false to return only the normalized XState source.

validate_machine

Checks whether a machine can be parsed and reports structural issues such as unreachable states. A successful response contains ok and an issues array.

Summary: validate a machine
Use Stately to validate this machine:

createMachine({
  id: 'player',
  initial: 'paused',
  states: {
    paused: { on: { PLAY: 'playing' } },
    playing: { on: { PAUSE: 'paused', STOP: 'stopped' } },
    stopped: { type: 'final' }
  }
});

convert_machine

Converts a machine between XState, SCXML, XGraph, and D2. The response contains the target format, converted content, and any warnings.

Summary: convert XState to SCXML
Use Stately to convert this machine to SCXML:

createMachine({
  id: 'player',
  initial: 'paused',
  states: {
    paused: { on: { PLAY: 'playing' } },
    playing: { on: { STOP: 'stopped' } },
    stopped: { type: 'final' }
  }
});
Summary: convert SCXML to XState
Use Stately to convert this SCXML machine to XState:

<scxml xmlns="http://www.w3.org/2005/07/scxml" name="player" initial="paused">
  <state id="paused">
    <transition event="PLAY" target="playing" />
  </state>
  <state id="playing">
    <transition event="STOP" target="stopped" />
  </state>
  <final id="stopped" />
</scxml>
Summary: convert XState to D2
Use Stately to convert this machine to D2:

createMachine({
  id: 'player',
  initial: 'paused',
  states: {
    paused: { on: { PLAY: 'playing' } },
    playing: { on: { STOP: 'stopped' } },
    stopped: { type: 'final' }
  }
});
Summary: convert XState to XGraph
Use Stately to convert this machine to XGraph:

createMachine({
  id: 'player',
  initial: 'paused',
  states: {
    paused: { on: { PLAY: 'playing' } },
    playing: { on: { STOP: 'stopped' } },
    stopped: { type: 'final' }
  }
});

diff_machines

Compares two machine documents structurally instead of comparing their source text. It returns a summary and semantic diff; set includePatches to request applicable patches.

Summary: compare two machine versions
Use Stately to compare these two versions of a machine and suggest patches:

Before:
createMachine({
  id: 'player',
  initial: 'paused',
  states: {
    paused: { on: { PLAY: 'playing' } },
    playing: {}
  }
});

After:
createMachine({
  id: 'player',
  initial: 'paused',
  states: {
    paused: { on: { PLAY: 'playing' } },
    playing: { on: { STOP: 'stopped' } },
    stopped: { type: 'final' }
  }
});

apply_machine_patches

Applies semantic patches to a machine and returns the updated document. Use to to choose the returned format.

Summary: update a machine
Use Stately to rename the playing state to active and return the updated XState machine:

createMachine({
  id: 'player',
  initial: 'paused',
  states: {
    paused: { on: { PLAY: 'playing' } },
    playing: {}
  }
});

generate_graph_paths

Generates shortest or simple paths through a machine. The response includes the event steps for each path plus state and transition coverage. Stately MCP returns at most five paths per call.

Summary: generate shortest paths
Use Stately to find up to five shortest paths through this machine:

createMachine({
  id: 'player',
  initial: 'paused',
  states: {
    paused: { on: { PLAY: 'playing' } },
    playing: { on: { PAUSE: 'paused', STOP: 'stopped' } },
    stopped: { type: 'final' }
  }
});

simulate_machine

Runs up to 100 events through a machine and returns a step-by-step trace of states, context, and executed action names. Guards are stubbed during this deterministic simulation.

Summary: simulate events
Use Stately to simulate PLAY followed by STOP on this machine:

createMachine({
  id: 'player',
  initial: 'paused',
  states: {
    paused: { on: { PLAY: 'playing' } },
    playing: { on: { STOP: 'stopped' } },
    stopped: { type: 'final' }
  }
});

visualize_machine

Renders each machine hierarchy level as a directly viewable PNG. Codex, Claude, and other image-capable MCP clients receive one native image block per parent node. Structured content contains parent IDs, labels, hierarchy levels, dimensions, and warnings without duplicating image data. Use parentNodeIds to select levels; omit it to render every parent with direct child states.

Each returned image uses the MCP ImageContent shape:

{ type: 'image', data: pngBase64, mimeType: 'image/png' }
Summary: visualize a machine
Use Stately to visualize this machine from left to right:

createMachine({
  id: 'player',
  initial: 'paused',
  states: {
    paused: { on: { PLAY: 'playing' } },
    playing: { on: { STOP: 'stopped' } },
    stopped: { type: 'final' }
  }
});

analyze_machine

Combines deterministic checks with AI review. Provide optional intent to assess the machine against its expected behavior. The response contains issues and may include suggested fixes. Use validate_machine when only deterministic checks are needed.

Summary: analyze intended behavior
Use Stately to check that STOP reaches a final state and playback cannot restart:

createMachine({
  id: 'player',
  initial: 'paused',
  states: {
    paused: { on: { PLAY: 'playing' } },
    playing: { on: { STOP: 'stopped' } },
    stopped: { type: 'final' }
  }
});

generate_test_code

Generates a runnable Vitest file with one test per generated path. Each test sends the path's events and asserts its final state. Guards and actions are stubbed.

Summary: generate Vitest tests
Use Stately to generate Vitest tests for the shortest paths through this machine:

createMachine({
  id: 'player',
  initial: 'paused',
  states: {
    paused: { on: { PLAY: 'playing' } },
    playing: { on: { STOP: 'stopped' } },
    stopped: { type: 'final' }
  }
});

extract_machines_from_code

Parses XState source code and returns the extracted machine as an XGraph document.

Summary: extract a machine from TypeScript
Use Stately to extract the machine from this TypeScript:

import { createMachine } from 'xstate';

export const player = createMachine({
  id: 'player',
  initial: 'paused',
  states: {
    paused: { on: { PLAY: 'playing' } },
    playing: { on: { STOP: 'stopped' } },
    stopped: { type: 'final' }
  }
});

All Stately MCP tools are registered as read-only, non-destructive, idempotent, and closed-world.

Self-hosting

Self-host Stately Studio, then replace the hosted URL above with your deployment's /api/mcp endpoint, for example https://studio.example.com/api/mcp.

For enterprise self-hosting options, see pricing and contact us.

On this page