complianceHowTo

MCP Security Best Practices

Secure MCP servers with auth, least privilege, tool approval, sandboxing, rate limits, and safe logging.

Quick Answer / TL;DR

Secure MCP by denying risky tools by default, validating schemas, isolating secrets, rate-limiting calls, logging safely, and requiring human approval for destructive actions. The protocol itself does not enforce authentication or authorization; that responsibility sits with whoever implements the server.

Key Takeaways

  • Least privilege first.
  • Never trust tool arguments.
  • Mask secrets in logs.
  • Pick an auth method that matches deployment risk: API keys for internal tools, OAuth for multi-tenant apps, mTLS for zero-trust networks.

Baseline policy

Security starts with a clear boundary. Every server should know which resources it may read, which actions it may perform, and which users or clients may invoke it.

json
{
  "auth": "required",
  "rateLimit": "60/minute",
  "sandbox": true,
  "denyTools": ["shell.exec", "payments.refund"],
  "requireApproval": ["write", "delete", "send_money"]
}

Choosing an authentication method

API keys are the simplest option and fit internal tools or single-tenant deployments: store the key in an environment variable, rotate it periodically, and reject any request whose header does not match.

OAuth 2.0 suits multi-tenant SaaS and user-facing integrations, since it verifies a bearer token against an identity provider on every request. mTLS gives the strongest guarantee for zero-trust or regulated environments (finance, healthcare, government) because both client and server present certificates, removing passwords and tokens from the equation entirely.

MethodBest fitKey requirement
API keyInternal tools, dev/stagingRotate on a schedule, never hardcode
OAuth 2.0Multi-tenant SaaS, user-facing appsVerify bearer token per request
mTLSZero-trust, regulated industriesClient and server certificates

Authorization with RBAC

Authentication answers who is connecting; authorization answers what they may do. Attach a role to each verified caller and check it before executing a tool, rather than trusting that authentication alone is sufficient.

typescript
const ROLE_PERMISSIONS: Record<string, string[]> = {
  admin: ["tools/call", "resources/read", "resources/write"],
  developer: ["tools/call", "resources/read"],
  readonly: ["resources/read"],
};

function authorize(role: string, method: string) {
  if (!ROLE_PERMISSIONS[role]?.includes(method)) {
    throw new Error(`Unauthorized: ${role} cannot execute ${method}`);
  }
}

MCP Security Best Practices FAQs

Direct answers for developers, operators, and Indian teams evaluating MCP.

M
MCPserver Team

MCP documentation and protocol implementation team

Published: 2026-07-16
Updated: 2026-07-21

References & Technical Specifications