Skip to content

Control what your AI agents can do. Deterministic MCP security proxy with CEL policies, RBAC, and full audit trail. Single binary, zero config.

License

Notifications You must be signed in to change notification settings

Sentinel-Gate/Sentinelgate

Repository files navigation

SentinelGate

SentinelGate

Control what your AI agents can do. See everything they did.

MCP security proxy with RBAC — authenticates, authorizes, and audits every AI tool call.
Single binary. Zero config. Admin UI included.

Get Started  Website  Docs

CI License: AGPL-3.0 Go 1.24+ Release GitHub Stars

SentinelGate Demo


The problem

Your AI agents — Claude Code, Codex, Gemini Cli, custom apps — connect to MCP servers and get access to everything: databases, filesystems, APIs, GitHub repos. There's no control over which agent can call which tool, no audit trail of what happened, and no way to block a destructive action before it reaches the server.

AI Agent → MCP Server → ⚠️ ANY tool, ANY data, ANY action
                         No authentication. No rules. No logs.

The fix

SentinelGate sits between your AI agents and your MCP servers. Every tool call passes through a security chain — authentication, policy evaluation, audit logging — before it ever reaches the upstream. Denied calls are blocked before the MCP server even knows someone asked.

SentinelGate architecture

Your AI agents don't know SentinelGate exists. They see a single MCP endpoint with a unified tool list. All enforcement happens transparently.

Why SentinelGate

Deterministic policy enforcement. Every tool call is evaluated against explicit rules — not AI judgment, not probabilistic filters. If your policy says "deny delete_*", it's denied. Always. No false positives, no drift, no "it usually works."

CEL-powered rules. Policies use Common Expression Language — the same engine behind Kubernetes, Firebase, and Envoy. Write rules as expressive as code without deploying code:

// Allow writes only to safe paths for non-admin users
tool_name == "write_file" && (
  tool_args.path.startsWith("/safe/") || "admin" in user_roles
)

Simple tool patterns (read_*, delete_*) cover 90% of cases. CEL handles the rest.


✨ Features

  • 🔒 Fine-grained access control — Allow or deny individual tools per identity, with wildcard patterns and CEL expressions for complex logic
  • 🖥️ Admin UI included — Dashboard to manage servers, rules, identities, and API keys. No YAML required
  • 📊 Full audit trail — Every tool call logged with identity, decision, matched rule, timestamp, and latency. Real-time streaming and CSV export
  • 🔗 Multi-server aggregation — Connect multiple MCP servers (stdio or HTTP) and expose them as a single unified endpoint
  • 🧪 Policy playground — Test your rules against simulated tool calls before deploying them
  • Zero-config start — Single binary, no dependencies. Running in under a minute

🖥️ Admin UI

Everything is managed from the browser. No config files, no CLI flags, no restarts needed.

Tools & Rules

Policy Rules

Access


🚀 Quick Start

Get running in under 60 seconds.

Download binary (recommended)

No build tools required. Pick your platform:

# macOS (Apple Silicon)
curl -L https://github.com/Sentinel-Gate/Sentinelgate/releases/latest/download/sentinel-gate_darwin_arm64.tar.gz | tar xz

# macOS (Intel)
curl -L https://github.com/Sentinel-Gate/Sentinelgate/releases/latest/download/sentinel-gate_darwin_amd64.tar.gz | tar xz

# Linux (amd64)
curl -L https://github.com/Sentinel-Gate/Sentinelgate/releases/latest/download/sentinel-gate_linux_amd64.tar.gz | tar xz

# Linux (arm64)
curl -L https://github.com/Sentinel-Gate/Sentinelgate/releases/latest/download/sentinel-gate_linux_arm64.tar.gz | tar xz
./sentinel-gate start

🎯 Expected output:

  SentinelGate v2.0.0
  ─────────────────────────────────────
  Admin UI:   http://localhost:8080/admin
  Proxy:      http://localhost:8080/mcp
  Upstreams:  0 connected / 0 configured
  Tools:      0 discovered
  Rules:      1 active
  ─────────────────────────────────────

Open http://localhost:8080/admin — the admin UI is ready. No password from localhost.

Build from source (requires Go 1.24+)
git clone https://github.com/Sentinel-Gate/Sentinelgate.git
cd Sentinelgate
go build -o sentinel-gate ./cmd/sentinel-gate
./sentinel-gate start
Docker (alternative)
docker compose up -d

