MCP servers do what agents tell them. There's no policy check between "the agent decided to run this query" and "the query executed." If you're running MCP servers in production, every tool call goes straight through.
We built sidclaw-mcp-guard to fix that. It's a CLI that wraps any MCP server with policy-based guardrails. YAML rules, local approval dashboard, audit trail. No signup, no SaaS dependency. Apache 2.0.
Here's what it looks like.
30-second demo
npx sidclaw-mcp-guard@latest demo
Output:
ALLOW SELECT * FROM users
Allowed: read query on users. Read-only queries are safe.
HOLD DELETE FROM users WHERE id = 42
Held for approval: delete from users. Data changes need approval.
BLOCK DROP TABLE users
Blocked: drop users. Schema changes are never allowed.
Three decisions. Safe reads pass through. Writes wait for a human. Destructive DDL gets blocked outright.
It catches compound statements too. SELECT 1; DROP TABLE users doesn't sneak through as a read -- the destructive part gets flagged.
How it works
mcp-guard is a proxy. It sits between your MCP client (Claude Desktop, Cursor, VS Code, whatever) and the upstream MCP server. Every tools/call request passes through the guard first.
MCP Client --> sidclaw-mcp-guard --> MCP Server (postgres, filesystem, etc.)
|
policy.yaml
|
localhost:9091 (approval dashboard)
The guard reads your policies, classifies the tool call using semantic patterns, and decides: allow, hold for approval, or deny.
Setting it up
npx sidclaw-mcp-guard@latest quickstart
This creates a policy.yaml, writes .mcp.json for your client, and starts the approval dashboard at localhost:9091.
To run it manually against any MCP server:
npx sidclaw-mcp-guard --upstream "npx -y @modelcontextprotocol/server-postgres postgresql://localhost/mydb" --ui
Policy rules
Policies are YAML. Each rule matches a semantic pattern and decides what happens.
rules:
- name: allow-reads
description: Read-only queries are safe
match:
pattern: sql-read
action: allow
- name: approve-writes
description: Data changes need human review
match:
pattern: sql-write
action: approve
- name: deny-destructive
description: Schema changes are never allowed
match:
pattern: sql-destructive
action: deny
default: deny
The patterns aren't regex. sql-read matches SELECT, EXPLAIN, SHOW. sql-write matches INSERT, UPDATE, DELETE. sql-destructive catches DROP, TRUNCATE, ALTER, CREATE. The guard parses the intent, not just the string.
Shell commands too
Works for filesystem and shell MCP servers, not just databases.
-
shell-safe-- ls, cat, echo -
shell-risky-- curl, wget, ssh -
shell-destructive-- rm -rf, chmod 777, dd
Same pattern. Same YAML. You can mix SQL and shell rules in one policy file if your agent connects to multiple MCP servers.
The audit trail
Every decision gets logged to .sidclaw/audit.jsonl:
{"timestamp":"...","tool":"query","args":{"sql":"SELECT * FROM users"},"decision":"allow","rule":"allow-reads"}
{"timestamp":"...","tool":"query","args":{"sql":"DELETE FROM users WHERE id=42"},"decision":"approve","rule":"approve-writes","status":"approved"}
{"timestamp":"...","tool":"query","args":{"sql":"DROP TABLE users"},"decision":"deny","rule":"deny-destructive"}
Every tool call, every decision, every approval. JSONL so you can grep it, pipe it, or ship it to whatever log aggregator you already use.
What this doesn't solve
mcp-guard governs tool calls. It doesn't filter LLM outputs, detect prompt injection, or validate agent reasoning. Those are different problems -- Pangea and Lakera handle the input/output layer. This sits at the action layer: the moment the agent decides to do something through an MCP server.
It also doesn't replace proper database permissions. If your postgres user has DROP access and you don't want agents dropping tables, fix the permissions too. mcp-guard is a second layer, not a replacement for the first.
- Repo: github.com/sidclawhq/mcp-guard
- npm:
sidclaw-mcp-guardv0.1.2 - License: Apache 2.0
- Demo:
npx sidclaw-mcp-guard@latest demo
Top comments (0)