Agent Ready Academy
Module 6: MCP — Model Context Protocol

MCP in Production

Security, authentication, performance, and deployment patterns for MCP servers

~12 min readIncludes code

Overview

An MCP server running on a developer's laptop during a coding session is one thing. An MCP server handling production data, authenticating against real services, and serving multiple agents simultaneously is another. This lesson covers the security, authentication, performance, and deployment concerns you must address before your MCP servers are production-ready. The goal is not to make things complicated -- it is to make things safe, reliable, and observable.

The Security Surface

Every MCP server is a bridge between an AI agent and an external system. That bridge is a security surface. The agent can send arbitrary tool calls, and the server executes them against real services. If the server is not careful, an agent could:

  • Exfiltrate sensitive data through overly permissive queries
  • Modify production data through unvalidated write operations
  • Exhaust API quotas through unbounded tool calls
  • Access resources outside its intended scope
Security threats and their defenses: Data Exfiltration is mitigated by Input Validation (schema + business rules), Unauthorized Writes by Least Privilege (minimal permissions), Resource Exhaustion by Rate Limiting (per-tool quotas), and Scope Creep by Audit Logging (every tool call recorded).

The defense is defense in depth: validate inputs, limit permissions, restrict rates, and log everything.

Authentication and Credential Management

MCP servers often need credentials to access downstream services -- API tokens, database passwords, OAuth secrets. How you manage these credentials determines your security posture.

The Golden Rules

  • Never hardcode credentials in server source code or configuration files that are committed to version control
  • Use environment variables for injecting credentials at runtime
  • Prefer short-lived tokens (OAuth access tokens, temporary credentials) over long-lived API keys
  • Scope credentials minimally -- a server that only reads issues should not have write access to the repository

Environment Variable Pattern

src/config.ts

OAuth 2.0 for Remote Servers

For SSE-based servers that run as shared services, implement OAuth 2.0 authentication. The MCP specification includes support for OAuth flows, allowing clients to authenticate before accessing server capabilities:

src/auth.ts

Input Validation

Zod schemas handle structural validation -- ensuring the right fields are present with the right types. But production servers need business rule validation too.

src/tools/database.ts

Principle of least privilege: Give each MCP server only the permissions it needs. A database server for exploration should use read-only credentials. A GitHub server for reading PRs should use a token scoped to read:repo only. Minimizing permissions limits the blast radius if something goes wrong.

Rate Limiting

Agents can be persistent. If a tool call fails, the agent might retry immediately. If an agent enters a loop, it could call the same tool hundreds of times in seconds. Without rate limiting, this can exhaust API quotas, overwhelm databases, or trigger abuse detection on downstream services.

src/middleware/rate-limit.ts

Different tools warrant different limits. A read-only search might allow 60 calls per minute. A tool that creates issues might allow only 10. A deployment tool might allow just 1 per 5 minutes.

Structured Logging

In production, you need to know what tools are being called, by whom, with what arguments, and whether they succeeded or failed. Structured logging makes this observable:

src/middleware/logging.ts

Critical reminder: MCP servers must write logs to stderr, never to stdout. The stdout stream is exclusively for JSON-RPC protocol messages. Mixing log output into stdout will corrupt the protocol stream and crash the connection.

Error Handling

Production MCP servers must handle errors gracefully. An unhandled exception in a tool handler can crash the server process, killing all active connections. Defensive error handling keeps the server running even when individual tool calls fail:

src/tools/metrics.ts

Key error handling principles:

  • Always return a content response, even on errors -- do not throw from tool handlers
  • Set isError: true so the agent knows the call failed
  • Do not leak internal details like stack traces, connection strings, or internal hostnames in error messages
  • Log the full error to stderr for debugging, but return a sanitized message to the agent

Deployment Patterns

Containerized Deployment

For SSE-based servers that serve multiple users or run remotely, containerize the server:

Dockerfile

Architecture for Shared Servers

When multiple agents or users need to access the same MCP server, deploy it as a shared service with proper isolation:

Shared MCP server architecture: multiple agent instances (Developer A, Developer B, CI Pipeline) connect via SSE to an API Gateway (authentication, rate limiting, access logging), which routes to an MCP Server Cluster, which accesses downstream services (Database, Internal APIs, Project Management).

Local vs. Remote: Decision Framework

Decision flowchart for MCP server deployment: single user without sensitive data → local stdio. Single user with sensitive data → local stdio + credential rotation. Team on same network → internal SSE + API gateway. Team across networks → remote SSE + OAuth + TLS.

Start with the simplest deployment that meets your needs. Most teams begin with local stdio servers and only move to remote SSE deployments when they need shared access or centralized management.

Production Checklist

Before deploying an MCP server to production, verify each of these items:

  • Authentication -- credentials are injected via environment variables, never hardcoded
  • Authorization -- the server enforces which operations are allowed, not just which are available
  • Input validation -- both schema validation (Zod) and business rule validation are in place
  • Rate limiting -- per-tool call limits prevent runaway agents from exhausting resources
  • Error handling -- tool handlers never throw; they return isError: true responses with sanitized messages
  • Logging -- every tool call is logged to stderr with timestamp, tool name, arguments, result, and duration
  • Least privilege -- downstream credentials are scoped to the minimum required permissions
  • Timeout handling -- API calls have timeouts; the server does not hang on unresponsive downstream services
  • Health checks -- for containerized deployments, a health endpoint confirms the server is responsive
  • Documentation -- CLAUDE.md describes what each MCP server does and when agents should use it

Summary

Running MCP servers in production requires attention to security, reliability, and observability. The core principles are least privilege (minimal credentials and permissions), defense in depth (input validation, rate limiting, and error handling at every layer), and observability (structured logging for every tool call). Deploy with the simplest architecture that meets your needs -- local stdio for single-user development, remote SSE with authentication for team-wide shared servers. The production checklist at the end of this lesson serves as your pre-deployment gate. With these patterns in place, your MCP servers become a reliable extension of your agent infrastructure -- trusted components that safely bridge AI reasoning and real-world systems.

Check Your Understanding

Question 1 of 3

What is the most important security principle when deploying MCP servers in production?