用 Python 编写一个能连接 MCP Server 的客户端
MCP Client 是连接 MCP Server 并调用其能力的程序。
如果你已经有一个能运行的 MCP Server,想用 Python 写一个客户端去连接它、列出工具并执行一次调用,下面的步骤可以直接照做。
先确认 Server 的启动方式和通信协议
在写客户端之前,需要先拿到 MCP Server 的两个信息:启动命令和通信方式。
常见情况是 Server 以子进程形式运行,通过标准输入输出(stdio)收发 JSON-RPC 消息;
另一种是 Server 提供 HTTP 端点。
本文以 stdio 方式为例,因为它在本地开发和调试中最直接。
确认 Server 能单独启动,例如运行 python server.py 后进程保持等待输入状态,就说明可以用 stdio 方式连接。
如果 Server 启动后立刻退出或打印错误,先解决 Server 本身的问题,客户端无法绕过。
还需要准备 Python 3.10 或以上版本,并安装 mcp 官方 Python SDK:
pip install mcp
建立连接并完成初始化握手
MCP 协议要求客户端在连接后先发送 initialize 请求,声明协议版本和客户端能力,然后发送 notifications/initialized 通知。
使用 SDK 可以简化这个过程。
下面是一个最小客户端,连接本地 server.py 并列出可用工具:
import asyncio
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
async def main():
server_params = StdioServerParameters(
command="python",
args=["server.py"],
)
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
tools = await session.list_tools()
for tool in tools.tools:
print(tool.name, tool.description)
if __name__ == "__main__":
asyncio.run(main())
把 server.py 换成你实际的 Server 路径。
运行后如果打印出工具名称和描述,说明初始化握手和工具列表请求都已成功。
如果卡住无输出,检查 Server 是否在等待输入,以及 args 路径是否正确。
调用一个工具并处理返回结果
拿到工具列表后,可以用 call_tool 执行具体工具。
假设 Server 提供了一个名为 add 的工具,接收两个数字参数:
result = await session.call_tool("add", {"a": 2, "b": 3})
print(result.content)
返回的 result.content 是一个内容块列表,通常包含文本结果。
不同 Server 返回结构可能略有差异,打印完整对象有助于确认字段。
调用时参数名必须与工具定义一致,否则 Server 会返回参数校验错误。
常见连接失败与超时排查
客户端连不上 Server 时,先区分是进程启动失败还是协议通信失败。
进程启动失败通常表现为 FileNotFoundError 或立即退出,检查 command 和 args 是否指向真实可执行文件。
协议通信失败常见于初始化超时,可以先用命令行手动启动 Server,观察它是否等待标准输入。
如果调用工具时超时,确认 Server 端工具实现没有阻塞过久,并检查客户端是否在 initialize 完成前就发送了其他请求。
MCP 要求初始化完成后才能调用其他方法。
验证客户端是否工作正常
一个可靠的验证顺序是:先运行客户端打印工具列表,确认连接和握手正常;
再调用一个无副作用的工具,确认参数和返回结构;
最后再接入业务逻辑。
每次修改 Server 或客户端后,重复这个顺序可以快速定位问题出在哪一层。
如果工具列表为空,检查 Server 是否真的注册了工具,以及初始化响应中的能力声明是否包含 tools。
客户端本身不需要额外配置,问题通常出在 Server 端注册或启动参数上。