MCP入门教程-第3章:MCP 提示 (Prompts)

145 阅读9分钟

MCP提示词不仅仅是简单的文本模板,它们是完整的交互蓝图,能够接受动态参数、整合资源上下文,并引导特定的工作流程。

什么是MCP提示词?

MCP提示词是服务器定义的可重用模板和工作流,客户端可以轻松地将其呈现给用户和LLM。它们提供了标准化和共享常见LLM交互的强大方式。

核心特性

MCP提示词具备以下能力:

  • 接受动态参数:根据用户输入定制内容
  • 整合资源上下文:自动包含相关数据和文件内容
  • 链式交互:支持多步骤工作流程
  • 引导特定工作流:为复杂任务提供结构化指导
  • UI集成:可作为斜杠命令、快捷操作等界面元素呈现

控制模式

MCP提示词采用用户控制的设计模式,这意味着它们从服务器暴露给客户端,目的是让用户能够明确选择使用它们。

提示词结构

每个MCP提示词都包含以下核心元素:

interface Prompt {
  name: string;              // 唯一标识符
  description: string;       // 详细描述
  arguments?: PromptArgument[]; // 可选参数列表
}

interface PromptArgument {
  name: string;              // 参数名称
  description: string;       // 参数描述
  required: boolean;         // 是否必需
}

TypeScript SDK实战演示

让我们通过一个完整的代码生成助手示例,展示如何使用TypeScript SDK实现强大的MCP提示词功能:

1. 基础服务器设置

import { McpServer } from '@modelcontextprotocol/sdk';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import fs from 'fs/promises';
import path from 'path';

// 创建MCP服务器实例
const server = new McpServer({
  name: "CodeAssistantServer",
  version: "1.0.0",
});

// 定义提示词模板数据库
interface PromptTemplate {
  name: string;
  description: string;
  arguments: Array<{
    name: string;
    description: string;
    required: boolean;
  }>;
  template: string;
  category: string;
}

// 预定义的提示词模板
const promptTemplates: PromptTemplate[] = [
  {
    name: "code_review",
    description: "对代码进行全面的质量审查和改进建议",
    arguments: [
      {
        name: "code",
        description: "需要审查的代码内容",
        required: true
      },
      {
        name: "language",
        description: "编程语言 (默认: javascript)",
        required: false
      },
      {
        name: "focus_area",
        description: "重点关注的方面 (performance, security, readability, etc.)",
        required: false
      }
    ],
    template: `请对以下{{language}}代码进行详细的代码审查:

{{language}}
{{code}}


审查要点:
- 代码质量和可读性
- 性能优化建议
- 安全性问题
- 最佳实践遵循情况
{{#focus_area}}
- 特别关注:{{focus_area}}
{{/focus_area}}

请提供具体的改进建议和优化方案。`,
    category: "development"
  },
  {
    name: "api_documentation",
    description: "为API端点生成详细的文档",
    arguments: [
      {
        name: "endpoint_url",
        description: "API端点URL",
        required: true
      },
      {
        name: "method",
        description: "HTTP方法 (GET, POST, PUT, DELETE等)",
        required: true
      },
      {
        name: "description",
        description: "API功能描述",
        required: true
      },
      {
        name: "parameters",
        description: "请求参数(JSON格式)",
        required: false
      },
      {
        name: "example_response",
        description: "示例响应",
        required: false
      }
    ],
    template: `# API 文档

## {{method}} {{endpoint_url}}

### 描述
{{description}}

### 请求方法
{{method}}

{{#parameters}}
### 请求参数

{{parameters}}

{{/parameters}}

{{#example_response}}
### 响应示例

{{example_response}}

{{/example_response}}

### 状态码
- 200: 成功
- 400: 请求参数错误
- 401: 未授权
- 500: 服务器内部错误

请基于以上信息生成完整的API文档,包括详细的参数说明、错误处理和使用示例。`,
    category: "documentation"
  },
  {
    name: "test_case_generator",
    description: "为函数或模块生成全面的测试用例",
    arguments: [
      {
        name: "function_code",
        description: "需要测试的函数代码",
        required: true
      },
      {
        name: "test_framework",
        description: "测试框架 (jest, mocha, pytest等)",
        required: false
      },
      {
        name: "coverage_type",
        description: "测试覆盖类型 (unit, integration, e2e)",
        required: false
      }
    ],
    template: `请为以下函数生成全面的测试用例:


{{function_code}}


测试要求:
{{#test_framework}}
- 使用 {{test_framework}} 测试框架
{{/test_framework}}
{{#coverage_type}}
- 测试类型:{{coverage_type}}
{{/coverage_type}}

请生成包含以下方面的测试:
1. 正常情况测试(Happy Path)
2. 边界条件测试
3. 异常情况测试
4. 错误处理测试
5. 性能测试(如适用)

每个测试用例应包含:
- 清晰的测试描述
- 完整的测试代码
- 预期结果说明`,
    category: "testing"
  }
];

