MCP Security: Risks, Best Practices, and Checklist
MCP security guide covering common risks, OAuth, token handling, least privilege, prompt injection, audit logs, revocation, and a production checklist.
What is MCP security?
MCP security is the set of controls that protects the path between an AI client, an MCP server, and the systems that server can reach. An MCP connection can expose tools for reading files, calling APIs, running SQL, or changing production data. That is useful precisely because it crosses several trust boundaries.
Do not secure that boundary by assuming the model will follow instructions. Prompts are not permissions, tool descriptions are not policy, and a confirmation dialog is not a database control.
A production design needs independent controls at four layers:
- the MCP client and its local environment
- the MCP transport and authentication flow
- the gateway or server that authorizes tool calls
- the database role that executes the final statement
The official MCP security guidance covers protocol-specific risks such as token passthrough, confused-deputy attacks, session hijacking, SSRF, unsafe authorization URLs, excessive scopes, and compromised local servers. This guide maps those risks to practical mitigations, then turns them into an operating checklist for production data access.
Common MCP security risks and mitigations
MCP is not inherently secure or insecure. The risk depends on the client, server, transport, credentials, exposed tools, backend permissions, and operating controls around them.
| Risk | How it appears | Minimum mitigation |
|---|---|---|
| Prompt injection and unsafe tool use | Untrusted content influences the client to request a harmful but available operation | Enforce permissions outside the model, narrow tools and resources, and require approval for sensitive actions where supported |
| Excessive permissions | One token, link, or backend role can reach unrelated tools, tables, endpoints, or environments | Start with the smallest scope and intersect MCP policy with backend grants |
| Token passthrough | A server accepts a token intended for another resource or forwards it to an upstream API | Validate tokens for the MCP resource and keep downstream credentials separate |
| Confused deputy | An MCP proxy reuses upstream OAuth identity or consent incorrectly across clients | Require per-client consent, exact redirect URI validation, and single-use state validation |
| Server-side request forgery | OAuth discovery or metadata URLs point a client toward internal services or cloud metadata | Require HTTPS in production, validate every URL and redirect, block private destinations, and restrict egress |
| Session hijacking | A stolen or guessed session ID is treated as proof of identity | Authenticate every protected request; use random, bound, expiring session identifiers only for session state |
| Malicious local server | A copied configuration launches unreviewed code with the user's privileges | Review exact commands, pin versions, prefer stdio, sandbox the process, and limit filesystem and network access |
| Credential or data leakage | Secrets appear in prompts, URLs, logs, repositories, or client configuration | Store backend credentials server-side, redact logs, separate client identity, and rotate exposed credentials |
| Weak audit and revocation | Teams cannot attribute an operation or disable one compromised client | Use individual identities or links, log allowed and denied operations, and test targeted revocation |
No single control resolves every row. OAuth can authenticate a caller but cannot neutralize prompt injection, reduce a database role, validate an upstream API's semantics, or replace an incident runbook.
The 12-point MCP security checklist for production
| Control | Minimum production standard | Evidence to keep |
|---|---|---|
| Trust boundaries | Document client, MCP server, gateway, database, and credential owners | Architecture diagram and data-flow review |
| Transport | HTTPS for remote MCP; isolated stdio for local servers | Endpoint configuration and TLS checks |
| Authentication | Authenticate every protected request | OAuth/API-key configuration and failed-auth logs |
| Token handling | Keep MCP credentials separate from database and upstream credentials | Credential inventory and secret locations |
| Least privilege | Start read-only and grant only required tables and operations | Permission policy per MCP link |
| Database role | Use a dedicated non-owner PostgreSQL role | GRANT review and role membership |
| Environment isolation | Separate production from development and staging | Distinct connections, roles, and MCP links |
| Secret storage | Keep credentials out of prompts, repositories, and shared configs | Secret scan and storage policy |
| Tool approval | Require human approval for sensitive operations where the client supports it | Client policy and test screenshots |
| Audit logging | Record successful, failed, and denied operations | Query history and permission-violation logs |
| Revocation | Be able to disable one client without rotating every backend credential | Tested link/key revocation procedure |
| Incident response | Define containment, investigation, rotation, and recovery steps | Runbook and completed drill |
Passing the checklist means you can show how access is constrained and how an incident would be contained. It does not mean that MCP, a gateway, or a database is universally “secure.”
Step 1: Map the complete trust boundary
Draw the request path before choosing controls:
User → AI client → MCP transport → MCP server or gateway → PostgreSQL
Add every place where credentials, prompts, SQL, query results, and logs are stored. For a local MCP server, that includes the developer machine and the package or binary being executed. For a remote server, it includes the authorization service, hosting environment, and any gateway between MCP and PostgreSQL.
Answer these questions:
- Who can edit the MCP client configuration?
- Does the client execute a local package with the same privileges as the user?
- Which system authenticates the client?
- Which component decides whether
SELECT,UPDATE, or DDL is allowed? - Which PostgreSQL role ultimately executes the query?
- Where are query results retained?
- Can one user's access be revoked without changing the database password for everyone?
If an answer is “the model decides,” the design is missing an enforceable control.
Step 2: Choose the transport deliberately
Local stdio servers reduce network exposure because the MCP client launches the process directly. They also run code on the user's machine, often with access to local files, environment variables, and network resources. Only install local MCP servers from sources you have reviewed, pin versions, and inspect the exact startup command.
Remote MCP centralizes operations but creates a network service that must be authenticated and served over HTTPS. The MCP transport specification also warns implementers of local HTTP servers to validate Origin and protect against DNS rebinding.
For production databases, choose the model whose operational controls you can actually maintain. “Local” does not automatically mean safe, and “hosted” does not automatically mean trusted.
Step 3: Authenticate every protected request
For remote MCP, require authentication before exposing tools or data. The current MCP authorization specification uses OAuth conventions, protected-resource metadata, PKCE, and access tokens intended for a specific MCP resource.
Practical rules:
- prefer OAuth with PKCE when both the MCP client and server support it
- validate credentials on every protected request, not only when a session starts
- do not use an MCP session identifier as authentication
- reject expired, invalid, or revoked credentials
- keep tokens out of logs and error messages
- prefer the
Authorizationheader over credentials embedded in URLs
Some legacy client configurations place an API key in the MCP URL. Treat the complete URL as a secret because it may leak through browser history, screenshots, proxy logs, or support tickets. Use an OAuth or header-based configuration when the client supports one.
Step 4: Separate MCP identity from backend credentials
The credential used by an AI client to reach MCP should not be the PostgreSQL password. It should also not be blindly passed to a downstream API.
MCP's security guidance explicitly rejects token passthrough: the server should validate a token intended for itself, while downstream credentials remain a separate security boundary.
For a database connection, the preferred pattern is:
MCP client credential → scoped MCP identity
Gateway-held credential → dedicated PostgreSQL role
This separation lets you revoke one client without replacing the database credential and prevents every developer machine from storing the production connection string.
Step 5: Enforce least privilege twice
Use two independent permission layers.
Database layer
Create a dedicated PostgreSQL login that is not a superuser, database owner, or schema owner. Grant access only to required databases, schemas, tables, sequences, and functions. A read-only MCP workflow usually needs CONNECT, USAGE on selected schemas, and SELECT on selected tables—not ownership and not broad write privileges.
Database privileges are the final boundary. If the MCP policy fails, PostgreSQL should still reject an operation the role cannot perform.
The PostgreSQL permissions guide for AI coding tools provides a focused role-and-grant workflow for Cursor, Claude, and similar clients before an MCP policy is added on top.
MCP layer
Create a separate MCP link or credential for each client, person, environment, or automation. Start with read-only. Add write operations only for a documented workflow, and restrict them to the required tables.
Do not share one full-access link across Cursor, ChatGPT, a CI agent, and an entire engineering team. Shared access destroys attribution and makes revocation unnecessarily disruptive.
For a concrete remote-app example, the ChatGPT PostgreSQL MCP guide starts with a dedicated database role and read-only link, then tests a denied write before workspace publication.
datamcp currently supports read-only, read-write, full-access, and custom PostgreSQL MCP links. Custom policies can restrict operations per table, and the backend validates a query against the link policy before execution. That control complements the PostgreSQL role; it does not replace careful database grants.
Step 6: Separate production from development
Use different database credentials and MCP links for development, staging, and production. Never point a link created for exploratory development at production merely because the schema looks similar.
For production:
- default to a read replica or restricted role when the workflow permits it
- exclude authentication, billing, secrets, and regulated-data tables unless explicitly required
- avoid broad
publicschema access when only a small table set is needed - use synthetic or redacted data for demos and prompt experiments
- review both permission layers whenever a migration adds a new table
Environment isolation reduces both accidental writes and prompt-driven data exposure.
Step 7: Keep secrets out of the client
Do not paste PostgreSQL connection strings, API tokens, or private keys into prompts. Do not commit them to MCP configuration examples. Do not distribute one shared .env file to a team.
Store backend credentials in a controlled server-side system and give the MCP client a separate revocable identity. Encrypt stored credentials at rest, restrict who can reveal or rotate them, and ensure application logs redact secrets.
datamcp stores supported backend credentials server-side and encrypts database credentials at rest with AES-256-GCM. This is a precise storage claim, not a compliance certification and not a substitute for using a restricted PostgreSQL role or verified TLS settings.
Step 8: Make sensitive operations require intent
Where the MCP client supports tool confirmation, keep approval enabled for writes, DDL, destructive actions, and unusually large reads. The user should see the operation and affected system before execution.
Do not rely on confirmation as the only control. A user can approve a misleading operation, and a prompt-injection attack may influence how the client explains it. The gateway and database must still enforce the maximum allowed scope.
For high-impact workflows, consider moving from generic SQL to narrow, purpose-built operations such as approve_invoice or close_support_ticket. A constrained tool is easier to authorize and audit than unrestricted write SQL.
Step 9: Log allowed and denied activity
An audit trail should answer:
- which user, client, or MCP link initiated the request
- which database connection was used
- what tool and operation were requested
- whether the request succeeded, failed, or violated policy
- how long execution took and how many rows were returned or affected
- when the event happened
Denied operations matter as much as successful ones. Repeated permission violations can reveal a broken automation, an overly broad prompt, or an attempted escalation.
datamcp records MCP query activity and permission violations. The dashboard exposes query text, status, execution time, and row count where available, and activity can be exported for review. Current retention is 7 days on Free, 30 days on Pro, and 365 days on Enterprise.
Do not put raw secrets in the activity stream. Decide separately whether query results or sensitive SQL literals need additional redaction under your data policy.
Step 10: Test revocation before you need it
Create a test MCP link, connect a client, delete or disable the link, and confirm that the old credential can no longer execute requests. Document the expected propagation time and who is allowed to perform the action.
Also test:
- removing a team member
- rotating a client API key
- rotating the PostgreSQL credential
- reducing a link from write access to read-only
- revoking access while an MCP session is already open
datamcp MCP links are individually deletable, and active-link lookup excludes inactive links. This supports targeted revocation without distributing a new PostgreSQL connection string to every client.
Step 11: Review the client and server supply chain
An MCP server can execute code or relay powerful operations. Review the package, repository, maintainer, release process, dependencies, and update mechanism before installing it.
For local servers:
- pin versions rather than executing an unreviewed latest release
- inspect
npx,uvx, Docker, and shell commands before approval - restrict filesystem and network access where the platform allows it
- avoid running the MCP client as an administrator
- remove unused servers from the client configuration
For hosted servers, review authentication, tenant separation, credential storage, logging, data retention, deletion, and incident-response documentation. Ask for evidence rather than relying on a “secure” badge.
Step 12: Prepare an MCP incident runbook
Your runbook should cover four phases.
Contain
Disable the affected MCP link or user, stop the automation, and reduce the PostgreSQL role's privileges if the blast radius is unclear.
Investigate
Export activity logs, identify successful and denied operations, inspect database logs, and determine whether credentials or query results were exposed.
Rotate
Rotate the MCP credential first. Rotate the backend credential if it may have been exposed or if the gateway boundary was compromised. Invalidate relevant sessions and remove unauthorized clients.
Recover
Restore data if needed, recreate narrowly scoped access, document the root cause, and add a regression test or monitoring rule before reconnecting the client.
Run this procedure with a harmless test link at least once. An untested revocation process is only an assumption.
What datamcp covers—and what remains yours
datamcp can provide a hosted HTTPS MCP endpoint, client authentication through API keys or OAuth 2.0 with PKCE, per-link PostgreSQL permissions, encrypted-at-rest database credentials, activity logs, and individual link deletion.
You still own:
- the PostgreSQL role and grants supplied to the connection
- database TLS configuration and network exposure
- which tables contain sensitive or regulated data
- the permission scope selected for every MCP link
- approval behavior and local security of each AI client
- team offboarding and credential-rotation procedures
- backups, recovery, compliance decisions, and incident response
That division of responsibility is the core production principle: use the gateway to narrow and observe access, then keep PostgreSQL as an independent enforcement boundary.
For the architecture behind that control layer, read MCP Gateway vs MCP Server. The MCP authorization guide explains OAuth identity, scopes, resource permissions, backend grants, and denial handling in detail. To configure a hosted PostgreSQL endpoint, see the PostgreSQL MCP server page and the datamcp gateway.
Final production review
Before connecting an AI client to production, confirm all of the following:
- The MCP client and server are approved and maintained
- Remote traffic uses HTTPS
- Every protected request requires a valid credential
- MCP credentials are separate from PostgreSQL credentials
- The PostgreSQL role is dedicated and non-owner
- The MCP link starts with the minimum table and operation scope
- Development, staging, and production use separate links and credentials
- Secrets are absent from prompts, repositories, screenshots, and logs
- Sensitive operations require explicit intent where supported
- Successful, failed, and denied operations are reviewable
- Individual access can be revoked without rotating every client
- The incident runbook has been tested
If any box is unresolved, keep the connection away from production until the missing control has an owner and a test.
MCP security FAQ
What are the biggest MCP security risks?
The main risks include prompt-driven misuse of legitimate tools, excessive permissions, credential leakage, token passthrough, confused-deputy attacks, SSRF during URL discovery, session hijacking, compromised local servers, weak supply-chain review, and insufficient audit or revocation controls.
Is MCP secure enough for production?
MCP can be used in production when the complete system is secured: authenticate protected requests, enforce least privilege at the MCP and backend layers, isolate credentials and environments, review server code and configuration, log outcomes, and test revocation and incident response. The protocol alone does not make a deployment safe.
Does OAuth prevent MCP prompt injection?
No. OAuth can establish identity and token scope, but prompt injection can still influence an authenticated client to request an operation. Server-side authorization, narrow tools, backend permissions, client approval, and monitoring must independently limit what that request can do.
Are local MCP servers safer than remote servers?
Not automatically. Local stdio avoids exposing a remote network endpoint, but the server process can run with the user's filesystem, environment, and network privileges. Remote MCP centralizes control but requires HTTPS, authentication, secure sessions, and operational hardening.
How should an MCP server protect production data?
Use a dedicated non-owner backend role, expose only required tools and resources, start read-only, keep client and backend credentials separate, authenticate every protected request, separate environments, log successful and denied operations, and verify that one client can be revoked without rotating every other credential.
Related articles
MCP Gateway vs MCP Server: Architecture, Security, and When You Need Each
An MCP server exposes tools. An MCP gateway controls how clients reach them. Compare architecture, auth, permissions, operations, and production tradeoffs.
SecurityMCP Governance for Production Teams: Policy, Ownership, and Control
Build an MCP governance program with server inventory, ownership, approval, least privilege, change control, monitoring, revocation, and incident response.
Need a controlled remote MCP layer?
Create a hosted link with separate client authentication, source-specific permissions, and independent revocation.
Create MCP linkExplore the DataMCP gateway · Questions? Read the docs or view pricing.