neon-guard-mcp
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@neon-guard-mcpCreate a branch for testing the new feature from main"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
neon-guard-mcp 🛡️
Neon's official MCP server is amazing, but giving an LLM full admin access to your infrastructure is terrifying. neon-guard-mcp acts as a local security proxy, giving your AI agent the exact tools it needs to branch and test code, while completely air-gapping your production data and master keys.
Features
Default-deny whitelist — only a small set of branch-scoped tools are exposed; there is no tool for deleting projects, managing users, modifying production, or accessing connection strings for branches the proxy did not create.
Provenance gating — authorization to retrieve a connection string, delete, or reset a branch requires that the proxy itself created it (tracked in
.neon-guard-state.json). A matching name prefix alone is not sufficient.Schema-only branches by default — new branches are created with
init_source: schema-only, so no production rows are ever copied into an agent-accessible branch.Short-lived branches — configurable expiry (default 24 h); Neon deletes the branch automatically, invalidating the embedded credential.
Project allowlist — the proxy refuses to act on any project not explicitly listed in your config, even if the API key has broader access.
NEON_API_KEY never leaves the proxy process — the LLM receives only tool results, never the key itself.
Configurable tool disabling — remove individual tools from the schema if your threat model requires it.
Related MCP server: SentinelGate
Architecture
Claude Code (or any MCP client)
|
| stdio (JSON-RPC)
v
+---------------------------+
| neon-guard-mcp proxy |
| - holds NEON_API_KEY |
| - enforces policy |
| - tracks provenance |
| - rewrites / filters |
+---------------------------+
|
| HTTPS (Neon REST API v2)
v
console.neon.techThe LLM calls tools. The proxy validates every call against config and provenance state, then translates allowed calls into Neon API requests. The master key is only ever present in the proxy process environment.
Why / threat model
The official Neon MCP server
Neon's official server maps MCP tools 1:1 to Neon REST API operations. This is intentional and useful — for a human developer who understands what they are authorizing. For an autonomous AI agent, it means the LLM can:
Delete any branch, including
main/ production.Read connection strings for any branch, including production.
Create branches that copy full production data.
Manage users, roles, and project settings.
One prompt-injection attack, one confused-deputy mistake, or one overly-helpful model decision is enough to destroy production data or exfiltrate it.
neon-guard-mcp
This proxy takes the opposite position: default-deny, least privilege, explicit allowlist. The agent gets only what it needs to create isolated test branches and run migrations/tests against them. Every other API surface simply does not exist as far as the LLM is concerned.
How the trust boundary works
Name prefix is NOT a security boundary.
It would be trivial for an attacker (or a confused model) to supply a branch name that happens to match the configured prefix. Authorization is instead gated on provenance: the proxy records every branch it creates in .neon-guard-state.json. A branch must appear in that record AND pass live server-side checks (not default, not protected, not the enforced parent branch) before the proxy will issue a connection string, delete it, or reset it.
The provenance store uses atomic file writes (write-then-os.replace) with mode 0o600 to prevent partial reads and limit filesystem exposure.
Installation
Recommended: uvx with a pinned version
uvx neon-guard-mcp==0.1.0Pinning the version is important for security: it prevents a supply-chain update from silently changing proxy behavior.
pip
pip install neon-guard-mcp==0.1.0From source (before the package is published)
Until neon-guard-mcp is published to PyPI, install it from a local checkout:
git clone https://github.com/your-org/neon-guard-mcp.git
cd neon-guard-mcp
uv sync # or: pip install -e .
uv run neon-guard-mcp # runs the server over stdioIn your MCP client config, point command at uv with args: ["run", "neon-guard-mcp"] (or uvx --from /abs/path/to/neon-guard-mcp neon-guard-mcp) instead of the published-package form below.
Configuration
Copy the example config and edit it:
cp neon-guard.json.example neon-guard.jsonNote:
neon-guard.jsonand.neon-guard-state.jsonare in.gitignoreand must never be committed. The example file (neon-guard.json.example) is safe to commit — it contains no secrets.
Configuration schema
Field | Type | Default | Description |
|
| required | Neon project IDs the proxy is permitted to act on. Any other project ID is rejected. |
|
| required | Prefix applied to all branches the proxy creates (e.g. |
|
| required | Name of the branch all agent branches must be parented from (e.g. |
|
|
| Controls Neon's |
|
|
| Hours after creation before Neon auto-deletes the branch. |
|
|
| If |
|
|
| Maximum number of live agent-created branches per project. Prevents runaway branch creation. |
|
| required | Database name used when generating connection strings. |
|
| required | Postgres role used when generating connection strings. Should be a dedicated least-privilege role (see Recommended Neon Setup). |
|
|
| Whether to request a PgBouncer pooled connection URI. |
|
|
| Tool names to omit from the MCP schema entirely. Useful for further restricting the agent's surface. |
Available tools
All tools are read-only or scoped to branches the proxy created. No tool can touch production or untracked branches.
Tool | What it does | Guard |
| Lists Neon projects filtered to | Intersection with server response; unlisted projects are invisible. |
| Lists branches for an allowed project, annotated with | Project must be in |
| Creates a new branch from | Project allowed; parent verified server-side; |
| Returns the connection URI for a guard-created branch. | Project allowed; branch must be in provenance store; branch must not be default, protected, or the enforced parent. |
| Returns branch state metadata. | Project allowed; branch must exist in the project. |
| Deletes a guard-created branch. | Only registered if |
| Restores a guard-created branch to its parent's current state. | Only registered if |
Claude Code .mcp.json integration
Add this to your project's .mcp.json (or ~/.claude/mcp.json for global use):
{
"mcpServers": {
"neon-guard": {
"command": "uvx",
"args": ["neon-guard-mcp==0.1.0"],
"env": {
"NEON_API_KEY": "${NEON_API_KEY}",
"NEON_GUARD_CONFIG": "/absolute/path/to/neon-guard.json"
}
}
}
}Important: The
envblock is passed only to theneon-guard-mcpsubprocess. Claude Code does not forward it to the LLM context.NEON_API_KEYnever appears in any tool call, tool result, or conversation message.
Note the "${NEON_API_KEY}" reference: Claude Code expands ${VAR} (and ${VAR:-default}) from your host environment at server-launch time, so the literal secret stays out of the config file. Use an absolute path for NEON_GUARD_CONFIG to avoid ambiguity about the working directory at startup.
Securing the master key
Claude Code passes NEON_API_KEY to the proxy as a process environment variable when it launches the server — that is the only way the key reaches the proxy, and it never reaches the model. But Claude Code does not encrypt this value anywhere. How you supply it is up to you; here are the options, most secure first.
⚠️ Myth: "
claude mcp add --envstores the key encrypted in~/.claude.json." False. It is stored as plaintext JSON. Treat anything you put in a config file or~/.claude.jsonas readable by anyone (or anything) with access to that file.
1. Secrets manager (recommended). The literal key never lands in any file — it lives in your vault and is injected into the environment only at launch. With the 1Password CLI, reference the key with an op:// secret reference and let op run resolve it:
{
"mcpServers": {
"neon-guard": {
"command": "op",
"args": ["run", "--", "uvx", "neon-guard-mcp==0.1.0"],
"env": {
"NEON_API_KEY": "op://Private/Neon/api-key",
"NEON_GUARD_CONFIG": "/absolute/path/to/neon-guard.json"
}
}
}
}The same pattern works with aws-vault exec, vault, doppler run, etc. — wrap the launch command, keep the secret in the manager.
2. Reference a host env var via ${...} expansion. Keep the real value in your shell environment (sourced from an uncommitted file or your secrets manager) and reference it — the config stays committable because it holds no secret:
export NEON_API_KEY="napi_…" # from ~/.zshrc sourcing an uncommitted ~/.secrets, a vault, etc."env": { "NEON_API_KEY": "${NEON_API_KEY}" }3. Local scope via the CLI (fine for a personal machine — but plaintext at rest). --scope local (the default) writes to ~/.claude.json, which is not committed to git, so it's safe from your repo — but the value is plaintext on disk:
claude mcp add --scope local --env NEON_API_KEY="napi_…" \
neon-guard -- uvx neon-guard-mcp==0.1.0Never hardcode the literal key in a project-scoped .mcp.json — that file is meant to be committed, so the secret would land in your git history in plaintext. Use ${NEON_API_KEY} expansion or a secrets-manager wrapper there instead. (neon-guard.json and .neon-guard-state.json are already git-ignored, but the master key is never written to either of them — it only ever comes from the environment.)
Security model and honest boundaries
What this protects
Master API key — never in LLM context; lives only in the proxy process environment.
Production branch — no tool can retrieve its connection string, delete it, or reset it (enforced server-side by checking the
defaultandprotectedflags and matching againstenforce_parent_branch).Non-allowed projects — refused at the policy layer before any API call.
Untracked branches — connection strings and destructive operations are refused for any branch not recorded in
.neon-guard-state.json.
What this does NOT fully protect
Connection strings are live credentials. When you call get_branch_connection_string, the returned URI contains a Postgres password. That URI enters the LLM context (it is the tool result). This is a fundamental constraint of how database connections work — the agent needs a credential to connect.
Mitigations applied by default:
Schema-only mode — even if the credential is exfiltrated, the branch contains no production rows.
Short expiry — the default 24 h expiry causes Neon to delete the branch, which invalidates the embedded password.
Dedicated non-owner role — the connection role (
neon_guard_aiin the example) should have only the privileges needed for migrations and tests, not superuser orneondb_owner.
Operational posture: treat any branch that an agent has touched as potentially compromised. Deleting the branch (or allowing it to expire) rotates the credential. Do not reuse agent branches for sensitive data.
Log redaction is a best-effort backstop, not the primary control. The proxy never passes the master key or a connection URI to a log, an error message, or stdout, and it scrubs known secret shapes (Neon keys, Bearer tokens, postgresql:// credentials, password= keyword forms) from every log record as defense-in-depth. Redaction is pattern-based, so the real guarantee is the "never log a secret" discipline above — do not add log lines that interpolate credentials and rely on the scrubber to catch them.
Prompt injection risk
If your agent processes untrusted input (web pages, user-provided files, database content from a previous branch), an adversary could embed instructions that attempt to exfiltrate the connection string or manipulate the agent into calling reset_test_branch on the wrong branch. The schema-only default and provenance gating significantly reduce the blast radius, but they do not eliminate the attack surface entirely. Consider whether your agent's task requires access to get_branch_connection_string at all; if not, add it to disabled_tools.
Recommended Neon setup
Create a dedicated database role with limited privileges rather than using neondb_owner:
-- Run as neondb_owner on your Neon project
CREATE ROLE neon_guard_ai WITH LOGIN PASSWORD 'choose-a-strong-password';
-- Grant only what your migrations/tests need
GRANT CONNECT ON DATABASE neondb TO neon_guard_ai;
GRANT USAGE ON SCHEMA public TO neon_guard_ai;
GRANT CREATE ON SCHEMA public TO neon_guard_ai; -- needed for migrations
-- Do NOT grant SUPERUSER, CREATEROLE, or CREATEDBSet connection.default_role to "neon_guard_ai" in your config. This ensures that even if a connection string is leaked, the role cannot escalate privileges, create new roles, or access other databases.
License
MIT — see LICENSE.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/hayian78/neon-guard-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server