5月28日 06:28

如何在 MCP 中管理和使用提示词(Prompts)?

MCP(Model Context Protocol)定义了三个核心原语:工具(Tools)、资源(Resources)和提示词(Prompts)。其中,提示词原语允许服务器向客户端暴露可复用、参数化的提示词模板,将提示工程从宿主应用转移到拥有领域知识的服务器端。本文将系统讲解 MCP 提示词的协议机制、实现方式和最佳实践。

MCP 提示词的协议机制

MCP 提示词不是简单的字符串拼接,而是有完整的协议生命周期:

  1. 发现阶段:客户端通过 prompts/list 请求获取服务器上所有可用的提示词模板列表
  2. 获取阶段:用户选择某个提示词后,客户端通过 prompts/get 请求获取具体的提示词内容
  3. 变更通知:当提示词列表发生变化时,服务器通过通知机制告知客户端刷新(需启用 listChanged 能力)

每个提示词的定义包含三个字段:

  • name:提示词的唯一标识符
  • description:人类可读的描述,用于客户端展示
  • arguments:参数列表,每个参数包含 namedescriptionrequired 标志
json
{ "name": "code_review", "description": "代码审查提示词模板", "arguments": [ { "name": "language", "description": "编程语言", "required": true }, { "name": "code", "description": "待审查的代码", "required": true } ] }

在 MCP 服务器中注册提示词

使用 Python SDK 注册提示词非常简洁:

python
from mcp.server import Server server = Server("my-mcp-server") @server.prompt( name="code_review", description="代码审查提示词模板" ) async def code_review_prompt( code: str, language: str = "python" ) -> str: """生成代码审查提示词""" return f"请审查以下 {language} 代码,关注代码质量、性能、安全性和最佳实践:\n\n{code}"

注册后,客户端调用 prompts/list 就能看到这个提示词,调用 prompts/get 并传入 languagecode 参数即可获取渲染后的提示词内容。

多消息提示词与资源嵌入

MCP 提示词不仅支持单条消息,还支持返回多消息数组,每条消息可以有不同的角色(userassistant)和内容类型。更重要的是,提示词可以嵌入资源引用,将服务器暴露的只读数据直接注入提示词上下文:

python
@server.prompt( name="analyze_project", description="分析项目日志和代码" ) async def analyze_project_prompt( timeframe: str, file_uri: str ) -> list: return [ { "role": "user", "content": { "type": "text", "text": f"分析近 {timeframe} 的系统日志和指定代码文件:" } }, { "role": "user", "content": { "type": "resource", "resource": { "uri": f"logs://recent?timeframe={timeframe}", "mimeType": "text/plain" } } }, { "role": "user", "content": { "type": "resource", "resource": { "uri": file_uri, "mimeType": "text/x-python" } } } ]

这种模式让提示词能够组合上下文信息,构建复杂的工作流。例如,一个日志分析提示词可以同时嵌入日志文件和源代码,让 LLM 在分析错误时直接参考相关实现。

提示词的参数验证与安全

MCP 规范要求服务器对所有提示词的输入和输出进行严格验证,防止注入攻击或未授权的资源访问。实现时应注意:

  • 必填参数校验:在渲染前检查所有 required: true 的参数是否已提供
  • 输出内容过滤:防止提示词渲染结果中包含恶意指令
  • 资源访问控制:嵌入的资源必须在服务器已声明的资源范围内
python
@server.prompt( name="safe_analysis", description="安全分析提示词" ) async def safe_analysis_prompt(code: str) -> str: # 验证输入长度,防止超长输入 if len(code) > 10000: raise ValueError("代码长度超过限制(最大 10000 字符)") # 验证输入不包含可疑模式 if "ignore previous" in code.lower(): raise ValueError("输入包含可疑内容") return f"请分析以下代码的安全性:\n\n{code}"

提示词变更通知

当服务器支持 listChanged 能力时,提示词列表变化后应主动通知客户端:

python
# 服务器初始化时声明能力 server = Server( "my-mcp-server", capabilities={"prompts": {"listChanged": True}} ) # 提示词变更后发送通知 await server.send_notification("notifications/prompts/list_changed")

客户端收到通知后应重新调用 prompts/list 刷新本地缓存。

提示词 vs 工具 vs 资源:何时用哪个?

MCP 三个原语各有定位,选择正确的是关键:

原语定位典型场景是否有副作用
资源(Resources)提供只读数据查询文件内容、数据库记录
工具(Tools)执行操作发送邮件、修改文件
提示词(Prompts)模板化交互代码审查模板、分析工作流

简单记忆:资源用于查询,工具用于操作,提示词用于标准化

最佳实践

  1. 保持确定性:相同输入应产生相同输出,避免在提示词中引入随机性
  2. 嵌入资源而非引用:直接将上下文数据嵌入提示词消息,减少 LLM 的额外请求
  3. 提供清晰的描述description 字段直接影响客户端 UI 中的可发现性
  4. 使用多消息结构:复杂场景拆分为多条消息,每条消息职责单一
  5. 实施版本管理:对重要提示词进行版本控制,确保客户端行为一致
  6. 验证所有输入输出:严格校验参数,防止注入攻击和越权访问

总结

MCP 提示词原语将提示工程从应用层下放到服务器层,让领域专家可以直接定义和优化提示词模板。通过 prompts/list 发现、prompts/get 获取、多消息与资源嵌入组合、变更通知这一完整机制,MCP 提示词实现了跨客户端的标准化交互模式。掌握提示词的协议机制和安全实践,是构建高质量 MCP 服务器的关键一步。

标签:MCP