The image uses distroless for minimal attack surface and runs as non-root. State is persisted to a /data volume.

SentinelGate does not require Docker — it's a single binary with zero runtime dependencies. Docker is available purely as an alternative deployment option.


How It Works

Three steps in the admin UI, then you're protected.

1. Add your MCP servers

Click "+ Add Upstream". SentinelGate connects, discovers all available tools, and displays them instantly.

Supports stdio (spawn a local process like npx @modelcontextprotocol/server-filesystem) and HTTP (connect to a remote MCP server) transports. I recommend using -y as the first argument, but it shouldn't be necessary.

  Company Files (14 tools)                                    ● Connected
  ┌─────────────────────────────────────────────────────────────────────┐
  │  read_file          Read a file from disk                 ✅ Allow  │
  │  write_file         Write content to a file               ⛔ Deny   │
  │  edit_file          Make line-based edits to a file       ⛔ Deny   │
  │  list_directory     List directory contents               ✅ Allow  │
  │  search_files       Search for files                      ✅ Allow  │
  │  ...                                                                │
  └─────────────────────────────────────────────────────────────────────┘

  GitHub (8 tools)                                            ● Connected
  ┌─────────────────────────────────────────────────────────────────────┐
  │  list_issues        List repository issues                ✅ Allow  │
  │  create_issue       Create a GitHub issue                 ✅ Allow  │
  │  delete_branch      Delete a branch                       ⛔ Deny   │
  │  ...                                                                │
  └─────────────────────────────────────────────────────────────────────┘

2. Set rules

Create policy rules using simple tool patterns or the CEL expression editor. Rules are evaluated by priority — first match wins.

Rule Tool Action Priority
block-all-writes write_file Deny 999
block-deletes delete_* Deny 998
allow-all * Allow 100

For complex logic:

tool_name == "write_file" && tool_args.path.startsWith("/safe/") && "admin" in user_roles

Test rules before deploying them with the built-in Policy Test playground.

3. Connect your AI client

Create an identity and API key from the Access page, then point your client to SentinelGate:

Claude Code:

claude mcp add --transport http -s user sentinelgate http://localhost:8080/mcp \
  --header "Authorization: Bearer YOUR_API_KEY"

Codex / Gemini CLI / Claude Code / any MCP client:

{
  "mcpServers": {
    "sentinelgate": {
      "url": "http://localhost:8080/mcp",
      "headers": {
        "Authorization": "Bearer YOUR_API_KEY"
      }
    }
  }
}

Your AI client sees all tools from all upstream servers as a single unified list. It has no idea SentinelGate is in between.

What happens on every tool call

When the AI calls a tool, the request passes through six interceptors:

AI Agent ─── tools/call "read_file" ──► SentinelGate

  1. Validation   ✓  JSON-RPC valid
  2. Rate Limit   ✓  Under limit (23/100 req/min)
  3. Auth         ✓  Key valid → identity "claude-agent", roles: ["user"]
  4. Policy       ✓  Rule "allow-reads" matched → ALLOW
  5. Audit        ✓  Logged: tool, identity, decision, timestamp
  6. Router       ✓  "read_file" → upstream "Company Files" → forward

  ◄── response ── file contents returned to AI

If a policy denies the call, the request never reaches the upstream server:

AI Agent ─── tools/call "delete_file" ──► SentinelGate

  1. Validation   ✓
  2. Rate Limit   ✓
  3. Auth         ✓  identity "claude-agent", roles: ["user"]
  4. Policy       ✗  Rule "block-deletes" matched → DENY
  ── STOP ──
  5. Audit        ✓  Logged: decision "DENY", rule "block-deletes"

  ◄── error ── "Access denied by policy"

The upstream server never receives the request. The file is never touched.


Why It Matters

Protect databases and APIs from AI agents

Your MCP servers give AI access to production databases, internal APIs, and GitHub repos with privileged tokens. Without SentinelGate, every agent has full access to every tool. One bad prompt, one hallucination, one runaway loop — and you're looking at deleted data, leaked secrets, or runaway API costs.

Know exactly what your AI agents are doing

Every tool call is logged with the identity that made it, the decision (allow/deny), the rule that matched, and the full arguments. Filter by tool, user, or time period. Stream events in real-time. Export to CSV for compliance.

Different agents, different permissions

