Skip to main content

Unwind

A reversibility layer for agentic tool use

Unwind sits between any AI agent and any MCP server, works out which actions can be taken back, quietly takes back the ones that go wrong, and interrupts you only for the ones that truly can't be undone.

CI codecov PyPI Python License: Apache-2.0 OpenSSF Scorecard Docs Discord Star History


Unwind demo: an agent overwrites a config, deletes a page, drops a table, and emails all staff; you type undo; three are reversed and the email is honestly flagged as irreversible.

Generated by make demo-svg. For an animated GIF, install VHS and run vhs docs/assets/demo.tape.


Why Unwind exists

Human oversight of agents is failing because approval prompts are undifferentiated. They are undifferentiated because nothing in the stack knows which actions are reversible. So every MCP client falls back to the same binary "Allow / Deny" dialog for reading a file and for wiring money — and when the prompts come too often, people develop an approve-approve-approve reflex. A prompt injection that triggers one approval you click through has bypassed human oversight entirely.

Unwind supplies the missing primitive — reversibility inference — and then exploits it twice: it auto-allows the reversible majority with a real undo log behind them, and reserves interruption for the irreversible minority. The approval signal stops being noise and starts meaning something.

Unwind is not an undo button. That's the demo, not the thesis. The thesis is that reversibility classification is the enabling mechanism that makes human oversight of agents work at all. See PROJECT.md.

The 20-second demo

An agent, wired through Unwind, runs loose across four servers:

🤖 agent> delete the "Q3 Planning" Notion page          → deleted
🤖 agent> drop the `sessions` table in the sqlite db     → dropped
🤖 agent> email the vendor to cancel the contract        → sent
🤖 agent> force-push my local branch over origin/main     → pushed

You realize the agent misunderstood. You type one word:

you> unwind

Unwind replays the undo log in reverse order, honestly reporting each outcome:

✔ force-push        restored      (reflog checkpoint re-pointed origin/main)
✔ drop table        restored      (table + rows recreated from pre-state snapshot)
✔ delete page       restored      (page un-trashed within retention window)
✖ send email        could not undo — this was R3 (mitigable only).
                    The message was already delivered. I should have asked
                    before sending. Here's the retraction draft and why.

Three actions come back. The fourth is flagged honestly — because a false undo guarantee is worse than none. That last line is the whole thesis in one screenshot, and it's honest.

One-line install

pip install rollback-mcp        # pip
uvx rollback-mcp --help         # zero-install, via uv
docker run ghcr.io/bhaskargurram-ai/unwind --help

The Node/TypeScript stdio shim (ts/) is real and tested, but it is not published to npm. Build and run it from source:

git clone https://github.com/bhaskargurram-ai/unwind && cd unwind/ts
npm install && npm run build
node dist/cli.js run -- npx -y @modelcontextprotocol/server-filesystem /work

Then wrap any upstream MCP server by prefixing its launch command with unwind run --:

# Before: your client spawns the filesystem server directly
npx -y @modelcontextprotocol/server-filesystem /work

# After: Unwind wraps it transparently
unwind run -- npx -y @modelcontextprotocol/server-filesystem /work

Unwind is invisible when idle: any method it doesn't understand is forwarded byte-faithfully, and unwind run --passthrough-only -- <cmd> is a panic switch that disables all classification.

MCP client configuration

Every snippet below wraps the reference filesystem server. Swap the command after -- for any server you already run. The pattern is identical everywhere: keep your existing server command, prefix it with unwind run --.

Claude Desktop  ·  claude_desktop_config.json
{
  "mcpServers": {
    "filesystem": {
      "command": "unwind",
      "args": ["run", "--", "npx", "-y", "@modelcontextprotocol/server-filesystem", "/work"]
    }
  }
}
Claude Code  ·  .mcp.json
{
  "mcpServers": {
    "filesystem": {
      "command": "unwind",
      "args": ["run", "--", "npx", "-y", "@modelcontextprotocol/server-filesystem", "/work"]
    }
  }
}

