Skip to Content
Connect your coding agent

Guides

Connect your coding agent

rystic mcp is a local MCP server. Through it your coding agent starts a simulator, loads a scenario, seeds records and moves the clock. It reads state and the calls and webhooks the simulator saw, and diffs state against where it started. It also rolls back to a snapshot, saves a scenario file and keeps a run as a test case, all without a curl line.

Requires a current rystic CLI. If rystic help mcp reports an unknown command, run rystic self-update. New to Rystic? Install the CLI and sign in first.

The server speaks MCP over stdio: the client launches rystic mcp as a subprocess. Each tool is a thin wrapper over a CLI command or a control-plane route, so it returns what that command or route returns on your plan. A simulator it starts keeps running after the client exits; stop_twin or rystic stop ends it. The tool names say “twin”, meaning a simulator, and take the product names rystic list prints, such as stripe-twin.

Install

In Cursor or VS Code, one click adds the server: Add to Cursor, Add to VS Code or Add to VS Code Insiders. The editor opens and asks before it adds the entry. Like --print, the entry’s command is plain rystic, so the CLI must be on the editor’s PATH and signed in. When it is not on the PATH, use the command below.

In Claude Desktop, install the rystic-mcp bundle (.mcpb) from the latest release ; it carries the binary. Claude Desktop asks for an optional Rystic API key when you install the bundle. Paste one from your account’s API keys page, or leave it empty to use the Rystic login or license already on this machine.

No account yet? Ask your agent to sign in to Rystic; it opens the sign-in page and finishes once you approve.

One command writes the server entry into your client’s config:

rystic mcp install --client claude-code
# created /p/.mcp.json (claude-code, project scope)
# next: restart Claude Code in this directory and approve the project's rystic server when it asks

The entry’s command is the absolute path of the rystic binary you ran, so the client finds it even when rystic is not on its PATH. An existing config file is merged: other servers and keys stay. A file that is not valid JSON, comments and trailing commas included, is refused and left unmodified. A new user-scope file is created readable only by you (mode 0600).

rystic mcp install --client <claude-code|cursor|codex|vscode|windsurf> [--scope project|user] [--name rystic] [--command <path>] [--force] [--dry-run] [--print] [--json]
                   [--twin <simulator>] [--instance <name>] [--read-only] [--tools a,b,c]
FlagEffect
--clientclaude-code, cursor, codex, vscode or windsurf
--scope project|userwhere the entry goes; default project for Claude Code, Cursor, Codex and VS Code, user for Windsurf. The paths are in the table under Configure by hand
--namethe server’s name in the config, default rystic; another name adds a second entry beside an existing one
--command <path>the binary the client launches, instead of the absolute path of the running rystic
--forcereplace a different entry already under that name
--dry-runshow the file it would write; write nothing
--printprint the client’s copy-paste block, the same as the blocks under Configure by hand; write nothing. Its command is plain rystic, so rystic must be on the client’s PATH. Takes no other flag but --client, --json and the scope flags
--jsonthe result as JSON
--twin, --instance, --read-only, --toolsthe scope flags, checked as rystic mcp checks them and written into the entry’s args, --twin as the simulator’s full name: "args": ["mcp", "--twin", "stripe-twin", "--read-only"]

Running it again with nothing to change, or with a different entry already there:

unchanged /p/.mcp.json (claude-code, project scope): "rystic" is already installed
rystic: /p/.mcp.json: already has a different "rystic" server; pass --force to replace it, or --name to add another (not modified)

It exits 2 on a bad flag, 9 on a conflicting entry without --force, and 1 when the existing file cannot be read or is not valid.

The last line of a write names the next step:

Client and scopeNext step
Claude Code, projectrestart Claude Code in this directory and approve the project’s rystic server when it asks
Claude Code, userrestart Claude Code; /mcp lists the server
Cursorrestart Cursor, or turn the server on under Settings > MCP
Codex, projectrestart Codex in this directory; Codex reads .codex/config.toml only in a trusted project
Codex, userrestart Codex
VS Codereload VS Code, then start the server from the MCP: List Servers command
Windsurfrestart Windsurf, or refresh the MCP servers in Cascade

VS Code’s user scope is not written by rystic. code --add-mcp takes one entry with a name, not the whole file: the rystic entry from rystic mcp install --client vscode --print with "name": "rystic" added.

code --add-mcp '{"name":"rystic","type":"stdio","command":"rystic","args":["mcp"]}'

Or paste that entry, without name, under "servers" in the file MCP: Open User Configuration opens.

Scope the server

By default rystic mcp serves every tool on every simulator running on this machine. Four flags narrow it:

rystic mcp [--twin <simulator>] [--instance <name>] [--read-only] [--tools a,b,c]
FlagEffect
--twin <simulator>serves one simulator, named as rystic run takes it. Its tools take no instance or twin argument, and start_twin takes no name: each acts on that simulator’s one running instance, and list_twins lists only its instances. start_twin starts the instance, and refuses with name_conflict while one runs. A call naming another simulator or instance fails with out_of_scope
--instance <name>only with --twin: the instance to act on when several run, and the name start_twin gives the one it starts
--read-onlyserves only the tools the MCP tool reference marks read-only
--tools a,b,cserves only the named tools. With --read-only, only read-only tools may be named

