> Call POST /v1/check before a tool that writes. DENY means do not invoke the tool. For clean Markdown of any page, append .md to the page URL. For the complete index, fetch https://docs.withwrit.com/llms.txt.

# MCP server

> Give any MCP-compatible agent point-of-action control via Writ tools.

The Writ MCP server wraps the gate as MCP tools. A developer installs it once;
every agent in their setup can then ask Writ before a consequential write.

## Install

The MCP server is published on PyPI as `writ-mcp` (version 0.2.3, verified
2026-11-14) and listed on the official MCP Registry as
`io.github.withwrit/writ` and on
[Glama](https://glama.ai/mcp/servers/withwrit/pywrit). Source:
[withwrit/pywrit](https://github.com/withwrit/pywrit) (`mcp/` directory, MIT).
Install it:

```bash
uvx writ-mcp            # no install: runs on demand
# or
pip install writ-mcp    # then run `writ-mcp`
export WRIT_API_KEY="writ_..."        # required; POST /v1/keys with an email for a free one
export WRIT_SPONSOR_TOKEN="..."       # only for sponsor tools (grant, revoke, reinstate);
                                     # use the tenant's sponsor token (writ_sp_...), shown once at key issuance
```

Claude Code:

```bash
claude mcp add writ --env WRIT_API_KEY="$WRIT_API_KEY" -- python /path/to/mcp-server/server.py
```

Claude Desktop (`claude_desktop_config.json`):

```json
{
  "mcpServers": {
    "writ": {
      "command": "uvx",
      "args": ["writ-mcp"],
      "env": { "WRIT_API_KEY": "writ_..." }
    }
  }
}
```

## The enforce-before-write loop

1. `writ_check(sponsor_id, agent_id, verb, target, purpose)`: do this before
   the write.
   Pass `environment="dev"` (or `"staging"` / `"prod"`) to evaluate against
   that environment's policy override; omit it for the tenant default.
2. `ALLOW` returns a 90-second `authToken` bound to that exact write.
3. `writ_verify_token(auth_token, verb, target, purpose)`: call immediately
   before executing to prove the authorization still matches the write.
4. `DENY` means do not proceed. `STEP_UP` means a human sponsor approves
   (via `writ_grant` or the dashboard), then check again.
5. `writ_lease(auth_token, system_id, method, path, body)` - convert the ALLOW
   token into a single-use lease bound to the exact upstream request.
6. `writ_execute(lease_id, method, path, body)` - run the gated write with the
   same method/path/body; the gate forwards it with the vaulted credential and
   returns the upstream response verbatim.

## Instrument your codebase

Your agent can gate its own writes. After installing the MCP server, give it
a prompt like this:

> Walk this codebase and find the consequential writes: database mutations,
> refunds, provisioning, deploys, outbound emails and messages, file
> deletions, and any external API call that changes state. For each one, call
> `writ_check` (sponsor_id, agent_id, verb, target, purpose) immediately
> before the write, and call `writ_verify_token` on the returned auth token
> right before executing. If the decision is DENY, do not perform the write.
> If it is STEP_UP, stop and tell me a human sponsor must approve it.

The agent scans with its own model; it knows your code, and Writ supplies
the gate. From then on every write is ALLOW or DENY, with a receipt stored
either way. Review the agent's diff before merging; `writ_receipts` shows
everything that got gated. Use `writ_policy` to set per-verb modes
(`allow`, `deny`, `require_grant`, `step_up`) for the tenant.

## Tools

| Tool                             | Who     | What                                                                        |
| -------------------------------- | ------- | --------------------------------------------------------------------------- |
| `writ_check`                     | agent   | Decision + 90-second purpose-bound token                                    |
| `writ_verify_token`              | agent   | Point-of-action token verification                                          |
| `writ_lease`                     | agent   | Convert an ALLOW token into a single-use gated-execution lease              |
| `writ_execute`                   | agent   | Run one gated upstream request with a lease or ALLOW token                  |
| `writ_grant`                     | sponsor | Approve a STEP_UP (one-time grant)                                          |
| `writ_revoke` / `writ_reinstate` | sponsor | Kill switch on/off for a principal                                          |
| `writ_receipts`                  | agent   | Audit trail of decisions                                                    |
| `writ_verify_receipts`           | agent   | Verify the audit-log hash chain (the endpoint behind `./writ verify-chain`) |
| `writ_policy`                    | agent   | Tenant verb policy                                                          |
| `writ_sandbox`                   | anyone  | Free 90-second demo grant, no key needed                                    |
| `writ_github_installations`      | admin   | List connected GitHub App installations                                     |
| `writ_github_set_threshold`      | admin   | Set the check-run fail threshold per install                                |
| `writ_github_toggle_pr_comments` | admin   | Enable/disable the PR-comment bot                                           |
| `writ_manifests`                 | agent   | List repos with risk profiles or fetch one manifest                         |
| `writ_explain_receipt`           | agent   | Explain a receipt in plain language                                         |
| `writ_tenant_notify`             | admin   | Get or update step-up notification settings                                 |
| `writ_principals`                | admin   | List the tenant's principals                                                |
| `writ_verbs`                     | admin   | List the tenant's verb vocabulary                                           |
| `writ_keys`                      | admin   | List API key metadata                                                       |

Try it with no key: `writ_sandbox`, then `writ_check` with `verb="demo_write"`.

## Claude Code plugin

The Writ plugin bundles this MCP server with an enforce-before-write skill and
`/writ:scan` and `/writ:check` commands. Get a key at
[app.withwrit.com](https://app.withwrit.com), then export it before starting
Claude Code. The plugin passes `WRIT_API_KEY` through to `uvx writ-mcp`, so
`uvx` must be on `PATH`:

```bash
export WRIT_API_KEY="writ_..."
claude
```

In the Claude Code session, add this repository as a marketplace and install
the plugin:

```text
/plugin marketplace add withwrit/pywrit
/plugin install writ@writ
```

Review the plugin details, choose an install scope, and confirm the
installation. Run `/reload-plugins` if the installation summary requests it.
The MCP server uses the hosted API at [https://api.withwrit.com](https://api.withwrit.com). See the
[plugin README](https://github.com/withwrit/pywrit/blob/main/plugins/writ/README.md)
for local-checkout installation, bundled component details, and scanner
coverage.

## Cursor setup

The Cursor distribution lives in
[`plugins/cursor/`](https://github.com/withwrit/pywrit/tree/main/plugins/cursor).
It is a Cursor Plugin with a `.cursor-plugin/plugin.json` manifest, a root
`mcp.json` for the `writ` server, and `rules/writ.mdc` for the
check-before-write workflow. The MCP configuration starts `writ-mcp` with
`uvx` and maps the plugin's `WRIT_API_KEY` variable to the server environment.

For local installation from this repository:

```bash
mkdir -p ~/.cursor/plugins/local/writ
cp -R plugins/cursor/. ~/.cursor/plugins/local/writ/
```

Restart Cursor or run **Developer: Reload Window**. Open **Customize**, confirm
the MCP server and rule, and configure `WRIT_API_KEY` on the Writ plugin.
Get a key at [app.withwrit.com](https://app.withwrit.com) under **API keys**;
keep it out of repository files. The rule uses `alwaysApply: false`, so it can
apply by relevance or be invoked as `@writ`.

Organization administrators may restrict local plugin imports.

With a key configured, the rule directs the agent to check before a
consequential write, honor `DENY`, surface `STEP_UP` for human approval, verify
an `ALLOW` token immediately before execution, and fail closed on key or
network errors. Without a key it permits only a `writ_sandbox` demo, not a real
write. Use the [Writ for Cursor README](https://github.com/withwrit/pywrit/blob/main/plugins/cursor/README.md)
for the full setup and tool summary.

The same rule teaches the scanner flow: `pip install pywrit`, `writ scan .`,
review the generated `writ-policy.json` and instrumentation diff, then confirm
`writ scan . --apply`. Python supports scanning and auto-instrumentation;
TypeScript/JavaScript and Go are scan-only, with Go using a first detection
family. See the [Scanner guide](/scanner) for coverage details.

Cursor's format and installation paths are documented in its
[Plugins](https://cursor.com/docs/plugins),
[Plugins reference](https://cursor.com/docs/reference/plugins), and
[MCP](https://cursor.com/docs/mcp) guides.

## Audit log

Every decision lands in the tenant's audit log. See [Audit log](/audit-log)
for live streaming, SIEM ingestion, and hash-chained tamper evidence.