同一段时间里,我们落地了两个 MCP Server。一个用 Python + FastMCP,一个用 Node.js + 官方 SDK。
很多人看到这个配置,第一反应是:“那 Python 和 Node,到底哪个更适合做 MCP Server?”
这个问题问错了。
因为这两个项目,根本不是同一类问题。一个是把企业内部一批现成能力”翻译”成 MCP 工具,给受控的内部 Agent 用;另一个是给外部客户端用的多租户平台。它们的调用方、租户模型、权限要求、审计压力、团队主语言全都不一样。
所以选了完全不同的两套栈,不是因为我们纠结,是因为它们本来就该用不同的栈。
这篇不讲”Python 好还是 Node 好”,讲的是:同一个团队,面对两个 MCP Server 需求时,为什么会做出截然不同的选型;以及换成你的场景,该怎么选。
两个 MCP Server 长什么样
先摆出两个项目的真实形态(下面分别叫”能力适配器”和”工具平台”)。
能力适配器(Python)。它把企业内部一批已有能力——企业 IM 消息推送、用户记忆管理、时间工具等——标准化成 MCP 工具,统一暴露给内部自研 Agent。特点很明确:
- 能力是现成的,核心是”翻译”成 MCP 协议;
- 调用方都是受控的内部 Agent,不对外;
- 要接入快、部署轻;
- 团队的 AI 能力栈本就是 Python(记忆系统、向量检索都在 Python 生态)。
工具平台(Node.js)。它是某个多租户 SaaS 平台的一部分,主体是 Next.js。它既给自研 Agent 用,也给外部 MCP 客户端用——Claude Desktop、Cursor、VS Code 里的 Copilot 都可能连进来。特点完全不同:
- 调用方不可控,有外部客户端;
- 多租户,不同 API Key 只能用自己被授权的工具;
- 对外服务,审计和合规压力大;
- 必须嵌进现有 Next.js 服务,而不是单独起一个进程。
两者并排放,差异一目了然:
| 维度 | 能力适配器(Python) | 工具平台(Node.js) |
|---|---|---|
| 调用方 | 内部自研 Agent,受控 | 自研 Agent + 外部客户端,不受控 |
| 多租户 | 否 | 是 |
| 权限粒度 | 粗,网络隔离 + 服务身份认证 | 细,每个 API Key 独立 scope |
| 审计压力 | 中 | 高,对外 + 合规 |
| 团队主语言 | Python(AI 原生) | TypeScript(平台主体) |
| 部署形态 | 独立容器 | 嵌进 Next.js |
这张表是后面所有选型的根。下面六个维度,基本都是它往下推的结果。
维度一:语言与框架
能力适配器选了 Python + FastMCP,原因不是”MCP 用 Python 好”,而是”这个团队的能力栈是 Python”。记忆系统用 Mem0,向量检索用 Redis,LLM 用 OpenAI 兼容接口——这些都在 Python 生态里最顺手。为一个 MCP Server 去换语言,得不偿失。
框架选了 FastMCP 而不是直接使用官方 mcp SDK 的低层接口。这里的 FastMCP 2.x 是独立维护的 Python 高级框架;它的 1.x 核心曾并入官方 Python SDK,但两个项目不能直接等同。FastMCP 可以用装饰器注册工具,并从函数签名和 docstring 生成 JSON Schema:
from fastmcp import FastMCP
mcp = FastMCP("企业内 MCP Server")
@mcp.tool()
def memory_search(query: str, user_id: str, limit: int = 20):
"""搜索用户记忆。"""
return memory.search(query=query, user_id=user_id, limit=limit)
对一个”核心是翻译现有能力”的项目,这种高抽象非常合适——少写协议层样板,多接工具。
工具平台选了 Node.js + @modelcontextprotocol/sdk,理由刚好相反。它的 MCP Server 不是独立进程,而是嵌在 Next.js 的 Route Handler 里。这意味着必须用 Web 标准的 Request/Response,必须和平台共享认证、会话、日志那一套基础设施。这种时候,用官方低层 SDK 反而更合适——控制力强,能精确接到平台已有的 API Key、scope、审计链路上。
选型规律一:让 MCP Server 跟着团队主语言走,而不是为 MCP 换语言。框架选高级还是低层,取决于你是”翻译现成能力”还是”深度嵌入平台”。
维度二:SDK 与版本
两个项目面对 MCP 生态的快速迭代,做了同一个选择:锁稳定版,不追新。
能力适配器用 FastMCP 2.12(底层 mcp 1.17),但 FastMCP 当时已出到 3.x。3.x 引入了 Apps 架构、交互式 UI、FormInput 等新特性。我们没跟,因为对这个项目,那些全是锦上添花,而稳定性和”不踩 v3 早期坑”更重要。
工具平台用 @modelcontextprotocol/sdk 1.29,而 2.0 还在 beta。v2 的包拆分、多框架适配器,以及面向 2026 无状态协议的迁移能力听着不错,但对当前单实例部署没有直接收益,而且已经有封装层隔着一层。同样不跟。
这里有个共同做法值得点出来:两边都加了一层薄封装(类似 createMcpServer 这种工厂函数)。这样未来 SDK 出破坏性变更时,改动能锁在封装内部,不扩散到业务代码。
选型规律二:MCP 生态迭代很快,SDK 版本要”稳定优先 + 封装隔离”。新版本的新特性,只有在它真的解决你当前问题时才上。
维度三:传输(SSE 还是 Streamable-HTTP)
这是两个项目分歧最大、也最有意思的地方。
能力适配器选了 SSE(Server-Sent Events)。工具平台选了 Streamable-HTTP。
同一时期、同一个团队,一个用了已被标记为 legacy 的 SSE,一个用了官方当前推荐的 Streamable-HTTP。这不是谁对谁错,是启动时机和场景不同:
- 能力适配器启动得早,那时 SSE 还是主流推荐,而且内网部署代理兼容性可控,SSE 的长连接对”实时进度推送”很自然;
- 工具平台是新服务,启动时 Streamable-HTTP 已是官方推荐标准;它比旧式 HTTP+SSE 更容易穿过常见代理,并可沿 2026 协议演进为无状态请求,Next.js 也能直接使用基于 Web 标准的 Request/Response 接口。
一个”老服务跟着当年推荐走”,一个”新服务直接上当前推荐”。
传输这块坑不少(SSE 的反向代理配置、断线恢复、迁移路径),我单独拆了一篇讲,见文末第四篇。
选型规律三:传输选型,先看部署环境(内网 vs 公网、是否多代理),再看是新服务还是老服务。新服务别再从 SSE 起步。
维度四:认证(JWT 还是 API Key)
能力适配器计划使用 JWT,但当前“代码已配置、运行时未启用”属于必须偿还的安全债,不能因为部署在内网就视为已完成认证。工具平台使用 API Key + scope。逻辑还是那张场景表。
能力适配器是内网服务间认证,调用方都是受控内部 Agent,JWT 这种轻量方案就够。它后续的演进路径是 HS256 → RS256 非对称 → DCR 动态注册,随着要对接的服务变多,认证再逐步加码。
工具平台是对外多租户,必须回答两个问题:这个调用是谁、它能用哪些工具。API Key + scope 是最自然的模型——每个 Key 独立、可吊销、可过期,每个 Key 只注册它被授权的工具集。Token 还做了 SHA-256 哈希存储、Redis 缓存、会话归属校验。
这里划一条线:工具平台的”权限码按 read/write/dangerous 分级""高风险动作走审批状态机”,那套设计我在另一篇里专门讲过,这篇只讲”为什么选 API Key”这个认证机制层面的事,不重复权限码设计。
选型规律四:认证选型看调用方,但网络位置不能替代身份。内部服务至少要有工作负载身份认证和最小权限;对外多租户还要增加细粒度 scope、吊销、过期和审计能力。
维度五:状态与会话
按 2025 版协议设计时,能力适配器曾计划用 stateless_http=True + Redis EventStore,为水平扩展做准备;工具平台则选了进程内存会话(Map + 30 分钟 TTL)。这两种都是旧版协议语境下的方案。
反过来看:能力适配器虽然目前也单实例,但在架构上预留了无状态水平扩展的口子;工具平台的进程内会话则是 2025 兼容协议下的阶段性方案。MCP 2026-07-28 已经移除 Streamable HTTP 的协议级 Session,工具平台升级后应把必要的业务状态改成显式任务或资源 ID。
两种都合理,共同点是:按当前规模选最简方案,但看清升级路径,别一上来就过度设计,也别把扩展路堵死。
选型规律五:会话存哪,看规模。单实例够用就别引入外部存储;要水平扩展时,确认你的传输和会话方案能无状态化。
维度六:可观测性
能力适配器目前这块偏弱(缺 metrics、缺 tracing,文档里直接列成了风险),规划补 OpenTelemetry。工具平台从第一天就记录审计日志,但目前的 Fire-and-forget 写法仍存在进程退出或下游故障时丢日志的风险,需要升级为有确认的持久队列或事务 Outbox。
差异根源还是场景。工具平台是对外服务,合规要求它一开始就建设可靠审计:每次工具调用都记录调用者、耗时、入参出参摘要和状态,并按实际政策设置保留期。能力适配器即使是内部服务,也不能完全后置身份日志和基础监控;可以后置的是更完整的 tracing、指标看板与长期分析能力。
选型规律六:身份日志、错误率和健康监控是所有生产服务的基线;对外或受监管服务还要增加可靠审计、完整追踪和更严格的保留策略。
一张选型决策树
把六个维度收成一个简单决策流程:
- 调用方可控吗? 全是内部受控 Agent → 仍启用服务身份认证和最小权限;有外部客户端 → 再增加细粒度 scope、吊销、限流和可靠审计。
- 要嵌进现有 Web 平台吗? 是 → 跟平台同语言,选官方低层 SDK;否 → 可选 FastMCP 这类高级框架。
- 多租户吗? 是 → API Key/OAuth + scope;否 → JWT、mTLS 等服务身份方案,网络隔离只作为补充防线。
- 要水平扩展吗? 是 → 采用 2026 无状态协议,并显式外置必要的业务状态;兼容旧协议时才评估会话存储与 EventStore。
- 团队主语言是什么? 让 MCP 跟着团队走,而不是为 MCP 换语言。
这张树能帮你绕开最常见的坑:一上来就纠结语言和框架,而忽略真正驱动选型的场景因素。
别被”语言之争”带偏
回到开头那个问题:“Python 还是 Node 更适合做 MCP Server?”
答案是:看场景。
MCP Server 的选型,语言和框架只是表象。真正决定选型的,是”调用方是否可控、是否多租户、是否对外、是否需要水平扩展、团队主语言是什么”。
这就是为什么我们用两套栈都合理——它们服务的,本来就是不同场景。如果你也在做 MCP Server 选型,先别看语言,先回答上面那张决策树。
这篇是总览
这是 MCP 技术选型系列的第一篇,只搭骨架。
- 能力适配器(Python 栈)的框架、记忆系统、LLM 怎么选,看 当 MCP Server 只是”翻译”现成能力:FastMCP + Mem0 + Redis 的选型逻辑;
- 工具平台(Node.js 栈)的 SDK、传输、会话、审计怎么落地,看 当 MCP Server 要”嵌进”对外平台:Node.js + 官方 SDK + API Key 的选型逻辑;
- 两套栈都绕不开的传输层演进(SSE 怎么迁到 Streamable-HTTP),看 SSE 已被 MCP 判为 legacy:存量服务怎么迁、新服务怎么选。