Or from the CLI: claude mcp add filesystem -- unwind run -- npx -y @modelcontextprotocol/server-filesystem /work

Cursor  ·  ~/.cursor/mcp.json
{
  "mcpServers": {
    "filesystem": {
      "command": "unwind",
      "args": ["run", "--", "npx", "-y", "@modelcontextprotocol/server-filesystem", "/work"]
    }
  }
}
VS Code (MCP)  ·  .vscode/mcp.json
{
  "servers": {
    "filesystem": {
      "command": "unwind",
      "args": ["run", "--", "npx", "-y", "@modelcontextprotocol/server-filesystem", "/work"]
    }
  }
}
Cline  ·  cline_mcp_settings.json
{
  "mcpServers": {
    "filesystem": {
      "command": "unwind",
      "args": ["run", "--", "npx", "-y", "@modelcontextprotocol/server-filesystem", "/work"]
    }
  }
}
Windsurf  ·  ~/.codeium/windsurf/mcp_config.json
{
  "mcpServers": {
    "filesystem": {
      "command": "unwind",
      "args": ["run", "--", "npx", "-y", "@modelcontextprotocol/server-filesystem", "/work"]
    }
  }
}
Goose  ·  ~/.config/goose/config.yaml
extensions:
  filesystem:
    type: stdio
    cmd: unwind
    args: ["run", "--", "npx", "-y", "@modelcontextprotocol/server-filesystem", "/work"]
    enabled: true
Zed  ·  settings.json
{
  "context_servers": {
    "filesystem": {
      "command": {
        "path": "unwind",
        "args": ["run", "--", "npx", "-y", "@modelcontextprotocol/server-filesystem", "/work"]
      }
    }
  }
}
n8n (MCP Client node)

Set the node's command to unwind and the arguments to run -- npx -y @modelcontextprotocol/server-filesystem /work. n8n spawns the stdio server through Unwind exactly like any other client.

The R0–R4 reversibility taxonomy

Reversibility is ordinal and environment-relative — the same write_file is R1 on a git-backed tree and R4 on a versionless one. Class is always a function of (tool, environment), never the tool alone.

Class Name Definition Examples
R0 Nullipotent No state change; safe to repeat. Classified once at tools/list time — never adds latency. get_*, list_*, search_*, read_file
R1 Self-reversible The same tool restores exact prior state, given captured pre-state. update_record, set_status, write_file (prior content captured)
R2 Compensable A different tool semantically undoes it; restores an acceptable approximation. create_pagedelete_page, add_memberremove_member, grantrevoke
R3 Mitigable only No true inverse; partial mitigation only, and third parties may already have observed the effect. send_email→retraction, post_message→delete (already read), publish→unpublish (already cached)
R4 Irreversible No inverse and no meaningful mitigation. payment capture, permanent delete with no trash, key destruction, physical actuation, immutable-ledger write

Misclassifying R4 as R1 is catastrophic; misclassifying R1 as R4 merely annoys. Unwind treats these asymmetrically and fails safe — unknown tool, failed classification, timeout, or crashed classifier all escalate to a human. It never auto-allows on uncertainty.

Alongside the class, every call carries three orthogonal dimensions: blast radius (how many entities are affected), externality (did third parties observe it?), and a reversibility half-life — email recall closes in ~30s, trash retention in ~30 days, a payment void before settlement. Reversibility is time-decaying, so the undo log is expiry-aware.

How it compares

Every open-source MCP gateway is a preventive control — it decides whether to allow or block a call. None of them can recover from one. That's the entire opening.

Project Auth / RBAC Rate limiting Tool filtering Reversibility class Compensation synthesis Cross-server undo
Docker MCP Gateway
Stacklok ToolHive
agentgateway (LF)
IBM ContextForge
MCPJungle
Unwind (by design) (by design) (by design)

Not a gateway

