Skip to navigation

MCP server

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. Source: withwrit/pywrit (mcp/ directory, MIT). Install it:

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:

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

Claude Desktop (claude_desktop_config.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

ToolWhoWhat
writ_checkagentDecision + 90-second purpose-bound token
writ_verify_tokenagentPoint-of-action token verification
writ_leaseagentConvert an ALLOW token into a single-use gated-execution lease
writ_executeagentRun one gated upstream request with a lease or ALLOW token
writ_grantsponsorApprove a STEP_UP (one-time grant)
writ_revoke / writ_reinstatesponsorKill switch on/off for a principal
writ_receiptsagentAudit trail of decisions
writ_verify_receiptsagentVerify the audit-log hash chain (the endpoint behind ./writ verify-chain)
writ_policyagentTenant verb policy
writ_sandboxanyoneFree 90-second demo grant, no key needed
writ_github_installationsadminList connected GitHub App installations
writ_github_set_thresholdadminSet the check-run fail threshold per install
writ_github_toggle_pr_commentsadminEnable/disable the PR-comment bot
writ_manifestsagentList repos with risk profiles or fetch one manifest
writ_explain_receiptagentExplain a receipt in plain language
writ_tenant_notifyadminGet or update step-up notification settings
writ_principalsadminList the tenant’s principals
writ_verbsadminList the tenant’s verb vocabulary
writ_keysadminList 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, then export it before starting Claude Code. The plugin passes WRIT_API_KEY through to uvx writ-mcp, so uvx must be on PATH:

export WRIT_API_KEY="writ_..."
claude

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

/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. See the plugin README for local-checkout installation, bundled component details, and scanner coverage.

Cursor setup

The Cursor distribution lives in 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:

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 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 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 for coverage details.

Cursor’s format and installation paths are documented in its Plugins, Plugins reference, and MCP guides.

Audit log

Every decision lands in the tenant’s audit log. See Audit log for live streaming, SIEM ingestion, and hash-chained tamper evidence.