1. 初始化是什么? #

客户端和 MCP 服务器建立连接后,第一件事必须是初始化(握手),然后才能调工具、读资源。

可以把它想成打电话:

步骤 打电话 MCP 初始化
1 拨号接通 客户端连上服务器(stdio 或 HTTP)
2 「听得见吗?我说中文」 客户端发 initialize,声明协议版本和能力
3 「听得见,我们说中文」 服务器回复支持的版本和能力
4 「好,开始聊」 客户端发 initialized 通知
5 正常聊天 调用 tools/list、tools/call 等

没有完成初始化就发业务请求,属于协议错误。

2. 初始化在交换什么? #

握手时双方交换三类信息,你只需知道含义,不必手写 JSON:

交换内容 谁发送 用途
协议版本 双方 确保说同一种「方言」(如 2025-11-25)
能力(capabilities) 双方 声明支持哪些功能(工具、资源、提示等)
实现信息(name / version) 双方 显示名称,方便调试和日志

2.1 服务器常见能力 #

能力字段 有了它才能…
tools 客户端调用 tools/list、tools/call
resources 客户端读取 resources/read
prompts 客户端使用 prompts/get

2.2 用 FastMCP 时你需要做什么? #

服务器端:几乎不用管。 注册 `@mcp.tool()后,FastMCP 会在初始化响应里自动声明tools` 能力。

客户端:调用一行 await session.initialize(),SDK 自动完成三步握手。

3. 三步握手流程 #

sequenceDiagram participant C as 客户端 participant S as 服务器 C->>S: ① initialize 请求 S-->>C: ② initialize 响应(版本 + 能力) C->>S: ③ notifications/initialized Note over C,S: 此后才能 list_tools / call_tool
步骤 方法 要不要等回复
① initialize 要,等服务器响应
② (服务器响应) —
③ notifications/initialized 不要,发完即走

规则:服务器在收到 initialized 之前,不应向客户端发业务请求(ping、日志除外)。

4. 消息长什么样? #

实际开发中由 SDK 自动生成。下面帮助你看懂 Inspector 里的原始 JSON。

4.1 客户端发的 initialize 请求 #

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize",
  "params": {
    "protocolVersion": "2025-11-25",
    "capabilities": {},
    "clientInfo": {
      "name": "example-client",
      "version": "1.0.0"
    }
  }
}

4.2 服务器回的响应 #

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2025-11-25",
    "capabilities": {
      "tools": { "listChanged": true }
    },
    "serverInfo": {
      "name": "hello-server",
      "version": "1.0.0"
    }
  }
}

4.3 客户端发的就绪通知 #

{
  "jsonrpc": "2.0",
  "method": "notifications/initialized"
}

注意:通知没有 id 字段,也不会收到回复。

5. 服务器端用法 #

服务器不需要自己写 initialize 处理逻辑。写好工具、启动服务即可。

5.1 服务器 #

initialize_server.py

# 导入 FastMCP 模块,用于自动处理 initialize 握手
from mcp.server.fastmcp import FastMCP

# 创建 FastMCP 服务器实例,name 参数会显示在 serverInfo 里
mcp = FastMCP(name="hello-server")

# 使用装饰器注册 greet 工具,初始化时会自动声明 tools 能力
@mcp.tool()
def greet(name: str = "World") -> str:
    # 返回问候语字符串
    return f"Hello, {name}!"

# 判断是否作为主程序运行
if __name__ == "__main__":
    # 以 stdio 模式启动服务器,等待客户端连接
    mcp.run(transport="stdio")

6. 客户端用法 #

客户端的核心就两步:连上服务器 → 调用 initialize()。

6.1 完整示例 #


# 官方客户端 API 是异步的
import asyncio
# 导入操作系统相关的模块,用于处理文件路径等
import os
# 导入系统相关的模块,用于获取解释器路径等
import sys

# 导入会话类和子进程启动参数,用于与服务器通信
from mcp import ClientSession, StdioServerParameters
# 导入 stdio 传输模块,用于通过标准输入输出连接服务器
from mcp.client.stdio import stdio_client


# 定义主异步函数
async def main() -> None:
    # 获取当前文件所在目录的绝对路径
    base_dir = os.path.dirname(os.path.abspath(__file__))
    # 拼接服务器脚本的完整路径
    server_path = os.path.join(base_dir, "initialize_server.py")

    # 配置服务器子进程启动参数
    server_params = StdioServerParameters(
        # 指定 Python 解释器的路径
        command=sys.executable,
        # 指定启动的服务器脚本
        args=[server_path],
    )

    # 建立 stdio 连接并自动启动子进程
    async with stdio_client(server_params) as (read, write):
        # 创建会话对象,与服务器进行通信
        async with ClientSession(read, write) as session:
            # ★ 进行初始化握手,必须最先调用
            result = await session.initialize()

            # 初始化成功后,输出协商得到的信息
            print("协议版本:", result.protocolVersion)
            # 判断服务器信息是否存在,存在就输出名称,否则输出“未知”
            print("服务器名称:", result.serverInfo.name if result.serverInfo else "未知")

            # 初始化完成后,可以调用业务接口
            tools = await session.list_tools()
            # 输出获取到的工具列表名称
            print("工具列表:", [t.name for t in tools.tools])


# 如果当前模块为主程序则执行 main
if __name__ == "__main__":
    asyncio.run(main())

6.2 运行 #

uv run initialize_client.py

期望输出:

协议版本: 2025-11-25
服务器名称: hello-server
工具列表: ['greet']

6.3 initialize() 返回什么? #

await session.initialize() 返回 InitializeResult 对象,常用字段:

字段 含义 示例
protocolVersion 协商后的协议版本 "2025-11-25"
capabilities 服务器支持的能力 含 tools 等
serverInfo 服务器名称和版本 name="hello-server"
instructions 可选,给客户端的说明文字 部分服务器会提供

6.4 常见写法注意点 #

注意点 说明
必须用 async with stdio_client 和 ClientSession 都是异步上下文管理器
initialize() 在最前面 不初始化就 list_tools() 会失败
用 sys.executable Windows 下避免 python 指向错误解释器

7. 用 Inspector 验证初始化 #

7.1 启动 Inspector #

npx @modelcontextprotocol/inspector uv run initialize_server.py

7.2 如何判断成功 #

浏览器打开后,看以下信号:

信号 说明
连接状态为 Connected 握手完成
Tools 标签页能看到 greet 说明 tools 能力协商成功
通知面板无初始化错误 没有版本不兼容等报错

7.3 在 Inspector 里观察消息顺序 #

展开通知/日志面板,正常顺序应为:

  1. initialize 请求 → 响应
  2. notifications/initialized
  3. 之后才有 tools/list 等

8. 初始化之后做什么? #

初始化只是「接通电话」,之后才能干正事:

flowchart LR A[initialize 握手] --> B[tools/list 发现工具] B --> C[tools/call 调用工具] A --> D[resources/read 读资源] A --> E[prompts/get 获取提示]
下一步 客户端方法 前提
列出工具 await session.list_tools() 服务器声明了 tools
调用工具 await session.call_tool(name, args) 同上
读取资源 await session.read_resource(uri) 服务器声明了 resources
获取提示 await session.get_prompt(name, args) 服务器声明了 prompts