Unwind is not another gateway, and never will be. Auth, RBAC, rate limiting, secret scanning, and container isolation are permanently out of scope — that space is saturated and well served by the projects above. Unwind does the one thing none of them do: recovery. It runs standalone, or as optional middleware inside any of those gateways, so it complements them rather than competes. If a feature doesn't sharpen reversibility classification or exploit it, it's out of scope.

The Unwind MCP tools

Unwind is itself an MCP server. It exposes its own tools so the agent can reason about and reverse its own actions — this is what makes Unwind agentic rather than a passive filter:

Tool What it does
unwind.preview Classify a proposed call (R0–R4 + confidence + blast radius) before it runs.
unwind.undo Reverse the last n actions across every connected server, in reverse order.
unwind.explain_risk Explain in plain language why a call is (ir)reversible and what residue an undo would leave.
unwind.history Inspect the durable, cross-server undo log with expiry state.
unwind.checkpoint Mark a labelled restore point to unwind back to.

Documentation & links

Project status & expectations

Unwind is early beta (0.1.x). The transparent proxy and the R1 undo path are the foundation; compensation synthesis, calibrated escalation, and the full ReversiBench harness are landing across the roadmap. We report reversibility fidelity graded, never as a boolean, and we would rather flag an action as "couldn't undo" than promise a rollback that won't hold. We target realistic adoption and never over-promise undo — because a false undo guarantee manufactures the exact auto-approve reflex this project exists to cure. Benchmark numbers are published only once they come from the live sandbox with bootstrap confidence intervals; until then this README describes capabilities qualitatively rather than quoting figures.

Community

Questions, ideas, and show-and-tell are welcome in GitHub Discussions. A Discord is coming soon. Please read the Code of Conduct.

Citation

If Unwind or ReversiBench is useful in your research, please cite it. A machine-readable CITATION.cff is included.

@article{gurram2026unwind,
  title   = {Unwind: Reversibility Inference and Compensation Synthesis for Agentic Tool Use},
  author  = {Gurram, Bhaskar},
  year    = {2026},
  eprint  = {TBD},
  archivePrefix = {arXiv},
  note    = {arXiv preprint. DOI: TBD}
}

arXiv ID and DOI are TBD and will be filled in on preprint release.

License

Licensed under the Apache License 2.0.

Built by Bhaskar Gurram. The reversibility layer for agentic tool use.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

rollback_mcp-0.2.0.tar.gz (455.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

rollback_mcp-0.2.0-py3-none-any.whl (79.7 kB view details)

Uploaded Python 3

File details

Details for the file rollback_mcp-0.2.0.tar.gz.

File metadata

  • Download URL: rollback_mcp-0.2.0.tar.gz
  • Upload date:
  • Size: 455.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for rollback_mcp-0.2.0.tar.gz
Algorithm Hash digest
SHA256 040101d9620def9f1386ec92fff0c08052721c0ce4771b7a793515daa640f07f
MD5 f74eeea7fb8cadcb2229b7b9d38dd85d
BLAKE2b-256 a1c88ffa10fdb0d55c1d6cdf9d085e59737721110a3716dc239b0607747fcf9f

See more details on using hashes here.

Provenance

The following attestation bundles were made for rollback_mcp-0.2.0.tar.gz:

Publisher: pypi-publish.yml on bhaskargurram-ai/unwind

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rollback_mcp-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: rollback_mcp-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 79.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for rollback_mcp-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ab5125e9e8517998acb556d2e26a683eadd7f625a55c0004be729197504f48da
MD5 3b80948945cad8f2618dda0851014727
BLAKE2b-256 62b70888a8a0d95cd2f35dd88da325d97eea11efdee7f1abd94f4aa9261d851e

See more details on using hashes here.

Provenance

The following attestation bundles were made for rollback_mcp-0.2.0-py3-none-any.whl:

Publisher: pypi-publish.yml on bhaskargurram-ai/unwind

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page