用 Python SDK 写第一个 MCP Server
按官方 quickstart 和 Python SDK 的真实接口,从零搭一个可被 Claude Desktop 或 Inspector 调试的 Python MCP Server。
按官方 quickstart 先走 v1 稳定线,用 `@modelcontextprotocol/sdk` 和 `zod` 从零搭一个可被 Claude Desktop 调用的 TypeScript MCP Server。
内容摘要
如果你想用 TypeScript 写第一个 MCP Server,当前最稳的路线不是盲目跟 `typescript-sdk` 仓库 `main` 分支走,而是**先按官方 quickstart 使用 v1 这条稳定线**。
如果你想用 TypeScript 写第一个 MCP Server,当前最稳的路线不是盲目跟 typescript-sdk 仓库 main 分支走,而是先按官方 quickstart 使用 v1 这条稳定线。
原因很简单:
@modelcontextprotocol/sdkmain README 又明确说明:main 是 v2 pre-alpha,生产仍推荐 v1.x所以今天要写“第一个可用的 TypeScript MCP Server”,最合理的做法是:
@modelcontextprotocol/sdkzod 定义输入 schemastdio 路线接 Claude Desktop| 要素 | 作用 |
|---|---|
@modelcontextprotocol/sdk | 官方 quickstart 当前仍使用的 v1 生产线包 |
zod | 用来声明工具参数 schema,README 和 quickstart 都围绕它展开 |
McpServer | TypeScript 路线上最核心的服务端对象 |
StdioServerTransport | 本地集成最直接的传输方式,适合桌面客户端和开发期调试 |
| 构建产物 | TypeScript 不能直接给 Claude Desktop 跑源码,最终要跑的是编译后的 build/index.js |
这一步是很多人第一次写 TS MCP Server 最容易漏掉的地方。
官方 quickstart 的 TypeScript 起手式是:
mkdir weather
cd weather
npm init -y
npm install @modelcontextprotocol/sdk zod
npm install -D @types/node typescript
mkdir src
touch src/index.ts
官方 quickstart 对 Node 的要求写的是:
但你如果后面想往 v2 主线迁移,当前 npm registry 上 @modelcontextprotocol/server / client 的 alpha 包已经要求 Node >=20。所以从长期角度看,本机环境直接准备 Node 20+ 会更稳。
package.json官方 quickstart 还要求你把 package.json 至少补成这样:
{
"type": "module",
"bin": {
"weather": "./build/index.js"
},
"scripts": {
"build": "tsc && chmod 755 build/index.js"
},
"files": [
"build"
]
}
这里最关键的不是 bin,而是:
type: "module"build 输出目录tsconfig.json官方 quickstart 示例是:
{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "./build",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}
下面这段结构,基本就是官方 quickstart 的最小核心:
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
const server = new McpServer({
name: "demo",
version: "1.0.0",
capabilities: {
resources: {},
tools: {},
},
});
server.tool(
"add",
"Add two numbers",
{
a: z.number(),
b: z.number(),
},
async ({ a, b }) => {
return {
content: [
{
type: "text",
text: String(a + b),
},
],
};
},
);
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Demo MCP Server running on stdio");
}
main().catch((error) => {
console.error("Fatal error:", error);
process.exit(1);
});
这里面最重要的几个点:
McpServer 是服务端主体server.tool(...) 注册工具zod 负责参数 schemaStdioServerTransport 负责本地 stdio 传输这一步官方 quickstart 强调得非常明确:
npm run build
如果你没做这一步,Claude Desktop 后面根本没有现成的 build/index.js 可跑。
官方 quickstart 给出的配置是:
{
"mcpServers": {
"weather": {
"command": "node",
"args": [
"/ABSOLUTE/PATH/TO/PARENT/FOLDER/weather/build/index.js"
]
}
}
}
这里的关键不是名字,而是:
nodebuild/index.js如果你这时已经把第一版跑通了,才值得回去看 TypeScript SDK 的 v2 主线。因为那时你已经有了:
再看拆包后的 @modelcontextprotocol/server / client,理解成本会低很多。
如果目标是“用 TS 写第一个 MCP Server”,几种常见路径可以这样看:
| 维度 | 官方 quickstart v1 路线 | 直接追 v2 main | Python FastMCP |
|---|---|---|---|
| 当前稳定性 | 更稳 | 预发布 | 稳定 |
| 入门资料一致性 | 高,quickstart 直给 | 中,得自己分辨版本线 | 高 |
| 适合谁 | 现在就要写可用 TS Server 的人 | 想预研未来方向的人 | Python 团队 |
| 主要抽象 | McpServer + zod + stdio | server/client split packages | FastMCP |
| 踩坑点 | build 步骤、绝对路径、ESM 配置 | 版本与包名混淆 | Python 环境和依赖管理 |
核心区别:
| 误区 | 准确理解 |
|---|---|
以为写完 src/index.ts 就能直接接客户端 | 不行。官方 quickstart 明确要求先编译成 build/index.js |
| 以为现在 TS 官方主线就该直接用 v2 | 不对。官方 main README 自己写了 v2 还是 pre-alpha,生产推荐 v1.x |
以为 zod 只是可选项 | 在官方 quickstart 和 v1 README 里,它是核心 schema 工具 |
| 以为相对路径传给 Claude Desktop 就够了 | 官方 quickstart 明确要求绝对路径 |
| 以为写 TS 路线就不需要理解 transport | 不对。哪怕最小 demo 也得知道 stdio 是怎么接上的 |
| 以为 TypeScript 版一定比 Python 版更“现代”所以更适合首发 | 不一定。当前哪条路线更适合你,取决于团队语言栈和版本稳定性要求 |
| 优势 | 劣势 |
|---|---|
| 前端 / Node 团队接入自然:语言栈统一,容易复用现有工程能力 | 构建步骤更明显:TS 不是写完就能直接给客户端跑 |
类型与 schema 配合好:zod 很适合把工具参数写清楚 | 当前版本格局更复杂:v1 和 v2 并存,容易看混 |
| stdio 路线清楚:quickstart 足够直接,第一版很快能跑起来 | 工程配置项不少:package.json、tsconfig.json、ESM、build 目录都得弄对 |
| 后续可平滑接 Node 侧更多能力:HTTP、框架、中间件生态强 | 对环境版本更敏感:Node 版本、依赖版本、模块系统都可能踩坑 |
| 和 TS SDK 文档生态衔接自然:后面可继续进入 server/client docs | 相比 Python FastMCP,抽象层略低:入门心智负担稍重 |
参考答案:
因为 TypeScript 本身不是直接执行环境,客户端最终运行的是 JavaScript。
Python 路线很多时候可以直接 python server.py 或 uv run ...,但 TypeScript 路线如果你不先编译,就没有一个稳定的 build/index.js 给 Claude Desktop 或其他宿主去启动。
所以在 TS 路线里,“build”不是附加步骤,而是交付链路的一部分。
参考答案:
因为第一个项目最重要的是建立完整闭环,而不是抢先踩未来接口。
你第一版真正要学会的是:
这些用 v1 quickstart 已经足够,而且官方当前还明确把它放在生产推荐线上。等你先把完整闭环跑通,再研究 v2 的拆包、middleware、运行时支持,会更合理。
参考答案:
因为你真正需要迁移的是“理解和能力模型”,不是单纯代码文本。
先写一版 v1 最小 Server,可以让团队先统一:
这些经验未来迁 v2 仍然有效。相反,如果你一开始就把学习成本和版本不确定性叠在一起,往往会导致团队既没学会 MCP,也没真正吃透新包结构。
v1.x README:https://github.com/modelcontextprotocol/typescript-sdk/blob/v1.x/README.md(查询日期 2026-04-11)v1.x server 文档:https://github.com/modelcontextprotocol/typescript-sdk/blob/v1.x/docs/server.md(查询日期 2026-04-11)优先展示同分类且标签更接近的内容,方便继续串联学习。
按官方 quickstart 和 Python SDK 的真实接口,从零搭一个可被 Claude Desktop 或 Inspector 调试的 Python MCP Server。
官方 Fetch Server 的价值不是“会发 HTTP 请求”,而是把网页内容安全抓取、分块截断和 Markdown 转换做成了可复用的 MCP 能力。
官方 Filesystem Server 的核心价值不是“能读文件”,而是把文件访问范围、读写能力和多客户端复用都标准化了。