使用说明
MCP Gatekeeper
Zero-standing-access token broker for AI coding agents. Sits between Claude Code (or any MCP client) and OpenBao / HashiCorp Vault, ensuring no secrets are accessible without explicit human approval via a DUO push to your phone.
The Problem
MCP servers inherit whatever access the host process has. Connect Claude Code to your infrastructure and it gets the same credentials you do — permanently, silently, for the entire session. There's no consent model, no escalation path, no timeout. The current MCP ecosystem gives you two options: full access or no access.
MCP Gatekeeper adds a third option: earned access — tiered, time-bounded, and re-approved at every step up.
How It Works
MCP Gatekeeper implements a three-tier access model where every tier transition requires a DUO push notification to your phone. The AI agent starts with nothing and must ask for what it needs.
┌─────────────────┐ DUO push ┌─────────────────┐ DUO push ┌─────────────────┐
│ No Access │──────────────▶│ Read-Only │──────────────▶│ Read-Write │
│ (default) │ authenticate │ (4hr TTL) │ escalate │ (15min TTL) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
▲ ▲ │ │
│ logout │ │ auto-renews on expiry │
│◀─────────────────────────────┘ │ (DUO push) │
│ │ │
│ logout │ expires (hard) / deescalate │
│◀────────────────────────────────│◀─────────────────────────────┘
│ drops to RO, not No Access
Consent Model
Session-scoped consent (RO): "Yes, I'm working." Auto-renews transparently when the 4-hour TTL expires. You approved a work session — reads shouldn't interrupt your flow.
Task-scoped consent (RW): "Yes, do this dangerous thing." 15-minute TTL, non-renewable — the RW token never auto-renews (enforced in code); when it expires the agent drops back to read-only and must explicitly re-escalate. Every write task requires a conscious approval decision.
Scope: Consent and token state live in a single server process and are global to it. Gatekeeper is single-operator, single-process by design — one process holds one shared RO/RW state; it does not isolate authorization per session or per principal. Don't front it with a proxy that multiplexes multiple clients into one process — they would share a tier.
Token Hierarchy
No standing access to your secrets. There is exactly one permanent credential — the bootstrap token — and its only power is to initiate an MFA challenge. Three tokens, three policies, each with only enough access to reach the next step:
- Bootstrap token — Injected by Vault Secrets Operator (VSO). Can only read
secret/data/claude/ro-loginandsecret/data/claude/rw-login. Effectively inert without your phone. - RO token — Obtained via
claude-rouserpass login + DUO push. Can read secrets within scoped paths. - RW token — Obtained via
claude-rwuserpass login + second DUO push. Can read and write secrets within scoped paths.
Even if the bootstrap token is compromised, an attacker can only request authentication. The DUO push goes to your phone. A compromised token becomes an alert system, not a silent exfiltration vector.
Tools
MCP Gatekeeper exposes eight tools to the AI agent:
| Tool | Requires | Description |
|---|---|---|
authenticate |
Nothing | Trigger DUO push to obtain RO token (4hr). Reads auto-trigger this, so explicit use is optional. |
escalate |
RO | Trigger second DUO push to obtain RW token (15min). Required before any write. |
deescalate |
RW | Revoke the RW token immediately and drop back to RO. Good practice after completing write tasks. |
logout |
RO+ | Revoke all tokens and drop to no_access. Use at session end for full disconnection. |
read_secret |
RO+ | Read a KV v2 secret. Uses RW token if held (bypasses RO deny rules), otherwise auto-renews RO. |
write_secret |
RW | Write a KV v2 secret. No auto-renewal — explicit escalation required. |
list_secrets |
RO+ | List secret keys at a path. Uses RW token if held, otherwise auto-renews RO. |
token_status |
Nothing | Report current tier and remaining TTL for held tokens. |
Prerequisites
- OpenBao or HashiCorp Vault with KV v2 secrets engine
- DUO MFA configured as an auth method enforcement on the Vault instance
- Two userpass accounts (
claude-ro,claude-rw) with DUO MFA enforcement - Three policies scoping each token tier's access
- Vault Secrets Operator (optional, for Kubernetes bootstrap token injection)
Configuration
Two environment variables:
| Variable | Description |
|---|---|
VAULT_ADDR |
OpenBao/Vault API address (e.g., https://vault.example.com) |
VAULT_TOKEN |
Bootstrap token — minimal policy, can only read userpass credentials |
Deployment
Kubernetes (recommended)
Deploy as a pod in a dedicated AI namespace with the bootstrap token injected via VSO:
docker build -t mcp-gatekeeper:latest .
# Push to your registry, deploy with your K8s manifests
The Dockerfile runs as a non-root user (mcpuser) and uses a multi-stage build with uv for fast installs.
Local Development
export VAULT_ADDR="https://vault.example.com"
export VAULT_TOKEN="hvs.bootstrap-token-here"
python -m mcp_gatekeeper
Design Principles
Invisible, not forbidden. Don't give the agent the option to be dumb. If Claude Code can see VSO pods, it will try to extract secrets from them instead of using the API. Hide infrastructure entirely rather than returning 403s that invite retry loops.
Every failure mode defaults to no access. DUO timeout → no token. Token expiry → no access. Network partition → nothing executes. Pod crash → session ends. There is no state where a failure grants more access than was intended.
DUO lives server-side. The 2FA gate is in the MCP server infrastructure, not the agent's prompt or context window. The agent can't see it, reason about it, or engineer around it. From its perspective: call the tool, either get a token or don't.
Design for compromise. Gatekeeper trusts its caller — it expects to sit behind an authenticating transport (e.g., an OIDC proxy) — so assume that transport is breached. What's the blast radius? Even then, a compromised caller can only request tokens; DUO push approval still goes to your physical device. The architecture treats every layer as already breached and asks "what's the worst that can happen?"
Session state as authorization context. Most MCP servers are stateless — same input, same output, every time. Gatekeeper maintains a server-side state machine that changes the behavior of every tool call: the same read_secret to the same path returns data or 403 depending on accumulated session consent, not on input parameters. DUO approvals are the mutations to that state. Unlike MCP's in-band elicitation — which flows back through the agent and is therefore manipulable — those approvals happen out-of-band, on a channel the agent can't see or influence.
Project Structure
mcp-gatekeeper/
├── src/mcp_gatekeeper/
│ ├── __init__.py
│ ├── __main__.py # Entrypoint, env config, FastMCP server init
│ ├── tools.py # Eight MCP tool definitions
│ └── vault_client.py # OpenBao HTTP client, token lifecycle, DUO flows
├── Dockerfile # Multi-stage build (uv + python:3.13-slim)
├── fastmcp.json # FastMCP server configuration
└── pyproject.toml # Python 3.13, fastmcp + httpx
License
Apache-2.0 — See LICENSE for details.