# MCP tool reference

Every tool, prompt, resource and error code rystic mcp serves, with each tool's arguments and annotations, generated from the released CLI.

The tools, prompts, resources and error codes below are generated from the released `rystic mcp`, as an MCP client lists them. Their text is the CLI's own, so a "twin" is a simulator and a "world" is a scenario. [Connect your coding agent](https://www.rystic.ai/docs/mcp-server.md) shows how to install the server, scope it and drive a simulator with it.

## Tools

Each tool declares MCP annotations. Read-only tools change no state. Destructive tools replace or drop state; idempotent ones are safe to repeat with the same arguments. Open-world tools reach beyond this machine, to download a simulator release, check your license or sign you in.

<!-- BEGIN generated: mcp-tools (python3 scripts/sync-cli-reference.py --binary <rystic>; do not edit) -->

| Tool | Title | Annotations |
|---|---|---|
| [`advance_clock`](#advance_clock) | Advance the clock | destructive |
| [`check_test_case`](#check_test_case) | Check a test case | none |
| [`diff_state`](#diff_state) | Diff state | read-only |
| [`inspect_state`](#inspect_state) | Inspect state | read-only |
| [`list_calls`](#list_calls) | List calls | read-only |
| [`list_scenarios`](#list_scenarios) | List scenarios | read-only |
| [`list_sent`](#list_sent) | List sent effects | read-only |
| [`list_twins`](#list_twins) | List twins | read-only |
| [`load_scenario`](#load_scenario) | Load a scenario | destructive, idempotent |
| [`reset`](#reset) | Reset state | destructive, idempotent |
| [`restore_twin`](#restore_twin) | Restore a snapshot | destructive, idempotent |
| [`save_test_case`](#save_test_case) | Save a test case | none |
| [`save_world`](#save_world) | Save a scenario file | destructive |
| [`seed`](#seed) | Seed records | destructive |
| [`set_clock`](#set_clock) | Set the clock | destructive, idempotent |
| [`sign_in`](#sign_in) | Sign in to Rystic | open-world |
| [`snapshot_twin`](#snapshot_twin) | Snapshot a twin | none |
| [`start_twin`](#start_twin) | Start a twin | open-world |
| [`stop_twin`](#stop_twin) | Stop a twin | destructive, idempotent |

### `advance_clock`

Move the instance's clock by whole seconds, forward or (negative) back: give seconds or duration, exactly one. Events fire as the clock passes them. Returns the clock the twin then reads.

| Argument | Type | Meaning |
|---|---|---|
| `instance` (required) | string | the instance: its name, its twin when that twin runs one instance, or \<twin>/\<name> (list_twins names them) |
| `duration` | string | a non-zero duration of whole seconds such as 90s, 15m or 48h |
| `seconds` | integer | a non-zero number of seconds |

### `check_test_case`

Grade the instance's run since its baseline against a saved test case's checks, as `rystic grade` does, with no model: capture the run as save_test_case does, with the twin's event timeline as world.json, into a new grid cell dir holding the case's eval, grade it, and write its verdict.json. case is the cell_dir or eval path save_test_case returned, or any eval file; a case dir's checks/ YAML files are graded too. The case's world must name exactly the instances' twins, by twin name or by grid name (the twin name without -twin). Returns result (pass, fail, error, or incomplete when every graded check passed but one was skipped), reason, cell_dir, notes, and per check its id (nothing_destructive, checks[i] in eval order, then checks/\<file>[j]), result (pass, fail, error or skipped), detail and, for a failure, the rows behind it. A script check is skipped, never run. To check a new run, reset or load_scenario the instance, run the agent, then call this.

| Argument | Type | Meaning |
|---|---|---|
| `case` (required) | string | an absolute path: the cell_dir or eval path save_test_case returned, or an eval file |
| `instance` | string | the instance: its name, its twin when that twin runs one instance, or \<twin>/\<name> (list_twins names them) |
| `instances` | array of strings, at least 1 item | several instances, one per twin, for a case across twins; instead of instance |
| `out_dir` | string | an absolute path, not yet existing or empty, to write the new run's cell dir to (default: a new temp dir) |

### `diff_state`

Compare the instance's state now with its baseline, the state it had when start_twin started it, load_scenario loaded a scenario or reset cleared it: rows created, changed (each changed field's JSON Pointer path, before and after) and deleted, per resource. register narrows it to one register. counts cover every row that differs (in register, when given); resources holds a page of them, in resource, then created, changed and deleted, then key order. concise (the default) gives created and deleted rows with string values over 256 bytes cut, and changed rows as their fields; detailed adds each changed row's state and cuts only a row over 12 KB. A cut row is marked truncated. A page holds at most limit rows and about 20 KB. When more remain, next_cursor reads the next page; whenever anything is cut, truncated is true and hint names the call that gets the rest. An instance with no baseline (started outside this server) gets one on the first call, which answers baseline first_seen and an empty diff.

| Argument | Type | Meaning |
|---|---|---|
| `instance` (required) | string | the instance: its name, its twin when that twin runs one instance, or \<twin>/\<name> (list_twins names them) |
| `cursor` | string | the next_cursor a page returned, to read the page after it; omit for the first page |
| `format` | `concise` or `detailed` | concise (the default) trims each entry to what picks the next call; detailed carries the whole entry |
| `limit` | integer, 1 to 500 | at most this many entries on the page (default 50); a page also stops near 20 KB |
| `register` | string | only this register's rows |

### `inspect_state`

Return the instance's state (GET /_rystic/inspect) a page at a time: state is resource, then row key, then row, in key order. register narrows it to one register, and key with it to one row; matched counts the rows they match. concise (the default) cuts string values over 256 bytes and lists those rows in cut_rows; detailed cuts only a row over 12 KB. A page holds at most limit rows and about 20 KB. When more remain, next_cursor reads the next page; whenever anything is cut, truncated is true and hint names the call that gets the rest. A state larger than one page also carries state_uri, a resource link to the whole state uncut. view asks for one of the twin's named views instead, such as identities, answered as {view, result}; a view that is a file, or larger than a page, comes back as its size and the URL to fetch it from.

| Argument | Type | Meaning |
|---|---|---|
| `instance` (required) | string | the instance: its name, its twin when that twin runs one instance, or \<twin>/\<name> (list_twins names them) |
| `cursor` | string | the next_cursor a page returned, to read the page after it; omit for the first page |
| `format` | `concise` or `detailed` | concise (the default) trims each entry to what picks the next call; detailed carries the whole entry |
| `key` | string | only the row with this key, in register |
| `limit` | integer, 1 to 500 | at most this many entries on the page (default 50); a page also stops near 20 KB |
| `register` | string | only this register's rows |
| `view` | string | a named view instead of the state, read whole |

### `list_calls`

List the API calls the instance served since its last reset (GET /_rystic/calls), oldest first, a page at a time; method, path_prefix, status and actor filter them. concise (the default) gives each call's seq, at, method, path, status and actor; detailed gives the twin's whole record. total counts every call since the reset, matched the kept calls the filters match. A page holds at most limit calls and about 20 KB. When more remain, next_cursor reads the next page; whenever anything is cut, truncated is true and hint names the call that gets the rest.

| Argument | Type | Meaning |
|---|---|---|
| `instance` (required) | string | the instance: its name, its twin when that twin runs one instance, or \<twin>/\<name> (list_twins names them) |
| `actor` | string | only calls made as this actor |
| `cursor` | string | the next_cursor a page returned, to read the page after it; omit for the first page |
| `format` | `concise` or `detailed` | concise (the default) trims each entry to what picks the next call; detailed carries the whole entry |
| `limit` | integer, 1 to 500 | at most this many entries on the page (default 50); a page also stops near 20 KB |
| `method` | string | only calls with this HTTP method, such as POST |
| `path_prefix` | string | only calls whose path starts with this, such as /v1/charges |
| `status` | integer or string | only calls answered with this status, such as 404, or this class, such as "4xx" |
| `tail` | integer, at least 1 | deprecated, prefer cursor: start the page at the last N entries |

### `list_scenarios`

List the named starting worlds the instance's twin ships (GET /_rystic/scenarios), each with a summary.

| Argument | Type | Meaning |
|---|---|---|
| `instance` (required) | string | the instance: its name, its twin when that twin runs one instance, or \<twin>/\<name> (list_twins names them) |

### `list_sent`

List what the instance sent since its last reset: webhooks, emails and other outbound effects (GET /_rystic/egress), oldest first, a page at a time. Each event names its effect and type as the twin's model calls them; no field marks a webhook apart from an email, so filter on effect or type. concise (the default) gives each event's seq, effect, type and owner; detailed adds the payload. delivery, when present, sums up webhook delivery with its newest 20 attempts in results (results_total counts the attempts the twin reports). total counts every event since the reset, matched the kept events the filters match. A page holds at most limit events and about 20 KB, and an event over 12 KB is cut and marked truncated. When more remain, next_cursor reads the next page; whenever anything is cut, truncated is true and hint names the call that gets the rest.

| Argument | Type | Meaning |
|---|---|---|
| `instance` (required) | string | the instance: its name, its twin when that twin runs one instance, or \<twin>/\<name> (list_twins names them) |
| `cursor` | string | the next_cursor a page returned, to read the page after it; omit for the first page |
| `effect` | string | only events with this effect |
| `format` | `concise` or `detailed` | concise (the default) trims each entry to what picks the next call; detailed carries the whole entry |
| `limit` | integer, 1 to 500 | at most this many entries on the page (default 50); a page also stops near 20 KB |
| `tail` | integer, at least 1 | deprecated, prefer cursor: start the page at the last N entries |
| `type` | string | only events of this type |

### `list_twins`

List the twin instances running on this machine: each one's name, twin, version, URL, runner and status from a live probe. Call it first to find the instance the other tools take.

No arguments.

### `load_scenario`

Replace the instance's state with a named scenario, keeping the twin's built-in records (POST /_rystic/scenario). The loaded state becomes diff_state's baseline.

| Argument | Type | Meaning |
|---|---|---|
| `instance` (required) | string | the instance: its name, its twin when that twin runs one instance, or \<twin>/\<name> (list_twins names them) |
| `name` (required) | string | the scenario, as list_scenarios names it |

### `reset`

Reset the instance to the twin's built-in records, dropping scenario and seeded state (POST /_rystic/reset), clearing its calls and sent log. The reset state becomes diff_state's baseline.

| Argument | Type | Meaning |
|---|---|---|
| `instance` (required) | string | the instance: its name, its twin when that twin runs one instance, or \<twin>/\<name> (list_twins names them) |

### `restore_twin`

Roll the instance back to a snapshot snapshot_twin saved: reset it, then land the snapshot's state, clock, id counters, pending scheduled events and network shaping, so ids minted after the restore continue where the snapshot left off. The restored state becomes diff_state's baseline. A snapshot taken on another version of the twin is refused. On a twin release older than the seed round trip, which holds no id counters, every result carries a warning: ids minted after the restore can collide with restored records, and per-account records can come back duplicated. A snapshot does not hold, so a restore does not bring back: the idempotency cache (a replayed request makes a new object), the request-id counter, the calls and sent logs (they start empty), the webhook delivery queue, credential bindings, upload sessions, the rate limiter, the clock's wall offset, scheduled events in full (only the pending events of the world's own schedule come back; one that uses a value a fired event bound is dropped, and a schedule loaded on its own replays from its start), built-in records deleted before the save (the reset brings them back), and whether a scenario installed the network shaping (once landed, the shaping stays through later resets). A pending default-actor call on a route that needs a credential binding fails the restore after the reset, which leaves the instance reset.

| Argument | Type | Meaning |
|---|---|---|
| `instance` (required) | string | the instance: its name, its twin when that twin runs one instance, or \<twin>/\<name> (list_twins names them) |
| `name` (required) | string | the snapshot's name, as snapshot_twin saved it |

### `save_test_case`

Save the instance's run since its baseline as a test case: write a grid cell dir (before is diff_state's baseline, after the state now, with the calls and sent log since the last reset) and draft an eval from it with `rystic grade --draft`. The draft expects each row the run created or changed, forbids any other creation, change, call actor or method, and allow_deletes each row it deleted; the saved cell passes it. The state after the last seed through this server since the baseline is the run's before, so seeded rows are setup, not the run's; rows a scenario timeline event seeds during the run count as the run's. Returns the draft YAML and cell_dir, whose eval.yaml holds the draft, so `rystic grade <cell_dir>` passes. Trim the checks to what the task requires before keeping them. An instance with no baseline is refused: reset, load_scenario or diff_state it before the run.

| Argument | Type | Meaning |
|---|---|---|
| `name` (required) | string | the case's name: the eval name in cell.json and the temp dir's prefix |
| `instance` | string | the instance: its name, its twin when that twin runs one instance, or \<twin>/\<name> (list_twins names them) |
| `instances` | array of strings, at least 1 item | several instances, one per twin, for a case across twins; instead of instance |
| `out_dir` | string | an absolute path, not yet existing or empty, to write the cell dir to (default: a new temp dir) |
| `prompt` | string | the task the agent was given, the draft's prompt (default: a placeholder to replace) |

### `save_world`

Save the instance's state as a scenario file at file, the scenario document `rystic run --seed <file>` boots and POST /_rystic/seed lands, so a teammate, a CI job or a later run starts a twin in this state. It holds what snapshot_twin holds: the whole state, the clock, the id counters, the pending scheduled events and, when your plan includes network shaping and a profile is installed, that shaping. The file names the twin but no instance, version or model hash; a twin release that cannot take a record refuses the load and lists the records. An existing file, a symlink included, is refused unless force is true, which replaces the file or writes through the symlink. New files are private to your user; replacing a file preserves its permissions. It refuses a pending event that acts as a named caller and a scenario too large for the seed route to take back. On a twin release older than the seed round trip, which holds no id counters, the result carries a warning: ids minted after a load can collide with loaded records. The file does not hold, so loading it does not bring back: the idempotency cache (a replayed request makes a new object), the request-id counter, the calls and sent logs (they start empty), the webhook delivery queue, credential bindings, upload sessions, the rate limiter, the clock's wall offset, scheduled events in full (only the pending events of the world's own schedule come back; one that uses a value a fired event bound is dropped, and a schedule loaded on its own replays from its start), built-in records deleted before the save (the reset brings them back), and whether a scenario installed the network shaping (once landed, the shaping stays through later resets). It holds no rng_seed and no credentials either, which the twin does not expose; add those keys to the file by hand when a run needs them. A pending default-actor call on a route that needs a credential binding fails the load.

| Argument | Type | Meaning |
|---|---|---|
| `instance` (required) | string | the instance: its name, its twin when that twin runs one instance, or \<twin>/\<name> (list_twins names them) |
| `file` (required) | string | the absolute path to write, such as a scenarios/ file in your repo |
| `force` | boolean | replace an existing file (default: refuse it) |

### `seed`

Merge records into the instance's state (POST /_rystic/seed). body is {register: {key: {field: value}}}; `rystic describe <twin> -json` shows each register with an example record. Seeding leaves diff_state's baseline where it is, so seeded rows read as created; save_test_case reads the seeded state as the run's starting state instead.

| Argument | Type | Meaning |
|---|---|---|
| `instance` (required) | string | the instance: its name, its twin when that twin runs one instance, or \<twin>/\<name> (list_twins names them) |
| `body` (required) | object | the seed document: {register: {key: {field: value}}} |

### `set_clock`

Pin the instance's clock to an RFC3339 instant (POST /_rystic/clock); events due by then fire. Returns the clock the twin then reads.

| Argument | Type | Meaning |
|---|---|---|
| `instance` (required) | string | the instance: its name, its twin when that twin runs one instance, or \<twin>/\<name> (list_twins names them) |
| `time` (required) | string | an RFC3339 instant such as 2026-05-01T09:00:00Z |

### `sign_in`

Sign in to Rystic, or sign up, in the browser, so start_twin can download twins: call it when a tool fails with license_or_lease. The first call returns a URL and a code at once; show both to the user, who opens the URL, checks that the page shows the same code and approves. Then call sign_in again: it answers pending until the user has approved, then stores the API key where `rystic login` stores it and answers signed_in. A link lasts 15 minutes; a call after that returns a new one. The API key never appears in a result.

No arguments.

### `snapshot_twin`

Save the instance's world under name, so restore_twin can roll back to it: try one path, roll back, try another. It holds the whole state, never a page,, the clock, the id counters, the pending scheduled events and, when your plan includes network shaping, that shaping. This CLI stores it per instance; it outlives a restart of the instance on the same twin version. A snapshot of the same name is replaced, and the result says so. Omit name to list the instance's snapshots. It refuses a pending event that acts as a named caller (a restore cannot rebind its credential) and a world too large for the seed route to take back. A snapshot does not hold, so a restore does not bring back: the idempotency cache (a replayed request makes a new object), the request-id counter, the calls and sent logs (they start empty), the webhook delivery queue, credential bindings, upload sessions, the rate limiter, the clock's wall offset, scheduled events in full (only the pending events of the world's own schedule come back; one that uses a value a fired event bound is dropped, and a schedule loaded on its own replays from its start), built-in records deleted before the save (the reset brings them back), and whether a scenario installed the network shaping (once landed, the shaping stays through later resets). A pending default-actor call on a route that needs a credential binding fails the restore after the reset, which leaves the instance reset.

| Argument | Type | Meaning |
|---|---|---|
| `instance` (required) | string | the instance: its name, its twin when that twin runs one instance, or \<twin>/\<name> (list_twins names them) |
| `name` | string | the snapshot's name (letters, digits, '.', '_' and '-', at most 64); omit to list the instance's snapshots |

### `start_twin`

Start a twin in the background, as `rystic run <twin> -d` does, and return its instance name and URL; point the code under test at the URL. A twin that is not installed is pulled first, as `rystic run` pulls one, which can take a minute; a call that carries a progressToken gets the download as notifications/progress, and cancelling the call stops the pull and any twin it started. It takes a free port unless port is given, and stores the state it boots into as diff_state's baseline. The twin keeps running after this server exits; stop_twin ends it.

| Argument | Type | Meaning |
|---|---|---|
| `twin` (required) | string | the twin's name, as `rystic list` prints it |
| `clock` | string | start the twin's clock at this RFC3339 instant |
| `name` | string | the instance name the other tools take (default: default) |
| `port` | integer, 0 to 65535 | listen port; omit or 0 for a free one |
| `project` | string | the project label `rystic ps --project` groups by (default: default) |
| `runner` | `native` or `docker` | how to run it (default: your rystic config, else native) |
| `scenario` | string | boot into this named scenario (the twin's own catalog) |
| `version` | string | the version to run (default: the installed current one, else the newest release) |

### `stop_twin`

Stop a running instance and remove its record and diff baseline, as `rystic stop` does.

| Argument | Type | Meaning |
|---|---|---|
| `instance` (required) | string | the instance: its name, its twin when that twin runs one instance, or \<twin>/\<name> (list_twins names them) |

<!-- END generated: mcp-tools -->

## Pages, filters and links

`inspect_state`, `list_calls`, `list_sent` and `diff_state` return one page at a time, at most `limit` entries and about 20 KB. [Tools](#tools) gives each one's filters and what `format` carries. Pass a page's `next_cursor` back as `cursor` for the next page. A cursor belongs to the baseline it was read against: after a `reset`, `load_scenario` or new baseline it is refused, and reading starts again without one.

Every page carries `truncated`. It is true when more pages remain or an entry was cut, and then `hint` names the exact call that gets the rest. `matched` counts the entries the filters match across every page. In either `format` an entry over 12 KB is cut and marked.

## Prompts

The server offers prompts, which a client lists as prompts or slash commands:

<!-- BEGIN generated: mcp-prompts (python3 scripts/sync-cli-reference.py --binary <rystic>; do not edit) -->

| Prompt | Title | Arguments | What it does |
|---|---|---|---|
| `reproduce_webhook_bug` | Reproduce a webhook bug | `twin` (required): the twin to run, as list_twins or `rystic list` names it; completes from the running and installed twins; `scenario`: a named starting world to load, as list_scenarios names it; completes from a running instance of the twin; `description`: what the webhook does wrong: fires twice, never fires, carries the wrong payload | Walk through reproducing a webhook bug on a twin and saving the run as a test case. |
| `write_test_for_flow` | Write a test for a flow | `twin` (required): the twin to run, as list_twins or `rystic list` names it; completes from the running and installed twins; `scenario`: a named starting world to load, as list_scenarios names it; completes from a running instance of the twin; `flow` (required): the flow to test, in a sentence or two: a customer subscribes, then cancels | Walk through driving a flow on a twin and saving it as a test case whose checks hold the flow's effects. |

<!-- END generated: mcp-prompts -->

Each walks the agent through `start_twin`, `load_scenario` or `seed`, the act step, `list_sent`, `list_calls` and `diff_state`, then `save_test_case`. `twin` takes a short name, `stripe` for `stripe-twin`. A simulator that is not running, installed or in your plan is refused with `unknown_twin`, and a scenario a running instance does not ship with `unknown_scenario`. Under `--twin`, the prompts take no `twin` argument.

Clients that support completion fill the arguments in:

- `twin` completes from the running simulators first, then the installed ones and those your license names, without a network call.
- `scenario` completes from a running instance of the simulator named in `twin`. With none running, it offers nothing.

## Resources

<!-- BEGIN generated: mcp-resources (python3 scripts/sync-cli-reference.py --binary <rystic>; do not edit) -->

| URI | Type | Holds |
|---|---|---|
| `rystic://guide` | `text/markdown` | The call order, instance argument forms, error recovery and a worked example. |
| `rystic://instances/{twin}/{name}/baseline` | `application/json` | The state diff_state compares the instance with, in the shape of the state resource, uncut: a deleted row and a changed field's before value are whole here. |
| `rystic://instances/{twin}/{name}/state` | `application/json` | A running instance's whole state as JSON: resource, then row key, then row, uncut. inspect_state links it when the state is larger than one page. |

<!-- END generated: mcp-resources -->

`{twin}` is the full simulator name, such as `stripe-twin`, and `{name}` the instance's name. Both template arguments complete from the running instances. A scoped server's guide says only what it serves.

## Results and errors

Every tool declares an `outputSchema` describing its result shapes and the error object, and every result carries `structuredContent` that matches it, error results included. A successful result's text content carries the same JSON, for a client that reads only text.

A failed call is an error result (`isError: true`), never a protocol error. Its structured content is `{"error": {"code", "message", "cause", "fix", "retryable", …}}`, and its text carries the same fields as lines. Extra fields appear where the code needs them, such as `retry_after_ms`, `upgrade_url`, `twin_errors` or `snapshots`. A malformed call is a `bad_argument` naming the argument: a wrong type, an unknown or missing argument, arguments that are not an object, a string over 64 KiB, or nesting over 64 levels.

A stdin line that is not one JSON-RPC message gets a JSON-RPC error, and the session goes on. That covers invalid JSON, a line nested over 10,000 levels, a line over 32 MiB, and any batch. Batches are not supported, so send each message on its own line. The error's code is `-32700` (parse error) or `-32600` (invalid request). It carries the request's `id` when the line names one and `null` otherwise, and each request in a batch gets its own error. The server logs each refused line to stderr. These are protocol errors, separate from the tool errors in the table below.

`retryable` says whether the same call, unchanged, may succeed later, and `retry_after_ms`, when present, how long to wait first. The table gives each code's default. An error after a write that may have taken effect, such as a `seed` or `advance_clock` whose answer was lost, is not retryable, and its `fix` says how to check before repeating it. Tools that are safe to repeat (`reset`, `load_scenario`, `set_clock`) keep the default. `rystic mcp -errors` prints this table.

<!-- BEGIN generated: mcp-errors (python3 scripts/sync-cli-reference.py --binary <rystic>; do not edit) -->

| code | retryable | retry_after_ms | cause | fix |
| --- | --- | --- | --- | --- |
| bad_argument | no | - | An argument is missing, unknown, of the wrong type, too large or out of range, or the arguments are not a JSON object. | Correct the argument the message names; tools/list carries each tool's input schema. |
| twin_not_running | no | - | No running instance has that name, or the instance did not answer. | Call list_twins for the running instances; start one with start_twin, or `rystic run <twin> -d` where this server serves no start_twin. |
| instance_ambiguous | no | - | The name matches more than one running instance. | Pass the instance as \<twin>/\<name>, one of the refs the message lists; a server started with `--twin` takes `--instance` \<name> instead. |
| feature_not_in_plan | no | - | The twin refused the call because your plan does not include the feature it needs. | Upgrade at the error's upgrade_url, or use a tool your plan includes; the error names the feature. |
| port_in_use | no | - | Another instance or process holds the port start_twin asked for. | Omit port, so the twin takes a free one, or name another port. |
| name_conflict | no | - | An instance of this twin with that name is already running. | Pass another name, or stop_twin the running instance first; under `--twin`, which pins the name, stop_twin it first. |
| unknown_scenario | no | - | The twin has no scenario by that name. | Call list_scenarios for the names this twin ships. |
| bad_seed_body | no | - | The twin refused the seed body: not a non-empty object of {register: {key: {field: value}}}, or a register, key or field it does not accept. | Fix what the error's twin_errors name; `rystic describe <twin> -json` shows each register with an example record. |
| license_or_lease | no | - | The license or API key is missing, expired, refused, or does not cover this twin. | Call sign_in, show the user the URL it returns, call it again once they approve, then retry; or paste an API key from https://www.rystic.ai/account/api-keys into this server's API key setting. With a shell: `rystic login` or `rystic license activate <file>`; `rystic doctor` names what is wrong. |
| unknown_twin | no | - | No release of that twin exists, at that version or for this platform. | Run `rystic list` for the twins your plan covers; omit version for the newest release. |
| download_failed | yes | - | The downloaded release failed its checksum or would not unpack, so nothing was installed. | Call start_twin again, which downloads afresh; if it fails again, `rystic feedback` with the message. |
| twin_unhealthy | yes | 1000 | The twin ran but did not serve, or answered with a server error. | Retry once after retry_after_ms; if it fails again, read the log lines the error carries, or `rystic logs <name>`, then stop_twin and start_twin again. |
| twin_refused | no | - | The twin refused the call with a status no other code covers. | Read the twin's message in the error; `rystic docs <twin>` describes its control routes. |
| out_of_scope | no | - | The call names a twin or instance other than the one this server serves (rystic mcp `--twin`, `--instance`). | Call the tool with no twin or instance argument, so it acts on the served instance; for another twin, run another rystic mcp. |
| no_baseline | no | - | The instance has no stored state to compare the run against: it was started outside this server and never reset, loaded or diffed through it. | Call reset, load_scenario or diff_state on the instance before the run, then save_test_case or check_test_case after it. |
| unknown_snapshot | no | - | The instance has no snapshot by that name; snapshots belong to one instance name of one twin. | Pick one of the names the error's snapshots lists, or call snapshot_twin without a name to list them; snapshot_twin takes a new one. |
| snapshot_version_mismatch | no | - | The snapshot was taken on another version of the twin than the instance runs now, so its records may not fit this one. | Take a new snapshot_twin on this version, or start_twin the instance at the version the message names and restore there. |
| snapshot_unsupported | no | - | The instance has a pending event that acts as a named caller, and neither a restore nor a load brings back credential bindings, so a snapshot or a saved world would not hold it. | Let the event fire or cancel it, then call snapshot_twin or save_world again. |
| snapshot_too_large | no | - | The world document is over the size the twin's seed route accepts, so a restore or a load could not land it. | Reduce the instance's state (reset, or delete records) and snapshot or save again; this world cannot be landed. |
| restore_failed | no | - | The instance was reset, but the twin refused the snapshot's world, so it now holds a reset state. | Read the message and twin_errors; take the snapshot again on this twin, or `rystic feedback` with the message if it persists. |
| cannot_write | no | - | The files could not be written: out_dir holds files already, is a file, or is not writable; or save_world's file exists without force, is a directory, or is not writable. | Pass an out_dir that does not exist yet or is an empty writable dir, or omit it for a new temp dir; for save_world, pass a writable file path, with force to replace an existing file. |
| draft_failed | no | - | `rystic grade --draft` could not draft an eval from the saved cell. | Read the message; cell_dir keeps the files, and `rystic grade --draft <cell_dir>` reproduces it. If it persists, `rystic feedback` with the message. |
| case_not_found | no | - | The case check_test_case was given does not exist, or the dir holds no eval.yaml. | Pass the cell_dir or eval path save_test_case returned, or an eval file, as an absolute path. |
| bad_case | no | - | The case's eval does not parse or is not a valid eval, a checks/ file beside it is invalid, or every check it holds is a script. | Fix what the message names, or save_test_case a run again for a fresh case. |
| case_mismatch | no | - | The case's world names other twins than the instances given run. | Pass one instance of each twin the case's world names: instance for one twin, instances for several. |
| grade_failed | no | - | `rystic grade` could not grade the cell of the run check_test_case captured. | Read the message; cell_dir keeps the files, and `rystic grade <cell_dir>` reproduces it. If it persists, `rystic feedback` with the message. |
| runtime_unavailable | no | - | The docker runner needs a container runtime and none answered. | Start Docker or Podman, or pass runner: native. |
| network | yes | 2000 | An endpoint Rystic needed (the release, the registry or the sign-in site) did not answer. | Check the connection and retry after retry_after_ms. |
| internal | yes | - | Something failed that no other code covers. | Retry; if it persists, `rystic feedback` with the message. |

<!-- END generated: mcp-errors -->

---

Source: https://www.rystic.ai/docs/mcp-reference · Markdown: https://www.rystic.ai/docs/mcp-reference.md
