生产级MCP服务器架构设计与落地实践
1. 项目概述当MCP服务器不再只是概念玩具而是能真正落地的协作中枢“MCP Servers That Are Actually Useful”——这个标题一出来我就在脑子里过了一遍过去两年里见过的所有MCPModel Context Protocol相关演示和开源仓库。绝大多数都卡在“能跑通demo”的阶段本地启动一个Python脚本调用一次LLM返回一段带JSON结构的响应然后戛然而止。没人提怎么鉴权、怎么限流、怎么对接企业已有身份系统没人讲清楚服务挂了之后上下文状态怎么恢复更没人说明白当你的前端团队想用WebSocket实时推送tool call结果时MCP服务器该暴露几个endpoint、每个endpoint该遵循什么重试语义。这标题里的“Actually Useful”不是修辞是硬指标——它意味着要经得起生产环境7×24小时调度、能嵌入现有CI/CD流水线、支持灰度发布、具备可观测性埋点、API变更有明确的版本迁移路径且文档里写的每行curl命令你复制粘贴后30秒内就能拿到真实响应。我去年帮一家做智能合同审核的SaaS公司重构AI网关时就踩过这个坑。他们最初用社区版MCP参考实现搭了个POC测试时一切完美但上线前压测发现并发超80 QPS时context store内存泄漏导致每小时OOM一次工具调用链路缺乏traceID透传排查超时问题要翻6个日志文件更麻烦的是他们的法务系统要求所有tool execution必须留审计日志并签名存证而原生MCP spec里压根没定义audit字段位置。最后我们不得不在MCP server层之上加了一层“合规适配器”把MCP request/response双向解析、注入签名头、写入区块链存证服务——这恰恰印证了标题的潜台词有用的MCP服务器从来不是对spec的机械实现而是对真实业务约束的精准翻译。本文不讲协议细节只聚焦三件事哪些架构设计能让MCP server扛住真实流量哪些核心模块必须自研而非套用模板以及——最关键的——如何用最小改动让现有MCP server通过ISO 27001审计检查项。适合正在评估MCP落地路径的架构师、需要交付AI能力接口的后端工程师以及被产品反复追问“为什么不能直接调用大模型”的技术负责人。2. 内容整体设计与思路拆解从协议规范到生产系统的四层跃迁2.1 为什么90%的MCP参考实现无法进入生产环境先说结论MCP协议本身是精巧的但它的设计哲学是“最小可行交互”而非“最大可用服务”。官方specv0.10.2全文仅17页核心定义集中在/server/execute和/server/heartbeat两个endpoint连最基础的错误码分类都只有invalid_request、tool_execution_failed、context_expired三个枚举值。这种极简主义在学术验证阶段是优势但在工程落地时就成了地雷阵。我统计了过去半年GitHub上star数超200的12个MCP server实现发现它们在四个关键维度存在系统性缺失状态管理维度12个项目中10个使用内存Map存储context2个用Redis但未实现context TTL自动续期逻辑。这意味着当用户对话中断5分钟再回来90%的服务会返回context_expired而非尝试从持久化层恢复。安全边界维度0个项目默认启用OAuth2.0 PKCE流程11个允许任意origin跨域请求7个在tool call参数校验中直接json.loads()而不做schema白名单过滤——这等于把LLM的function calling能力裸露在公网。可观测性维度所有项目日志格式不统一仅3个提供OpenTelemetry exporter0个内置Prometheus metrics endpoint如mcp_server_tool_call_duration_seconds_bucket。运维契约维度12个项目均无健康检查探针liveness/readiness11个未定义配置热加载机制当需要动态调整rate limit时必须重启进程。提示不要被“支持MCP协议”这个表述迷惑。就像说“支持HTTP协议”不等于能当Web服务器用一样“支持MCP”只代表能解析{type:execute,tools:[...]}这类payload离“可用”差着至少四层抽象。2.2 四层架构设计把MCP server变成可运维的基础设施我把生产级MCP server拆解为四个垂直分层每层解决一类工程问题且层间有清晰契约第一层协议适配层Protocol Adapter Layer这是唯一与MCP spec强绑定的部分职责极其单纯接收HTTP/WebSocket请求 → 校验JSON Schema → 转换为内部Context对象 → 调用下层执行器。关键设计点在于零业务逻辑。我们强制规定此层代码禁止出现if user.role admin这类判断所有权限控制下沉到第二层。实测下来这层代码量稳定在300行以内Go语言且能用spec官方提供的JSON Schema自动生成validator极大降低协议升级成本。第二层执行协调层Execution Orchestrator Layer这是真正的“大脑”处理所有非协议逻辑工具调用编排当LLM返回多个tool calls时决定是串行执行如先查数据库再发邮件还是并行执行如同时调用天气API和股票API并实现超时熔断例如单个tool call超过8s自动cancel并标记失败上下文生命周期管理context创建时生成唯一context_id关联到用户ID设备指纹时间戳哈希每次访问时检查TTL若剩余时间30s则自动延长至2h需满足业务规则如金融场景不允许延长医疗场景允许延长但需二次确认审计日志注入在tool call执行前后插入审计钩子记录user_id、tool_name、input_hash、output_truncated、signature五元组输出到专用审计Kafka Topic第三层工具连接层Tool Connector Layer这里彻底解耦MCP server与具体工具实现。我们采用“工具描述即配置”的模式每个工具对应一个YAML文件例如jira_create_issue.yamlname: jira_create_issue description: Create a Jira issue with title and description input_schema: type: object properties: project_key: {type: string, maxLength: 10} summary: {type: string, maxLength: 255} description: {type: string} required: [project_key, summary] output_schema: {type: object, properties: {issue_key: {type: string}}} auth_method: oauth2_client_credentials endpoint: https://api.atlassian.com/ex/jira/{cloudId}/rest/api/3/issueMCP server启动时扫描此目录自动生成OpenAPI文档、构建类型安全的调用客户端并在运行时根据auth_method自动注入token。这样新增一个工具只需写YAML无需改一行Go/Python代码。第四层运维支撑层Operational Support Layer这才是让MCP server“Actually Useful”的关键。包含/healthz和/readyz端点其中/readyz会真实探测context store连接池、tool connector认证服务、审计日志Kafka集群的可用性Prometheus metrics除标准HTTP指标外特设mcp_server_context_ttl_seconds直方图监控各context剩余存活时间分布配置中心集成支持从Consul/Nacos动态拉取rate limit策略例如{user_tier: premium, max_rps: 200, burst: 500}灰度发布开关通过配置项feature.mcp_v2_protocol_enabled: true控制是否启用MCP v0.11新特性避免全量升级风险这四层不是理论模型而是我们线上环境的真实部署拓扑。每一层都有独立的Docker镜像、资源配额和告警规则。当某天Jira工具调用超时率飙升时运维同学只需看第三层的mcp_tool_call_duration_seconds_bucket{tooljira_create_issue}指标完全不用关心协议层或执行层代码——这就是分层的价值。3. 核心细节解析与实操要点五个必须亲手打磨的关键模块3.1 Context Store别再用Redis当万能胶水几乎所有MCP教程都说“用Redis存context”但生产环境必须回答三个问题当Redis主节点宕机时正在执行的tool call如何保证不丢失如何防止恶意用户构造超长context_id耗尽Redis内存审计要求context数据留存7年Redis的TTL机制如何与冷热分层存储协同我们的方案是双写分层存储热存储Redis Cluster仅存context元数据结构为context:{id}:meta包含created_at、last_accessed_at、user_id、ttl_seconds四个字段TTL设为2小时。所有读写操作走Pipeline实测QPS达12万。温存储PostgreSQL存完整context快照表结构含context_idUUID、content_jsonb压缩后的JSONB、version乐观锁版本号、archived_at归档时间。每次context更新时先更新Redis元数据再异步写入PostgreSQL通过Debezium捕获binlog触发。冷存储S3 GlacierPostgreSQL每日凌晨执行pg_dump将7天前的context快照加密后上传至S3对象key为s3://mcp-context-archive/{year}/{month}/{day}/{context_id}.sql.gpg。关键实操细节Redis key命名强制小写下划线避免大小写混用导致的缓存穿透如context:ABC123和context:abc123被视为不同keyPostgreSQL的content_jsonb字段启用pglz压缩实测平均压缩率62%单条context从8KB降至3KBS3上传前用gpg --symmetric --cipher-algo AES256加密密钥由KMS托管解密密钥轮换周期为90天注意不要在context store里存原始LLM prompt。我们只存LLM的structured output如{type:tool_call,name:search_db,args:{query:user email}}和tool execution result。原始prompt由前端负责缓存MCP server只管“执行”和“状态”这是职责分离的铁律。3.2 Tool Call Security比JWT更狠的三重防护MCP最大的安全隐患在于LLM生成的tool call参数完全不可信。攻击者可能诱导模型输出{name:delete_user,args:{user_id:*}}若后端不做校验后果不堪设想。我们实施三重防护第一重Schema白名单校验在工具YAML定义中声明input_schemaMCP server启动时用jsonschema.Draft202012Validator预编译validator。执行前调用validate(instancetool_args, schemainput_schema)。重点在于拒绝任何未在schema中声明的字段。例如schema只要求project_key和summary若LLM传入{project_key:PROJ,summary:test,priority:high}则直接拒绝并返回invalid_request错误。第二重参数内容沙箱对高危字段做正则拦截user_id类字段必须匹配^[a-zA-Z0-9_-]{8,32}$拒绝..、/etc/passwd等路径遍历字符SQL相关字段如query用sqlparse.parse()检测是否存在DROP、UNION SELECT等关键词命中则触发告警并阻断文件路径字段强制以/safe/path/开头且os.path.normpath()后不能跳出该前缀第三重执行时长熔断每个tool connector启动独立goroutine执行主goroutine设置context.WithTimeout(ctx, 8*time.Second)。若超时主动调用tool.Cancel()需tool实现Cancelable接口并记录tool_call_timeout{tooldb_query, timeout_ms8000}指标。实测发现8秒阈值能覆盖99.2%的正常工具调用而SQL注入类攻击往往因死循环卡在15秒以上此时熔断机制已生效。3.3 审计日志让每一次tool call都可追溯、可存证ISO 27001 Annex A.8.2.3明确要求“所有特权操作必须生成不可篡改的日志”。MCP server的tool call正是典型特权操作。我们的审计日志设计遵循“五不可”原则不可伪造、不可篡改、不可删除、不可延迟、不可混淆。日志结构JSON格式单行输出{ event_id: evt_abc123def456, timestamp: 2024-06-15T08:23:45.123Z, context_id: ctx_xyz789, user_id: usr_123456, tool_name: send_email, input_hash: sha256:abcd1234..., output_truncated: sent to admincompany.com, status: success, duration_ms: 1245, signature: ecdsa:qwer789tyu... }关键技术点input_hash对tool args JSON序列化后计算SHA256避免日志中明文记录敏感参数如邮箱密码output_truncated对tool返回结果做长度截断默认256字符并脱敏如邮箱显示为a***b***.comsignature用ECDSA私钥对event_idtimestampcontext_idinput_hash签名公钥由审计部门统一管理任何日志修改都会导致验签失败日志输出到Kafka时topic按mcp-audit-{year}-{month}分片每个分区配置retention.ms259200000030天同时开启min.insync.replicas2确保至少2个副本写入成功才返回ACK。Kafka Consumer Group由审计系统独占其他服务无权限消费该topic。3.4 流量治理Rate Limit不是数字游戏而是业务规则映射MCP server的rate limit绝不能简单设成“100 RPS”。我们按三个维度精细化控制维度一用户等级从身份系统同步用户tier信息存入Redis Hashuser:tier:usr_123456 - {tier: enterprise, max_rps: 500, burst: 2000}限流算法用令牌桶Token Bucket但桶容量和填充速率动态计算capacity max_rps * 2保证突发流量fill_rate max_rps / 10每100ms填充1个token维度二工具敏感度在工具YAML中声明sensitivity_level: high|medium|lowhigh如delete_user单用户每分钟最多5次且需二次确认前端弹窗medium如update_config单用户每分钟最多30次low如get_weather不限制但全局QPS不超过5000维度三上下文活跃度对context_id做滑动窗口统计过去60秒内同一context的tool call次数超过10次则触发context_flood告警自动降级为只允许get_status类只读工具。限流中间件用Go的golang.org/x/time/rate但做了关键改造每个限流器key为{user_id}:{tool_name}:{context_id}实现三维联合限流当触发限流时返回HTTP 429响应body含{retry_after: 30, reason: context_flood}前端据此决定是等待还是提示用户3.5 健康检查/healthz不是摆设而是故障定位的第一现场很多团队的/healthz只是返回{status:ok}这毫无价值。我们的/healthz和/readyz是两套独立逻辑/healthz存活探针检查进程自身状态Go runtime内存runtime.ReadMemStats()中HeapInuse 80%总内存Goroutine数量runtime.NumGoroutine() 5000阈值根据实例规格动态计算GC暂停时间最近1分钟内gc_pause_total_ns 500ms/readyz就绪探针检查依赖服务连通性Redis连接池redis.Ping()响应时间 50ms且Info(clients)中connected_clients 0PostgreSQL执行SELECT 1超时1s且pg_is_in_recovery()返回falseKafka Producer发送测试消息到mcp-health-testtopic等待ACK超时2sTool Auth Service调用GET /oauth2/token/introspect验证token有效性关键实操技巧/readyz检查项可配置开关例如readyz.check.kafkafalse用于Kafka维护期间避免误判所有检查结果以结构化JSON返回含component、status、latency_ms、error字段供Prometheus抓取当任一检查失败时Kubernetes会停止向该Pod转发流量但进程不退出便于人工介入排查4. 实操过程与核心环节实现从零搭建生产级MCP server的七步法4.1 环境准备用容器化抹平环境差异我们放弃“本地开发-测试-生产”三套环境全部基于Docker Compose定义。核心服务如下# docker-compose.yml version: 3.8 services: mcp-server: build: ./mcp-server ports: [8080:8080] environment: - MCP_CONTEXT_STOREredis://redis:6379/0 - MCP_TOOL_STOREfile:///app/tools - MCP_AUDIT_KAFKAPLAINTEXT://kafka:9092 depends_on: [redis, postgres, kafka] redis: image: redis:7.2-alpine command: redis-server --save 60 1 --appendonly yes volumes: [./redis-data:/data] postgres: image: postgres:15-alpine environment: - POSTGRES_DBmcp - POSTGRES_USERmcp - POSTGRES_PASSWORDmcp123 volumes: [./postgres-data:/var/lib/postgresql/data] kafka: image: bitnami/kafka:3.5 environment: - KAFKA_CFG_NODE_ID1 - KAFKA_CFG_PROCESS_ROLEScontroller,broker - KAFKA_CFG_LISTENERSPLAINTEXT://:9092,CONTROLLER://:9093 - KAFKA_CFG_ADVERTISED_LISTENERSPLAINTEXT://kafka:9092 - KAFKA_CFG_CONTROLLER_QUORUM_VOTERS1kafka:9093关键配置说明Redis启用AOF持久化appendonly yes避免容器重启后context元数据丢失PostgreSQL数据卷挂载到宿主机确保pg_dump备份脚本能访问原始文件Kafka使用Bitnami镜像而非Confluent因其轻量且默认启用Controller Quorum符合我们小规模部署需求4.2 协议适配层实现用代码生成器消灭手写bugMCP spec的JSON Schema定义在https://github.com/modelcontextprotocol/spec/blob/main/schema/server.json。我们用jsonschema2go工具自动生成Go结构体# 生成代码 jsonschema2go \ --input https://raw.githubusercontent.com/modelcontextprotocol/spec/main/schema/server.json \ --package mcp \ --output ./internal/mcp/schema.go \ --struct-name ServerRequest生成的ServerRequest结构体自动包含json:type标签和Validate()方法。协议适配层核心逻辑仅47行func (h *Handler) Execute(w http.ResponseWriter, r *http.Request) { var req mcp.ServerRequest if err : json.NewDecoder(r.Body).Decode(req); err ! nil { http.Error(w, invalid json, http.StatusBadRequest) return } if err : req.Validate(); err ! nil { // 调用自动生成的校验 http.Error(w, invalid request, http.StatusBadRequest) return } ctx, cancel : context.WithTimeout(r.Context(), 30*time.Second) defer cancel() result, err : h.orchestrator.Execute(ctx, req) if err ! nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set(Content-Type, application/json) json.NewEncoder(w).Encode(result) }为什么不用框架因为MCP协议极简引入Gin/Echo等框架反而增加学习成本和潜在漏洞面。纯net/http 自动化代码生成既保证性能实测吞吐量比Gin高12%又杜绝手写JSON解析的常见错误如json.Unmarshal忘记检查err。4.3 执行协调层用状态机驱动复杂流程当LLM返回多个tool calls时我们不简单并行执行而是构建有限状态机FSMtype ExecutionState int const ( StatePending ExecutionState iota StateExecuting StatePartialSuccess StateFailed ) type ExecutionContext struct { State ExecutionState ContextID string ToolCalls []mcp.ToolCall Results map[string]mcp.ToolResult Errors map[string]error } func (e *ExecutionContext) Next() { switch e.State { case StatePending: e.startAll() case StateExecuting: if e.isAllDone() { e.State StatePartialSuccess e.handlePartialSuccess() } } }状态流转逻辑StatePending→ 启动所有tool call goroutine每个goroutine完成时调用e.markDone(toolName, result, err)StateExecuting→ 每100ms检查一次若所有goroutine结束则进入StatePartialSuccessStatePartialSuccess→ 对成功结果聚合对失败结果按retry_policy决定是否重试如网络超时重试3次SQL错误不重试实测效果当LLM返回3个tool calls查DB、发邮件、写日志时FSM能确保DB查询失败时邮件和日志仍正常执行避免传统串行逻辑的“一损俱损”。4.4 工具连接层YAML驱动的零代码集成以集成Slack通知为例创建slack_notify.yamlname: slack_notify description: Send notification to Slack channel input_schema: type: object properties: channel_id: {type: string, pattern: ^C[A-Z0-9]{8,}$} text: {type: string, maxLength: 2000} blocks: {type: array, items: {type: object}} required: [channel_id, text] output_schema: {type: object, properties: {ts: {type: string}}} auth_method: slack_bot_token endpoint: https://slack.com/api/chat.postMessageMCP server启动时自动解析YAML生成SlackNotifyTool结构体创建HTTP client自动注入Authorization: Bearer ${SLACK_BOT_TOKEN}生成OpenAPI文档片段合并到/openapi.json注册/tools/slack_notify调试端点支持curl测试调试技巧访问http://localhost:8080/tools/slack_notify/debug输入JSON参数实时查看HTTP请求/响应日志中自动标记toolslack_notify methodPOST urlhttps://slack.com/api/chat.postMessage status2004.5 运维支撑层让指标说话我们暴露的Prometheus指标全部遵循 OpenMetrics规范 关键指标如下指标名类型说明示例mcp_server_http_request_duration_seconds_bucketHistogramHTTP请求延迟分布le0.1表示≤100ms的请求数mcp_server_context_ttl_secondsHistogramcontext剩余TTL分布le3600表示剩余时间≤1h的context数mcp_tool_call_duration_seconds_bucketHistogram工具调用延迟分布tooldb_query标签区分工具mcp_server_audit_log_errors_totalCounter审计日志写入失败次数持续增长需立即告警Grafana看板配置要点主面板显示rate(mcp_server_http_request_duration_seconds_count[5m])即每秒请求数下钻面板用histogram_quantile(0.95, sum(rate(mcp_tool_call_duration_seconds_bucket[5m])) by (le, tool))计算P95延迟告警规则当mcp_server_audit_log_errors_total1分钟增量0时触发PagerDuty告警4.6 部署上线金丝雀发布与回滚预案我们用Argo CD管理Kubernetes部署mcp-server的Deployment配置关键字段apiVersion: apps/v1 kind: Deployment metadata: name: mcp-server spec: replicas: 3 strategy: canary: steps: - setWeight: 10 # 先切10%流量 - pause: {duration: 300} # 观察5分钟 - setWeight: 30 - pause: {duration: 300} - setWeight: 100回滚预案若mcp_server_http_request_duration_seconds_sum / mcp_server_http_request_duration_seconds_count平均延迟突增200%自动触发kubectl rollout undo deployment/mcp-server若mcp_server_audit_log_errors_total持续增长手动执行kubectl set env deploy/mcp-server MCP_AUDIT_KAFKA临时关闭审计日志保障核心功能4.7 生产验证用真实业务场景压测我们用公司内部的“智能会议纪要”场景做最终验证模拟1000个并发用户每人发起3轮对话每轮含2次tool callextract_action_itemscreate_jira_ticket压测工具k6脚本模拟真实MCP请求流压测结果AWS c5.4xlarge实例指标数值达标情况P95延迟420ms≤500ms ✅错误率0.02%≤0.1% ✅CPU使用率68%≤80% ✅内存使用率72%≤85% ✅审计日志写入成功率99.998%≥99.99% ✅关键发现当并发从800升至1000时Redis连接池耗尽redis.Ping()超时。解决方案将max_active从100调至200并启用连接池预热create_jira_ticket工具在高并发下出现429错误Jira API限流。解决方案在工具YAML中添加rate_limit: {requests_per_second: 5}MCP server自动做客户端限流5. 常见问题与排查技巧实录那些文档里不会写的血泪教训5.1 Context ID冲突UUID不是银弹现象线上环境偶发context_id重复导致用户A的对话状态覆盖用户B的。根因分析我们最初用uuid.NewUUID().String()生成ID但Go的uuid包在容器环境下若/dev/urandom不可用会回退到时间戳PID生成而Kubernetes Pod重启时PID可能复用造成碰撞。解决方案改用github.com/google/uuid的Must(uuid.NewRandom())并增加校验生成后立即redis.SetNX(context:id:id, 1, 1*time.Hour)若返回false则重试。实测碰撞率从0.003%降至0。5.2 Tool Call参数编码URL编码陷阱现象调用search_db工具时若query参数含空格前端传{query:select * from users}后端收到{query:select%20*%20from%20users}。根因前端用encodeURIComponent()编码整个JSON字符串而非仅编码参数值。解决方案在协议适配层增加解码逻辑if strings.ContainsRune(string(body), %) { decoded, _ : url.QueryUnescape(string(body)) json.Unmarshal([]byte(decoded), req) }但更根本的解决是前端规范要求前端只对参数值做URL编码MCP server不承担解码责任。5.3 审计日志性能瓶颈JSON序列化拖垮TPS现象开启审计日志后QPS从1200骤降至300。根因审计日志结构体含大量嵌套JSONjson.Marshal()耗时占请求总耗时65%。解决方案改用github.com/json-iterator/go性能提升3.2倍对input_hash和output_truncated等字段预计算避免每次请求都算SHA256Kafka Producer启用compression.typelz4日志体积减少40%5.4 Kubernetes DNS解析失败服务发现玄学现象MCP server启动时偶尔报错dial tcp: lookup redis on 10.96.0.10:53: no such host。根因Kubernetes CoreDNS在Pod启动初期可能未就绪而MCP server的initContainer未等待CoreDNS。解决方案在Deployment中添加initContainerinitContainers: - name: wait-for-dns image: busybox:1.35 command: [sh, -c, until nslookup redis; do echo waiting for DNS; sleep 2; done]5.5 MCP v0.11升级协议演进的平滑过渡现象MCP spec发布v0.11新增/server/cancelendpoint但老版本客户端仍在调用v0.10。解决方案服务端同时监听/server/executev0.10和/server/v011/executev0.11在/server/execute响应头中添加X-MCP-Version: 0.10客户端据此决定是否升级旧客户端调用新endpoint时返回400 Bad Request并提示Upgrade required: use /server/v011/execute5.6 故障排查速查表问题现象可能原因排查命令解决方案/readyz返回503Redis连接超时kubectl exec -it mcp-pod -- redis-cli -h redis ping检查Redis服务状态调整read_timeoutTool call返回context_expiredcontext TTL未续期redis-cli get context:abc123:meta检查执行协调层的ExtendTTL()逻辑审计日志缺失Kafka Producer配置错误kubectl logs mcp-pod | grep kafka error检查MCP_AUDIT_KAFKA环境变量格式P95延迟突增PostgreSQL慢查询kubectl exec -it postgres-pod -- psql -U mcp -c SELECT * FROM pg_stat_statements ORDER BY total_time DESC LIMIT 5;添加索引或优化查询多个tool call串行执行FSM状态机卡死kubectl logs mcp-pod | grep stateExecuting检查goroutine是否panic增加recover()实操心得每次上线新工具必须在/tools/{name}/debug页面手动测试三次正常参数、边界参数如空字符串、恶意参数如SQL注入。这10分钟能避免80%的线上事故。6. 性能调优与扩展性设计当QPS突破5000时的应对策略6.1 水平扩展无状态设计的红利MCP server的四层架构中协议适配层、执行协调层、运维支撑层全部无状态唯一有状态的是Context Store。这意味着水平扩展极其简单增加MCP server实例数Kubernetes Service自动负载均衡Context Store的Redis Cluster和PostgreSQL读写分离压力分散我们实测