Give Claude Code full access. Restrict Cursor to read-only. Give the intern's custom chatbot access to search and summarize — nothing else. Each identity gets its own API key and role-based policy set.


Configuration

SentinelGate works with zero configuration. Everything — servers, rules, identities, keys — is managed from the admin UI at runtime and persisted to state.json.

For infrastructure settings (port, rate limits, audit output), an optional YAML file is available:

server:
  http_addr: ":8080"

rate_limit:
  enabled: true
  ip_rate: 100       # requests/minute per IP
  user_rate: 1000    # requests/minute per user

audit:
  output: "stdout"   # or "file:///var/log/sentinel-gate/audit.log"

Full example: sentinel-gate.example.yaml

Policy engine (CEL) reference

Policies use CEL (Common Expression Language).

Available variables:

Variable Type Description
tool_name string Tool being called ("read_file")
tool_args map Arguments passed to the tool ({"path": "/tmp/data.txt"})
user_roles list Roles of the authenticated identity (["user", "admin"])
identity_id string UUID of the identity making the request
identity_name string Name of the identity ("claude-agent")
session_id string MCP session ID
request_time timestamp Request timestamp

Custom function: glob(pattern, string) — filesystem-style pattern matching (e.g., glob("read_*", tool_name)).

Note: Roles are pure string labels with no built-in privileges. There is no implicit "admin bypass" — all permissions must be defined explicitly through policy rules.

Examples:

# Block all destructive tools
tool_name.startsWith("delete_") || tool_name.startsWith("drop_")

# Allow writes only to safe directories
tool_name == "write_file" && tool_args.path.startsWith("/safe/")

# Custom rule: allow everything for a specific role (roles have no built-in privileges)
"admin" in user_roles

# Read-only for a specific role
"reader" in user_roles && !(tool_name.startsWith("write_") || tool_name.startsWith("delete_"))
CLI reference
sentinel-gate start                       # Start with zero-config (creates state.json automatically)
sentinel-gate start --dev                  # Dev mode: skip authentication
sentinel-gate start --config config.yaml   # Start with YAML configuration
sentinel-gate start --state /path/state.json  # Custom state file location
sentinel-gate start -- npx @modelcontextprotocol/server-filesystem /tmp  # Inline stdio upstream
sentinel-gate version                      # Print version, commit, build date
sentinel-gate hash-key "my-api-key"        # Generate SHA-256 hash for YAML config
sentinel-gate --help                       # Show all commands
Flag Default Description
--config sentinel-gate.yaml Path to YAML config file (optional)
--state state.json Path to state persistence file
--dev false Dev mode: auto-creates dev identity and default policy

The state path can also be set via SENTINEL_GATE_STATE_PATH environment variable.


Security

SentinelGate is designed to run behind a reverse proxy (nginx, Caddy) that handles TLS. Do not expose it directly to the internet without TLS termination.

Built-in protections: CSRF (double-submit cookie), Content Security Policy headers, SameSite=Strict cookies, configurable rate limiting (per-IP, per-user), CEL expression hardening (length limits, cost limits, compile-time checks), path traversal protection, JSON-RPC validation with method whitelist and 1MB payload limit.

The admin UI is accessible only from localhost. For remote access, use an SSH tunnel:

ssh -L 8080:localhost:8080 your-server

🏢 Enterprise

Need SSO, compliance reports, or human-in-the-loop approvals? SentinelGate Pro adds:

  • SSO/SAML — Okta, Azure AD, Google Workspace + SCIM provisioning
  • SIEM integration — Splunk, Datadog, Azure Sentinel
  • Human-in-the-Loop — Approval workflows for sensitive tool calls
  • Content scanning — PII detection and secret detection on tool arguments
  • Compliance — EU AI Act and SOC2 evidence generation
  • Multi-tenant — Isolated policies and audit per team

→ Learn more at sentinelgate.co.uk  |  → Contact us


Contributing

We welcome contributions — bug fixes, features, documentation, and feedback. See CONTRIBUTING.md for guidelines.

A CLA is required for code contributions to support dual-licensing. See CLA.md.

Not sure where to start? Look for issues tagged good first issue.


License

AGPL-3.0 — see LICENSE. Free to use, modify, and self-host.

For commercial licensing without AGPL obligations, contact us.


Twitter · Website · Discussions

If SentinelGate is useful to you, consider giving it a ⭐ — it helps others find it.