跳到主要内容
工程Mar 28, 2026

MCP 在生产环境中:解决 Transport、Auth 和扩展挑战

OS
Open Soft Team

Engineering Team

从原型到生产:有什么变化

构建一个在笔记本电脑上运行的 MCP server 很简单。运行一个能处理数千个并发 AI agent 会话的分布式基础设施则是完全不同的工程挑战。生产 MCP 部署必须解决五个原型可以忽略的问题:transport 可扩展性身份验证和授权大规模会话管理审计跟踪多服务器编排

本文是一份技术指南,面向将 MCP server 从开发环境迁移到生产环境的工程团队。我们假设您已构建过至少一个 MCP server 并了解协议基础。如果没有,请先阅读我们关于构建第一个 MCP server 的配套文章。

Transport 可扩展性:stdio vs SSE vs Streamable HTTP

MCP 定义了三种传输机制。为生产环境选择正确的传输是您的第一个架构决策。

stdio Transport

stdio transport 通过标准输入/输出流进行通信。Host 应用程序将 MCP server 作为子进程启动,并通过 stdin/stdout 交换 JSON-RPC 消息。

优势:

  • 零网络配置
  • 进程级隔离
  • 无端口冲突
  • 最低延迟(无网络堆栈)

局限性:

  • Server 必须与 host 在同一台机器上运行
  • 每个 client 会话一个 server 进程
  • 无法进行负载均衡
  • 无水平扩展

最适合: 本地开发工具、IDE 扩展、单用户桌面应用程序。

SSE (Server-Sent Events) Transport

SSE transport 使用 HTTP 进行 client 到 server 的消息传递,使用 Server-Sent Events 进行 server 到 client 的消息传递。Server 作为 HTTP 服务运行。

优势:

  • 可通过网络访问(远程服务器)
  • 与现有 HTTP 基础设施兼容
  • 支持多个并发 client
  • 可穿越防火墙和代理

局限性:

  • 单向流(仅 server 到 client 通过 SSE)
  • 需要会话亲和性(有状态连接)
  • 某些负载均衡器在处理长连接 SSE 时有困难
  • 协议中没有内置的重连语义

最适合: 中小型部署、内部工具、拥有现有 HTTP 基础设施的团队。

Streamable HTTP Transport

Streamable HTTP 是最新的 transport,专为生产部署设计。它对所有消息使用标准 HTTP POST,对长时间运行的操作使用可选的 SSE 流。

优势:

  • 完全无状态的请求/响应模型
  • 与任何 HTTP 负载均衡器兼容
  • 通过 Mcp-Session-Id 头内置会话管理
  • 支持流式和非流式响应
  • CDN 和代理兼容

局限性:

  • 需要服务器端会话存储(Redis、数据库)
  • 每消息开销略高于 stdio
  • 较新的 transport——生态系统工具较少

最适合: 生产云部署、多租户平台、企业环境。

Transport 比较矩阵

特性stdioSSEStreamable HTTP
网络访问仅本地远程远程
负载均衡不可能Session-sticky标准 HTTP LB
水平扩展有限
防火墙友好N/A
重连N/A手动内置
并发 client1多个多个
延迟最低
无状态性有状态有状态可无状态
生产就绪度仅开发中等

身份验证:SSO 集成、API Key 和 OAuth

生产中的 MCP server 必须同时验证 AI host 应用程序和代表其行事的最终用户的身份。

远程服务器的 OAuth 2.0

MCP 规范包含用于远程(基于 HTTP)服务器的内置 OAuth 2.0 流程:

  1. MCP client 发送不带凭据的 initialize 请求。
  2. Server 响应 HTTP 401 和指向 OAuth 授权端点的 WWW-Authenticate 头。
  3. Host 应用程序打开浏览器进行用户身份验证。
  4. 身份验证成功后,host 收到 access token。
  5. 后续 MCP 请求在 Authorization: Bearer 头中包含 token。
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import express from "express";

const app = express();

app.use("/mcp", async (req, res, next) => {
  const token = req.headers.authorization?.replace("Bearer ", "");
  if (!token) {
    res.status(401).json({
      error: "unauthorized",
      oauth_url: "https://auth.example.com/oauth/authorize",
    });
    return;
  }
  const user = await validateToken(token);
  if (!user) {
    res.status(403).json({ error: "invalid_token" });
    return;
  }
  req.mcpUser = user;
  next();
});

API Key 身份验证

对于服务间 MCP 通信(无人类用户参与),API key 更为简单:

const API_KEYS = new Map([
  ["sk-prod-abc123", { name: "analytics-service", scopes: ["read"] }],
  ["sk-prod-def456", { name: "admin-service", scopes: ["read", "write"] }],
]);

function authenticateApiKey(key: string) {
  return API_KEYS.get(key) || null;
}

SSO 集成模式

对于企业部署,与现有 SSO(SAML、OIDC)集成:

