- 人工智能
- MCP 服务
- MCP Clients
【免费下载链接】python-sdk
The official Python SDK for Model Context Protocol servers and clients
这篇指南围绕官方 Python SDK(本仓库 src/mcp/server/mcpserver/server.py 中的MCPServer)展开,系统梳理服务器向客户端暴露的三种核心原语——工具(tools)、资源(resources)与提示词(prompts),以及围绕它们的自动补全、媒体返回与错误处理能力。读完你将掌握"谁有权调用什么"这一 MCP 服务器设计的主线,明确各原语的声明方式、协议行为与适用场景,并知道下一步该阅读哪份参考文档。
一张图理解服务器:三种原语,三种"决策者"
MCPServer向已连接的客户端暴露三种原语,它们的根本区别在于谁决定使用它们:
- 工具(tool):由模型挑选并调用的动作。这是大多数人最先需要的页面,其配套参考是结构化输出(Structured Output)——它回答"工具返回值的形状是什么"。
- 资源(resource):由应用决定读取的只读数据。其配套参考是URI 模板(URI templates)——完整的寻址语法与路径安全规则。
- 提示词(prompt):由人通过菜单或斜杠命令按名称调用的消息模板。
在三大原语之外,服务器还会声明其余能力:
- 自动补全(Completions):为提示词参数和资源模板参数提供服务器端补全建议。
- 图像、音频与图标(Media):覆盖工具在文本之外还能返回的一切内容,以及客户端在服务器旁展示的图标。
- 错误处理(Handling errors):解释"模型可以从中恢复的错误"与"模型绝不应看到的错误"之间的差别。
从源码结构看,这一设计落在 src/mcp/server/mcpserver/ 下的tools/、prompts/与resources/三个子包中:MCPServer构造时分别创建ToolManager、PromptManager与ResourceManager来登记和管理三类原语(见 server.py 附近),并在Settings中提供了warn_on_duplicate_tools、warn_on_duplicate_resources、warn_on_duplicate_prompts三个去重告警开关。
工具(Tools):模型挑选并调用的动作
工具是模型可以直接调用的函数。声明方式极为简单——在普通 Python 函数上加上@mcp.tool()装饰器,这就是全部 API:
from mcp.server import MCPServer mcp = MCPServer("Bookshop") @mcp.tool() def search_books(query: str, limit: int) -> str: """Search the catalog by title or author.""" return f"Found 3 books matching {query!r} (showing up to {limit})."(完整可运行版本见 docs_src/tools/tutorial001.py。)没有 schema、没有 JSON、没有协议细节,SDK 从函数中读取三样东西:
- 名称:函数名,即
search_books; - 描述:docstring,模型看到的说明;
- 允许传入的参数:类型注解,如
query: str和limit: int。
输入 schema 的生成与校验
SDK 从类型注解生成 JSON Schema,并在tools/list期间发送给客户端。两个参数都没有默认值,因此都出现在required中。值得强调:这里的类型注解不是文档,而是契约——如果客户端发送"limit": "ten",SDK 会在你的函数运行之前就拒绝它。
给参数一个默认值,它就不再是必填项,并自动获得"default": 10。用Annotated[..., Field(...)]可以附加参数级描述与约束:
Field(description=...):模型在阅读 docstring 之外还能看到的逐参数描述;Field(ge=1, le=50):数值边界,落入 schema 的"minimum": 1, "maximum": 50;Literal["fiction", "non-fiction", "poetry"]:枚举,模型只能从中选择。
约束不是装饰。调用limit=999时,SDK 会在函数执行前以工具错误应答(Input should be less than or equal to 50),该错误作为工具结果回到模型,模型读到后会用合法值重试——你只写了一次le=50,就免费得到了会自我纠错的 Agent。这与 FastAPI/Pydantic 完全是同一套Field、Annotated与校验机制,没有 MCP 特有的新知识。
参数模型、异步与元信息
参数超过两三个时,可以把它们收进一个 Pydantic 模型:Book的 schema 会作为$defs引用嵌套进工具的输入 schema,模型以 JSON 对象填充,你的函数收到的是一个已经过校验的真实Book实例,带有.title、.author、.year属性。
执行 I/O 的工具应声明为async def并在内部await,SDK 会等待它;普通def工具同样可用,SDK 会在线程中运行它以免阻塞服务器,无需额外配置。
装饰器里还可以覆盖 SDK 推断出的一切:title是给 UI 的可读名称;annotations是对客户端的行为提示,例如read_only_hint=True表示该工具不改变任何状态、open_world_hint=False表示它作用于封闭集合(该目录)而非开放网络。行为良好的客户端会据此决定"运行前是否需要询问用户"——但它们只是提示,不是安全机制。name=与description=同样可以直接传给@mcp.tool()。
关于工具返回值的形状(content文本通道、structured_content结构化数据通道、output_schema契约),见 结构化输出参考。
资源(Resources):应用决定读取的只读数据
资源是供应用读取的数据:配置文件、记录、文档等,应用将其加载并作为上下文放到模型面前。声明方式与工具同构,只多了一样东西——URI:资源按地址寻址,客户端请求的是config://app,而不是get_config。
@mcp.resource("config://app") def get_config() -> str: """The active shop configuration.""" return "theme=dark\nlanguage=en"SDK 仍然从函数读取名称、docstring 与返回值。在resources/list中客户端得到{"name": "get_config", "uri": "config://app", "description": "...", "mimeType": "text/plain"};当它读取config://app时你的函数才运行,返回文本。
关键行为(详见 资源参考):
- 列出是廉价的:
resources/list期间函数不会被调用,只在resources/read且仅对请求的那个 URI 调用。暴露一千个资源,只为被打开的那些付费。 - URI 模板:URI 中的
{placeholder}与函数同名参数一一对应,即成为资源模板,从resources/list迁移到resources/templates/list,一个函数服务所有匹配 URI(如users://42/profile)。占位符与参数必须一致,名字对不上会在导入期直接报ValueError: Mismatch between URI parameters ...,让 bug 无法带着错误启动服务器。模板语法遵循 RFC 6570,完整操作符集与路径安全检查见 URI 模板与路径安全。 - 返回值类型决定传输方式:
str原样作为文本;bytes转为 base64 编码的BlobResourceContents;其余 JSON 可序列化对象(dict、Pydantic 模型、dataclass、列表)序列化为 JSON 文本。mime_type由你声明,默认text/plain,SDK 从不猜测。 - 没有可写的函数时,src/mcp/server/mcpserver/ 下的
resources模块提供了现成的TextResource、BinaryResource、FileResource、HttpResource、DirectoryResource类,通过mcp.add_resource(...)注册。
客户端还可以订阅资源并在其变化时收到通知,那是客户端的另一半故事,见 客户端章节。
提示词(Prompts):人从菜单中挑选的消息模板
工具服务模型,提示词则相反:用户从客户端菜单中选择(斜杠命令、按钮),填写参数,渲染出的消息像用户自己输入一样进入对话。
@mcp.prompt() def review_code(code: str) -> str: """Review a piece of code.""" return f"Please review this code:\n\n{code}"(可运行版本见 docs_src/prompts/tutorial001.py。)SDK 读取的仍然是函数名、docstring 和参数。与工具不同,提示词参数没有 JSON Schema——它们是扁平的命名字符串值列表,是供人填写的表单,而非模型构造的载荷。prompts/list返回{"name": "review_code", "description": "...", "arguments": [{"name": "code", "required": true}]}。
提示词的生命周期极短:按名称列出、按需渲染、丢进聊天。prompts/get渲染时,函数返回的str变成一条 user 消息。required在函数运行前强制执行:渲染缺少code的review_code会让整个请求以 JSON-RPC 错误失败,因为没有模型在回路里,调用直接抛出,原因记录在服务器日志。
返回str之外,返回UserMessage/AssistantMessage列表(来自mcp.server.mcpserver.prompts.base)可以种下一整段多轮对话——预填一条assistant消息是在不替用户打字的前提下引导模型下一句回复的手法。title=与Annotated[str, Field(description=...)]提供给客户端绘制表单所需的一切。消息还可以携带EmbeddedResource(附上带 URI 与 MIME 类型的文档)或Image/Audio(base64 图片/音频块),完整示例见 提示词参考。
提示词列表还可以在客户端已连接时动态变更:mcp.add_prompt(Prompt.from_function(...))与mcp.remove_prompt(name)用于增删,随后await ctx.notify_prompts_changed()通知 2026-07-28 客户端、await ctx.session.send_prompt_list_changed()通知旧版客户端(详见 服务旧版客户端 与 订阅)。
自动补全(Completions):提示词与资源模板的参数建议
基于你的服务器构建 UI 的客户端,希望在用户输入时自动补全参数值(语言名、仓库名、文件路径)。自动补全正是服务器提供这些建议的机制。它只作用于两处:提示词的参数与资源模板的参数。
服务器只需注册一个@mcp.completion()处理器(必须是async def,SDK 会 await 它),所有补全请求都汇聚到这里,你通过参数分派:
ref:被补全的是哪个提示词或资源模板,以PromptReference或ResourceTemplateReference呈现,用isinstance区分;argument:argument.name是被补全的参数名,argument.value是用户已输入的前缀;context:已解析的参数(用于依赖参数,见下)。
返回Completion(values=[...]),或无事可offer 时返回None。注意 SDK不会替你过滤——values里放什么 UI 就显示什么,startswith逻辑要自己写。None表示"没有建议",永远不会是错误,UI 会退回普通文本框。
注册处理器即声明能力:连接客户端后client.server_capabilities.completions会变成CompletionsCapability()。每个可选能力都这样运作——处理器本身就是声明;而三大原语不是可选的,MCPServer始终声明它们。没有处理器时请求会以Method not found失败,能力字段为None——这正是能力声明的意义:行为良好的客户端会先检查再发送。
context.arguments携带用户已解析的参数(如资源模板github://repos/{owner}/{repo}中先选定的owner),客户端以context_arguments=提供,实现依赖补全。Completion还接受total=与has_more=,用于 values 只是长列表切片时提示 UI"还有 200 个"。完整示例与客户端调用方式见 自动补全参考。
媒体返回与图标(Media):文本之外的一切
文本不是工具能返回的唯一内容。SDK 为二进制结果提供两个助手(Image与Audio),以及一个Icon类型,用于给服务器、工具、资源、提示词在客户端 UI 中一张"脸"。
- 返回图片/音频:把返回类型注解为
Image,指向文件路径path=或原始字节data=,返回即可。MIME 类型按后缀推断(Image:.png、.jpg、.jpeg、.gif、.webp;Audio:.wav、.mp3、.ogg、.flac、.aac、.m4a),不认识的类型回退到application/octet-stream。在线上,返回值变成ImageContent/AudioContent块——字节 base64 编码加 MIME 类型。Image是 SDK 便利类型而非协议类型:没有输出 schema,structured_content为None,因为图像是给模型看的内容,不是给应用解析的数据。 data=时必须给format=:没有文件名就没有后缀可猜,忘记format=会回退到image/png/audio/wav默认值——用 MP3 字节这样构建Audio,客户端会被告知audio/wav然后忠实解码失败。- 内嵌资源:返回
EmbeddedResource(文本或 base64 blob 连同 URI 与 MIME 类型),客户端可以把它显示为附件或识别已认识的资源;只发送指针则返回ResourceLink。 - 图标:
Icon是元数据而非内容,它通过srcURI 指向图片(https:或无需额外抓取的data:URI),可选mime_type、sizes(如"48x48"或可缩放的"any")与theme="light"/"dark"。icons=[...]关键字被MCPServer(...)、@mcp.tool()、@mcp.resource()、@mcp.prompt()共同接受,客户端分别在server_info.icons、tools/list的Tool、resources/list的Resource、prompts/list的Prompt上找到它们。
详见 图像、音频与图标参考。
错误处理(Handling errors):三种失败,三种去处
工具可能以三种方式失败,SDK 对每种区别对待(实现位于 src/mcp/server/mcpserver/exceptions.py):
- 抛出
ToolError:模型看到你的消息。调用仍然"成功"——存在结果,调用方没有异常——但is_error=True,你的消息(前缀工具名)就在模型读取的content中,structured_content为None。这是工具告诉模型"出事了"的标准方式,几乎总是你想要的:模型读到No book titled 'Nothing' in the catalog.,意识到猜错了书名,再用正确书名重试。服务器端只是一条无 traceback 的INFO日志。 - 抛出
MCPError:协议看到它。它是工具包装器唯一不捕获的异常,会向上传播,使整个tools/call请求以 JSON-RPC 错误失败(如{"code": -32602, "message": "..."}),没有结果、没有is_error,主机应用像"工具不存在"一样收到它。code、message、data原样传递,mcp.types以常量导出各错误码(INVALID_PARAMS等),不必手写魔法数字。 - 抛出任何其他异常:是一次崩溃。调用仍返回
is_error=True(模型知道失败并可以继续),但模型只得到Error executing tool <name>——内部异常文本可能描述服务器内部细节,所以绝不离开服务器。traceback 以ERROR级别进入你的日志。
选择标准一句话:一个更聪明的模型本可以避免这个错误吗?能 →ToolError;不能 →MCPError。执行层面的失败(拼错书名、上游超时、行不存在)是工具错误;请求本身应被拒绝(客户端缺能力、服务器状态不可服务、调用方跳过了必要步骤)是协议错误。
资源画着同一条线:资源模板匹配"任何"标题,但"URI 合法"与"书存在"是两回事,只有你的函数能回答后者。回答不了时抛出ResourceNotFoundError,SDK 将其转为规范指定的协议错误-32602并把请求的 URI 放进data({"code": -32602, "message": "...", "data": {"uri": "books://Nothing"}})。资源没有is_error=True半结果——读取要么返回内容要么失败。ResourceError是非"未找到"失败的同一机制(-32603),两者都只是一条INFO日志;其他异常(MCPError除外)是崩溃。导入方式:from mcp import MCPError,from mcp.server.mcpserver.exceptions import ToolError, ResourceError, ResourceNotFoundError。
还有一类你永远不需要写 raise的错误:坏参数在进入函数前就被输入 schema 拒之门外,以同样的is_error=True工具错误形式让模型可读、可纠正——不要重复校验自己的类型注解。完整对照与日志行为见 错误处理参考。
下一步:从索引页出发的阅读路径
本节每个页面都自足,可以直接跳到你需要的那一页:
- 还没建过服务器?先从 快速上手(First steps) 开始,而不是本节页面。
- 你注册的函数内部发生什么——
Context、依赖注入、调用中途向用户索要更多信息——属于下一节 Inside your handler(处理器内部)。 - 各参考页面(工具、结构化输出、资源、URI 模板与路径安全、提示词、自动补全、图像/音频与图标、错误处理)均以可运行的
docs_src/教程代码为骨架,配套测试位于 tests/docs_src/(如 test_tools.py、test_prompts.py),可对照阅读验证行为。
- 人工智能
- MCP 服务
- MCP Clients
【免费下载链接】python-sdk
The official Python SDK for Model Context Protocol servers and clients
相关推荐
Zotero文献管理界面单调?zotero-style插件让你的学术工作流焕然一新
Zotero文献管理界面单调?zotero style插件让你的学术工作流焕然一新 如果你是一名科研工作者、学生或学术研究者,正在使用Zotero管理文献资料,
人工智能MCP 服务MCP Clientspython-sdk 服务端开发指南:MCPServer 三大原语、可选能力与错误处理全解析
python sdk 服务端开发指南:MCPServer 三大原语、可选能力与错误处理全解析 MCP(Model Context Protocol)服务端向已连
人工智能MCP 服务MCP ClientsEchoSet数据集深度解析:TIGER-DnR如何应对复杂声学环境下的语音分离挑战
EchoSet数据集深度解析:TIGER DnR如何应对复杂声学环境下的语音分离挑战 TIGER DnR(Time Frequency Interleaved
人工智能MCP 服务MCP Clients
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考