Skip to main content
ClaudeWave

The safety gate between AI agents and your servers. An MCP server for structured, policy-checked, audited infrastructure operations.

MCP ServersOfficial Registry1 stars0 forks● GoMITUpdated today
ClaudeWave Trust Score
95/100
✓ Verified
Passed
  • ✓Open-source license (MIT)
  • ✓Actively maintained (<30d)
  • ✓Clear description
  • ✓Topics declared
  • ✓Documented (README)
Last scanned: 10/18/2026
Install in Claude Code / Claude Desktop
Method: Manual · opsgate
Claude Code CLI
git clone https://github.com/polymatx/opsgate
claude_desktop_config.json (Claude Desktop)
{
  "mcpServers": {
    "opsgate": {
      "command": "opsgate"
    }
  }
}
1. Run the command above in your terminal (Claude Code), or paste the JSON config into claude_desktop_config.json (Claude Desktop).
2. Replace any <placeholder> values with your API keys or paths.
3. Restart Claude. The MCP server and its tools appear automatically.
💡 Install the binary first: go install github.com/polymatx/opsgate@latest (make sure it ends up on your PATH).
Use cases

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.

[![CI](https://github.com/polymatx/opsgate/actions/workflows/ci.yml/badge.svg)](https://github.com/polymatx/opsgate/actions/workflows/ci.yml)
[![Go Report Card](https://goreportcard.com/badge/github.com/polymatx/opsgate)](https://goreportcard.com/report/github.com/polymatx/opsgate)
[![Go Reference](https://pkg.go.dev/badge/github.com/polymatx/opsgate.svg)](https://pkg.go.dev/github.com/polymatx/opsgate)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![Go 1.26+](https://img.shields.io/badge/Go-1.26%2B-00ADD8?logo=go&logoColor=white)](https://go.dev)
[![MCP](https://img.shields.io/badge/MCP-server-6E56CF)](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 overrides
ai-agentsaiopsaudit-logclaudeclaude-codedevopsdockergolanghacktoberfestinfrastructure-as-codemcpmcp-servermodel-context-protocolobservabilityplatform-engineeringsecuritysresshsysadminsystemd

What 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.

Featured on ClaudeWave: polymatx/opsgate
[![Featured on ClaudeWave](https://claudewave.com/api/badge/polymatx-opsgate)](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

opsgate alternatives