用 TypeScript 写第一个 MCP Server
按官方 quickstart 先走 v1 稳定线,用 `@modelcontextprotocol/sdk` 和 `zod` 从零搭一个可被 Claude Desktop 调用的 TypeScript MCP Server。
按官方 quickstart 和 Python SDK 的真实接口,从零搭一个可被 Claude Desktop 或 Inspector 调试的 Python MCP Server。
内容摘要
如果你已经理解了 MCP 的三大原语,下一步最自然的问题就是:**自己怎么写一个 Server?**
如果你已经理解了 MCP 的三大原语,下一步最自然的问题就是:自己怎么写一个 Server?
官方给 Python 路线的答案很明确:优先用 Python SDK + FastMCP。它会帮你把协议层那些烦人的事先包掉,比如:
也就是说,你的主要工作不再是“手搓 JSON-RPC”,而是把业务能力用 Python 函数表达出来。
这里有两个官方事实需要先说清:
我又查了 PyPI 当前元数据:截至 2026-04-11,mcp 包最新版本是 1.27.0,要求 Python >=3.10。
| 要素 | 作用 |
|---|---|
| FastMCP | 官方推荐的高层接口,用装饰器注册 tool / resource / prompt,最适合第一版开发 |
| uv | 官方文档和 quickstart 都优先推荐的 Python 项目管理方式 |
mcp[cli] | 安装 SDK 的同时带上 CLI 开发工具,方便 mcp dev、mcp install |
| 传输方式 | 本地调试最常见是 stdio;生产部署更推荐 Streamable HTTP |
| 调试链路 | 开发时优先 uv run mcp dev server.py + Inspector;接客户端时再 mcp install |
对第一版服务器来说,FastMCP 几乎总是对的默认选项。
官方 quickstart 推荐先用 uv 初始化项目:
uv init weather
cd weather
uv venv
source .venv/bin/activate
uv add "mcp[cli]" httpx
如果你只是做最小本地 demo,不一定非要叫 weather,但安装思路就是这样。
下面这个例子保留了官方 quickstart 和 Python SDK README 的核心结构,但缩成最适合入门理解的版本:
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("demo")
@mcp.tool()
def add(a: int, b: int) -> int:
"""Add two numbers."""
return a + b
@mcp.resource("greeting://{name}")
def greeting(name: str) -> str:
"""Return a greeting resource."""
return f"Hello, {name}!"
@mcp.prompt()
def review_prompt(topic: str) -> str:
"""Generate a simple review prompt."""
return f"Please review the topic: {topic}"
if __name__ == "__main__":
mcp.run()
这里最关键的不是代码长短,而是这三行装饰器分别在做什么:
@mcp.tool():注册“可执行动作”@mcp.resource():注册“可读取数据”@mcp.prompt():注册“可复用提示词模板”Python SDK README 里给的最快调试方式是:
uv run mcp dev server.py
如果你的 Server 依赖额外包,也可以直接在开发命令里临时带上:
uv run mcp dev server.py --with pandas --with numpy
这条命令背后做的事情可以简单理解成:
这一点非常适合边写边试。
官方 README 里还提供了直接安装到 Claude Desktop 的方式:
uv run mcp install server.py
也支持:
uv run mcp install server.py --name "My Analytics Server"
uv run mcp install server.py -v API_KEY=abc123 -v DB_URL=postgres://...
uv run mcp install server.py -f .env
这比你手改 JSON 配置更省事,尤其在开发期非常舒服。
Python SDK README 还给了 direct execution 的路线:
python server.py
或者:
uv run mcp run server.py
不过有个官方限制一定要记住:
uv run mcp run和uv run mcp dev只支持 FastMCP,不支持 low-level server 变体。
如果你只是本地桌面客户端调试,stdio 已经够了。但 Python SDK README 也明确写了:生产部署更推荐 Streamable HTTP,并建议:
stateless_http=Truejson_response=True一个最小示意:
from mcp.server.fastmcp import FastMCP
mcp = FastMCP(
"StatelessServer",
stateless_http=True,
json_response=True,
)
@mcp.tool()
def hello(name: str = "World") -> str:
"""Say hello."""
return f"Hello, {name}!"
if __name__ == "__main__":
mcp.run(transport="streamable-http")
“用 Python 写第一个 MCP Server”也有不同写法:
| 维度 | FastMCP | low-level server | 直接手搓协议层 |
|---|---|---|---|
| 上手速度 | 最快 | 中 | 最慢 |
| 适合人群 | 第一次写 MCP Server 的大多数人 | 需要更细协议控制的人 | 几乎只适合框架作者或特殊底层场景 |
| 能否自动生成 schema | 能,依赖类型注解和 docstring | 较少自动化 | 基本没有 |
| 调试工具支持 | 很好,mcp dev / mcp run 直接支持 | 受限 | 需要自己兜底 |
| 学习成本 | 低 | 中高 | 高 |
核心区别:
| 误区 | 准确理解 |
|---|---|
| 以为写 MCP Server 就得手写 JSON-RPC | 对大多数 Python 开发者来说,不需要。FastMCP 已经把大部分协议细节包好了 |
| 以为只有 Tool 才值得先学 | Tool 最常用,但 Resource 和 Prompt 也是正式原语,第一版就应该知道怎么注册 |
以为 mcp dev 只是启动一下脚本 | 不止,它本质上是把开发中的 FastMCP Server 快速接入 Inspector 调试链路 |
以为安装 mcp 就够了,CLI 可以后面再说 | 如果你要用 mcp dev、mcp install,官方推荐直接装 mcp[cli] |
| 以为本地写通了 stdio,生产就照抄 | 生产部署官方更推荐 Streamable HTTP,而且配置重点会变 |
| 以为 README 里的所有接口都适用于 low-level server | 不是。官方明确说 mcp run 和 mcp dev 主要支持 FastMCP,不支持 low-level 变体 |
| 优势 | 劣势 |
|---|---|
| 上手快:类型注解 + docstring + 装饰器就能变成 MCP 能力 | 抽象层更高:想完全掌控底层协议时,FastMCP 不如 low-level 直接 |
开发体验好:mcp dev、Inspector、mcp install 都是现成链路 | 需要理解两层概念:业务函数一层,MCP 原语一层,新手刚开始会混 |
| Python 生态强:接数据分析、脚本自动化、内部 API 都很顺手 | 部署形态会分叉:本地 stdio 简单,到了远程 HTTP 就要考虑更多工程细节 |
| 从 demo 到真实服务过渡自然:可以先 stdio,再逐步迁移到 Streamable HTTP | 官方接口仍在持续演进:虽然稳定可用,但版本和最佳实践还在更新 |
| 文档和示例丰富:quickstart、README、examples、testing 文档都比较齐 | 如果只看零散博客容易踩坑:API 名称、版本、运行命令很容易看混 |
参考答案:
因为你第一次写 MCP Server,真正的目标通常不是研究协议栈,而是尽快把一个业务能力暴露出来。
FastMCP 让你把注意力放在“我有哪些工具、资源、提示词”上,而不是“JSON-RPC 消息怎么组织、生命周期事件怎么接、schema 怎么序列化”。对绝大多数业务开发者来说,这个分层是合理的。
等你真的遇到更细的协议控制需求,再下沉到 low-level server,会更划算。
参考答案:
如果你还在开发中,需要频繁验证:
那 mcp dev server.py 更合适,因为它天然接 Inspector,调试效率高。
如果你已经很明确自己只是要把服务跑起来,或者你在做更定制的运行环境实验,那直接 python server.py 或 uv run mcp run server.py 会更接近真实执行方式。
简单记:
mcp devpython server.py 或 mcp run参考答案:
因为这两个传输方式解决的是不同场景。
stdio 最适合本地单机:配置简单、零网络、调试直观。你在 Claude Desktop、本地 IDE、Inspector 里开发时,它几乎是最省脑子的路线。
但一旦进到生产环境,问题就变成:
这时 Streamable HTTP 的优势就出来了,它更贴近现代服务部署习惯。Python SDK README 也明确给了生产导向建议:优先 stateless_http=True 和 json_response=True。
mcp 包信息:https://pypi.org/project/mcp/(查询日期 2026-04-11)优先展示同分类且标签更接近的内容,方便继续串联学习。
按官方 quickstart 先走 v1 稳定线,用 `@modelcontextprotocol/sdk` 和 `zod` 从零搭一个可被 Claude Desktop 调用的 TypeScript MCP Server。
官方 Fetch Server 的价值不是“会发 HTTP 请求”,而是把网页内容安全抓取、分块截断和 Markdown 转换做成了可复用的 MCP 能力。
官方 Filesystem Server 的核心价值不是“能读文件”,而是把文件访问范围、读写能力和多客户端复用都标准化了。