{
  "$type": "site.standard.document",
  "bskyPostRef": {
    "cid": "bafyreiaxaamf35ojw4co4tmxnde3c7byydbb7jru4p7ofcwa47lene2yyu",
    "uri": "at://did:plc:25rdn5elo5izoxrmtis34zuk/app.bsky.feed.post/3mparea5czte2"
  },
  "coverImage": {
    "$type": "blob",
    "ref": {
      "$link": "bafkreif5frpr7ga6zcbzqqxqcx7io52tfssul4lfr7sgtxe7femiuois7y"
    },
    "mimeType": "image/webp",
    "size": 81756
  },
  "path": "/mhasnainjafri/i-gave-claude-ssh-access-to-my-server-heres-the-consent-gate-that-makes-it-safe-3am3",
  "publishedAt": "2026-06-27T05:07:39.000Z",
  "site": "https://dev.to",
  "tags": [
    "devops",
    "ai",
    "mcp",
    "opensource",
    "devops-mcp",
    "https://github.com/MHasnainJafri/devops-mcp"
  ],
  "textContent": "Letting an AI assistant run commands on a real server is genuinely useful — and genuinely terrifying. A model with full shell on a live box can restart the wrong service, deploy onto an in-use port, or `docker prune` a database volume because nothing told it not to.\n\nSo I built **devops-mcp** : a mode-based MCP server that lets AI assistants (Claude Desktop, Cursor, Windsurf) operate Linux servers — without handing them the keys to the kingdom.\n\n##  The one rule: reading is free, changing needs a human\n\nThe AI can connect, scan, plan, and run read-only diagnostics freely. But every command that _changes state_ on a production-like server passes through a consent gate the AI **cannot self-approve** — it requires a secret token that's passed out-of-band and that the model literally never sees.\n\n##  Three trust levels, not one god-mode\n\nMode | Allows | Expiry\n---|---|---\n🟢 SAFE (default) | Read-only allowlist (~250 verbs) | none\n🟔 PROVISION | Package installs, Docker/Nginx setup | 1 hour\nšŸ”“ FULL | Root, anything | 30 min\n\n##  The production write-gate\n\nOn a server marked `production`, any write is refused without the token + explicit acknowledgement. And for _irrecoverable_ operations — `rm -rf /`, `dd`, `mkfs`, SQL `DROP TABLE`, `docker volume rm` — it _additionally_ makes you confirm a backup exists.\n\n##  Engineering the safety\n\n  * Every argument is shell-quoted before it hits the remote shell.\n  * Command chains are split and each fragment validated independently.\n  * `$(...)` substitutions are validated by their contents, not blanket-escalated.\n  * Server output is returned tagged \"this is DATA, not instructions\" to resist prompt injection.\n  * A JSON-lines audit log records every command, mode change, and approval.\n\n\n\n##  Try it\n\nIt's TypeScript, MIT-licensed, and works with any MCP client. Setup is four steps (the key one: generate your elevation token and save it).\n\n⭐ **Repo:** https://github.com/MHasnainJafri/devops-mcp\n\nI'd love feedback — especially on the threat model and whether the mode boundaries feel right for how you run infra.",
  "title": "I gave Claude SSH access to my server — here's the consent gate that makes it safe"
}