User -> AI Host -> MCP Client -> MCP Server -> SSO Provider
                                      |
                                      v
                              验证 OIDC token
                              提取用户角色
                              应用工具级 RBAC

每个 MCP tool 可以在执行前检查已验证用户的角色:

server.tool(
  "delete_record",
  "按 ID 删除数据库记录",
  { table: z.string(), id: z.string() },
  async ({ table, id }, { authContext }) => {
    if (!authContext.roles.includes("admin")) {
      return {
        content: [{ type: "text", text: "禁止:需要管理员角色" }],
        isError: true,
      };
    }
    // 继续删除操作
  }
);

扩展:有状态会话 vs 负载均衡器

MCP 会话本质上是有状态的:initialize 握手协商能力,服务器可能在会话内的工具调用之间维护上下文。这与水平扩展之间存在矛盾。

会话存储架构

将会话状态从服务器进程提取到外部存储:

interface McpSession {
  id: string;
  userId: string;
  capabilities: ServerCapabilities;
  createdAt: Date;
  lastActivityAt: Date;
  metadata: Record<string, unknown>;
}

class RedisSessionStore {
  constructor(private redis: Redis) {}

  async create(session: McpSession): Promise<void> {
    await this.redis.set(
      `mcp:session:${session.id}`,
      JSON.stringify(session),
      "EX", 3600
    );
  }

  async get(sessionId: string): Promise<McpSession | null> {
    const data = await this.redis.get(`mcp:session:${sessionId}`);
    return data ? JSON.parse(data) : null;
  }
}

使用 Streamable HTTP 进行水平扩展

通过外部化会话和 Streamable HTTP transport,您可以在标准负载均衡器后运行多个 MCP server 实例。无需 session-sticky 路由。任何服务器实例都可以通过从 Redis 加载会话来处理任何请求。

Auto-Scaling 配置

MCP server 的 Kubernetes HPA 示例:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: mcp-server
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: mcp-server
  minReplicas: 2
  maxReplicas: 20
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70
    - type: Pods
      pods:
        metric:
          name: mcp_active_sessions
        target:
          type: AverageValue
          averageValue: "100"

审计跟踪和日志记录

生产中的每个 MCP tool 调用都必须记录,以用于安全、合规和调试。

结构化日志 Schema

interface McpAuditLog {
  timestamp: string;
  sessionId: string;
  userId: string;
  toolName: string;
  toolInput: Record<string, unknown>;
  toolOutput: string;
  durationMs: number;
  success: boolean;
  errorMessage?: string;
  ipAddress: string;
  userAgent: string;
}

合规性考虑

要求实现
GDPR 数据访问记录 AI 通过 MCP tools 访问了哪些用户数据
SOC 2 审计跟踪带时间戳的所有工具调用不可变日志
PII 保护在日志记录前编辑工具输入中的敏感字段
数据保留设置符合合规要求的日志 TTL
访问审查记录身份验证事件和权限检查

多服务器部署的 Gateway 模式

企业环境通常需要数十个 MCP server——每个内部系统一个。MCP Gateway 集中管理:

Gateway 提供:

  1. 统一身份验证:所有后端服务器一个认证流程。
  2. 工具命名空间路由:工具以服务器名称为前缀(jira.create_issueslack.send_message)。
  3. 集中式速率限制:按用户、按工具和按服务器的限制。
  4. 请求路由:将工具调用路由到相应的后端服务器。
  5. 熔断器:如果后端服务器不健康,gateway 返回优雅的错误而非挂起。

常见问题

问:在生产中应该使用 stdio 还是 HTTP transport? 答:对于需要扩展到单台机器以外的任何部署,使用 Streamable HTTP。仅在 AI host 和 MCP server 在同一台机器上运行的本地桌面集成中使用 stdio。

问:一个 MCP server 可以处理多少并发会话? 答:使用 Streamable HTTP 和外部化会话,单个 Node.js 服务器实例通常处理 500-1,000 个并发会话。使用 Rust 或 Go 服务器,可实现 5,000-10,000 个。超出此范围时进行水平扩展。

问:如何处理 MCP server 停机? 答:实现健康检查(/health 端点),使用 Kubernetes 存活/就绪探针,并为 gateway 配置熔断器。MCP client 将收到连接错误,AI host 可将其呈现为“工具暂时不可用“。

问:MCP server 可以调用其他 MCP server 吗? 答:可以。MCP server 也可以是 MCP client,形成链式调用。这是 agent 间通信的基础。谨慎使用此模式——深层链增加延迟和故障概率。

问:如何管理 MCP server API 版本? 答:使用 initialize 响应中的服务器版本字段。对于破坏性更改(删除工具、更改 schema),升级主版本号并在迁移期间同时支持新旧版本。

问:MCP 消息的最大大小是多少? 答:协议本身没有定义最大值,但实际限制取决于 transport 和基础设施。对于 Streamable HTTP,将响应保持在 10 MB 以下。对于 stdio,系统管道缓冲区(通常 64 KB)可能需要对大型响应进行分块。