Home AI Securing MCP Servers for Claude Code: Best Practices

Securing MCP Servers for Claude Code: Best Practices

Published: May 27, 2026

Securing MCP Servers for Claude Code: Best Practices

MCP servers dramatically extend what Claude Code can do, connecting it to databases, APIs, and custom tools. But with that power comes risk: an insecure MCP server can leak credentials, allow unauthorized actions, or open a doorway into your network. This guide covers the essential security practices you need to deploy MCP servers safely in any environment.

If you’re building a Claude Code extension ecosystem, start with our main guide Claude Code Skills and Plugins for a complete overview of skills, plugins, and MCP servers.

Understanding the Threat Model

Before implementing security controls, you need to know what you’re protecting against. An MCP server typically runs with certain privileges; access to API keys, file systems, or external services. Potential adversaries include malicious actors.

  • External attackers: If the MCP server is exposed to the internet, they could try to exploit vulnerabilities, steal data, or abuse your tools.
  • Malicious insiders: Someone with legitimate access might misuse the server to perform unauthorized actions, like querying data they shouldn’t.
  • Compromised client: An attacker who gains control of a Claude Code instance could send crafted requests to your MCP server, attempting injection or denial-of-service.
  • Supply chain: Vulnerable dependencies in your MCP server code could provide an entry point.

Key assets to protect:

  • Secrets: API keys, database credentials, OAuth tokens.
  • Data: Any data the MCP server can access, including customer information.
  • Availability: The server must remain responsive for legitimate users.
  • Integrity: Tools must not execute unintended actions.

A robust threat model guides your security investments. For most MCP servers, the highest risks are credential theft and injection attacks.

Pro Tip

Think in terms of layers. A single defense can fail; combining firewalls, authentication, input validation, and monitoring gives you depth.

Authentication & Authorization

MCP servers should never trust that a request is legitimate without verification. Authentication proves the identity of the caller; authorization determines what they’re allowed to do.

Authentication methods:

  • API keys: Simple shared secrets passed in headers. Easy to implement but require secure distribution and rotation.
  • OAuth 2.0: More robust, supports token expiration, scopes, and refresh flows. Ideal for enterprise environments.
  • Mutual TLS: Certificates on both client and server. Strongest network-level auth but heavier to manage.

Claude Code itself doesn’t provide credentials to MCP servers automatically; instead, it prompts the user to supply them when configuring the server. That’s a good pattern: never hardcode secrets in your MCP server code. Read them from environment variables or a secrets manager at runtime.

Authorization is about limiting the actions each caller can perform. If your MCP server exposes multiple tools, consider implementing role-based access control. For instance, a read-only tool might be allowed for all users, while a write tool requires elevated privileges.

Always enforce authentication over HTTPS. Without TLS, credentials can be intercepted.

Input Validation & Sanitization

LLMs can be coaxed into producing unexpected or malicious arguments. Never assume that because a request came from Claude Code it’s safe. Validate every input against a strict schema.

Use a JSON schema validator like ajv (Node.js) or jsonschema (Python). Define the expected types, required fields, and value constraints.

// Example: validating arguments for a "get_weather" tool
const schema = {
  type: "object",
  properties: {
    city: { type: "string", minLength: 2, maxLength: 100 },
    units: { type: "string", enum: ["metric", "imperial"] }
  },
  required: ["city"]
};

Sanitization goes beyond schema checks. If your tool passes arguments to shell commands, databases, or URLs, you must neutralize injection attempts.

  • Command injection: Never concatenate user input into shell strings. Use parameterized APIs (e.g., subprocess.run([...]) with an array).
  • SQL injection: Use prepared statements with bound parameters.
  • SSRF (Server-Side Request Forgery): If your tool fetches URLs, validate that the URL’s hostname is in an allowlist, or restrict to public HTTP/HTTPS. Block requests to private IP ranges like 127.0.0.1 or 10.0.0.0/8.
  • XSS: If echoing user-provided data into HTML, escape appropriately.

Input validation should be the first line of defense, rejecting malformed requests before they reach business logic.

Warning

A common pitfall is trusting the “origin” header. Attackers can spoof headers. Always validate on the server side regardless of what the client claims.

Network Security

How you deploy your MCP server determines its exposure. Follow these guidelines:

  • Use TLS 1.2 or higher. Obtain certificates from a trusted CA (Let’s Encrypt works fine). Disable weak ciphers.
  • Firewall: Restrict inbound traffic to only the IPs that need access. If the server is only for your local machine, bind to 127.0.0.1.
  • VPN or private networking: For corporate environments, keep the MCP server inside a private network and require a VPN to reach it.
  • API gateway: Placing a gateway (like Kong, Apigee, or AWS API Gateway) in front adds rate limiting, IP blocking, and additional auth layers.
  • Keep dependencies updated: Vulnerabilities in libraries can expose you to attacks. Use tools like Dependabot or Renovate.

Avoid exposing your MCP server directly to the internet without strong authentication and rate limiting. The cost of a breach far outweighs the convenience.

Monitoring & Auditing

You can’t secure what you can’t see. Implement comprehensive logging:

  • Request logs: Timestamp, client identity (API key ID or user), tool invoked, arguments (but scrub secrets!), response status, latency.
  • Error logs: Stack traces, but avoid exposing internal details to callers.
  • Audit trails: For compliance, you might need to retain logs for a period. Ensure logs are immutable and access-controlled.

