|Security

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.

Andrei
Founder of datamcp

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:

  1. the MCP client and its local environment
  2. the MCP transport and authentication flow
  3. the gateway or server that authorizes tool calls
  4. 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.

RiskHow it appearsMinimum mitigation
Prompt injection and unsafe tool useUntrusted content influences the client to request a harmful but available operationEnforce permissions outside the model, narrow tools and resources, and require approval for sensitive actions where supported
Excessive permissionsOne token, link, or backend role can reach unrelated tools, tables, endpoints, or environmentsStart with the smallest scope and intersect MCP policy with backend grants
Token passthroughA server accepts a token intended for another resource or forwards it to an upstream APIValidate tokens for the MCP resource and keep downstream credentials separate
Confused deputyAn MCP proxy reuses upstream OAuth identity or consent incorrectly across clientsRequire per-client consent, exact redirect URI validation, and single-use state validation
Server-side request forgeryOAuth discovery or metadata URLs point a client toward internal services or cloud metadataRequire HTTPS in production, validate every URL and redirect, block private destinations, and restrict egress
Session hijackingA stolen or guessed session ID is treated as proof of identityAuthenticate every protected request; use random, bound, expiring session identifiers only for session state
Malicious local serverA copied configuration launches unreviewed code with the user's privilegesReview exact commands, pin versions, prefer stdio, sandbox the process, and limit filesystem and network access
Credential or data leakageSecrets appear in prompts, URLs, logs, repositories, or client configurationStore backend credentials server-side, redact logs, separate client identity, and rotate exposed credentials
Weak audit and revocationTeams cannot attribute an operation or disable one compromised clientUse 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

ControlMinimum production standardEvidence to keep
Trust boundariesDocument client, MCP server, gateway, database, and credential ownersArchitecture diagram and data-flow review
TransportHTTPS for remote MCP; isolated stdio for local serversEndpoint configuration and TLS checks
AuthenticationAuthenticate every protected requestOAuth/API-key configuration and failed-auth logs
Token handlingKeep MCP credentials separate from database and upstream credentialsCredential inventory and secret locations
Least privilegeStart read-only and grant only required tables and operationsPermission policy per MCP link
Database roleUse a dedicated non-owner PostgreSQL roleGRANT review and role membership
Environment isolationSeparate production from development and stagingDistinct connections, roles, and MCP links
Secret storageKeep credentials out of prompts, repositories, and shared configsSecret scan and storage policy
Tool approvalRequire human approval for sensitive operations where the client supports itClient policy and test screenshots
Audit loggingRecord successful, failed, and denied operationsQuery history and permission-violation logs
RevocationBe able to disable one client without rotating every backend credentialTested link/key revocation procedure
Incident responseDefine containment, investigation, rotation, and recovery stepsRunbook 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 Authorization header 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 public schema 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.

MCPsecurityMCP risksPostgreSQLAI agents

Need a controlled remote MCP layer?

Create a hosted link with separate client authentication, source-specific permissions, and independent revocation.

Create MCP link

Explore the DataMCP gateway · Questions? Read the docs or view pricing.