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]
| Flag | Effect |
|---|---|
--client | claude-code, cursor, codex, vscode or windsurf |
--scope project|user | where 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 |
--name | the 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 |
--force | replace a different entry already under that name |
--dry-run | show the file it would write; write nothing |
--print | print 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 |
--json | the result as JSON |
--twin, --instance, --read-only, --tools | the 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 scope | Next step |
|---|---|
| Claude Code, project | restart Claude Code in this directory and approve the project’s rystic server when it asks |
| Claude Code, user | restart Claude Code; /mcp lists the server |
| Cursor | restart Cursor, or turn the server on under Settings > MCP |
| Codex, project | restart Codex in this directory; Codex reads .codex/config.toml only in a trusted project |
| Codex, user | restart Codex |
| VS Code | reload VS Code, then start the server from the MCP: List Servers command |
| Windsurf | restart 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]
| Flag | Effect |
|---|---|
--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-only | serves only the tools the MCP tool reference marks read-only |
--tools a,b,c | serves 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:
list_twinsorstart_twin(returns the URL)seed, orload_scenario- Act against that URL with your own code
settle, which waits until the app under test is doneinspect_state,list_calls,list_sent,diff_statesave_test_case, orcheck_test_caseagainst 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.
| Client | Project scope | User 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.json | code --add-mcp, or the file MCP: Open User Configuration opens (Install has the line) |
| Windsurf | none | ~/.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 mcp | Docs MCP | |
|---|---|---|
| Where it runs | on your machine, launched by the client over stdio | hosted at https://www.rystic.ai/mcp, over HTTP |
| What it does | starts and drives simulators | searches and fetches these docs |
| Tools | every tool in the MCP tool reference | search_rystic_docs, fetch_rystic_doc |
| Needs | the rystic CLI and an API key or license | nothing |
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.