The safety gate between AI agents and your servers. An MCP server for structured, policy-checked, audited infrastructure operations.
- ✓Open-source license (MIT)
- ✓Actively maintained (<30d)
- ✓Clear description
- ✓Topics declared
- ✓Documented (README)
git clone https://github.com/polymatx/opsgate{
"mcpServers": {
"opsgate": {
"command": "opsgate"
}
}
}MCP Servers overview
<div align="center">
# opsgate
**The safety gate between AI agents and your servers.**
An MCP server that lets Claude, Cursor, or any AI agent operate real infrastructure —
without handing it a root shell.
[](https://github.com/polymatx/opsgate/actions/workflows/ci.yml)
[](https://goreportcard.com/report/github.com/polymatx/opsgate)
[](https://pkg.go.dev/github.com/polymatx/opsgate)
[](LICENSE)
[](https://go.dev)
[](https://modelcontextprotocol.io)
[What it looks like](#what-it-looks-like) ·
[30-second try](#try-it-in-30-seconds-no-server-needed) ·
[Break it yourself](#break-it-yourself) ·
[Tools](#tools) ·
[Security model](#security-model) ·
[Contributing](#contributing)
<img src="docs/demo.gif" alt="An agent's calls to opsgate: a shell injection, a path traversal and a restart in observe mode are all refused, nothing runs, and each attempt is in the hash-chained audit log" width="820">
</div>
---
## What it looks like
You ask a question. The agent investigates with read-only tools and answers.
> **You:** Something's listening on port 8000 on my server and I don't remember what. Check it.
```
▸ listening_ports(host: "hetzner")
Netid State Recv-Q Send-Q Local Address:Port Process
tcp LISTEN 0 511 0.0.0.0:443 users:(("nginx",pid=249619),…)
tcp LISTEN 0 511 0.0.0.0:80 users:(("nginx",pid=249619),…)
tcp LISTEN 0 4096 0.0.0.0:22 users:(("sshd",pid=237597),…)
tcp LISTEN 0 151 127.0.0.1:3306 users:(("mysqld",pid=237695),…)
tcp LISTEN 0 5 127.0.0.1:8000 users:(("python3",pid=237608),…)
▸ service_list(host: "hetzner", state: "running")
docker.service loaded active running Docker Application Container Engine
mysql.service loaded active running MySQL Community Server
nginx.service loaded active running A high performance web server…
php8.3-fpm.service loaded active running The PHP 8.3 FastCGI Process Manager
pm2-root.service loaded active running PM2 process manager
```
> **Claude:** Port 8000 is a bare `python3` process (pid 237608) bound to localhost only, so
> it isn't reachable from outside. It's not managed by systemd — no unit owns it — which
> means it won't survive a reboot. It's most likely something started by hand in a shell.
Now something that changes state. In `operate` mode the agent cannot just do it:
> **You:** OK, nginx config changed. Reload it.
```
▸ nginx_test(host: "hetzner")
nginx: configuration file /etc/nginx/nginx.conf test is successful
▸ nginx_reload(host: "hetzner")
┌─ opsgate: approval required ─────────────────────────────────┐
│ allow nginx_reload on host "hetzner"? │
│ │
│ The nginx configuration passed validation. │
│ This will reload nginx. │
│ │
│ Command: 'nginx' '-s' 'reload' │
│ [ Approve ] [ Deny ] │
└─────────────────────────────────────────────────────────────┘
```
You click Deny, and nothing happens — the agent is told the operator refused. Approve, and
it runs and lands in the audit log. Either way you saw the exact command first.
*(Tool output above is real output from a live server; the prompt is rendered by your MCP
client, so it looks however that client draws it.)*
## Try it in 30 seconds (no server needed)
opsgate runs with **no config file at all** — local machine, read-only:
```bash
go install github.com/polymatx/opsgate/cmd/opsgate@latest
opsgate serve
```
```
opsgate dev | mode=observe | default_host=local | audit=~/.opsgate/audit.jsonl
```
That's it. No config, no SSH, and it defaults to `observe` — so it can read your disk usage
and journal, and it will refuse to change anything:
```
▸ disk_usage() → works
▸ service_restart(...) → Refused by opsgate policy: host is in observe mode
```
Point your client at it and ask "what's using disk space on this machine?" When you're
ready for real hosts, add a config with `opsgate init`.
### Which clients can reach it
opsgate runs **on your machine** (or on the server itself) and holds your SSH key, so the
transport you need depends on where your client actually executes:
| Client | Transport | Works because |
|---|---|---|
| Claude Code (terminal) | stdio | Runs natively on your machine and launches the binary |
| Claude Desktop, Cursor, VS Code | stdio | Same — a local process |
| Cloud or sandboxed surfaces (web chat, VM-backed agents) | **HTTP** | They cannot launch a local process, or even see your SSH key — they can only reach a URL |
If your client reports it has no access to your servers, it is almost certainly one of the
sandboxed kind. Serve over [HTTP](#any-client-over-http) instead of stdio.
Before publishing that endpoint, read the warning there: it puts an
infrastructure-management API on whatever network you expose it to.
### Wire it up to your client
<details>
<summary><b>Claude Code</b></summary>
As a plugin: the MCP server, a `server-ops` skill that teaches the agent to diagnose before
it acts and to treat refusals as final, and a read-only `/opsgate:health-check [host]` command.
```
/plugin marketplace add polymatx/opsgate
/plugin install opsgate@opsgate
```
The plugin runs `opsgate serve`, which reads `./opsgate.yaml`, then `~/.opsgate/config.yaml`.
Or add just the MCP server:
```bash
claude mcp add opsgate -- opsgate serve --config ~/.opsgate/config.yaml
```
</details>
<details>
<summary><b>Claude Desktop / Cursor</b> (<code>claude_desktop_config.json</code> or <code>.cursor/mcp.json</code>)</summary>
```json
{
"mcpServers": {
"opsgate": {
"command": "opsgate",
"args": ["serve", "--config", "/absolute/path/to/opsgate.yaml"]
}
}
}
```
</details>
<details>
<summary><b>Docker</b> (<code>ghcr.io/polymatx/opsgate</code>)</summary>
For hosts reached over SSH. Inside a container, `local` is the container itself.
```bash
docker run -i --rm \
-v ~/.opsgate:/root/.opsgate \
-v ~/.ssh:/root/.ssh:ro \
ghcr.io/polymatx/opsgate serve
```
The image is also how opsgate is listed in the [MCP Registry](https://registry.modelcontextprotocol.io)
as `io.github.polymatx/opsgate`.
</details>
<details id="any-client-over-http">
<summary><b>Any client, over HTTP</b> (needed for cloud/sandboxed clients)</summary>
```yaml
http:
addr: "127.0.0.1:8080"
auth_token: "a-long-random-token" # sent as: Authorization: Bearer <token>
```
```bash
opsgate serve --http 127.0.0.1:8080
```
The tidiest deployment is to run opsgate **on the server it manages** — then it needs no SSH
key at all (`default_host: local`) — behind a TLS-terminating reverse proxy:
```
client ──HTTPS──▶ nginx / Caddy ──▶ 127.0.0.1:8080 opsgate
+ Bearer token
```
> [!WARNING]
> Exposing this endpoint puts an infrastructure-management API on that network, and the
> bearer token becomes the only thing protecting it. If you must publish it: keep
> `mode: observe`, generate 32+ bytes of randomness for the token, require TLS, and add an
> IP allowlist at the proxy. Binding it to a VPN interface (WireGuard, Tailscale) instead of
> the public internet is strictly safer — your own devices reach it, nobody else can.
>
> Note also that `operate` mode expects a human who can answer an approval prompt. An
> unattended HTTP deployment usually means `observe`.
</details>
## The problem this solves
Letting an AI agent run your servers today means giving it `exec("<any string>")` over SSH.
The usual mitigation is a denylist of commands that *look* dangerous.
That does not work. Denylists are guesswork against an adversary with infinite phrasings:
```
rm -rf / → blocked
r''m -rf / → not blocked
echo cm0gLXJmIC8K | base64 -d | sh → not blocked
```
And "dangerous-looking" isn't even the hard part. `systemctl restart nginx` is a perfectly
ordinary command that is catastrophic at 3pm on Black Friday.
## The approach
opsgate does not filter strings. **It never gives the agent a string to fill in.**
The agent gets 25 typed tools — `service_restart(name)`, `docker_logs(container)`,
`journal_tail(unit, since, priority)` — and opsgate builds the command itself as an `argv`
array. There is no shell to inject into, because no shell string is ever assembled from
agent input.
```go
// What opsgate does — the name is one argv element, whatever it contains
argv := []string{"systemctl", "restart", in.Name}
// What it never does
argv := []string{"sh", "-c", "systemctl restart " + in.Name}
```
Send `nginx; rm -rf /` as the service name and `systemctl` receives it as a single literal
argument and fails as an unknown unit. Nothing else runs.
Every call then passes through four gates:
```mermaid
flowchart LR
A[Agent calls a tool] --> B{Policy<br/>mode + allowlist}
B -->|deny| X[Refused<br/>+ audited]
B -->|allow| D[Build argv]
B -->|needs approval| C{Human}
C -->|deny| X
C -->|approve| D
D --> E[Execute]
E --> F[Audit<br/>hash-chained]
```
| Layer | What it does |
|---|---|
| **Structured tools** | Commands are built as `argv`, never string-concatenated. Injection is impossible by construction, not by filtering. |
| **Deny-by-default policy** | Three modes — `observe` (read-only), `operate` (writes need approval), `full`. Per-host overridesWhat people ask about opsgate
What is polymatx/opsgate?
+
polymatx/opsgate is mcp servers for the Claude AI ecosystem. The safety gate between AI agents and your servers. An MCP server for structured, policy-checked, audited infrastructure operations. It has 1 GitHub stars and its last recorded update is dated 2026-10-17.
How do I install opsgate?
+
You can install opsgate by cloning the repository (https://github.com/polymatx/opsgate) or following the README instructions on GitHub. ClaudeWave also provides quick install blocks on this page.
Is polymatx/opsgate safe to use?
+
Our security agent has analyzed polymatx/opsgate and assigned a Trust Score of 95/100 (tier: Verified). See the full breakdown of passed checks and flags on this page.
Who maintains polymatx/opsgate?
+
polymatx/opsgate is maintained by polymatx. The last recorded GitHub activity is dated 2026-10-17, with 4 open issues.
Are there alternatives to opsgate?
+
Yes. On ClaudeWave you can browse similar mcp servers at /categories/mcp, sorted by popularity or recent activity.
Deploy opsgate to your cloud
Ship this repo to production in minutes. Each platform spins up its own environment with editable env vars.
Maintain this repo? Add a badge to your README
Drop the badge into your GitHub README to show it's tracked on ClaudeWave. Each badge links back to this page and reflects the live Trust Score.
[](https://claudewave.com/repo/polymatx-opsgate)<a href="https://claudewave.com/repo/polymatx-opsgate"><img src="https://claudewave.com/api/badge/polymatx-opsgate" alt="Featured on ClaudeWave: polymatx/opsgate" width="320" height="64" /></a>More MCP Servers
Reverse engineer anything with agents, from app behavior down to native binaries.
Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.
User-friendly AI Interface (Supports Ollama, OpenAI API, ...)
An open-source AI agent that brings the power of Gemini directly into your terminal.
Real-time global intelligence dashboard. AI-powered news aggregation, geopolitical monitoring, and infrastructure tracking in a unified situational awareness interface
🕷️ A Web Scraping framework that handles everything from a single request to a full-scale crawl! Don't be shy, join here: https://discord.gg/EMgGbDceNQ and follow here for daily tips and tricks: https://x.com/Scrapling_dev