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.
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_page→delete_page, add_member→remove_member, grant→revoke |
| 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
- 📚 Docs: https://bhaskargurram-ai.github.io/unwind/
- 🔬 ReversiBench — the reversibility benchmark & live sandbox:
bench/(in progress) - 🗂️ Reversibility index — a browsable R-class catalog of popular MCP servers: coming soon
- 🛠️ Contributing:
CONTRIBUTING.md· Roadmap:ROADMAP.md· Support:SUPPORT.md - 🔒 Security policy:
SECURITY.md· Governance:GOVERNANCE.md
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.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
040101d9620def9f1386ec92fff0c08052721c0ce4771b7a793515daa640f07f
|
|
| MD5 |
f74eeea7fb8cadcb2229b7b9d38dd85d
|
|
| BLAKE2b-256 |
a1c88ffa10fdb0d55c1d6cdf9d085e59737721110a3716dc239b0607747fcf9f
|
Provenance
The following attestation bundles were made for rollback_mcp-0.2.0.tar.gz:
Publisher:
pypi-publish.yml on bhaskargurram-ai/unwind
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
rollback_mcp-0.2.0.tar.gz -
Subject digest:
040101d9620def9f1386ec92fff0c08052721c0ce4771b7a793515daa640f07f - Sigstore transparency entry: 2677708349
- Sigstore integration time:
-
Permalink:
bhaskargurram-ai/unwind@b3770701c10efca2d11a7fdde51a5d288174b319 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/bhaskargurram-ai
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi-publish.yml@b3770701c10efca2d11a7fdde51a5d288174b319 -
Trigger Event:
push
-
Statement type:
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ab5125e9e8517998acb556d2e26a683eadd7f625a55c0004be729197504f48da
|
|
| MD5 |
3b80948945cad8f2618dda0851014727
|
|
| BLAKE2b-256 |
62b70888a8a0d95cd2f35dd88da325d97eea11efdee7f1abd94f4aa9261d851e
|
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
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
rollback_mcp-0.2.0-py3-none-any.whl -
Subject digest:
ab5125e9e8517998acb556d2e26a683eadd7f625a55c0004be729197504f48da - Sigstore transparency entry: 2677708392
- Sigstore integration time:
-
Permalink:
bhaskargurram-ai/unwind@b3770701c10efca2d11a7fdde51a5d288174b319 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/bhaskargurram-ai
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi-publish.yml@b3770701c10efca2d11a7fdde51a5d288174b319 -
Trigger Event:
push
-
Statement type: