python-sdk 客户端开发指南:用 `Client` 与 MCP 服务器交互的完整实战
人工智能MCP 服务MCP Clients【免费下载链接】python-sdkThe official Python SDK for Model Context Protocol servers and clients项目地址https://gitcode.com/gh_mirrors/pythonsd/python-sdk点击查看免费下载Client是 python-sdk 提供给 Python 程序与 MCP 服务器对话的高层入口一个对象、一个生命周期、一组类型化的async方法。本文以仓库文档 docs/client/index.md 为骨架带你从零搭建第一个 Streamable HTTP 客户端并逐一讲解工具调用、资源读取、提示词渲染、补全、分页与测试内使用同时结合 src/mcp/client/client.py 的源码佐证每个结论。读完你将能独立编写与任意 MCP 服务器交互的客户端程序。第一个客户端生命周期即一切客户端需要一个服务器来对话。本文所有代码片段连接的是同一个 Bookshop 服务器源码见 docs_src/client/tutorial001.py请保存为server.py并通过 HTTP 保持运行# 内容见 docs_src/client/tutorial001.py from pydantic import BaseModel from mcp.server import MCPServer from mcp.server.mcpserver.exceptions import ToolError from mcp.types import Completion, CompletionArgument, CompletionContext, PromptReference, ResourceTemplateReference mcp MCPServer(Bookshop, instructionsSearch the catalog before recommending a book.) GENRES [fiction, non-fiction, poetry] class Book(BaseModel): title: str author: str year: int mcp.tool(titleSearch the catalog) def search_books(query: str, limit: int 10) - str: Search the catalog by title or author. return fFound 3 books matching {query!r} (showing up to {limit}). mcp.tool() def lookup_book(title: str) - Book: Look up a book by its exact title. if title ! Dune: raise ToolError(fNo book titled {title!r} in the catalog.) return Book(titleDune, authorFrank Herbert, year1965) mcp.resource(catalog://genres) def genres() - list[str]: The genres the catalog is organised by. return GENRES mcp.resource(catalog://genres/{genre}) def books_in_genre(genre: str) - str: Every title we stock in one genre. return f3 books filed under {genre}. mcp.prompt(titleRecommend a book) def recommend(genre: str) - str: Ask for a recommendation in a genre. return fRecommend one {genre} book from the catalog and say why. mcp.completion() async def complete_genre( ref: PromptReference | ResourceTemplateReference, argument: CompletionArgument, context: CompletionContext | None, ) - Completion | None: return Completion(values[genre for genre in GENRES if genre.startswith(argument.value)])uv run mcp run server.py --transport streamable-http启动后服务器运行在http://localhost:8000/mcp。客户端是独立程序保存为client.py在第二个终端执行python client.py# 内容见 docs_src/client/tutorial001_client.py import anyio from mcp import Client async def main() - None: async with Client(http://localhost:8000/mcp) as client: print(client.server_info) print(client.server_capabilities) print(client.protocol_version) print(client.instructions) if __name__ __main__: anyio.run(main)三个关键点Client(http://localhost:8000/mcp)传入的是URL 字符串因此通过 Streamable HTTP 连接到你刚启动的服务器。async with就是生命周期进入时连接并完成协议协商退出时断开。没有connect()/close()配对方法块结束后Client不可复用。进入块之后连接信息已经以普通属性的形式就绪无需额外等待。从源码看Client的类文档src/mcp/client/client.py明确支持四类连接对象内部通过_Connector按类型分派到不同的传输构建路径。可以传给Client的四种东西Client只接收一个位置参数根据其类型决定传输方式传入对象传输方式适用场景URL 字符串如Client(http://localhost:8000/mcp)Streamable HTTP部署在服务器后面的正式连接StdioServerParameters以子进程方式启动命令通过其 stdin/stdout 对话本地进程通信任意传输对象Transport直接使用只要满足async with ... as (read, write)协议例如用你自己的 HTTP 客户端包装的streamable_http_client(url, http_client...)MCPServer或低层Server实例进程内连接无子进程、无端口测试场景docs/get-started/testing.md 正是基于此构建本文其余内容对四种方式完全一致。关于请求头、子进程参数、超时以及Transport协议本身的细节见 docs/client/transports.md。连接后客户端上的属性进入块的那一刻四个只读属性即被填充client.server_info服务器的身份标识。对于 2026 世代但不报告身份信息的服务器返回Nonepython-sdk 的服务器默认会报告。本例中server_info.name为Bookshopserver_info.version为服务器报告的值。client.server_capabilities服务器具备的能力tools、resources、prompts、completions等。服务器不具备的能力值为None。client.protocol_version双方协商一致的协议版本本例为2026-07-28。client.instructions服务器的instructions字符串未设置则为None。你从未手动选择过协议版本默认情况下Client会探测服务器对旧世代服务器回退到传统握手流程因此同一个客户端可以适配任何世代的服务器。需要手动控制时参见 docs/protocol-versions.md。源码中对应的是Client.mode参数auto/legacy/ 协议版本字符串默认auto见 src/mcp/client/client.py。提示client.session是底层ClientSessionsrc/mcp/client/session.py作为低层逃生通道存在本文内容用不到它。列出工具list_tools()# 内容见 docs_src/client/tutorial002.py import anyio from mcp import Client async def main() - None: async with Client(http://localhost:8000/mcp) as client: result await client.list_tools() for tool in result.tools: print(tool.name) print(tool.title) print(tool.description) print(tool.input_schema) if __name__ __main__: anyio.run(main)list_tools()返回ListToolsResult工具位于.tools中。每个工具都是主机host会直接交给模型的完整定义。第一个工具如下tool.name # search_books tool.title # Search the catalog tool.description # Search the catalog by title or author.而tool.input_schema是服务器从函数类型注解推导出的 JSON Schema{ type: object, properties: { query: {title: Query, type: string}, limit: {default: 10, title: Limit, type: integer} }, required: [query], title: search_booksArguments }这张 Schema 既包含 UI 渲染参数表单所需的全部信息也包含模型生成合法参数所需的全部信息。第二个工具lookup_book注册时未带title因此其tool.title为None。提示title是可选的向人类展示工具的 UI 需要自行抉择——有title用title没有就用name。from mcp.shared.metadata_utils import get_display_name恰好实现了这一逻辑并同时支持工具、资源、资源模板与提示词四种对象。调用工具call_tool()返回三样东西call_tool(name, arguments)执行工具并返回CallToolResult# 内容见 docs_src/client/tutorial003.py import anyio from mcp import Client from mcp.types import TextContent async def main() - None: async with Client(http://localhost:8000/mcp) as client: result await client.call_tool(lookup_book, {title: Dune}) for block in result.content: if isinstance(block, TextContent): print(block.text) print(result.structured_content) print(result.is_error) if __name__ __main__: anyio.run(main)服务器的lookup_book返回一个 PydanticBook。客户端看到的是result.content # [TextContent(typetext, text{\n title: Dune,\n author: Frank Herbert,\n year: 1965\n})] result.structured_content # {title: Dune, author: Frank Herbert, year: 1965} result.is_error # False一个返回值三样可读的东西各有各的消费方。从 src/mcp/client/client.py 的签名看call_tool还支持read_timeout_seconds、progress_callback、input_responses、request_state、meta等高级参数用于超时控制、进度回调和多轮输入请求InputRequiredResult的自动重试。content给模型读的content是内容块content block的list内容块是联合类型TextContent、ImageContent、AudioContent、ResourceLink或EmbeddedResource一个工具可以返回多个不同类型的块。这就是为什么main在触碰block.text之前先用isinstance(block, TextContent)收窄类型。注意isinstance之外没有.text——类型检查器不会允许因为ImageContent有的是.data而不是.text。这个联合类型如实反映了工具允许发送给你的内容你的代码也应如此。structured_content给应用代码读的structured_content是工具返回值对应的 JSON与工具声明的output_schema一致。无需字符串解析、无需猜测。当两者同时存在时它们是有意地重复说同一件事content给模型structured_content给代码。结构化那一半从何而来、如何控制见 docs/servers/structured-output.md。is_error工具是否失败抛出异常的工具不会在客户端抛出异常而是作为一个is_errorTrue的普通结果返回。验证向lookup_book查询Solaris目录中不存在的书名函数会抛出ToolError但调用仍然正常返回result.is_error # True result.content # [TextContent(typetext, textError executing tool lookup_book: No book titled Solaris in the catalog.)] result.structured_content # NoneToolError的消息落进了content那里模型可以读到并重试。这是有意设计工具错误是对话的一部分而不是崩溃。如果工具以其他异常崩溃content里只会写Error executing tool lookup_book。在信任structured_content之前务必先检查is_error。警告is_errorTrue覆盖的范围不止你自己写的raise。请求一个服务器上根本不存在的工具call_tool(does_not_exist, {})也不会抛出任何异常你会得到相同形状的结果——is_errorTruecontent中包含Unknown tool: does_not_exist。Client的方法只会在服务器以 JSON-RPC错误而非结果应答时才抛出MCPError。服务器何时返回哪种见 docs/servers/handling-errors.md。资源两种列举 一种读取资源的动词成对出现列举有两种读取有一种。# 内容见 docs_src/client/tutorial004.py import anyio from mcp import Client from mcp.types import TextResourceContents async def main() - None: async with Client(http://localhost:8000/mcp) as client: listed await client.list_resources() print([resource.uri for resource in listed.resources]) templates await client.list_resource_templates() print([template.uri_template for template in templates.resource_templates]) result await client.read_resource(catalog://genres/poetry) for contents in result.contents: if isinstance(contents, TextResourceContents): print(contents.text) if __name__ __main__: anyio.run(main)list_resources()返回具体资源即 URI 固定的那些。本例为[catalog://genres]。list_resource_templates()返回参数化资源。本例为[catalog://genres/{genre}]。两者是两个独立列表因为模板在填入值之前不可读。read_resource(uri)接收普通的strURI对两者都适用传入catalog://genres/poetry服务器会把它匹配到模板上。read_resource返回contents是TextResourceContents或BlobResourceContents的列表。思路与工具内容一致先用isinstance收窄再读.text或.blob。客户端还可以在资源变更时收到通知。在 2025 世代的连接上是subscribe_resource(uri)/unsubscribe_resource(uri)——这对方法MCPServer并未实现因此在 2026-07-28 协议上这些动词已不存在请求会得到-32601Method not found。2026 年的替代方案是subscriptions/listen流MCPServer确实提供它此时server_capabilities.resources.subscribe为True用client.listen(...)消费它的方法见 docs/client/subscriptions.md。提示词list_prompts()与get_prompt()# 内容见 docs_src/client/tutorial005.py import anyio from mcp import Client async def main() - None: async with Client(http://localhost:8000/mcp) as client: listed await client.list_prompts() print(listed.prompts) result await client.get_prompt(recommend, {genre: poetry}) for message in result.messages: print(message.role, message.content) if __name__ __main__: anyio.run(main)list_prompts()告诉你服务器提供什么、每个提示词需要什么参数prompt.name # recommend prompt.title # Recommend a book prompt.arguments # [PromptArgument(namegenre, requiredTrue)]get_prompt(name, arguments)负责渲染。参数 dict 是str - str类型提示词参数永远是字符串。结果是messages即PromptMessage列表每个都有role和content块message.role # user message.content # TextContent(typetext, textRecommend one poetry book from the catalog and say why.)主机把这些消息原样交给模型这个功能到此为止。补全complete()带补全处理器的服务器可以在用户输入时为提示词参数和资源模板参数提供自动补全。# 内容见 docs_src/client/tutorial006.py import anyio from mcp import Client from mcp.types import PromptReference async def main() - None: async with Client(http://localhost:8000/mcp) as client: result await client.complete( refPromptReference(typeref/prompt, namerecommend), argument{name: genre, value: p}, ) print(result.completion.values) if __name__ __main__: anyio.run(main)ref指明你在补全哪个提示词或模板PromptReference或ResourceTemplateReference。argument是{name: ..., value: ...}参数名加上用户目前已输入的内容。答案在result.completion.values中。输入p服务器返回[poetry]。服务器端的实现以及处理器如何利用其他已填充参数缩小建议范围见 docs/servers/completions.md。分页cursor与next_cursor所有list_*方法都接受cursor关键字参数所有结果都带有next_cursor。当next_cursor为None时说明已取完。# 内容见 docs_src/client/tutorial007.py import anyio from mcp import Client from mcp.types import Tool async def list_all_tools(client: Client) - list[Tool]: tools: list[Tool] [] cursor: str | None None while True: page await client.list_tools(cursorcursor) tools.extend(page.tools) if page.next_cursor is None: return tools cursor page.next_cursor async def main() - None: async with Client(http://localhost:8000/mcp) as client: tools await list_all_tools(client) print([tool.name for tool in tools]) if __name__ __main__: anyio.run(main)list_all_tools对任何服务器都是正确的MCPServer一次性返回全部内容next_cursor为None循环只执行一次——这正是大多数代码从不写这个循环的原因。真正分页的服务器以及游标遵循的规则见 docs/advanced/pagination.md。测试中使用进程内连接本文所有的client.py都是通过 HTTP 访问server.py的。测试时跳过网络直接把服务器对象交给Clientfrom server import mcp然后Client(mcp)。无需进程、无需端口上面所有方法的行为完全一致。为此准备的构造参数只有一个Client(mcp, raise_exceptionsTrue)。它只在进程内连接时生效其作用与围绕它构建的整套测试模式见 docs/get-started/testing.md。该参数在 src/mcp/client/client.py 中有明确定义与文档。总结Client(x)对 URL 字符串走 Streamable HTTP对StdioServerParameters启动子进程对传输对象直接进入测试时接收服务器对象本身。async with即完整生命周期。块内server_capabilities与protocol_version已填充服务器提供时server_info与instructions亦然。list_tools()给出每个工具的name、title、description和input_schema。call_tool()返回给模型的content、给代码的structured_content以及is_error。抛出异常的工具返回的是结果不是异常。content是块类型的联合读取前用isinstance收窄。list_resources/list_resource_templates/read_resource、list_prompts/get_prompt、complete构成完整的动词集合。所有list_*都接受cursor循环直到next_cursor为None。服务器能反过来向客户端请求什么、以及你如何响应见 docs/client/callbacks.md。赞分享人工智能MCP 服务MCP Clients【免费下载链接】python-sdkThe official Python SDK for Model Context Protocol servers and clients项目地址https://gitcode.com/gh_mirrors/pythonsd/python-sdk点击查看免费下载相关推荐MCP Python SDK 客户端回调Client Callbacks完全指南用 Callback 应答服务端发起的请求MCP Python SDK 客户端回调Client Callbacks完全指南用 Callback 应答服务端发起的请求 导读 在 Model Cont人工智能MCP 服务MCP ClientsMCP Python SDK 客户端回调Client Callbacks完全指南应答服务器的反向请求MCP Python SDK 客户端回调Client Callbacks完全指南应答服务器的反向请求 导读 在 Model Context Protoco人工智能MCP 服务MCP ClientsMCP 客户端回调Client Callbacks实战指南用 Client(...) 应答服务端发起的请求MCP 客户端回调Client Callbacks实战指南用 Client ... 应答服务端发起的请求 在 MCPModel Context Prot人工智能MCP 服务MCP Clients上一篇从入门到实战2025深度学习全栈教程基于dl_tutorials项目下一篇Heimdallr配置完全指南从环境变量到多渠道通知分组创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

react-native-vector-icons 的 FontAwesomeProSolid 图标包:自备字体、安装配置与源码实现全解析

react-native-vector-icons 的 FontAwesomeProSolid 图标包:自备字体、安装配置与源码实现全解析

react-native-vector-icons 的 FontAwesomeProSolid 图标包:自备字体、安装配置与源码实现全解析 【免费下载链接】react-native-vector-icons Customizable Icons for React Native with support for image source and full styling. 项目地址: https://gitcode.…

2026/9/21 16:36:34 阅读更多 →
论文降重与文本改写服务避坑指南:从风险识别到流程自建

论文降重与文本改写服务避坑指南:从风险识别到流程自建

1. 引言:为什么降重服务频频翻车 毕业论文写作的最后一公里,往往卡在重复率上。面对知网、维普、格子达等查重系统的严格标准,不少同学选择求助论文降重或文本改写服务。然而,市面上的服务良莠不齐,踩坑者比比皆是。本…

2026/9/22 19:02:27 阅读更多 →
Flow 类型现代化实战:将 `$TupleMapi` 重构为原生 Mapped Types(以 flow 仓库 modernize_015 为例)

Flow 类型现代化实战:将 `$TupleMapi` 重构为原生 Mapped Types(以 flow 仓库 modernize_015 为例)

开发工具静态分析代码质量 【免费下载链接】flow Adds static typing to JavaScript to improve developer productivity and code quality. 项目地址: https://gitcode.com/gh_mirrors/flow30/flow 点击查看 免费下载 导读 本文围绕 flow 仓库中 SWE-bench 风格 …

2026/9/22 19:01:53 阅读更多 →

最新新闻

深圳华为公司研发岗避坑指南:从入门到精通的底层逻辑

深圳华为公司研发岗避坑指南:从入门到精通的底层逻辑

深圳华为公司研发岗避坑指南:从入门到精通的底层逻辑 面试被问原理答不上来,是不是当场大脑一片空白?这种尴尬在面试深圳华为公司的研发岗位时尤为致命。很多候选人背了八股文,却连最基础的并发模型都讲不清楚,导致直接挂掉。想真正拿下这个Offer,…

2026/9/22 19:05:11 阅读更多 →
3个坑让新手血亏:王者荣耀代练脚本开发避坑指南

3个坑让新手血亏:王者荣耀代练脚本开发避坑指南

3个坑让新手血亏:王者荣耀代练脚本开发避坑指南 版本升级后 API 全变了,上一周还能跑通的脚本,今天直接报错 AttributeError…

2026/9/22 19:05:11 阅读更多 →
下下片常见报错与解决:保姆级教程带你避开90%的坑

下下片常见报错与解决:保姆级教程带你避开90%的坑

下下片常见报错与解决:保姆级教程带你避开90%的坑 复制来的代码跑不通,报错信息像天书,你是不是也卡在调试的泥潭里拔不出来?别急,这种“下下片”级别的尴尬场面,老手都经历过,但新手往往因为缺乏系统性排查思路,越改越乱。今天这篇保姆级教程,不…

2026/9/22 19:05:10 阅读更多 →
3分钟搞定readme:一文搞懂GitHub项目门面搭建实战

3分钟搞定readme:一文搞懂GitHub项目门面搭建实战

3分钟搞定readme:一文搞懂GitHub项目门面搭建实战 GitHub仓库打开就是一片代码海洋,官方文档翻到第三章还没找到入口?别急,今天带你用一套标准化流程,把 README.md…

2026/9/22 19:05:10 阅读更多 →
潘帕斯雄鹰部署卡顿?3步优化完整示例提速50%

潘帕斯雄鹰部署卡顿?3步优化完整示例提速50%

潘帕斯雄鹰部署卡顿?3步优化完整示例提速50% 配置环境就卡半天,是不是你也遇到过?明明照着教程敲代码,服务器却像死机一样没反应。很多开发者在部署潘帕斯雄鹰相关服务时,常陷入“改一行、重启一次、等待十分钟”的死循环。…

2026/9/22 19:05:10 阅读更多 →
2026最新绿荫继承者调试指南:3招解决代码复制跑不通难题

2026最新绿荫继承者调试指南:3招解决代码复制跑不通难题

2026最新绿荫继承者调试指南:3招解决代码复制跑不通难题 刚把掘金技术社区热帖里的代码复制下来,双击运行,控制台直接红屏报错?别慌,这不是你笨,也不是代码烂。很多转岗进开发圈的朋友都卡在第一步:看着别人跑通的“绿荫继承者”模式示例,自己环…

2026/9/22 19:04:09 阅读更多 →

日新闻

3台商务办公笔记本实测:手写实现环境配置,告别卡半天

3台商务办公笔记本实测:手写实现环境配置,告别卡半天

3台商务办公笔记本实测:手写实现环境配置,告别卡半天 配置环境就卡半天?别怪机器慢,多半是你没选对工具链。在Java、Go或Python的项目现场, 手写实现…

2026/9/22 0:00:41 阅读更多 →
剑帝加点速查手册:3分钟搞懂核心逻辑

剑帝加点速查手册:3分钟搞懂核心逻辑

剑帝加点速查手册:3分钟搞懂核心逻辑 面试被问原理答不上来,是不是常态?别慌。很多开发者对着 GitHub 开源仓库里的代码发呆,看似简单实则暗藏玄机。今天这份【剑帝加点】速查手册,直接带你拆解核心实现,把面试必考的原理讲透。…

2026/9/22 0:00:41 阅读更多 →
手写实现图片压缩网站核心:搞定WebP转换与质量调优

手写实现图片压缩网站核心:搞定WebP转换与质量调优

手写实现图片压缩网站核心:搞定WebP转换与质量调优 复制来的代码跑不通不知道怎么调?别慌,这种“复制粘贴地狱”在开发圈太常见了。尤其是做 图片压缩网站…

2026/9/22 0:00:41 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/22 4:32:41 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/22 4:38:57 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/22 8:51:04 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/21 15:36:51 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/21 15:36:51 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/22 2:43:42 阅读更多 →