MCP Server 开发完全教程:FastMCP 3.0 + TypeScript SDK 从零跑通到上线

MCP Server 开发完全教程:FastMCP 3.0 + TypeScript SDK 从零跑通到上线

TL;DR —— 写一个 MCP server 在 2026 年比一年前简单太多:Python 用 FastMCP 3.0 的 @mcp.tool decorator,30 行能跑通;TypeScript 用 @modelcontextprotocol/sdk + Zod 拿类型安全;本地调试用 npx @modelcontextprotocol/inspector 一条命令。Transport 层 2025-11 spec 里 Streamable HTTP 已经取代了旧 SSE,远程部署也变干净了。本文按”30 分钟跑通 + 上线”路径走一遍,最后给 Claude Desktop / Cursor / Codex CLI 三个主流客户端的配置示例。

MCP 现在到底什么状态

Model Context Protocol 是 Anthropic 2024 年 11 月开源的协议,统一 AI 应用和外部工具/数据源之间的双向连接。2026 年 5 月的现状:

  • 最新协议规范 2025-11-25
  • 官方 SDK 覆盖 Python / TypeScript / Java / Kotlin / C# 五种语言
  • Python 生态最常用的高层框架 FastMCP 3.02026 年 2 月 18 日发布(PrefectHQ 维护,独立于官方 SDK),加了 OAuth、OpenTelemetry、composition 等能力
  • 公开 MCP server 10,000+(GitHub / npm / PyPI / Smithery / Glama / PulseMCP 等渠道),mcp-server topic 仓库 7,800+
  • Transport 层 Streamable HTTP 在 2025-11 spec 里替换了旧的 SSE,写远程 server 不再要双 endpoint

也就是说协议本身已经稳了,主流 client(Claude Desktop、Cursor、Codex、各种 OpenClaw 类客户端)都支持,写 server 的成本断崖式下降。

如果对 MCP 协议本身还不熟,先看 什么是 MCP(Model Context Protocol);对协议的 agent tools 用法不熟,看 MCP 协议 + AI Agent Tools 指南。本文不重复这些基础概念,直接进入 server 开发。

Python 路线:FastMCP 3.0 的最小可用 server

环境准备 Python 3.10+,装 FastMCP 包(FastMCP 2.0/3.0 是独立包,不在官方 mcp 包里):

pip install fastmcp

下面 30 行写一个 MCP server,提供两个 tool:查询当前时间、查一个城市的天气(这里用假数据演示)。

from fastmcp import FastMCP
from datetime import datetime

mcp = FastMCP("demo-server")

@mcp.tool
def get_current_time(timezone: str = "UTC") -> str:
    """Return current time in the given timezone (IANA name)."""
    return datetime.now().isoformat()

@mcp.tool
def get_weather(city: str) -> dict:
    """Get current weather for a city."""
    return {"city": city, "temp_c": 22, "condition": "sunny"}

if __name__ == "__main__":
    mcp.run()  # 默认 stdio transport

两件事值得注意。一是 @mcp.tool 会读 type hints 和 docstring 自动生成 JSON schema,client 端拿到的 tool 描述就是这些 hint 和 docstring。所以写函数签名要认真,不要省 type annotation。二是 mcp.run() 不传参数默认走 stdio,这是给本地客户端(Claude Desktop / Cursor)用的方式。

要切 Streamable HTTP 部署到远端,改一行:

if __name__ == "__main__":
    mcp.run(transport="http", host="0.0.0.0", port=8080)

FastMCP 3.x 里 Streamable HTTP 的 transport 参数名就是 "http"(兼容旧的 "streamable-http" 写法)。server 会在 http://0.0.0.0:8080/mcp 暴露统一 endpoint,client 用 HTTP POST 打过去就行,不再需要旧 SSE 的 /sse + /messages 双 endpoint。

TypeScript 路线:SDK + Zod

Node 18+ 起步:

npm i @modelcontextprotocol/sdk zod

同样两个 tool:

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-server", version: "0.1.0" });

server.tool("get_weather",
  { city: z.string().describe("City name") },
  async ({ city }) => ({
    content: [{ type: "text", text: JSON.stringify({ city, temp_c: 22 }) }],
  })
);

const transport = new StdioServerTransport();
await server.connect(transport);

Zod schema 在这里干两件事:一是给 client 一份精确的 input 描述(自动转 JSON Schema),二是运行时校验 client 传过来的参数,参数不合格直接抛错,省去手写校验的脏活。