A bad scope flag exits 2 and names the valid choices. A scoped server’s instructions and its guide describe only what it serves, and a prompt that needs a tool it hides is hidden too. rystic mcp install takes the same flags and writes them into the client’s entry.

Example session

The agent’s prompt: “Test that our checkout code charges the customer once and sends one receipt webhook.”

start_twin {"twin": "stripe-twin", "scenario": "design_studio", "name": "stripe"}
→ {"instance": "stripe", "ref": "stripe-twin/stripe", "url": "http://localhost:53124", "port": 53124, "runner": "native", "baseline": "stored", …}

# the agent points its Stripe client at http://localhost:53124 and runs the checkout test

list_calls {"instance": "stripe", "method": "POST"}
→ {"calls": [the POST /v1/charges the test made, with its caller], "matched": 1, "truncated": false, …}

list_sent {"instance": "stripe"}
→ one charge.succeeded event

diff_state {"instance": "stripe"}
→ {"baseline": "start_twin", "counts": {"created": 1, "changed": 0, "deleted": 0}, "resources": […], "truncated": false, …}

advance_clock {"instance": "stripe", "duration": "48h"}
→ {"instance": "stripe", "clock": "…"}

save_test_case {"instance": "stripe", "name": "checkout-charges-once", "prompt": "Charge the customer once and send one receipt webhook."}
→ {"name": "checkout-charges-once", "cell_dir": "…/checkout-charges-once-…", "draft": "…", "twins": [{"instance": "stripe", "twin": "stripe-twin", "scenario": "design_studio", "counts": {"created": 1, "changed": 0, "deleted": 0}, …}], …}

# later, after a code change: load the scenario again, rerun the checkout test, grade the new run

load_scenario {"instance": "stripe", "name": "design_studio"}
check_test_case {"instance": "stripe", "case": "…/checkout-charges-once-…"}
→ {"result": "pass", "cell_dir": "…", "checks": [{"id": "nothing_destructive", "result": "pass", …}, …], …}

stop_twin {"instance": "stripe"}

Call order

At startup the server hands the client instructions with this order of calls:

  1. list_twins or start_twin (returns the URL)
  2. seed, or load_scenario
  3. Act against that URL with your own code
  4. settle, which waits until the app under test is done
  5. inspect_state, list_calls, list_sent, diff_state
  6. save_test_case, or check_test_case against a saved case

Your own code acts against the URL start_twin returned, as it would against the real API; the agent does not call the API through MCP. set_clock and advance_clock control time. snapshot_twin and restore_twin let the agent try one path, roll back and try another. Snapshots and test cases explains the baseline diff_state compares against, snapshots, scenario files and test cases. The guide resource walks each step, and the MCP tool reference lists every tool.

Configure by hand

Each block is a complete config file holding the rystic entry. Merge the entry into a file you already have.

ClientProject scopeUser scope
Claude Code.mcp.json~/.claude.json
Cursor.cursor/mcp.json~/.cursor/mcp.json
Codex.codex/config.toml (trusted projects only)~/.codex/config.toml
VS Code.vscode/mcp.jsoncode --add-mcp, or the file MCP: Open User Configuration opens (Install has the line)
Windsurfnone~/.config/devin/mcp_config.json; $XDG_CONFIG_HOME/devin/mcp_config.json when that is set, %AppData%\devin\mcp_config.json on Windows

Claude Code

{
  "mcpServers": {
    "rystic": {
      "type": "stdio",
      "command": "rystic",
      "args": [
        "mcp"
      ]
    }
  }
}

Cursor

{
  "mcpServers": {
    "rystic": {
      "type": "stdio",
      "command": "rystic",
      "args": [
        "mcp"
      ]
    }
  }
}

Codex

[mcp_servers.rystic]
command = "rystic"
args = ["mcp"]

VS Code

{
  "servers": {
    "rystic": {
      "type": "stdio",
      "command": "rystic",
      "args": [
        "mcp"
      ]
    }
  }
}

Windsurf

{
  "mcpServers": {
    "rystic": {
      "command": "rystic",
      "args": [
        "mcp"
      ]
    }
  }
}

If the client cannot find rystic, set command to its absolute path (command -v rystic prints it).

The docs MCP is a different server

rystic mcpDocs MCP
Where it runson your machine, launched by the client over stdiohosted at https://www.rystic.ai/mcp, over HTTP
What it doesstarts and drives simulatorssearches and fetches these docs
Toolsevery tool in the MCP tool referencesearch_rystic_docs, fetch_rystic_doc
Needsthe rystic CLI and an API key or licensenothing

Add both: the docs MCP answers how a simulator behaves, rystic mcp runs one. Agent quick start → Machine-readable surfaces shows the one-line install for the docs MCP.

Last updated on