Skip to content
plugmcp
DirectorySkillsCategoriesBlog
EN/中文
Sign inSign up
Home/Servers/Writ

Writ

by io.github.AvenueDAdmin

Commit-time policy checks for AI agent writes (ALLOW/DENY/STEP_UP) with a tamper-evident audit log.

Power your agent

Add this server

The publisher's own command. Not a PlugMCP endpoint.

Local command
uvx writ-mcp==0.1.2
Credentials from the publisher
  • WRIT_API_KEY — Writ API key (get one free at https://withwrit.com)
  • WRIT_SPONSOR_TOKEN — Writ sponsor token, only required for sponsor tools (grant, revoke, reinstate)
  • WRIT_BASE_URL — Optional custom Writ API base URL (default: https://api.withwrit.com)
Provider
Claude Code
WRIT_API_KEY=<secret> WRIT_SPONSOR_TOKEN=<secret> WRIT_BASE_URL=<value> claude mcp add io.github.avenuedadmin-writ -- uvx writ-mcp==0.1.2

Run in a terminal.

Claude Desktop
{
  "mcpServers": {
    "io.github.avenuedadmin-writ": {
      "command": "uvx",
      "args": [
        "writ-mcp==0.1.2"
      ],
      "env": {
        "WRIT_API_KEY": "<secret>",
        "WRIT_SPONSOR_TOKEN": "<secret>",
        "WRIT_BASE_URL": "<value>"
      }
    }
  }
}

claude_desktop_config.json

Step-by-step: add this in Claude

Remote URL or a command on your machine? How the two installs differ

Run on PlugMCP

Host a copy with our keys and logs.

A new server you create. It is not this listing's official endpoint. Use the publisher install when you want their URL and their credentials.

Launch

Related MCP

View more
  • Firecrawl🔥 Official Firecrawl MCP Server - Adds powerful web scraping and search to Cursor, Claude and any other LLM clients.
  • N
    NotionToken-auth Notion MCP: pages, databases, blocks, comments, files. Runs headless in CI and agents.
  • Context7Context7 Platform -- Up-to-date code documentation for LLMs and AI code editors

Related skills

View all
  • rea-changelog-updatePrepare or rewrite REA release changelogs and GitHub release notes from pinned Git history, with verified contributor thanks and Release Please synchronization.
  • D
    doc-coauthoringGuide users through a structured workflow for co-authoring documentation. Use when user wants to write documentation, proposals, technical specs, decision docs, or similar structured content. This wor
  • I
    internal-commsA set of resources to help me write all kinds of internal communications, using the formats that my company likes to use. Claude should use this skill whenever asked to write some sort of internal com

Commit-time policy checks for AI agent writes (ALLOW/DENY/STEP_UP) with a tamper-evident audit log.

pywrit

Find the dangerous writes in your Python agent's code, then gate it. pywrit is the Python client and writ CLI for Writ: an allow/deny gate that sits in front of your agent's consequential writes (database, HTTP, files, email, queues, AWS) and records a hash-chained receipt for every decision.

writ scan finds 4 write sites in a Python agent (0/4 gated); writ scan --apply inserts gates; a re-scan shows 4/4 gated

writ scan is local, deterministic, and free: it parses your code with Python's ast module, makes no network calls, and needs no API key.

Install

pip install pywrit

Requires Python 3.9+. Installs the writ command and the pywrit Python client.

JavaScript/TypeScript devs: run the scanner with no Python setup via npm:

npx writ-scan .

The writ-scan package wraps the same scanner (including TS/JS support). On first run it installs pywrit[polyglot] from PyPI using your Python 3.9+ (one-time); afterwards it starts instantly. See npm/ for details, environment overrides (WRIT_PYTHON, WRIT_SCAN_NO_INSTALL), and the install test.

60-second quickstart: scan → wrap → gate

1. Scan. See which functions write, and how many of them are gated.

writ scan .
writ scan: /path/to/support-agent
  files scanned: 4  skipped: 0
  write sites: 4 in 3 function(s)
  gated: 0/4 (0%)
  verbs discovered: 3
    crm.update
    payments.refund
    tickets.close

It also prints a risk report (0-100, weighted by risk tier), writes the discovered verbs to writ-policy.json, and shows the instrumentation it would add as a unified diff. Nothing in your code changes yet. writ scan . --score prints just the risk report.

2. Wrap. One command takes the repo from unwrapped to wrapped: scan, show the diff, ask for explicit approval, apply the gates, and report before/after coverage.

writ wrap .        # interactive approval
writ wrap . --yes  # no prompt (e.g. in CI)

--dry-run previews the plan and exits before prompting; --diff-only prints the unified diff for review tools. Each gated function now asks Writ before it writes, and fails closed:

def issue_refund(charge_id, amount_cents):
    if _writ_check("payments.refund") != "ALLOW":
        raise PermissionError("writ denied payments.refund")
    ...

writ scan . --apply is still available as the manual alternative. Re-run writ scan . and you'll see gated: 4/4 (100%).

3. Gate. Get a free API key, load the discovered policy, and run your agent.

writ key --email [email protected]                  # free API key + tenant
export WRIT_API_KEY=writ_...                      # read by the inserted gate
export WRIT_SPONSOR=acme WRIT_AGENT=support-agent # optional: who is acting
writ scan . --push-policy --key "$WRIT_API_KEY"   # upload the discovered verb policy

Every gated write now gets ALLOW, DENY, or STEP_UP (a human sponsor must approve), and every decision is written to your tenant's tamper-evident audit log:

writ receipts --key "$WRIT_API_KEY"       # latest receipts
writ verify-chain --key "$WRIT_API_KEY"   # verify the receipt hash chain
writ stream --key "$WRIT_API_KEY"         # tail decisions live
writ report --key "$WRIT_API_KEY"         # Agent Action Report

What writ scan detects

Python (.py) files, parsed with the stdlib ast (no extra dependencies):

CategoryExamples
Databasecursor.execute(...) / executemany / executescript (write SQL only; SELECT/WITH/... skipped), session.add / commit / delete / merge / flush
HTTPrequests.post / put / patch, client.delete(...), session.request(...)
Filesopen(..., "w"/"a"/"x"/"+"), Path.write_text / write_bytes / unlink / rename, os.remove / rename / makedirs, shutil.rmtree / move / copy
Emailsendmail, send_message, send_email
Queuespublish, produce, enqueue, queue.send(...)
AWS SDKput_object, put_item, delete_item, upload_file, send_message, start_execution, ...
  • Each write is mapped to a verb such as payments.refund or crm.update, inferred from the file path and function name.
  • A function that already calls writ_check(...) / _writ_check(...) counts as gated.
  • Skipped: tests, hidden directories, virtualenvs, node_modules, dist, build. Use --exclude SUBSTR (repeatable) to skip more.
  • Not covered (review by hand): writes behind dynamically built SQL, third-party SDK calls such as stripe.Refund.create(...), deferred task queues, or shared clients several layers down. The risk report lists these gaps every time.

TypeScript / JavaScript (scan-only)

writ scan also finds write sites in TypeScript and JavaScript. It needs the optional extra (tree-sitter based):

pip install 'pywrit[polyglot]'
writ scan .

Without the extra, the scanner prints a one-line hint and keeps going — Python scanning never needs it.

TS/JS is scan-only: findings are listed with verbs for your policy file, but writ scan --apply never rewrites TS/JS files — gate those by hand. Covered patterns: fetch/axios writes, fs writes, SQL through knex-style clients, Prisma writes, and JS SDK calls such as stripe.refunds.create(...). (Still not covered: the Python SDK equivalents like stripe.Refund.create(...) — see "Not covered" above.)

writ scan on a TypeScript agent finds 5 write sites, 1 of 5 gated

GitHub Action

Scan every pull request for ungated write sites. Findings land as check annotations on the exact file and line, plus a Markdown risk report in the job summary. The check fails when an ungated finding meets your fail-on-risk threshold (default: high).

- uses: actions/checkout@v4
- uses: withwrit/pywrit@v0
  with:
    fail-on-risk: high   # high | medium | low | never

No API key needed. Full reference: docs/github-action.md · example workflow: examples/github-action/writ-scan.yml

MCP server (writ-mcp)

Give any MCP-compatible agent point-of-action policy checks. writ-mcp is a Model Context Protocol server (stdio transport, built on the MCP Python SDK) that exposes the Writ gate as 8 MCP tools: the agent calls writ_check before a consequential write and gets back ALLOW, DENY, or STEP_UP — with a tamper-evident, hash-chained audit receipt for every decision.

uvx writ-mcp            # no install — runs on demand
# or
pip install writ-mcp   # then run `writ-mcp`
ToolWhat it does
writ_checkThe gate: ALLOW / DENY / STEP_UP for a proposed write
writ_verify_tokenValidate an ALLOW auth token (catches purpose drift)
writ_grantHuman-sponsor approval for the STEP_UP path
writ_revoke / writ_reinstateThe kill switch
writ_receiptsRead the tenant's audit log
writ_policyManage the verb policy
writ_sandboxKeyless 90-second demo grant — no API key needed

The gate tools need a free Writ API key (WRIT_API_KEY): 10,000 receipts/month free, no credit card. writ_sandbox works with no key at all.

The server implementation lives in mcp/ (MIT). Also published on the official MCP Registry as io.github.withwrit/writ, on Smithery, and listed on Glama.

Python client

from pywrit import WritClient

client = WritClient(api_key="writ_...")

result = client.check(
    sponsor_id="acme",
    agent_id="agent-7",
    verb="db.write",
    target="prod.customers",
    purpose="backfill region field",
)

if result.decision == "ALLOW":
    # result.auth_token is a short-lived token bound to this exact write
    perform_write(...)
elif result.decision == "STEP_UP":
    # a human sponsor must approve first: client.grant(...), then re-check
    ...
else:
    # DENY
    ...

No API key yet? Try the keyless sandbox:

client = WritClient()
client.sandbox({
    "sponsorId": "acme",
    "agentId": "agent-7",
    "verb": "demo_write",       # sandbox only allows demo_write ...
    "target": "demo-customers", # ... on targets starting with demo-
    "purpose": "trying the gate",
})

What's covered:

  • check(...): the gate. ALLOW / DENY / STEP_UP, plus a receipt every time
  • verify_token(...): validate an ALLOW auth token (catches purpose drift)
  • grant(...): human-sponsor approval for the STEP_UP path
  • get_policy() / set_policy(...): manage the tenant policy
  • revoke(...) / reinstate(...) / revoked(): the kill switch
  • receipts() / receipt(id) / verify_chain() / stream_receipts(): the audit log
  • sandbox(...): keyless trial, no API key required

CLI reference

writ wrap .                         # scan, diff, approve, apply, verify coverage
writ wrap . --dry-run               # preview only
writ wrap . --yes                   # non-interactive CI mode
writ check --key writ_... --sponsor acme --agent agent-7 \
  --verb db.write --target prod.customers --purpose "backfill region field"
writ policy --key writ_... --set payments.refund require_grant
writ revoke --sponsor acme --agent agent-7 --reason "runaway loop"   # kill switch (sponsor token)
writ grant --sponsor acme --agent agent-7 --verb payments.refund \
  --target ch_123 --purpose "approved refund"                        # STEP_UP approval (sponsor token)

Sponsor-token commands (revoke, reinstate, revoked, grant) read --sponsor-token or WRIT_SPONSOR_TOKEN. Run writ --help for the full command list.

README badge

Show that your agent's writes are gated by Writ. Two flavors:

Static (works today, no API key) — same design, no live count:

[](https://withwrit.com)

Dynamic (live 30-day gated-write count from your audit log) — mint a badge token, then embed the snippet the API returns:

curl -s https://api.withwrit.com/v1/badge/tokens \
  -H "Authorization: Bearer writ_..." \
  -H "Content-Type: application/json" \
  -d '{}'

The dynamic endpoint ships with the gate — until it's live, POST /v1/badge/tokens returns 404 and the static badge above is the one to use.

See badge/ for embed docs and the verification model (what the badge proves — and what it doesn't).

Docs

Full docs: docs.withwrit.com · Quickstart: docs.withwrit.com/quickstart · Site: withwrit.com

License

MIT

How do I install Writ?
Copy the stdio config for Cursor, Claude Desktop, Claude Code, or VS Code on this page. It uses the publisher's install, not a PlugMCP proxy.
Does Writ need an API key?
The publisher lists these environment variables: WRIT_API_KEY, WRIT_SPONSOR_TOKEN, WRIT_BASE_URL.
What transport does Writ use?
Writ runs locally over stdio.
When was Writ last checked?
Last checked 2026-10-16. Commit-time policy checks for AI agent writes (ALLOW/DENY/STEP_UP) with a tamper-evident audit log.

No tool list yet. Remote servers get one after the first health check.

plugmcp

Plug any tool into any agent. MCP servers for people who do not write servers. Gateway for volume, n8n for apps.

  • github.com/TODO
  • x.com/TODO
  • linkedin.com/company/TODO

PlugMCP, 2026

Product
  • Browse
  • Install
  • Host your own
  • Voice mode
  • Browser
Directory
  • All MCP servers
  • Agent skills
  • Categories
  • New
  • Voice
  • Submit a server
Developers
  • Docs
  • Blog
  • What is MCP
  • What is WebMCP
  • Status
Company
  • About
  • Contact
  • Terms
  • Privacy
  • DPA