TypeScript 比 Python 啰嗦一点,但好处是大型 codebase 里类型流转更安全,team 协作场景推荐。

用 MCP Inspector 调试

Server 写完不要直接接到 Claude Desktop 去试,那边的 log 不好看、问题难定位。先用官方 Inspector:

npx @modelcontextprotocol/inspector python server.py
# 或 TypeScript:
npx @modelcontextprotocol/inspector node dist/server.js

跑起来会开一个本地 Web UI(默认 http://localhost:6274),里面能看 tool 列表、手动构造参数调用、看完整请求/响应 JSON。开发期的 bug 先在 Inspector 里复现一遍再去接客户端,能省下大量来回重启 Claude Desktop 的时间。

三个主流客户端的接入配置

Claude Desktop(macOS 路径 ~/Library/Application Support/Claude/claude_desktop_config.json,Windows 路径 %APPDATA%\Claude\claude_desktop_config.json):

{
  "mcpServers": {
    "demo": {
      "command": "python",
      "args": ["/Users/you/path/to/server.py"]
    }
  }
}

写绝对路径,相对路径很多时候不工作。改完重启 Claude Desktop。具体在 Claude Desktop / Claude Code 里怎么用 MCP tool,看 Claude Code 国内使用 + Opus 4.6 编程体验

Cursor(全局配 ~/.cursor/mcp.json,项目配 .cursor/mcp.json,同名时项目优先):

{
  "mcpServers": {
    "demo": {
      "command": "python",
      "args": ["/abs/path/server.py"]
    }
  }
}

注意必须套一层 mcpServers 外层 key(和 Claude Desktop 同格式),漏掉这层 Cursor 不会识别。配完打开 Cursor 的 Settings → MCP,能看到 server 已 connected。

Codex CLI~/.codex/config.toml):

[mcp_servers.demo]
command = "python"
args = ["/abs/path/server.py"]

Codex 的 MCP 支持是去年加的,配置方式和工作流细节参考 Codex CLI 真实编程工作流

Streamable HTTP 远程部署

本地 stdio 适合个人工具,团队/生产场景要把 server 跑在云上让多个 client 共用。FastMCP 切 transport="streamable-http" 后,把进程跑在云端任意支持 HTTP 的环境(容器、Lambda、Cloudflare Workers 都行)。

client 端通常需要在客户端的 MCP 配置里指定 URL 而不是 command,比如 Cursor 的远程 MCP server 配置:

{
  "mcpServers": {
    "demo-remote": {
      "url": "https://mcp.yourcompany.com/mcp",
      "headers": {
        "Authorization": "Bearer YOUR_TOKEN"
      }
    }
  }
}

production 部署要补的两件事:一是 auth(最简单的方式是 server 检查 Authorization header 里的 token,自己接 OAuth/JWT 都行);二是请求日志和限流(FastAPI 套一层 middleware 是常见做法)。

常见报错和怎么排

报错通常原因处理
Server failed to start (客户端)命令路径不对 / 依赖没装在 terminal 直接跑 python server.py 复现,看 stderr
Tool not found工具名拼错 / server 加载失败Inspector 里看 tool 列表实际是什么
Validation error参数 schema 不匹配Python 检查 type hint,TS 检查 Zod schema
Connection closed (HTTP transport)server 进程崩了 / 网络断看 server log,确认 Streamable HTTP endpoint 实际监听
Claude Desktop 看不到 serverconfig JSON 写错python -m json.tool < config.json 检查语法

进一步的 API 报错对照参考 AI API 报错大全;如果 server 里调用 LLM 又遇到模型/厂商相关报错,看 模型特定报错排查手册

国内开发的实用建议

MCP server 本身和大模型无关,它只是给 client 提供 tool 的协议层,开发期没有任何网络问题。瓶颈在于”测试 server 时要让 client 真的调通 LLM”这一步。两个方式:

  1. 把 client 的 OpenAI 兼容 endpoint 切到 https://api.ofox.ai/v1,直接走国内出口。这套对 Cursor / Codex CLI / 自己写的 client 都适用,env vars 就是 OPENAI_API_KEY + OPENAI_BASE_URL
  2. server 内部如果需要调 LLM 做”二阶推理”(比如 server 实现一个”总结网页”的 tool,内部要打模型),同样指到 ofox 网关,调用 Claude / DeepSeek / Qwen 全统一一个 base_url。

Claude 系列的 tool use 协议是 MCP 的概念前身,理解 tool/function calling 的底层语义可以看 Claude function calling + tool use 完全教程

进一步阅读