创建可复用的提示模板和工作流

提示(Prompts)使服务器能够定义可复用的提示模板和工作流,客户端可以轻松向用户和 LLM(大语言模型)展示这些内容。它们提供了一种强大的方式来标准化和共享常见的 LLM 交互。

提示被设计为用户可控的,这意味着它们从服务器暴露给客户端,目的是让用户能够明确选择并使用它们。

概述

MCP(模型上下文协议)中的提示是预定义的模板,可以:

  • 接受动态参数
  • 包含来自资源的上下文
  • 串联多个交互
  • 引导特定的工作流
  • 作为 UI 元素(例如斜杠命令)显示

提示结构

每个提示由以下结构定义:

  1. {
  2. name: string; // 提示的唯一标识符
  3. description?: string; // 人类可读的描述
  4. arguments?: [ // 可选的参数列表
  5. {
  6. name: string; // 参数标识符
  7. description?: string; // 参数描述
  8. required?: boolean; // 是否为必填参数
  9. }
  10. ]
  11. }

发现提示

客户端可以通过 prompts/list 端点发现可用的提示:

  1. // 请求
  2. {
  3. method: "prompts/list"
  4. }
  5. // 响应
  6. {
  7. prompts: [
  8. {
  9. name: "analyze-code",
  10. description: "分析代码以改进",
  11. arguments: [
  12. {
  13. name: "language",
  14. description: "编程语言",
  15. required: true
  16. }
  17. ]
  18. }
  19. ]
  20. }

使用提示

要使用提示,客户端可以发送 prompts/get 请求:

  1. // 请求
  2. {
  3. method: "prompts/get",
  4. params: {
  5. name: "analyze-code",
  6. arguments: {
  7. language: "python"
  8. }
  9. }
  10. }
  11. // 响应
  12. {
  13. description: "分析 Python 代码以改进",
  14. messages: [
  15. {
  16. role: "user",
  17. content: {
  18. type: "text",
  19. text: "请分析以下 Python 代码并提供改进建议:\n\n```python\ndef calculate_sum(numbers):\n total = 0\n for num in numbers:\n total = total + num\n return total\n\nresult = calculate_sum([1, 2, 3, 4, 5])\nprint(result)\n```"
  20. }
  21. }
  22. ]
  23. }

动态提示

提示可以是动态的,并且包含:

嵌入式资源上下文

  1. {
  2. "name": "analyze-project",
  3. "description": "分析项目日志和代码",
  4. "arguments": [
  5. {
  6. "name": "timeframe",
  7. "description": "要分析日志的时间范围",
  8. "required": true
  9. },
  10. {
  11. "name": "fileUri",
  12. "description": "要审查的代码文件 URI",
  13. "required": true
  14. }
  15. ]
  16. }

当处理 prompts/get 请求时:

  1. {
  2. "messages": [
  3. {
  4. "role": "user",
  5. "content": {
  6. "type": "text",
  7. "text": "分析这些系统日志和代码文件是否存在问题:"
  8. }
  9. },
  10. {
  11. "role": "user",
  12. "content": {
  13. "type": "resource",
  14. "resource": {
  15. "uri": "logs://recent?timeframe=1h",
  16. "text": "[2024-03-14 15:32:11] ERROR: 网络超时于 network.py:127\n[2024-03-14 15:32:15] WARN: 正在重试连接 (尝试 2/3)\n[2024-03-14 15:32:20] ERROR: 超过最大重试次数",
  17. "mimeType": "text/plain"
  18. }
  19. }
  20. },
  21. {
  22. "role": "user",
  23. "content": {
  24. "type": "resource",
  25. "resource": {
  26. "uri": "file:///path/to/code.py",
  27. "text": "def connect_to_service(timeout=30):\n retries = 3\n for attempt in range(retries):\n try:\n return establish_connection(timeout)\n except TimeoutError:\n if attempt == retries - 1:\n raise\n time.sleep(5)\n\ndef establish_connection(timeout):\n # 连接实现\n pass",
  28. "mimeType": "text/x-python"
  29. }
  30. }
  31. }
  32. ]
  33. }

多步骤工作流

  1. const debugWorkflow = {
  2. name: "debug-error",
  3. async getMessages(error: string) {
  4. return [
  5. {
  6. role: "user",
  7. content: {
  8. type: "text",
  9. text: `这是我遇到的错误:${error}`
  10. }
  11. },
  12. {
  13. role: "assistant",
  14. content: {
  15. type: "text",
  16. text: "我会帮你分析这个错误。你尝试过哪些方法?"
  17. }
  18. },
  19. {
  20. role: "user",
  21. content: {
  22. type: "text",
  23. text: "我尝试过重启服务,但错误仍然存在。"
  24. }
  25. }
  26. ];
  27. }
  28. };

示例实现

在 MCP 服务器中实现提示

TypeScript 实现:

  1. import { Server } from "@modelcontextprotocol/sdk/server";
  2. import {
  3. ListPromptsRequestSchema,
  4. GetPromptRequestSchema
  5. } from "@modelcontextprotocol/sdk/types";
  6. const PROMPTS = {
  7. "git-commit": {
  8. name: "git-commit",
  9. description: "生成 Git 提交信息",
  10. arguments: [
  11. {
  12. name: "changes",
  13. description: "Git 差异(diff)或变更描述",
  14. required: true
  15. }
  16. ]
  17. },
  18. "explain-code": {
  19. name: "explain-code",
  20. description: "解释代码的作用",
  21. arguments: [
  22. {
  23. name: "code",
  24. description: "需要解释的代码",
  25. required: true
  26. },
  27. {
  28. name: "language",
  29. description: "编程语言",
  30. required: false
  31. }
  32. ]
  33. }
  34. };
  35. const server = new Server({
  36. name: "example-prompts-server",
  37. version: "1.0.0"
  38. }, {
  39. capabilities: {
  40. prompts: {}
  41. }
  42. });
  43. // 列出可用的提示
  44. server.setRequestHandler(ListPromptsRequestSchema, async () => {
  45. return {
  46. prompts: Object.values(PROMPTS)
  47. };
  48. });
  49. // 获取特定提示
  50. server.setRequestHandler(GetPromptRequestSchema, async (request) => {
  51. const prompt = PROMPTS[request.params.name];
  52. if (!prompt) {
  53. throw new Error(`未找到提示: ${request.params.name}`);
  54. }
  55. if (request.params.name === "git-commit") {
  56. return {
  57. messages: [
  58. {
  59. role: "user",
  60. content: {
  61. type: "text",
  62. text: `为以下变更生成一个简洁但描述性的提交信息:\n\n${request.params.arguments?.changes}`
  63. }
  64. }
  65. ]
  66. };
  67. }
  68. if (request.params.name === "explain-code") {
  69. const language = request.params.arguments?.language || "未知";
  70. return {
  71. messages: [
  72. {
  73. role: "user",
  74. content: {
  75. type: "text",
  76. text: `解释这段 ${language} 代码的作用:\n\n${request.params.arguments?.code}`
  77. }
  78. }
  79. ]
  80. };
  81. }
  82. throw new Error("未找到提示实现");
  83. });

最佳实践

  1. 使用清晰、描述性的提示名称
  2. 为提示和参数提供详细描述
  3. 验证所有必需参数
  4. 优雅地处理缺少参数的情况
  5. 考虑为提示模板添加版本控制
  6. 适当缓存动态内容
  7. 实现错误处理
  8. 记录参数格式
  9. 设计可组合的提示
  10. 测试各种输入情况