ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

python-sdk 服务端 Prompts 全指南:从声明、渲染到运行时动态管理

python-sdk 服务端 Prompts 全指南:从声明、渲染到运行时动态管理 python-sdk 服务端 Prompts 全指南从声明、渲染到运行时动态管理【免费下载链接】python-sdkThe official Python SDK for Model Context Protocol servers and clients项目地址: https://gitcode.com/gh_mirrors/pythonsd/python-sdk导读Prompts提示词模板是 MCPModel Context Protocol服务端三大核心能力之一与面向模型自动调用的 Tools 相反Prompts 由用户主动挑选——用户在客户端菜单斜杠命令、按钮中选中一个模板、填写参数渲染出的消息便如同用户亲手输入一般进入对话。本文基于本仓库gh_mirrors/pythonsd/python-sdk官方 Python MCP SDK的 法语文档 与英文原档 docs/servers/prompts.md完整讲解mcp.prompt()的声明方式、prompts/list与prompts/get的协议行为、多消息对话播种、富内容嵌入文档与图片以及运行时动态增删 Prompt 与变更通知。读完你将能独立实现一个拥有完整、可交互、可动态更新的 Prompt 菜单的 MCP 服务端。什么是 Prompt与 Tools 的本质区别在 MCP 协议中Prompt 是一条由用户挑选的消息模板。官方文档用一句话点破它与 Tools 的关系Tools 是给模型用的Prompt 恰恰相反——用户在客户端的菜单里一条斜杠命令、一个按钮选择一个填写它的参数渲染出的消息像用户亲自输入一样进入对话。二者的差异贯穿整个生命周期维度ToolsPrompts触发者模型自动调用用户主动挑选触发方式tools/callprompts/listprompts/get参数形态JSON Schema 定义的复杂结构扁平的有名字符串列表表单而非模型构造的载荷结果去向工具结果返回给模型渲染出的消息直接进入对话声明一个 Prompt 的方式极其简单把一个返回文本的函数加上mcp.prompt()装饰器即可。它复用了与 Tool 完全相同的读函数元数据机制名称取自函数名描述取自 docstring参数取自函数签名。第一个 Prompt声明、列出与渲染声明在 docs_src/prompts/tutorial001.py 中一个最简 Prompt 只有 9 行from mcp.server import MCPServer mcp MCPServer(Code Helper) mcp.prompt() def review_code(code: str) - str: Review a piece of code. return fPlease review this code:\n\n{code}SDK 从函数上读取与 Tool 相同的三样东西名称函数名review_code描述docstringReview a piece of code.由客户端展示参数来自函数签名。code没有默认值因此是必填参数。客户端通过 prompts/list 看到什么客户端调用prompts/list得到的就是一个扁平参数列表——这里没有 JSON Schema因为 Prompt 参数是一个人填写的表单不是模型构造的载荷{ name: review_code, description: Review a piece of code., arguments: [ {name: code, required: true} ] }渲染prompts/get客户端用prompts/get并传入参数来渲染模板。你的函数被执行返回的str变成一条用户消息{ description: Review a piece of code., messages: [ { role: user, content: { type: text, text: Please review this code:\n\ndef add(a, b): return a b } } ], resultType: complete }这就是一个 Prompt 的全部生命周期按名列出、按需渲染、投放进对话。必填参数缺失时的行为文档特别标注了一个与 Tools 的关键差异required校验发生在你的函数执行之前。不带code渲染review_code整个请求本身就会以 JSON-RPC 错误code-32603失败mcp.shared.exceptions.MCPError: Internal server error这里不存在Tools 那种把错误结果交还给模型的通道因为整个循环中没有模型参与——调用直接抛出异常。原因Missing required arguments: {code}会进入服务端日志。从源码看这一校验实现在 Prompt.render()它先收集arguments中requiredTrue的参数名集合与调用方实际提供的参数求差集一旦存在缺失立即抛出ValueError(Missing required arguments: ...)。立即体验MCP Inspector用 MCP Inspector 启动服务端uv run mcp dev server.py打开Prompts标签页并选择review_code。Inspector 会绘制一个带必填字段code的表单。填写后点击渲染返回的正是上文那条用户消息。返回多条消息为多轮对话播种一次代码评审只是一条消息一次调试会话则是一整段对话而一个 Prompt 可以完整地启动它。返回一个消息列表而不是单个str即可。参考 docs_src/prompts/tutorial002.pyfrom mcp.server import MCPServer from mcp.server.mcpserver.prompts.base import AssistantMessage, Message, UserMessage mcp MCPServer(Code Helper) mcp.prompt() def review_code(code: str) - str: Review a piece of code. return fPlease review this code:\n\n{code} mcp.prompt() def debug_error(error: str) - list[Message]: Start a debugging conversation. return [ UserMessage(Im seeing this error:), UserMessage(error), AssistantMessage(Ill help debug that. What have you tried so far?), ]这里有两个要点UserMessage和AssistantMessage来自mcp.server.mcpserver.prompts.base。传给它一个str它会自动包装成TextContent角色就是类名。Message是二者的公共基类用它作为返回注解即可。渲染debug_error会按顺序产生三条消息{ description: Start a debugging conversation., messages: [ {role: user, content: {type: text, text: Im seeing this error:}}, {role: user, content: {type: text, text: TypeError: int object is not iterable}}, { role: assistant, content: {type: text, text: Ill help debug that. What have you tried so far?} } ], resultType: complete }注意最后一条。预填一个assistant回合是引导模型下一句回复的方向而不必让用户亲手打出这段引导的惯用技巧——对话一开场模型就被带入了你设定的节奏。源码视角消息如何被构建在 base.py 中Message的构造函数对传入的content做了三种归一化base.py#L39-L46传入str→ 包装为TextContent(typetext, text...)传入Image→ 调用to_image_content()转为ImageContent传入Audio→ 调用to_audio_content()转为AudioContent。UserMessage与AssistantMessage只是把各自的role固定为user或assistantbase.py#L49-L64。render()的返回值处理也值得注意base.py#L192-L207非列表结果会被包成单元素列表每一项若已是Message则原样保留若是dict则用message_validatorTypeAdapter[UserMessage | AssistantMessage]按左到右联合模式校验验证若是裸str/内容块/Image/Audio则包装为一条UserMessage。同时无论函数是同步还是异步is_async_callable判断渲染都能正确处理——同步函数通过anyio.to_thread.run_sync在线程池中执行避免阻塞事件循环。标题与参数描述让客户端画出好表单review_code是函数名不是按钮上的文案。给客户端一个更适合展示在按钮上的名字并为每个参数写描述表单就能自解释。参考 docs_src/prompts/tutorial003.pyfrom typing import Annotated from pydantic import Field from mcp.server import MCPServer mcp MCPServer(Code Helper) mcp.prompt(titleCode review) def review_code( code: Annotated[str, Field(descriptionThe code to review.)], language: Annotated[str, Field(descriptionThe language the code is written in.)] python, ) - str: Review a piece of code. return fPlease review this {language} code:\n\n{code}三个关键点titleCode review是人类可读名称与 Tool 的title完全一致Annotated[str, Field(description...)]与 Tools 文档 中描述工具参数用的是同一套模式——区别只在描述落到参数上而非 Schema 里language有默认值python因此它不再是必填参数。此时prompts/list的条目就带上了客户端绘制一个好表单所需的全部信息{ name: review_code, title: Code review, description: Review a piece of code., arguments: [ {name: code, description: The code to review., required: true}, {name: language, description: The language the code is written in., required: false} ] }如官方文档所提示如果你读过 Tools 文档到这里你其实已经掌握了一切——同样的装饰器、同样的 docstring 作描述、同样的Annotated/Field唯一变化的是谁触发用户和结果去哪进入对话。源码视角元数据如何被抽取Prompt.from_functionbase.py#L97-L156在注册时完成元数据抽取名称取name参数或fn.__name__lambda 必须显式命名否则抛ValueError通过find_context_parameter探测函数的 context 形参并跳过它用func_metadata(...)构建参数模型把 JSON Schema 的properties转成扁平的PromptArgument列表——每个PromptArgument包含name、description、required三个字段base.py#L78-L84required由参数是否在 schema 的required数组中决定最后用validate_call(fn)包装函数确保参数在渲染前被正确校验与转换。这正是文档所说没有 JSON Schema的实现缘由PromptArgument只保留名称、描述与必填性不再携带复杂类型结构。超越纯文本嵌入文件与图片UserMessage和AssistantMessage在接收str的位置上同样接受一个内容块或一个Image/Audio工具类。Prompt 场景里最典型的两个用例是附上文档、附上图片。嵌入文件参考 docs_src/prompts/tutorial004.py。这里的风格指南是一个位于style://python的资源参见 Resources 文档从server.py旁边的style-guide.md读取from pathlib import Path from mcp.server import MCPServer from mcp.server.mcpserver import Message, UserMessage from mcp.types import EmbeddedResource, TextResourceContents mcp MCPServer(Code Helper) STYLE_GUIDE_FILE Path(__file__).parent / style-guide.md # or the path to your file on disk mcp.resource(style://python, mime_typetext/markdown) def style_guide() - str: The teams Python style guide. return STYLE_GUIDE_FILE.read_text(encodingutf-8) mcp.prompt() def review_code(code: str) - list[Message]: Review this code against the team style guide. guide TextResourceContents(uristyle://python, mime_typetext/markdown, textstyle_guide()) return [ UserMessage(EmbeddedResource(resourceguide)), UserMessage(fReview this code against the style guide above:\n\n{code}), ]要点EmbeddedResource(resourceTextResourceContents(...))两者都来自mcp.types以第一条消息携带文件含 URI 与 MIME 类型随后引用它的请求以纯文本形式跟进嵌入而不是把指南拼进 f-string客户端可以把文件当作附件展示、稍后重新打开style://python模型也拿到未经篡改的原文二进制文件请改用BlobResourceContents配合 base64 编码的blob字段。渲染后第一条消息的content是一个resource块{type: resource, resource: {uri: style://python, mimeType: text/markdown, text: * Prefer early returns.\n...}}附加图片参考 docs_src/prompts/tutorial005.pyfrom pathlib import Path from mcp.server import MCPServer from mcp.server.mcpserver import Image, Message, UserMessage mcp MCPServer(Code Helper) DIAGRAM_FILE Path(__file__).parent / architecture.png # or the path to your file on disk mcp.prompt() def explain_component(component: str) - list[Message]: Explain one component using the architecture diagram. return [ UserMessage(Image(pathDIAGRAM_FILE)), UserMessage(fWhere does {component} sit in this architecture, and what does it talk to?), ]Image是 Images、audio 与 icons 文档 中的工具类。在 Prompt 渲染时UserMessage会把它转换为ImageContent块文件以 base64 编码MIME 类型根据.png扩展名推断Audio同理转换为AudioContent对应源码即 base.py#L42-L45 的to_image_content()/to_audio_content()分支把任意名为architecture.png的 PNG 放在server.py旁边即可。Prompt 参数是字符串因此图片永远来自服务端component参数只负责提供文字。渲染结果中的图片块{type: image, data: iVBORw0KGgoAAAANSUhEUg..., mimeType: image/png}运行时动态增删把 Prompt 菜单变成用户自己的Prompt 可以在客户端连接期间动态添加——例如允许用户把自己的指令保存为专属菜单项。注册 Prompt 后再通知即可。参考 docs_src/prompts/tutorial006.pyfrom contextlib import suppress from mcp.server import MCPServer from mcp.server.mcpserver import Context from mcp.server.mcpserver.prompts import Prompt mcp MCPServer(Code Helper) mcp.prompt() def review_code(code: str) - str: Review a piece of code. return fPlease review this code:\n\n{code} mcp.tool() async def save_template(name: str, instruction: str, ctx: Context) - str: Save an instruction as a prompt the user can pick from the menu. def template(code: str) - str: return f{instruction}\n\n{code} with suppress(ValueError): # replace an existing entry of the same name mcp.remove_prompt(name) mcp.add_prompt(Prompt.from_function(template, namename, descriptioninstruction)) await ctx.notify_prompts_changed() await ctx.session.send_prompt_list_changed() return fSaved {name} to the prompt menu.四个要点mcp.add_prompt(Prompt.from_function(fn, name..., description...))以与mcp.prompt()完全相同的方式注册一个函数mcp.remove_prompt(name)是逆操作。这里有一个容易被忽略的行为add_prompt遇到同名已存在条目时会保留旧条目而不是覆盖见 manager.py#L40-L48若warn_on_duplicate_promptsTrue还会记一条警告日志所以工具先remove_prompt旧条目、让保存变成真正的替换。注册后prompts/list立即反映变化。await ctx.notify_prompts_changed()向所有监听subscriptions/listen流的2026-07-28协议客户端发送notifications/prompts/list_changed参见 Abonnements/Subscriptions。await ctx.session.send_prompt_list_changed()在调用方客户端早于 2026 协议版本时把通知发给调用方客户端参见 Serving legacy clients/兼容旧客户端。两个都要调用当没有可通知的对象时各自静默不做任何事。收到通知的客户端会再次调用prompts/list。在 Python 的Client中写法是async with client.listen(prompts_list_changedTrue) as sub:会产出PromptsListChanged事件。源码视角装饰器与注册路径mcp.prompt()装饰器定义在 server.py#L959-L1020它支持name、title、description、icons四个可选参数若直接使用prompt漏掉括号会抛出明确的TypeError提示Did you forget to call it?。装饰器内部正是调用Prompt.from_function(...)并交给self.add_prompt(prompt)注册。PromptManagermanager.py负责存储与分发list_prompts()返回全部已注册 Promptrender_prompt(name, arguments, context)按名取出Prompt并委托给其render()——未知名称会抛出ValueError: Unknown prompt。整套列表 → 渲染协议流程都建立在这几十行管理器之上与prompts/list、prompts/get两个 MCP 方法一一对应。小结mcp.prompt()放在函数上即可声明 Prompt名称来自函数名描述来自 docstringPrompt 是用户控制的客户端列出、用户挑选、填写参数参数是扁平的命名字符串列表无 Schema带默认值的参数即为可选返回str会成为一条用户消息返回UserMessage/AssistantMessage列表则可播种多轮对话title与Field(description...)是客户端界面展示的内容来源必填参数缺失会使整个请求失败Prompt 不存在每个参数的错误结果这一概念把EmbeddedResource或Image包进UserMessage即可附加文档或图片运行时可用mcp.add_prompt(...)/mcp.remove_prompt(...)增删 Prompt随后调用await ctx.notify_prompts_changed()与await ctx.session.send_prompt_list_changed()通知客户端。Prompt 参数或资源模板参数的服务端自动补全属于 Completions 的范畴若想深入了解消息类与渲染器的实现细节可直接阅读 src/mcp/server/mcpserver/prompts/base.py 与 src/mcp/server/mcpserver/prompts/manager.py所有教程代码均可参考 docs_src/prompts/ 目录下的 tutorial001tutorial006 示例。【免费下载链接】python-sdkThe official Python SDK for Model Context Protocol servers and clients项目地址: https://gitcode.com/gh_mirrors/pythonsd/python-sdk创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表