写在前面:本章会出现少量代码,但真的很少。 如果你完全不会写代码,照着抄也能跑通;如果你会一点点 Python 或 JS,会读得很轻松。
一、为什么"自己写 MCP"是件值得做的事
很多人觉得"用现成的 MCP 就够了"。 自己写一个的真正价值不在功能本身,在于:
- 理解 MCP 的本质——读再多文档,都不如自己 hello world 一次;
- 解决"小众但只你需要"的问题——比如读你公司内部的某个奇怪系统;
- 把工作流"打包"成 MCP 给团队——别人不用复制提示词,直接调用工具;
- 建立"我能创造 AI 工具"的信心——这种感觉可能改变你看世界的方式。
二、最简的 Python MCP:30 行写一个"今日天气"
准备
# 装 uv(已装请跳过)
curl -LsSf https://astral.sh/uv/install.sh | sh
# 建项目
uv init weather-mcp
cd weather-mcp
# 装 MCP 官方 Python SDK
uv add "mcp[cli]" httpx
写代码
新建 weather_mcp.py:
import httpx
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("weather")
@mcp.tool()
async def get_weather(city: str) -> str:
"""查询某个城市的当前天气。
Args:
city: 城市名,例如 "Beijing"、"Shanghai"
"""
url = f"https://wttr.in/{city}?format=3"
async with httpx.AsyncClient() as client:
resp = await client.get(url, timeout=10)
return resp.text.strip()
if __name__ == "__main__":
mcp.run()
就这 16 行。 包括空行、注释、装饰器。
它干的事:暴露一个 get_weather(city) 工具给 AI。
跑起来
uv run weather_mcp.py
看到提示就跑通了,但 stdio 方式下它在等 Claude 来连接。
接进 Claude Desktop
打开 claude_desktop_config.json,加入:
"weather": {
"command": "uv",
"args": [
"--directory",
"/Users/you/weather-mcp",
"run",
"weather_mcp.py"
]
}
重启 Claude,对话里输入:
杭州现在天气怎么样?
Claude 会调用 get_weather("Hangzhou"),返回当前天气。
你写的第一个 MCP 上线了。
三、TypeScript 版:读取本地待办
很多人喜欢 JS/TS。我们写一个"读取本地待办"MCP:
读取 ~/todo.txt 的内容,并支持新增。
准备
mkdir todo-mcp && cd todo-mcp
npm init -y
npm install @modelcontextprotocol/sdk zod
npm install -D typescript tsx @types/node
npx tsc --init
写代码 index.ts
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import * as fs from "node:fs/promises";
import * as path from "node:path";
import * as os from "node:os";
const TODO_PATH = path.join(os.homedir(), "todo.txt");
const server = new McpServer({ name: "todo", version: "0.1.0" });
server.tool(
"list_todos",
"列出当前所有待办事项",
{},
async () => {
try {
const text = await fs.readFile(TODO_PATH, "utf8");
return { content: [{ type: "text", text }] };
} catch {
return { content: [{ type: "text", text: "(待办文件不存在或为空)" }] };
}
}
);
server.tool(
"add_todo",
"新增一条待办",
{ item: z.string().describe("待办内容") },
async ({ item }) => {
await fs.appendFile(TODO_PATH, `- ${item}\n`);
return { content: [{ type: "text", text: `已添加:${item}` }] };
}
);
const transport = new StdioServerTransport();
await server.connect(transport);
跑起来
npx tsx index.ts
接进 Claude
"todo": {
"command": "npx",
"args": ["tsx", "/Users/you/todo-mcp/index.ts"]
}
重启 Claude。试:
列一下我的待办; 加一条:"买生日蛋糕"。
看到响应就成功了。
四、写 MCP 的 5 个黄金原则
原则 1:工具粒度要"小而清晰"
不要写一个 do_everything(action: str, params: any) 这种万能工具。
拆成 list_todos、add_todo、remove_todo,AI 才能更好地知道什么时候用哪个。
原则 2:参数和返回值都用结构化 schema
像 zod、Pydantic 这种类型校验,AI 才能精准生成调用参数。
原则 3:给每个工具写"清晰的 description"
AI 是看 description 决定"什么时候用我"的。
不要写 "do something",要写 "列出当前所有未完成的待办事项"。
原则 4:错误要友好
报错时返回人话,比如 "待办文件不存在",
不要直接抛 stack trace——AI 看不懂、用户更看不懂。
原则 5:默认只读,写操作要显式
写 / 删 / 发 / 付,要明确命名,AI 才会更慎重; 也方便用户在客户端那边设"该工具需要二次确认"。
五、把 MCP 升级成"远程版"
stdio MCP 只能本地用。要给团队 / 别的设备用,要做成 HTTPS。
Python 版
# 改 main:
if __name__ == "__main__":
mcp.run(transport="streamable-http", host="0.0.0.0", port=3000)
跑:
uv run weather_mcp.py
然后通过反向代理(nginx / Cloudflare)暴露到公网,加 HTTPS + token 鉴权。
TypeScript 版
把 StdioServerTransport 换成 StreamableHttpServerTransport,并配 Express。
SDK 文档里有详细模板。
偷懒:用 mcp-remote 包一层
不想改代码?最简单:用 mcp-remote 把本地 stdio 包成 HTTPS(见第十四章)。
六、把 MCP 发布到社区
1. npm 上发布
如果是 TypeScript MCP,可以发布到 npm:
npm version 0.1.0
npm publish --access public
包名建议带 mcp-server- 前缀,比如 mcp-server-todo,方便别人搜。
2. PyPI 上发布
Python MCP 用 uv:
uv build
uv publish
3. 上社区目录
- 提 PR 到 github.com/punkpeye/awesome-mcp-servers;
- 提交到 getmcp.es 商店;
- 提交到 mcp.run / mcpx 商店;
- 写一篇"为什么我做了这个 MCP"博客,发到 dev.to / 掘金。
社区会迅速给你反馈和星标—— 你不仅做了一个 MCP,还在搭建自己的开发者影响力。
七、5 个适合"小而美"的 MCP 创意
如果你想从写 MCP 入手,下面这些点子简单、有用、也容易爆款:
mcp-server-applescript:用 AppleScript 操作 Mac 上一切(Finder、邮件、备忘录);mcp-server-rss:把指定 RSS Feed 的最新内容拉给 AI;mcp-server-bookmarks:读你浏览器书签 / Pocket / Instapaper;mcp-server-pomodoro:番茄钟开始 / 暂停 / 统计;mcp-server-recipe:自己家的"菜谱本",AI 能查能加新食谱。
任何一个,半天写完,发出去就有人用。
八、关于"开源"和"商业化"
如果你的 MCP 真的火了,会面临一个选择:
- 纯开源(MIT / Apache):人人能用,但商业化空间小;
- 开源核心 + 付费高阶(Open Core):免费版基础够用,付费版加高阶功能(如团队、SSO、SLA);
- 服务化(SaaS MCP):直接做成 OAuth 远程服务,按使用量计费。
2026 年开始已经有一些 MCP 创业公司走通了 SaaS 路线,月营收过万美元。 这个生态机会还很大,普通开发者也能上桌。
九、本章小结
- 写 MCP 不可怕,Python 30 行就能跑;
- 5 个原则:小工具 / 结构化 / 清晰描述 / 友好错误 / 写操作显式;
- 升级远程:直接换 transport,或用 mcp-remote 包;
- 发布渠道:npm / PyPI / awesome-mcp-servers / getmcp / mcp.run;
- 写 MCP 是 2026 年最低成本的"开发者影响力建设"。
十、动手任务(120 分钟)
按下面顺序做:
- 30 分钟:跑通本章的 Python "今日天气"或 TypeScript "待办" MCP;
- 30 分钟:在它基础上加一个工具(比如天气 MCP 加一个"未来 3 天预报",待办 MCP 加一个"标记完成");
- 30 分钟:写一个真正属于你自己生活 / 工作的小 MCP(比如读你 Apple Notes、读公司某个 Excel);
- 30 分钟:发到 GitHub,提 PR 到 awesome-mcp-servers。
完成 → 你就从"用户"升级成了"贡献者"。 这是这本橙皮书想送你的最远的一段路。
第四篇至此结束。下一篇我们回到普通用户视角, 讲安全、讲 FAQ、讲未来。