跳到主内容

MCP 客户端开发入门:用 Python SDK 亲手写一个调用端

100%
MCP 客户端开发入门:用 Python SDK 亲手写一个调用端

MCP 客户端开发入门:一句话结论

MCP 客户端的三板斧是「建立传输 → 初始化会话 → list_tools / call_tool」,用官方 Python SDK 十几行代码就能跑通一个能调用工具的客户端——写客户端不比写服务端难。

客户端和主机是什么关系

先澄清概念:Claude Desktop 、 Cursor 这些产品是 MCP 主机(Host),主机内嵌的连接器才是 客户端(Client)。客户端负责与一个或多个服务端建立 1:1 连接、完成初始化握手、发现并调用工具。自己写客户端的典型场景:给你的应用接工具能力、做聚合网关、写集成测试。

十行起步:Streamable HTTP 客户端

官方 Python SDK(pip install "mcp[cli]",要求 Python 3.10+)提供了高层客户端接口。先看最简形态——连一个 HTTP 服务端:

import asyncio
from mcp import Client

async def main() -> None:
    async with Client("http://localhost:8000/mcp") as client:
        result = await client.call_tool("add", {"a": 1, "b": 2})
        print(result.structured_content)  # {'result': 3}

asyncio.run(main())

传 URL 就是走 Streamable HTTP(部署首选传输);传本地命令则走 stdio 子进程。传输方式的选择依据见 MCP 传输方式对比。

完整版:Session 风格客户端

需要更细的控制(资源、提示词、采样回调)时用 ClientSession 风格:

import asyncio
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client

server_params = StdioServerParameters(
    command="uv",
    args=["run", "server", "fastmcp_quickstart", "stdio"],
)

async def run():
    async with stdio_client(server_params) as (read, write):
        async with ClientSession(read, write) as session:
            await session.initialize()          # 握手,必须第一步
            tools = await session.list_tools()  # 发现工具
            print([t.name for t in tools.tools])
            result = await session.call_tool("add", {"a": 5, "b": 3})
            print(result.content[0].text)       # 8
            print(result.structuredContent)     # 结构化结果

asyncio.run(run())

三段式结构固定不变:stdio_client(或 streamable_http_client)建立传输层拿到读写流 → ClientSession 包装会话 → await session.initialize() 完成协议握手。之后 list_tools 、 call_tool 、 list_resources 、 read_resource 、 get_prompt 随便用。

五个容易踩的坑

重定向规则是 2026 版 SDK 最容易翻车的新细节,先记住再写代码。
  • 忘了 initialize:握手不做,后续所有调用直接报错。它必须先于一切。
  • 重定向不跟:HTTP 传输只连你给的 origin,307/308 仅在同 scheme+host+port 内跟随(含 http→https 同主机);跳到别的域直接报 Redirect not followed。传给 httpx 的 follow_redirects 对 MCP 请求无效,别指望它。
  • stdio 服务端写 stdout:服务端把日志打进 stdout 会污染协议流,客户端立刻失联。服务端日志必须走 stderr(详见 MCP Server 搭建教程)。
  • 连接要复用:管理多个服务端时,把初始化好的 ClientSession 存进字典按名字复用,而不是每次调用重新建连——握手是有成本的。
  • 错误处理两层:call_tool 的失败有两形态:异常(请求层失败)和 result.is_error == True(工具执行失败,结果在 content 里)。两层都要接。

进阶方向

SDK 还内置了 OAuth 授权支持(OAuthClientProvider),连受保护的远程服务端时用它做 token 管理,落地细节参考 远程 MCP 服务器的 OAuth 授权的做法——同一套思路客户端侧直接复用。

常见问题

MCP 客户端和直接用 Function Calling 有什么区别?
Function Calling 要自己写工具注册、参数校验、传输逻辑;MCP 客户端把这些下沉到协议层——只要对端是 MCP 服务端,发现、调用、类型 schema 全是标准的,一个客户端能连任意服务端。选型对比见 MCP 与 Function Calling 的分工分析。

需要异步编程基础吗?
SDK 全程 asyncio,是的。不过模式固定:async with 嵌套 + await 调用,照抄官方示例改参数就能跑,不需要深入理解事件循环。

怎么测试自己写的客户端?
先用 MCP Inspector 直接连服务端确认服务端正常,再连你的客户端——先排除服务端问题再查客户端。长任务可给 call_tool 传 progress_callback 接收进度通知。

这篇有帮助吗?
云上的幻象
云上的幻象查看主页

七彩云博客,分享 WordPress 建站实战与 AI 工具测评,覆盖服务器运维、站长工具、软件资源与电商运营干货,专注原创实用的主题插件、网站加速与安全优化教程。

906文章4评论

相关文章

评论 (0)

欢迎你,新朋友,感谢参与互动!文明发言,理性交流 · 首次评论将在审核后展示