MCP
The Parity MCP server: one tool per API call, for coding agents.
Parity serves its API as MCP tools. Each tool is one API call made with the caller's token, so a tool can do exactly what the token can. Give an agent a sandbox token and its tools reach that sandbox only.
Connect
Remote, over Streamable HTTP, with the token as a bearer header:
{
"mcpServers": {
"parity": {
"type": "http",
"url": "https://api.parity.ninja/mcp",
"headers": { "Authorization": "Bearer ${PARITY_TOKEN}" }
}
}
}Local, over stdio, with the parity CLI:
{
"mcpServers": {
"parity": {
"command": "parity",
"args": ["mcp"],
"env": { "PARITY_API": "https://api.parity.ninja", "PARITY_TOKEN": "pst_…" }
}
}
}The stdio server can also read and write local files: proof_add takes a path, and proof_export and inbox_attachment take save_to.
Behaviour
- No call waits more than about 50 seconds. A tool that is still waiting returns what it has with a
nexthint: callsandbox_statuswithwait, orjob_status, again. - Errors are the API's problem details, with
codeandretryable(see Errors). - With a sandbox token,
sandboxdefaults to the token's own sandbox, andsandbox_createandsandbox_listare not offered.
The server sends these instructions to the agent on connect:
Parity sandboxes: a full copy of an app (services, database, mail inbox, auth) for one task.
Use the sandbox's own public URL (sandbox_status: services[].public_urls) to drive the app like a user.
Typical loop: sandbox_status until "ready"; create users (auth_user_create, or the app's own sign-up);
inbox_wait for verification mail and use its links/codes; job_run to trigger work; sandbox_logs and
sandbox_exec to debug; proof_add for evidence (screenshots, test output); proof_export at the end.
No call waits more than about 50 seconds: a tool that is still waiting returns what it has with a
"next" hint (call sandbox_status with wait, or job_status, again).
With a project token, a call that names no sandbox acts on $PARITY_SANDBOX, else the sandbox named
after the current git branch, as the parity CLI does; sandbox_destroy always names its sandbox.
Errors are RFC 9457 problem details {"type", "title", "status", "detail", "code", "retryable"}:
not_ready (retry shortly), dependency_failed (a job failed; log_tail says why), wrong_sandbox (this
token is for another sandbox), rate_limited (slow down; retry_after says when).
Mail links carry internal: true when they point at this sandbox; prefer those. For "the next mail
after my action", take inbox_list's cursor first, act, then inbox_wait with after set to it.Tools
auth_signin
Mint a one-time sign-in link for an auth user. Opening it in a browser runs the app's own OIDC login, so the app sets its own session. Returns {url, expires_at}; the link works once, for 15 minutes.
| Argument | Type | Required | Description |
|---|---|---|---|
org | string | Org the session carries (default the user's first) | |
redirect | string | Where the browser should land after sign-in. | |
sandbox | string | Sandbox id; optional with a sandbox token (defaults to its own sandbox), and with parity mcp and a project token (defaults to $PARITY_SANDBOX, else the current git branch's sandbox, as the CLI does) | |
user | string | yes | User id or email. |
auth_user_create
Create a user in the sandbox's auth resource (its OIDC provider), with orgs and roles. Returns {id, email, password, orgs}; the password is shown once. Only for apps that declare an auth resource (no_auth otherwise: use the app's own sign-up). Then auth_signin gives a one-time sign-in link.
| Argument | Type | Required | Description |
|---|---|---|---|
email | string | yes | The user's email; verified, no MFA. |
orgs | object[] | Org memberships with roles. | |
password | string | Password; generated and returned once when empty. | |
sandbox | string | Sandbox id; optional with a sandbox token (defaults to its own sandbox), and with parity mcp and a project token (defaults to $PARITY_SANDBOX, else the current git branch's sandbox, as the CLI does) |
auth_user_delete
Delete an auth user.
| Argument | Type | Required | Description |
|---|---|---|---|
sandbox | string | Sandbox id; optional with a sandbox token (defaults to its own sandbox), and with parity mcp and a project token (defaults to $PARITY_SANDBOX, else the current git branch's sandbox, as the CLI does) | |
user | string | yes | User id or email. |
auth_user_list
List the users of the sandbox's auth resource, with their orgs and roles, in creation order: {users, total_size, next_page_token}. q keeps emails containing it. While next_page_token is set, more are on the next page (page_token).
| Argument | Type | Required | Description |
|---|---|---|---|
limit | integer | Items per page (default 50, at most 500) | |
page_token | string | next_page_token of the previous page. | |
q | string | Only users whose email contains this, ignoring case. | |
sandbox | string | Sandbox id; optional with a sandbox token (defaults to its own sandbox), and with parity mcp and a project token (defaults to $PARITY_SANDBOX, else the current git branch's sandbox, as the CLI does) |
auth_user_update
Change an auth user's email, password or memberships. orgs replaces every membership. Returns the user.
| Argument | Type | Required | Description |
|---|---|---|---|
email | string | New email. | |
orgs | object[] | Replaces every membership; [] removes them all. | |
password | string | New password; an empty string generates one. | |
sandbox | string | Sandbox id; optional with a sandbox token (defaults to its own sandbox), and with parity mcp and a project token (defaults to $PARITY_SANDBOX, else the current git branch's sandbox, as the CLI does) | |
user | string | yes | User id or email. |
environment_status
Read a project's environments (staging, production, customer deployments: whatever its manifest declares): whether each is frozen or pinned by a rollback, its current rollout and status, and the block jobs waiting for a person with their prompts. With environment, that one in full. Builds move between environments through releases: see release_status. Agents can't promote, approve or reject: tell the user what is waiting and that they decide it (parity approve <step> --env <environment>, or the console).
| Argument | Type | Required | Description |
|---|---|---|---|
environment | string | One environment, such as production; empty lists them all. | |
project | string | yes | The project. |
inbox_attachment
Download one attachment of a message, by its part or file name (inbox_read lists them), as an embedded resource with its content type; with parity mcp, save_to writes it to a local file. Without part, lists the attachments.
| Argument | Type | Required | Description |
|---|---|---|---|
id | string | yes | Message id. |
part | string | The attachment's part or file name, from the message's attachments; empty lists them. | |
sandbox | string | Sandbox id; optional with a sandbox token (defaults to its own sandbox), and with parity mcp and a project token (defaults to $PARITY_SANDBOX, else the current git branch's sandbox, as the CLI does) | |
save_to | string | Parity mcp only: write the file to this local path instead of returning it. |
inbox_list
List the mail the sandbox received (every address at the sandbox's domains lands here), newest first: id, to, from, subject, received_at, snippet, and the links, codes and attachments extracted from each. Filter by recipient, subject text or regexp, since, or after (a cursor); q searches every message, not just one page. The answer's cursor is the newest message: pass it as inbox_wait's after to get the next mail once you have acted. inbox_read gives one message's text. While next_page_token is set, older mail is on the next page (page_token).
| Argument | Type | Required | Description |
|---|---|---|---|
after | string | Cursor: only mail received after this message id; now (the newest message when the call starts) or start (the whole inbox). inbox_list answers cursor to pass here. | |
limit | integer | Items per page (default 50, at most 500) | |
page_token | string | next_page_token of the previous page. | |
q | string | Search the whole inbox, not one page (Mailpit's search: words, to:, from:, subject:); can't be combined with after. | |
sandbox | string | Sandbox id; optional with a sandbox token (defaults to its own sandbox), and with parity mcp and a project token (defaults to $PARITY_SANDBOX, else the current git branch's sandbox, as the CLI does) | |
since | string | Only mail newer than this: a duration such as 5m, or an RFC 3339 time. | |
subject | string | Text the subject contains (case-insensitive) | |
subject_re | string | Regular expression (RE2) the subject matches; start it with (?i) for any case. | |
to | string | Recipient: an address, or a local part alone (bob) for that name at any domain; To, Cc and Bcc count. |
inbox_read
Read one message: its text, the extracted links and codes (one-time codes, verification links) and its attachments (part, name, content_type, size; inbox_attachment downloads one). The HTML part only with html: true.
| Argument | Type | Required | Description |
|---|---|---|---|
html | boolean | Also return the HTML part (default: text only; has_html says there is one) | |
id | string | yes | Message id from inbox_list. |
sandbox | string | Sandbox id; optional with a sandbox token (defaults to its own sandbox), and with parity mcp and a project token (defaults to $PARITY_SANDBOX, else the current git branch's sandbox, as the CLI does) |
inbox_wait
Wait for a message (to an address, with subject text or a subject regexp) and return it with its text, links, codes and attachments. Without after, it returns the newest match, even one that came before the call, so call it right after the action that sends mail. With after (a message id, or the cursor inbox_list gave before you acted), it returns the first match after that message, so old mail never answers. expect_none asserts that no match arrives in the window instead (signed evidence that something was not sent). Waits at most 50 seconds, sending progress; on timeout call again with the after the answer gives. Prefer links with internal: true.
| Argument | Type | Required | Description |
|---|---|---|---|
after | string | Cursor: only mail received after this message id; now (the newest message when the call starts) or start (the whole inbox). inbox_list answers cursor to pass here. | |
expect_none | boolean | Assert that no matching mail arrives (after the cursor, default now) within the timeout: answers {none: true} when none did, and an unexpected_mail error naming the message when one did. | |
html | boolean | Also return the HTML part. | |
sandbox | string | Sandbox id; optional with a sandbox token (defaults to its own sandbox), and with parity mcp and a project token (defaults to $PARITY_SANDBOX, else the current git branch's sandbox, as the CLI does) | |
since | string | Only mail newer than this: a duration such as 5m, or an RFC 3339 time. | |
subject | string | Text the subject contains (case-insensitive) | |
subject_re | string | Regular expression (RE2) the subject matches; start it with (?i) for any case. | |
timeout_seconds | integer | How long to wait, at most 50 (the default); call again (with after) to keep waiting. | |
to | string | Recipient: an address, or a local part alone (bob) for that name at any domain; To, Cc and Bcc count. |
job_run
Run one of the manifest's jobs now (a seed, a migration, a cron's task), from the app version the sandbox runs. Waits up to about 50 seconds, sending progress, and returns {job, name, status, log_tail, duration_seconds}; a failure is dependency_failed with the log tail. A job still running returns status running with next: call job_status with its name.
| Argument | Type | Required | Description |
|---|---|---|---|
job | string | yes | Job name from the manifest. |
sandbox | string | Sandbox id; optional with a sandbox token (defaults to its own sandbox), and with parity mcp and a project token (defaults to $PARITY_SANDBOX, else the current git branch's sandbox, as the CLI does) | |
wait | boolean | Wait for it to finish (default true) |
job_status
The state of one job run (from job_run's name), waiting up to about 50 seconds for it to finish, with progress.
| Argument | Type | Required | Description |
|---|---|---|---|
job | string | yes | Job name from the manifest. |
run | string | yes | The run's name, from job_run (name) |
sandbox | string | Sandbox id; optional with a sandbox token (defaults to its own sandbox), and with parity mcp and a project token (defaults to $PARITY_SANDBOX, else the current git branch's sandbox, as the CLI does) |
proof_add
Attach evidence to the sandbox's proof bundle: a screenshot, a test log, an API response. It lands in files/ of the export, with your note and its content type. Give text as content, bytes as content_base64 (or, with parity mcp, a local path); several files at once in files. Returns {name, size, sha256, content_type}, or {files: [...]} for several.
| Argument | Type | Required | Description |
|---|---|---|---|
content | string | Text content. | |
content_base64 | string | Binary content, base64. | |
content_type | string | Media type; default from the name's extension, else sniffed. | |
files | object[] | Several files in one call; note above is the note of those without one. | |
name | string | File name in the bundle, such as checkout.png or test-output.txt (default: path's base name) | |
note | string | What the file shows. | |
path | string | Parity mcp only: a local file to attach instead of content. | |
sandbox | string | Sandbox id; optional with a sandbox token (defaults to its own sandbox), and with parity mcp and a project token (defaults to $PARITY_SANDBOX, else the current git branch's sandbox, as the CLI does) |
proof_export
Export the proof bundle as a zip: proof.json (sandbox, commit, image digests, times, users created, your verdict), calls.jsonl (every API call this token made), inbox/.eml, egress.json, logs/.log and files/*. Fill claim, result and summary for the reviewer. Returns the list of entries and the zip as an embedded resource (or writes it to save_to with parity mcp).
| Argument | Type | Required | Description |
|---|---|---|---|
claim | string | What you claim the change does; goes into proof.json verdict.claim. | |
result | string | Your verdict, such as pass or fail; proof.json verdict.result. | |
sandbox | string | Sandbox id; optional with a sandbox token (defaults to its own sandbox), and with parity mcp and a project token (defaults to $PARITY_SANDBOX, else the current git branch's sandbox, as the CLI does) | |
save_to | string | Parity mcp only: write the zip to this local path. | |
summary | string | What a reviewer should read first; proof.json verdict.summary. |
release_status
Read a project's releases, newest first: each is one build moving through the manifest's release steps (promote into environments, block for approval, wait, run a job, group). Shows where each release is and what it waits for: a block's prompt and approvals, a promote's environments (held: frozen or pinned by a rollback), a wait's end. With number, that release in full. Agents can't approve, reject or skip: tell the user what waits and that they decide it (parity approve <step>, or the console).
| Argument | Type | Required | Description |
|---|---|---|---|
number | integer | One release's number; empty lists the newest five. | |
project | string | yes | The project. |
sandbox_create
Create a sandbox for one task: the app's services, database, mail and auth in their own namespace. Needs a project token. The sandbox's createdBy is the person the token was minted for. Returns the sandbox (id, status, domain, services[].public_urls) and its token at once: give that sandbox token to the agent doing the task. With wait (the default) it then waits up to about 50 seconds for ready, sending progress; if the sandbox is still starting it returns with next: call sandbox_status with wait until status is ready. A failed setup job is dependency_failed with the log tail. Pass idempotency_key to make a retry return the same sandbox and token.
| Argument | Type | Required | Description |
|---|---|---|---|
agent | string | The agent acting, such as Claude Code. | |
commit | string | Git commit the sandbox runs. | |
id | string | Sandbox id: lowercase letters, digits and -; generated when empty. | |
idempotency_key | string | Any unique string; a retry with the same key and arguments returns the same sandbox and token instead of a second sandbox. | |
images | object | Image per service, such as {"web": "registry/app@sha256:..."}; required for build-only services. | |
manifest | string | parity.yaml text; applied as the project's app first. Empty uses the app as it is. | |
pr | string | Pull request number or URL. | |
ref | string | Git branch the sandbox is for. | |
task | string | The task: a title, optionally followed by a URL. | |
ttl | string | Lifetime such as 2h; default the manifest's sandbox.ttl. | |
wait | boolean | Wait until ready (default true; at most about 50 seconds per call, then call sandbox_status with wait) |
sandbox_destroy
Destroy the sandbox and all its data. Its token stops working. Exported proofs and calls.jsonl are kept by Parity (GET /v0/proofs), but export the proof first: nothing can be exported after.
| Argument | Type | Required | Description |
|---|---|---|---|
sandbox | string | Sandbox id; optional with a sandbox token (defaults to its own sandbox), and with parity mcp and a project token (defaults to $PARITY_SANDBOX, else the current git branch's sandbox, as the CLI does) |
sandbox_egress
Every outbound call the sandbox made: DNS queries for outside names and connections to outside hosts (HTTP Host, TLS server name), blocked or let through, with the service that tried and a count. A blocked host needs adding to the manifest's externals. sandbox_status lists the blocked hosts too.
| Argument | Type | Required | Description |
|---|---|---|---|
sandbox | string | Sandbox id; optional with a sandbox token (defaults to its own sandbox), and with parity mcp and a project token (defaults to $PARITY_SANDBOX, else the current git branch's sandbox, as the CLI does) |
sandbox_exec
Run a command in a running service or resource container (such as psql in db, or a script in web) and return {exit_code, stdout, stderr}. Output is capped at 1 MiB per stream. The sandbox's generated values are replaced with [redacted] where they appear verbatim, as a courtesy: exec can read the env, so treat its output as secret-bearing.
| Argument | Type | Required | Description |
|---|---|---|---|
command | string[] | yes | Argv, such as ["sh", "-c", "ls /app"]. |
sandbox | string | Sandbox id; optional with a sandbox token (defaults to its own sandbox), and with parity mcp and a project token (defaults to $PARITY_SANDBOX, else the current git branch's sandbox, as the CLI does) | |
service | string | yes | Service or resource name, such as web or db. |
stdin | string | Text sent to the command's stdin. | |
timeout | string | Duration, default 60s, at most 10m. |
sandbox_extend
Push the sandbox's expiry back by a duration, such as 1h, up to the manifest's max_ttl. Returns the sandbox with the new expires_at.
| Argument | Type | Required | Description |
|---|---|---|---|
by | string | yes | How much longer, such as 1h; capped at the manifest's max_ttl. |
sandbox | string | Sandbox id; optional with a sandbox token (defaults to its own sandbox), and with parity mcp and a project token (defaults to $PARITY_SANDBOX, else the current git branch's sandbox, as the CLI does) |
sandbox_list
List the sandboxes this token can see, with status and expiry, a page at a time: while next_page_token is set, call again with it as page_token.
| Argument | Type | Required | Description |
|---|---|---|---|
limit | integer | Items per page (default 50, at most 500) | |
page_token | string | next_page_token of the previous page. |
sandbox_logs
Read logs as text: one service, resource or job, or the whole sandbox when neither is given. Several containers are prefixed with [pod/container]. Use since to see only what an action just caused.
| Argument | Type | Required | Description |
|---|---|---|---|
job | string | Job name (all its runs) | |
sandbox | string | Sandbox id; optional with a sandbox token (defaults to its own sandbox), and with parity mcp and a project token (defaults to $PARITY_SANDBOX, else the current git branch's sandbox, as the CLI does) | |
service | string | Service or resource name. | |
since | string | Only lines newer than this duration, such as 10m. | |
tail | integer | Last N lines per container (default 200, or 100 for the whole sandbox) |
sandbox_status
Get a sandbox: status (starting, ready, failed, expiring), expires_at, services with public_urls and health, resources, lifecycle jobs and conditions. With wait, it waits up to about 50 seconds for ready (or failed), sending progress; call it again while status is starting. The app's URL is services[].public_urls.
| Argument | Type | Required | Description |
|---|---|---|---|
sandbox | string | Sandbox id; optional with a sandbox token (defaults to its own sandbox), and with parity mcp and a project token (defaults to $PARITY_SANDBOX, else the current git branch's sandbox, as the CLI does) | |
wait | boolean | Wait (at most about 50 seconds) for the sandbox to become ready or fail, sending progress. |
sandbox_sync
Roll the sandbox onto a changed parity.yaml (manifest: its text), new prebuilt images (images: {service: ref}), or both; deploy jobs such as migrations run again. Waits up to about 50 seconds for ready unless wait is false. To run changed source code, use parity up from the working directory: it uploads the tree and Parity rebuilds the services that only have build:.
| Argument | Type | Required | Description |
|---|---|---|---|
commit | string | Git commit the new images were built from. | |
images | object | New image per service; source sync needs image builds, which don't exist yet. | |
manifest | string | A changed parity.yaml (its text) for the sandbox to pin; deploy jobs run again. | |
sandbox | string | Sandbox id; optional with a sandbox token (defaults to its own sandbox), and with parity mcp and a project token (defaults to $PARITY_SANDBOX, else the current git branch's sandbox, as the CLI does) | |
wait | boolean | Wait until ready again (default true) |