2. 实现提示词发现功能

// 处理提示词列表请求
server.setRequestHandler('prompts/list', async () => {
  return {
    prompts: promptTemplates.map(template => ({
      name: template.name,
      description: template.description,
      arguments: template.arguments
    }))
  };
});

// 实现分类和搜索功能
server.setRequestHandler('prompts/list', async (request) => {
  const { category, search } = request.params || {};
  
  let filteredPrompts = promptTemplates;
  
  // 按分类过滤
  if (category) {
    filteredPrompts = filteredPrompts.filter(p => p.category === category);
  }
  
  // 按关键词搜索
  if (search) {
    const searchLower = search.toLowerCase();
    filteredPrompts = filteredPrompts.filter(p => 
      p.name.toLowerCase().includes(searchLower) ||
      p.description.toLowerCase().includes(searchLower)
    );
  }
  
  return {
    prompts: filteredPrompts.map(template => ({
      name: template.name,
      description: template.description,
      arguments: template.arguments
    }))
  };
});

3. 实现提示词生成功能

// 模板引擎:简单的Mustache风格模板处理
function renderTemplate(template: string, variables: Record<string, any>): string {
  let rendered = template;
  
  // 处理必需变量 {{variable}}
  rendered = rendered.replace(/{{(\w+)}}/g, (match, key) => {
    return variables[key] !== undefined ? String(variables[key]) : match;
  });
  
  // 处理条件块 {{#variable}}...{{/variable}}
  rendered = rendered.replace(/{{#(\w+)}}([\s\S]*?){{/\1}}/g, (match, key, content) => {
    return variables[key] ? content : '';
  });
  
  return rendered;
}

// 处理提示词生成请求
server.setRequestHandler('prompts/get', async (request) => {
  const { name, arguments: args = {} } = request.params;
  
  // 查找提示词模板
  const template = promptTemplates.find(p => p.name === name);
  if (!template) {
    throw new Error(`提示词模板 '${name}' 不存在`);
  }
  
  // 验证必需参数
  const missingArgs = template.arguments
    .filter(arg => arg.required && !args[arg.name])
    .map(arg => arg.name);
  
  if (missingArgs.length > 0) {
    throw new Error(`缺少必需参数: ${missingArgs.join(', ')}`);
  }
  
  // 设置默认值
  const processedArgs = { 
    language: 'javascript',
    test_framework: 'jest',
    coverage_type: 'unit',
    ...args 
  };
  
  try {
    // 渲染模板
    const renderedContent = renderTemplate(template.template, processedArgs);
    
    return {
      messages: [
        {
          role: 'user',
          content: {
            type: 'text',
            text: renderedContent
          }
        }
      ]
    };
  } catch (error) {
    throw new Error(`模板渲染失败: ${error.message}`);
  }
});

4. 动态提示词和资源整合

// 高级提示词:整合资源上下文
const advancedPrompts: PromptTemplate[] = [
  {
    name: "project_analysis",
    description: "分析整个项目结构和代码质量",
    arguments: [
      {
        name: "project_path",
        description: "项目根目录路径",
        required: true
      },
      {
        name: "analysis_depth",
        description: "分析深度 (shallow, medium, deep)",
        required: false
      }
    ],
    template: `请分析以下项目的结构和代码质量:

项目路径:{{project_path}}

{{#project_files}}
## 项目文件结构
{{project_files}}
{{/project_files}}

{{#main_files_content}}
## 主要文件内容
{{main_files_content}}
{{/main_files_content}}

请提供:
1. 项目架构分析
2. 代码质量评估
3. 潜在问题识别
4. 改进建议
5. 最佳实践建议`,
    category: "analysis"
  }
];

// 扩展的提示词处理,包含资源整合
server.setRequestHandler('prompts/get', async (request) => {
  const { name, arguments: args = {} } = request.params;
  
  // 查找模板(包含高级模板)
  const allTemplates = [...promptTemplates, ...advancedPrompts];
  const template = allTemplates.find(p => p.name === name);
  
  if (!template) {
    throw new Error(`提示词模板 '${name}' 不存在`);
  }
  
  // 处理需要资源整合的提示词
  if (name === 'project_analysis' && args.project_path) {
    const enhancedArgs = await enhanceWithProjectContext(args);
    const renderedContent = renderTemplate(template.template, enhancedArgs);
    
    return {
      messages: [
        {
          role: 'user',
          content: {
            type: 'text',
            text: renderedContent
          }
        }
      ]
    };
  }
  
  // 标准处理流程
  const processedArgs = { ...args };
  const renderedContent = renderTemplate(template.template, processedArgs);
  
  return {
    messages: [
      {
        role: 'user',
        content: {
          type: 'text',
          text: renderedContent
        }
      }
    ]
  };
});

// 项目上下文增强函数
async function enhanceWithProjectContext(args: any) {
  const { project_path, analysis_depth = 'medium' } = args;
  
  try {
    // 读取项目文件结构
    const fileStructure = await getProjectStructure(project_path);
    
    // 根据分析深度读取文件内容
    let mainFilesContent = '';
    if (analysis_depth !== 'shallow') {
      const mainFiles = await getMainProjectFiles(project_path);
      mainFilesContent = await readMainFiles(mainFiles);
    }
    
    return {
      ...args,
      project_files: fileStructure,
      main_files_content: mainFilesContent
    };
  } catch (error) {
    console.error('增强项目上下文失败:', error);
    return args;
  }
}

// 项目结构分析辅助函数
async function getProjectStructure(projectPath: string): Promise<string> {
  const structure = await fs.readdir(projectPath, { withFileTypes: true });
  
  const formatStructure = (items: any[], indent = 0) => {
    return items.map(item => {
      const prefix = '  '.repeat(indent) + (item.isDirectory() ? '📁 ' : '📄 ');
      return prefix + item.name;
    }).join('\n');
  };
  
  return formatStructure(structure);
}

async function getMainProjectFiles(projectPath: string): Promise<string[]> {
  const importantFiles = [
    'package.json',
    'README.md',
    'tsconfig.json',
    'webpack.config.js',
    'next.config.js',
    '.gitignore'
  ];
  
  const existingFiles = [];
  for (const file of importantFiles) {
    try {
      const filePath = path.join(projectPath, file);
      await fs.access(filePath);
      existingFiles.push(filePath);
    } catch {
      // 文件不存在,跳过
    }
  }
  
  return existingFiles;
}

async function readMainFiles(filePaths: string[]): Promise<string> {
  const contents = [];
  
  for (const filePath of filePaths) {
    try {
      const content = await fs.readFile(filePath, 'utf-8');
      const fileName = path.basename(filePath);
      contents.push(`### ${fileName}\n```\n${content}\n````);
    } catch (error) {
      contents.push(`### ${path.basename(filePath)}\n读取失败: ${error.message}`);
    }
  }
  
  return contents.join('\n\n');
}

5. 工作流链式提示词

// 复杂工作流提示词:多步骤代码重构
const workflowPrompts: PromptTemplate[] = [
  {
    name: "refactoring_workflow",
    description: "完整的代码重构工作流程",
    arguments: [
      {
        name: "original_code",
        description: "需要重构的原始代码",
        required: true
      },
      {
        name: "refactoring_goals",
        description: "重构目标(性能、可读性、可维护性等)",
        required: true
      },
      {
        name: "step",
        description: "当前步骤 (analyze, plan, implement, test, review)",
        required: false
      }
    ],
    template: `{{#step_analyze}}
# 步骤 1: 代码分析

请分析以下代码并识别需要重构的问题:

{{original_code}}

重构目标:{{refactoring_goals}}

请提供:
1. 代码质量问题识别
2. 架构问题分析
3. 性能瓶颈识别
4. 可维护性问题
5. 重构优先级建议
{{/step_analyze}}

{{#step_plan}}
# 步骤 2: 重构计划

基于之前的分析,请制定详细的重构计划:

原始代码:

{{original_code}}

请提供:
1. 重构步骤分解
2. 风险评估
3. 测试策略
4. 向后兼容性考虑
5. 预期改进效果
{{/step_plan}}

{{#step_implement}}
# 步骤 3: 实施重构

请实施重构并提供重构后的代码:

原始代码:
{{original_code}}

重构目标:{{refactoring_goals}}

请提供:
1. 重构后的完整代码
2. 关键变更说明
3. 新增的设计模式或架构
4. 性能改进点
{{/step_implement}}`,
    category: "workflow"
  }
];

// 工作流状态管理
const workflowState = new Map<string, any>();

// 处理工作流提示词
server.setRequestHandler('prompts/get', async (request) => {
  const { name, arguments: args = {} } = request.params;
  
  if (name === 'refactoring_workflow') {
    return await handleRefactoringWorkflow(args);
  }
  
  // 其他提示词处理逻辑...
});

async function handleRefactoringWorkflow(args: any) {
  const { original_code, refactoring_goals, step = 'analyze' } = args;
  const workflowId = `refactor_${Date.now()}`;
  
  // 保存工作流状态
  workflowState.set(workflowId, {
    original_code,
    refactoring_goals,
    current_step: step,
    created_at: new Date()
  });
  
  // 根据步骤设置条件变量
  const stepConditions = {
    [`step_${step}`]: true
  };
  
  const template = workflowPrompts.find(p => p.name === 'refactoring_workflow');
  const renderedContent = renderTemplate(template.template, {
    ...args,
    ...stepConditions
  });
  
  return {
    messages: [
      {
        role: 'user',
        content: {
          type: 'text',
          text: renderedContent
        }
      }
    ],
    metadata: {
      workflow_id: workflowId,
      current_step: step,
      next_steps: getNextSteps(step)
    }
  };
}

function getNextSteps(currentStep: string): string[] {
  const stepFlow = {
    analyze: ['plan'],
    plan: ['implement'],
    implement: ['test'],
    test: ['review'],
    review: []
  };
  
  return stepFlow[currentStep] || [];
}

6. UI集成和通知系统

// 提示词更新通知
server.setNotificationHandler('notifications/prompts/list_changed', () => {
  console.log('提示词列表已更新');
});

// 动态添加新提示词
function addCustomPrompt(promptData: PromptTemplate) {
  promptTemplates.push(promptData);
  
  // 通知客户端提示词列表变更
  server.sendNotification('notifications/prompts/list_changed', {});
}

// 提示词使用统计
const promptUsageStats = new Map<string, number>();

// 在提示词使用时记录统计
server.setRequestHandler('prompts/get', async (request) => {
  const { name } = request.params;
  
  // 更新使用统计
  const currentCount = promptUsageStats.get(name) || 0;
  promptUsageStats.set(name, currentCount + 1);
  
  // 执行原有逻辑...
  // (此处省略之前的实现代码)
});

// 获取使用统计
server.setRequestHandler('prompts/stats', async () => {
  return {
    usage_stats: Object.fromEntries(promptUsageStats.entries()),
    total_prompts: promptTemplates.length,
    most_used: getMostUsedPrompts()
  };
});

function getMostUsedPrompts() {
  return Array.from(promptUsageStats.entries())
    .sort(([,a], [,b]) => b - a)
    .slice(0, 5)
    .map(([name, count]) => ({ name, count }));
}

7. 启动服务器

// 启动服务器
async function main() {
  // 创建标准输入输出传输
  const transport = new StdioServerTransport();
  
  // 连接服务器和传输
  await server.connect(transport);
  
  console.log('MCP提示词服务器已启动');
  console.log(`已加载 ${promptTemplates.length} 个提示词模板`);
  
  // 输出可用的提示词列表
  console.log('\n可用提示词:');
  promptTemplates.forEach(prompt => {
    console.log(`- ${prompt.name}: ${prompt.description}`);
  });
}

// 处理优雅关闭
process.on('SIGINT', async () => {
  console.log('\n正在关闭提示词服务器...');
  
  // 保存使用统计
  console.log('提示词使用统计:');
  promptUsageStats.forEach((count, name) => {
    console.log(`  ${name}: ${count} 次`);
  });
  
  await server.close();
  process.exit(0);
});

// 启动应用
main().catch(console.error);

最佳实践

1. 提示词设计原则

  • 清晰性:使用描述性的提示词名称和详细说明
  • 模块化:将复杂任务分解为可组合的提示词
  • 参数验证:验证所有必需参数并优雅处理缺失参数
  • 版本控制:考虑为提示词模板实现版本控制
  • 错误处理:实现全面的错误处理和用户友好的错误消息

2. 性能优化

  • 缓存机制:对动态内容适当实施缓存
  • 懒加载:对复杂的资源整合使用懒加载策略
  • 超时处理:为长时间运行的操作实现超时机制
  • 资源管理:合理管理内存和文件句柄

3. 安全考虑

  • 输入验证:验证和清理所有用户输入
  • 访问控制:实现适当的权限检查
  • 速率限制:防止提示词被滥用
  • 注入防护:防范提示词注入攻击
  • 敏感数据处理:谨慎处理包含敏感信息的提示词

4. 用户体验

  • UI集成:将提示词作为斜杠命令、快捷操作等呈现
  • 实时反馈:为长时间运行的操作提供进度反馈
  • 上下文感知:根据当前上下文智能推荐相关提示词
  • 可发现性:通过分类和搜索功能提高提示词的可发现性

总结

MCP提示词为AI交互提供了标准化、可重用且强大的模板系统。通过TypeScript SDK,我们可以构建出既智能又灵活的提示词服务器,为用户提供丰富的AI交互体验。

从简单的代码审查模板到复杂的多步骤工作流,MCP提示词系统都能够胜任。结合资源整合、动态参数和链式交互,我们可以创建出真正智能的AI助手工具。

掌握MCP提示词的设计和实现,将为构建下一代AI应用程序的交互层奠定坚实基础,让AI真正成为用户工作流程中不可或缺的智能伙伴。