怎么搭建MCP服务器?用Python一步步从零写起
怎么搭建MCP服务器?用Python和SDK 2.0写工具,在MCP Inspector里测试,再一步步接入Claude Code和Claude Desktop。
本文的其他语言版本:العربيةDeutschEnglishEspañolFrançaisItaliano日本語Polski
本文内容
怎么搭建MCP服务器?用 Python 的话,一个文件加上官方的 MCP Python SDK 就够了:写一个带类型标注和 docstring 的普通函数,加上 @mcp.tool() 装饰器,SDK 会自己把它变成 Claude、ChatGPT 或 Cursor 能调用的工具。文档示例里的整个服务器只有十几行。
在这篇教程里,我们从零写一个服务器,在 MCP Inspector 里测试,再把它接入 Claude Code 和 Claude Desktop。命令和代码来自官方教程“Build an MCP server”、SDK 的 README 和 Claude Code 文档。
需要准备什么?
我假设你已经知道 MCP 是什么,也就是主机、客户端、服务器和工具这几个概念(如果还不清楚,先看 MCP是什么这篇教程)。动手之前需要:
- Python 3.11+(当前 SDK 的 README 要求这个版本),
- 包管理器 uv,官方教程用的就是它,
- Node.js 22.19.0 或更高版本,如果想在 MCP Inspector 里测试服务器的话,
- 一个用来验证整体效果的 MCP 主机,比如 Claude Code 或 Claude Desktop。
开始之前有一点要注意:SDK 2.0 版改了主类的名字。根据 v2 的变更说明,以前的 from mcp.server.fastmcp import FastMCP 现在是 from mcp.server import MCPServer。网上不少教程展示的还是旧版本,而官方教程要求 SDK 2.0.0 或更高版本。
第 1 步:怎样准备项目?
先安装 uv(macOS 和 Linux):
curl -LsSf https://astral.sh/uv/install.sh | sh
Windows 上在 PowerShell 里执行:
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
装完后重启终端,这样才能找到 uv 命令。然后创建项目并安装 SDK:
uv init my-server
cd my-server
uv venv
source .venv/bin/activate
uv add "mcp[cli]"
touch server.py
附加项 [cli] 会安装 mcp 命令(包含 mcp dev、mcp run 和 mcp install),测试时用得上。 (在 Windows 上用 .venv\Scripts\activate 激活环境)
第 2 步:怎样搭建MCP服务器并写出第一个工具?
把 SDK README 里的示例写进 server.py,再像官方教程那样在末尾补上启动服务器的代码:
from mcp.server import MCPServer
mcp = MCPServer("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:
"""Greet someone by name."""
return f"Hello, {name}!"
if __name__ == "__main__":
mcp.run(transport="stdio")
这就是一个完整的 MCP 服务器:一个工具(add)和一个带地址模板的资源(greeting://{name})。有意思的是,我们一行 JSON Schema 都不用写:按照 README 的说法,函数签名 a: int, b: int 就是 schema,docstring 则成为模型读到的工具描述。请求解析、校验和协议细节都由 SDK 处理。
所以 docstring 值得认真写。模型是根据名称和描述来选工具的,“Add two numbers.”只是最低限度,真正的工具还要把参数也写清楚,就像官方的天气示例那样:
@mcp.tool()
async def get_forecast(latitude: float, longitude: float) -> str:
"""Get weather forecast for a location.
Args:
latitude: Latitude of the location
longitude: Longitude of the location
"""
(这个示例用的是美国国家气象局 NWS 的 API,所以只对美国境内的地点有效)
第 3 步:为什么不能用 print()?
这是写第一个服务器时最常见的错误。本地服务器通过标准输入输出(stdio)和主机通信,消息格式是 JSON-RPC。文档的警告很直接:往 stdout 写内容会破坏 JSON-RPC 消息,让服务器失效,而 print() 默认正是写到 stdout。
替代办法是用 logging 模块,它写到 stderr:
import logging
logger = logging.getLogger(__name__)
logger.info("Processing request") # 写到 stderr
HTTP 服务器没有这个问题,因为写到 stdout 的日志不会和 HTTP 响应混在一起。
第 4 步:怎样在 MCP Inspector 里测试服务器?
MCP Inspector 是官方的服务器测试工具。装了 SDK 之后,一条命令就能启动:
uv run mcp dev server.py
浏览器会打开 Inspector。按照 README,用参数 a=1 和 b=2 调用 add 会返回 3。同一个界面里还能看到工具和资源的列表,以及原始的 JSON-RPC 消息,出问题时排查起来方便很多。
Inspector 还有终端版(--tui)和供脚本使用的模式(--cli)。后者会输出工具列表之类的结果然后退出,所以适合放进 CI:
npx @modelcontextprotocol/inspector --cli uv run server.py --method tools/list
(用 node --version 检查 Node.js 版本,Inspector 要求 22.19.0 或更高)
第 5 步:怎样把服务器接入 Claude Code?
本地服务器作为 stdio 类型的服务器添加。-- 之后的所有内容就是 Claude Code 要运行的命令:
claude mcp add --transport stdio demo -- uv --directory /FULL/PATH/my-server run server.py
路径必须是绝对路径(在项目目录里执行 pwd 就能查到)。连接状态可以用 claude mcp get demo 查看,在 Claude Code 会话里则用 /mcp。现在就可以提要求了,比如“用 add 工具把 1234 和 5678 加起来”,然后批准这次调用。
Claude Code 文档里有两点马上就用得上:
- 服务器的启动时间用环境变量
MCP_TIMEOUT调整,比如MCP_TIMEOUT=10000 claude给服务器 10 秒, - 工具结果超过 10 000 个 token 时 Claude Code 会发出警告,默认在 25 000 个 token 处截断(这个上限由变量
MAX_MCP_OUTPUT_TOKENS调整),所以工具不该把整个数据库都返回出来。
第 6 步:怎样把服务器添加到 Claude Desktop?
在 Claude Desktop 里,本地服务器要写进配置文件 claude_desktop_config.json。它在 macOS 上位于 ~/Library/Application Support/Claude/,在 Linux 上位于 ~/.config/Claude/,在 Windows 上位于 %AppData%\Claude\(没有这个文件就自己建一个)。配置项长这样:
{
"mcpServers": {
"demo": {
"command": "uv",
"args": [
"--directory",
"/FULL/PATH/my-server",
"run",
"server.py"
]
}
}
}
然后彻底退出应用(macOS 上按 Cmd+Q,只关窗口不够),再重新打开。服务器应该会出现在加号图标下的“Connectors”菜单里。如果没有,文档建议检查 JSON 语法、确认路径是绝对路径,并在 command 字段里填 uv 的完整路径(用 which uv 可以查到)。日志在 ~/Library/Logs/Claude(macOS)或 ~/.config/Claude/logs/(Linux)里,文件名是 mcp.log 和 mcp-server-NAME.log。
第 7 步:怎样通过 HTTP 运行 MCP 服务器?
stdio 服务器只能在我们自己的电脑上用。要把它作为远程服务器对外提供,就通过 Streamable HTTP 来运行,按照 SDK README 的说法,生产环境部署用的就是这种传输方式:
uv run mcp run server.py --transport streamable-http
这时服务器监听 http://localhost:8000/mcp,在 Claude Code 里像添加其他远程服务器一样添加它:
claude mcp add --transport http demo-http http://localhost:8000/mcp
要让这样的服务器在网页版 Claude 应用里作为所谓的“custom connector”使用,它必须能从互联网访问,因为 Claude 是从 Anthropic 的云端连接它的。到那一步还需要登录机制:MCP 文档介绍了通过 OAuth 2.1 给服务器做授权的方法。
需要注意什么?
第一,工具允许做什么。MCP 服务器让模型能在我们的电脑上真正动手,所以工具的范围要写得尽量窄:与其“运行任意命令”,不如“读取这个目录下的文件”。
第二,外部数据。如果工具从互联网或邮件里抓取内容,就可能带回提示词注入(prompt injection),也就是给模型的隐藏指令。这方面我在 AI 智能体安全这篇教程里写得更详细。
第三,密钥。API 密钥通过环境变量传入(Claude Code 里用 --env),不要写在代码里。根据文档,Inspector 会把令牌存进系统钥匙串,没有钥匙串时(比如在容器里)则存进未加密的文件 ~/.mcp-inspector/secrets.json。
这样的服务器之后还可以接到自己写的智能体上,做法我在怎样用 Python 构建 AI 智能体这篇教程里演示过。
FAQ
搭建MCP服务器最简单的办法是什么?
SDK README 里最简单的服务器只有十几行:一个 MCPServer 对象、一个带 @mcp.tool() 装饰器的函数,再加上 mcp.run()。剩下的部分,也就是参数 schema 和协议处理,都由 SDK 完成。
FastMCP 是什么?
它是 MCP Python SDK 里服务器主类以前的名字。2.0 版把它改成了 MCPServer,导入语句是 from mcp.server import MCPServer。
MCP 服务器可以用 Python 以外的语言写吗?
可以。官方教程提供了 TypeScript、Java、Kotlin、C#、Ruby、Rust 和 Go 等语言的版本。
MCP 服务器只能和 Claude 一起用吗?
不是。MCP 是开放标准,所以同一个服务器能在任何支持该协议的主机里运行,比如 ChatGPT、Visual Studio Code 或 Cursor。