Set up alerts for suspicious activity:

  • High request rates (possible DoS)
  • Authentication failures from a single source (brute force)
  • Use of deprecated tools or unexpected arguments
  • Sudden spikes in error responses

Integrate with your existing monitoring stack (Prometheus, Grafana, Datadog). Export metrics: requests_total, request_duration_seconds, errors_total, active_connections.

Regularly review logs and run security scans. Conduct penetration testing if the server handles sensitive data.

Note

Be mindful of privacy regulations (GDPR, CCPA). If your MCP server processes personal data, you may need to implement additional safeguards and data subject rights handling.

Deployment Checklist

Use this checklist before putting an MCP server into production. Treat it as a gate in your CI/CD pipeline.

Checklist Item Implemented? Notes
HTTPS enabled with valid certificate Yes Use Let’s Encrypt or corporate CA
Authentication required (API key/OAuth) Yes Never allow anonymous access
Input validation on all tool arguments Yes JSON Schema + custom sanitization
Rate limiting per client Yes 100 req/min is a sensible default
Secrets stored in environment variables or vault Yes No hardcoded credentials
Structured logging with sensitive data redacted Yes Log arguments but mask API keys
Firewall rules restrict access to trusted IPs Yes Localhost only if possible
Dependencies scanned for vulnerabilities Yes Weekly Dependabot updates
Error messages don’t leak internals Yes Generic messages to clients
Monitoring alerts configured Yes PagerDuty integration active

Case Study: Securing a Database Query MCP Server

Let’s walk through securing a realistic MCP server that executes read-only SQL queries against a PostgreSQL database. This server is used by Claude Code to answer questions about project data.

The risks: If an attacker can influence the SQL query, they could exfiltrate data, modify records, or drop tables. They might also try to use the server as a pivot to attack the database server directly.

Security measures implemented:

  1. Read-only database user: The MCP server connects with a user that has only SELECT privileges on specific schemas. Even if an injection occurs, damage is limited.
  2. Strict parameterized queries: All queries use prepared statements with bound parameters. The table name and column names are fixed; only WHERE clause values are parameterized. No string concatenation.
  3. Input whitelisting: The allowed query arguments are an enum of predefined query types (e.g., “list_customers”, “get_order”). The server maps these to predefined query templates. Arbitrary SQL is never accepted.
  4. Rate limiting: The server enforces 50 queries per minute per API key to prevent brute-force data extraction.
  5. Network isolation: The MCP server runs in a Docker container on the same host as the database, but the database only accepts connections from that container’s IP. The MCP server’s HTTP endpoint is bound to 127.0.0.1, so only local Claude Code instances can reach it.
  6. TLS for HTTP: Even though it’s localhost, the server uses HTTPS with a self-signed cert to satisfy Claude Code’s security requirements and to encrypt traffic in case the host is compromised.
  7. Comprehensive logging: Every query is logged with user, query type, parameters, row count returned, and duration. Suspicious patterns (e.g., many queries with large result sets) trigger alerts.

This defense-in-depth approach ensures that even if one layer fails, others remain.

The result: a robust, auditable, and secure MCP server that safely empowers Claude Code with data access.

Conclusion

Securing MCP servers isn’t optional; it’s a prerequisite for production use. By following the practices in this guide; authentication, input validation, network hardening, and monitoring; you can confidently extend Claude Code without exposing your systems. Remember the core principles: least privilege, defense in depth, and never trust user input. For more on building Claude Code extensions, revisit our main guide. Claude Code Skills and Plugins.

Frequently Asked Questions

FAQs

Hardcoding API keys or database credentials. Always externalize secrets via environment variables or secret management services like HashiCorp Vault. It’s tempting to drop a key in the source for convenience, but that leads to leaks when you share code or push to version control. Treat secrets like passwords: they should never be in the codebase.

Technically, yes, but it’s extremely risky. Without authentication, anyone who can reach the server can invoke your tools. That could lead to abuse, data exfiltration, or resource exhaustion. Authentication is the first line of defense. At minimum, use an API key that is long and randomly generated.

SSRF occurs when an attacker tricks your server into making requests to internal resources. To prevent it: validate and sanitize all URLs; enforce an allowlist of allowed domains; block requests to private IP ranges (127.0.0.1, 10.0.0.0/8, 192.168.0.0/16); use a sandboxed HTTP client with network policy restrictions. Additionally, run your server with minimal network privileges.

Yes, if they pass arguments directly to a database or shell. Always use parameterized queries or prepared statements. For shell commands, avoid passing user input as part of the command string; instead, pass arguments as separate array elements. Use a library that handles escaping for you. Never trust that the LLM will generate safe input.

Log metadata: who made the request, which tool was called, timestamp, latency, outcome. Do not log sensitive data: API keys, passwords, personal information, query results. If you need to record arguments for debugging, redact secrets. Use structured logging (JSON) to make it easy to parse and filter.

There’s no one-size answer. For production systems handling sensitive data, rotate API keys and passwords at least every 90 days. If a key is ever exposed, rotate immediately. Automate rotation where possible using secret management tools that provide short-lived tokens. Also rotate TLS certificates every 60-90 days.