第 4-6 章:核心组件开发详解
2025/9/1大约 13 分钟
第 4-6 章:核心组件开发详解
第 4 章:Tools工具开发
学习目标
- 理解Tools的概念和作用机制
- 学会定义工具的schema和参数
- 掌握工具的执行和结果返回
- 实现常用的工具类型(文件操作、网络请求等)
- 学习工具的错误处理和验证
4.1 工具系统架构
// 工具定义的核心接口
interface MCPTool {
name: string;
description: string;
inputSchema: JSONSchema;
handler: ToolHandler;
metadata?: {
category?: string;
tags?: string[];
version?: string;
author?: string;
};
}
interface JSONSchema {
type: 'object';
properties: Record<string, {
type: string;
description: string;
enum?: any[];
default?: any;
pattern?: string;
minimum?: number;
maximum?: number;
minLength?: number;
maxLength?: number;
}>;
required?: string[];
additionalProperties?: boolean;
}
type ToolHandler = (args: Record<string, any>, context?: ToolExecutionContext) => Promise<ToolResult>;
interface ToolExecutionContext {
requestId: string;
clientInfo?: {
name: string;
version: string;
};
permissions?: string[];
metadata?: Record<string, any>;
}
interface ToolResult {
content: Array<{
type: 'text' | 'image' | 'resource';
text?: string;
data?: string;
mimeType?: string;
uri?: string;
}>;
isError?: boolean;
metadata?: Record<string, any>;
}
// 工具注册和管理系统
class MCPToolRegistry {
private tools: Map<string, MCPTool> = new Map();
private categories: Map<string, string[]> = new Map();
// 注册工具
registerTool(tool: MCPTool): void {
this.validateTool(tool);
this.tools.set(tool.name, tool);
// 按分类组织
const category = tool.metadata?.category || 'general';
if (!this.categories.has(category)) {
this.categories.set(category, []);
}
this.categories.get(category)!.push(tool.name);
console.log(`Tool registered: ${tool.name} (${category})`);
}
// 获取工具
getTool(name: string): MCPTool | undefined {
return this.tools.get(name);
}
// 列出所有工具
listTools(category?: string): MCPTool[] {
if (category) {
const toolNames = this.categories.get(category) || [];
return toolNames.map(name => this.tools.get(name)!).filter(Boolean);
}
return Array.from(this.tools.values());
}
// 搜索工具
searchTools(query: string): MCPTool[] {
const lowerQuery = query.toLowerCase();
return Array.from(this.tools.values()).filter(tool =>
tool.name.toLowerCase().includes(lowerQuery) ||
tool.description.toLowerCase().includes(lowerQuery) ||
tool.metadata?.tags?.some(tag => tag.toLowerCase().includes(lowerQuery))
);
}
// 验证工具定义
private validateTool(tool: MCPTool): void {
if (!tool.name || typeof tool.name !== 'string') {
throw new Error('Tool name must be a non-empty string');
}
if (!tool.description || typeof tool.description !== 'string') {
throw new Error('Tool description must be a non-empty string');
}
if (!tool.inputSchema || typeof tool.inputSchema !== 'object') {
throw new Error('Tool inputSchema must be a valid JSON Schema object');
}
if (typeof tool.handler !== 'function') {
throw new Error('Tool handler must be a function');
}
// 检查名称冲突
if (this.tools.has(tool.name)) {
throw new Error(`Tool with name '${tool.name}' already exists`);
}
}
// 执行工具
async executeTool(name: string, args: Record<string, any>, context?: ToolExecutionContext): Promise<ToolResult> {
const tool = this.getTool(name);
if (!tool) {
throw new Error(`Tool not found: ${name}`);
}
// 验证参数
this.validateArguments(tool.inputSchema, args);
try {
const result = await tool.handler(args, context);
return this.normalizeResult(result);
} catch (error) {
return {
content: [{
type: 'text',
text: `Tool execution error: ${error.message}`
}],
isError: true,
metadata: {
error: error.message,
stack: error.stack
}
};
}
}
private validateArguments(schema: JSONSchema, args: Record<string, any>): void {
// 简化的参数验证
if (schema.required) {
for (const requiredField of schema.required) {
if (!(requiredField in args)) {
throw new Error(`Missing required parameter: ${requiredField}`);
}
}
}
for (const [key, value] of Object.entries(args)) {
const propSchema = schema.properties?.[key];
if (propSchema) {
this.validateValue(value, propSchema, key);
}
}
}
private validateValue(value: any, schema: any, fieldName: string): void {
if (schema.type === 'string' && typeof value !== 'string') {
throw new Error(`${fieldName} must be a string`);
}
if (schema.type === 'number' && typeof value !== 'number') {
throw new Error(`${fieldName} must be a number`);
}
if (schema.enum && !schema.enum.includes(value)) {
throw new Error(`${fieldName} must be one of: ${schema.enum.join(', ')}`);
}
}
private normalizeResult(result: ToolResult): ToolResult {
// 确保结果格式正确
if (!result.content || !Array.isArray(result.content)) {
return {
content: [{
type: 'text',
text: typeof result === 'string' ? result : JSON.stringify(result)
}],
isError: false
};
}
return result;
}
}
4.2 文件系统操作工具
// 文件系统工具集
import { promises as fs } from 'fs';
import path from 'path';
class FileSystemTools {
private allowedPaths: string[];
constructor(allowedPaths: string[] = [process.cwd()]) {
this.allowedPaths = allowedPaths;
}
// 验证路径安全性
private validatePath(filePath: string): string {
const resolvedPath = path.resolve(filePath);
const isAllowed = this.allowedPaths.some(allowedPath =>
resolvedPath.startsWith(path.resolve(allowedPath))
);
if (!isAllowed) {
throw new Error(`Access denied: Path '${filePath}' is not in allowed directories`);
}
return resolvedPath;
}
// 读取文件工具
getReadFileTool(): MCPTool {
return {
name: 'read_file',
description: '读取指定文件的内容',
inputSchema: {
type: 'object',
properties: {
path: {
type: 'string',
description: '文件路径'
},
encoding: {
type: 'string',
description: '文件编码',
enum: ['utf8', 'ascii', 'base64', 'hex'],
default: 'utf8'
}
},
required: ['path']
},
handler: async (args) => {
const { path: filePath, encoding = 'utf8' } = args;
const safePath = this.validatePath(filePath);
try {
const content = await fs.readFile(safePath, encoding);
const stats = await fs.stat(safePath);
return {
content: [{
type: 'text',
text: content
}],
metadata: {
path: safePath,
size: stats.size,
mtime: stats.mtime.toISOString(),
encoding
}
};
} catch (error) {
throw new Error(`Failed to read file: ${error.message}`);
}
},
metadata: {
category: 'filesystem',
tags: ['file', 'read', 'io']
}
};
}
// 写入文件工具
getWriteFileTool(): MCPTool {
return {
name: 'write_file',
description: '写入内容到指定文件',
inputSchema: {
type: 'object',
properties: {
path: {
type: 'string',
description: '文件路径'
},
content: {
type: 'string',
description: '要写入的内容'
},
encoding: {
type: 'string',
description: '文件编码',
enum: ['utf8', 'ascii', 'base64', 'hex'],
default: 'utf8'
},
createDirectories: {
type: 'boolean',
description: '是否自动创建不存在的目录',
default: false
}
},
required: ['path', 'content']
},
handler: async (args) => {
const { path: filePath, content, encoding = 'utf8', createDirectories = false } = args;
const safePath = this.validatePath(filePath);
try {
if (createDirectories) {
await fs.mkdir(path.dirname(safePath), { recursive: true });
}
await fs.writeFile(safePath, content, encoding);
const stats = await fs.stat(safePath);
return {
content: [{
type: 'text',
text: `Successfully wrote ${stats.size} bytes to ${safePath}`
}],
metadata: {
path: safePath,
size: stats.size,
encoding
}
};
} catch (error) {
throw new Error(`Failed to write file: ${error.message}`);
}
},
metadata: {
category: 'filesystem',
tags: ['file', 'write', 'io']
}
};
}
// 列出目录工具
getListDirectoryTool(): MCPTool {
return {
name: 'list_directory',
description: '列出目录中的文件和文件夹',
inputSchema: {
type: 'object',
properties: {
path: {
type: 'string',
description: '目录路径'
},
recursive: {
type: 'boolean',
description: '是否递归列出子目录',
default: false
},
includeHidden: {
type: 'boolean',
description: '是否包含隐藏文件',
default: false
}
},
required: ['path']
},
handler: async (args) => {
const { path: dirPath, recursive = false, includeHidden = false } = args;
const safePath = this.validatePath(dirPath);
try {
const entries = await this.listDirectory(safePath, recursive, includeHidden);
return {
content: [{
type: 'text',
text: JSON.stringify(entries, null, 2)
}],
metadata: {
path: safePath,
count: entries.length,
recursive
}
};
} catch (error) {
throw new Error(`Failed to list directory: ${error.message}`);
}
},
metadata: {
category: 'filesystem',
tags: ['directory', 'list', 'files']
}
};
}
private async listDirectory(dirPath: string, recursive: boolean, includeHidden: boolean): Promise<any[]> {
const entries = [];
const items = await fs.readdir(dirPath, { withFileTypes: true });
for (const item of items) {
if (!includeHidden && item.name.startsWith('.')) {
continue;
}
const fullPath = path.join(dirPath, item.name);
const stats = await fs.stat(fullPath);
const entry = {
name: item.name,
path: fullPath,
type: item.isDirectory() ? 'directory' : 'file',
size: stats.size,
mtime: stats.mtime.toISOString()
};
entries.push(entry);
if (recursive && item.isDirectory()) {
const subEntries = await this.listDirectory(fullPath, recursive, includeHidden);
entries.push(...subEntries);
}
}
return entries;
}
}
4.3 网络请求工具
// HTTP客户端工具
class HTTPTools {
private maxRedirects: number;
private timeout: number;
constructor(options: { maxRedirects?: number; timeout?: number } = {}) {
this.maxRedirects = options.maxRedirects || 5;
this.timeout = options.timeout || 30000;
}
getHTTPRequestTool(): MCPTool {
return {
name: 'http_request',
description: '发送HTTP请求',
inputSchema: {
type: 'object',
properties: {
url: {
type: 'string',
description: '请求URL'
},
method: {
type: 'string',
description: 'HTTP方法',
enum: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'],
default: 'GET'
},
headers: {
type: 'object',
description: '请求头',
additionalProperties: { type: 'string' }
},
body: {
type: 'string',
description: '请求体(用于POST/PUT等)'
},
timeout: {
type: 'number',
description: '超时时间(毫秒)',
minimum: 1000,
maximum: 60000,
default: 30000
}
},
required: ['url']
},
handler: async (args) => {
const { url, method = 'GET', headers = {}, body, timeout = this.timeout } = args;
try {
// 使用fetch API
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeout);
const response = await fetch(url, {
method,
headers,
body: body ? body : undefined,
signal: controller.signal
});
clearTimeout(timeoutId);
const responseHeaders = Object.fromEntries(response.headers.entries());
const responseBody = await response.text();
return {
content: [{
type: 'text',
text: JSON.stringify({
status: response.status,
statusText: response.statusText,
headers: responseHeaders,
body: responseBody
}, null, 2)
}],
metadata: {
url,
method,
status: response.status,
contentLength: responseBody.length
}
};
} catch (error) {
if (error.name === 'AbortError') {
throw new Error(`Request timeout after ${timeout}ms`);
}
throw new Error(`HTTP request failed: ${error.message}`);
}
},
metadata: {
category: 'network',
tags: ['http', 'request', 'api']
}
};
}
getWebScrapeTool(): MCPTool {
return {
name: 'web_scrape',
description: '抓取网页内容并提取文本',
inputSchema: {
type: 'object',
properties: {
url: {
type: 'string',
description: '要抓取的网页URL'
},
selector: {
type: 'string',
description: 'CSS选择器(可选)'
},
extractText: {
type: 'boolean',
description: '是否只提取文本内容',
default: true
}
},
required: ['url']
},
handler: async (args) => {
const { url, selector, extractText = true } = args;
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
let content = await response.text();
// 简化的HTML文本提取(实际应该使用JSDOM或类似库)
if (extractText) {
content = this.extractTextFromHTML(content);
}
return {
content: [{
type: 'text',
text: content
}],
metadata: {
url,
contentLength: content.length,
contentType: response.headers.get('content-type') || 'unknown'
}
};
} catch (error) {
throw new Error(`Web scraping failed: ${error.message}`);
}
},
metadata: {
category: 'network',
tags: ['web', 'scrape', 'html']
}
};
}
private extractTextFromHTML(html: string): string {
// 简化的HTML标签移除
return html
.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '')
.replace(/<style\b[^<]*(?:(?!<\/style>)<[^<]*)*<\/style>/gi, '')
.replace(/<[^>]+>/g, ' ')
.replace(/\s+/g, ' ')
.trim();
}
}
第 5 章:Resources资源管理
学习目标
- 理解Resources的概念和用途
- 学会创建和管理各种资源类型
- 掌握资源的读取、更新和监听机制
- 实现文件系统、数据库等资源提供者
- 学习资源权限和安全控制
5.1 资源管理系统
// 资源定义接口
interface MCPResource {
uri: string;
name: string;
description?: string;
mimeType?: string;
metadata?: {
category?: string;
tags?: string[];
version?: string;
lastModified?: string;
size?: number;
};
provider: ResourceProvider;
}
interface ResourceProvider {
read(): Promise<ResourceContent>;
watch?(callback: (uri: string) => void): void;
unwatch?(): void;
}
interface ResourceContent {
content: string | Buffer;
mimeType?: string;
metadata?: Record<string, any>;
}
// 资源管理器
class MCPResourceManager {
private resources: Map<string, MCPResource> = new Map();
private subscribers: Map<string, Set<(uri: string) => void>> = new Map();
private watchers: Map<string, any> = new Map();
// 注册资源
registerResource(resource: MCPResource): void {
this.validateResource(resource);
this.resources.set(resource.uri, resource);
// 设置监听
if (resource.provider.watch) {
const watcher = resource.provider.watch((uri) => {
this.notifySubscribers(uri);
});
this.watchers.set(resource.uri, watcher);
}
console.log(`Resource registered: ${resource.uri}`);
}
// 读取资源
async readResource(uri: string): Promise<ResourceContent> {
const resource = this.resources.get(uri);
if (!resource) {
throw new Error(`Resource not found: ${uri}`);
}
try {
return await resource.provider.read();
} catch (error) {
throw new Error(`Failed to read resource ${uri}: ${error.message}`);
}
}
// 列出资源
listResources(category?: string): MCPResource[] {
const resources = Array.from(this.resources.values());
if (category) {
return resources.filter(r => r.metadata?.category === category);
}
return resources;
}
// 订阅资源变更
subscribe(uri: string, callback: (uri: string) => void): void {
if (!this.resources.has(uri)) {
throw new Error(`Resource not found: ${uri}`);
}
if (!this.subscribers.has(uri)) {
this.subscribers.set(uri, new Set());
}
this.subscribers.get(uri)!.add(callback);
}
// 取消订阅
unsubscribe(uri: string, callback: (uri: string) => void): void {
const subscribers = this.subscribers.get(uri);
if (subscribers) {
subscribers.delete(callback);
if (subscribers.size === 0) {
this.subscribers.delete(uri);
}
}
}
// 通知订阅者
private notifySubscribers(uri: string): void {
const subscribers = this.subscribers.get(uri);
if (subscribers) {
subscribers.forEach(callback => {
try {
callback(uri);
} catch (error) {
console.error(`Subscriber callback error for ${uri}:`, error);
}
});
}
}
private validateResource(resource: MCPResource): void {
if (!resource.uri || typeof resource.uri !== 'string') {
throw new Error('Resource URI must be a non-empty string');
}
if (!resource.name || typeof resource.name !== 'string') {
throw new Error('Resource name must be a non-empty string');
}
if (!resource.provider || typeof resource.provider.read !== 'function') {
throw new Error('Resource must have a valid provider with read method');
}
if (this.resources.has(resource.uri)) {
throw new Error(`Resource with URI '${resource.uri}' already exists`);
}
}
}
// 文件系统资源提供者
class FileSystemResourceProvider implements ResourceProvider {
constructor(private filePath: string) {}
async read(): Promise<ResourceContent> {
try {
const content = await fs.readFile(this.filePath, 'utf-8');
const stats = await fs.stat(this.filePath);
return {
content,
mimeType: this.getMimeType(this.filePath),
metadata: {
size: stats.size,
lastModified: stats.mtime.toISOString()
}
};
} catch (error) {
throw new Error(`Failed to read file ${this.filePath}: ${error.message}`);
}
}
watch(callback: (uri: string) => void): void {
// 使用文件系统监听
const watcher = fs.watch(this.filePath, () => {
callback(`file://${this.filePath}`);
});
return watcher;
}
private getMimeType(filePath: string): string {
const ext = path.extname(filePath).toLowerCase();
const mimeTypes: Record<string, string> = {
'.json': 'application/json',
'.js': 'application/javascript',
'.ts': 'text/typescript',
'.html': 'text/html',
'.css': 'text/css',
'.md': 'text/markdown',
'.txt': 'text/plain',
'.xml': 'application/xml',
'.yaml': 'application/x-yaml',
'.yml': 'application/x-yaml'
};
return mimeTypes[ext] || 'text/plain';
}
}
// HTTP资源提供者
class HTTPResourceProvider implements ResourceProvider {
constructor(private url: string, private options?: { headers?: Record<string, string> }) {}
async read(): Promise<ResourceContent> {
try {
const response = await fetch(this.url, {
headers: this.options?.headers
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const content = await response.text();
const mimeType = response.headers.get('content-type') || 'text/plain';
return {
content,
mimeType,
metadata: {
url: this.url,
status: response.status,
lastModified: response.headers.get('last-modified') || new Date().toISOString()
}
};
} catch (error) {
throw new Error(`Failed to fetch ${this.url}: ${error.message}`);
}
}
}
// 配置资源提供者
class ConfigResourceProvider implements ResourceProvider {
constructor(private config: any) {}
async read(): Promise<ResourceContent> {
return {
content: JSON.stringify(this.config, null, 2),
mimeType: 'application/json',
metadata: {
lastModified: new Date().toISOString()
}
};
}
}
第 6 章:Prompts模板系统
学习目标
- 理解Prompts的作用和设计原则
- 学会创建可复用的prompt模板
- 掌握参数化prompt的实现
- 学习prompt的版本管理和优化
- 实现动态prompt生成系统
6.1 提示模板系统
// 提示模板接口
interface MCPPrompt {
name: string;
description?: string;
arguments?: PromptArgument[];
metadata?: {
category?: string;
tags?: string[];
version?: string;
author?: string;
};
template: PromptTemplate;
}
interface PromptArgument {
name: string;
description: string;
type: 'string' | 'number' | 'boolean' | 'array' | 'object';
required?: boolean;
default?: any;
enum?: any[];
validation?: {
pattern?: string;
minLength?: number;
maxLength?: number;
minimum?: number;
maximum?: number;
};
}
interface PromptTemplate {
generate(args: Record<string, any>): Promise<PromptResult>;
}
interface PromptResult {
messages: PromptMessage[];
metadata?: Record<string, any>;
}
interface PromptMessage {
role: 'system' | 'user' | 'assistant';
content: {
type: 'text' | 'image';
text?: string;
data?: string;
mimeType?: string;
};
}
// 提示模板管理器
class MCPPromptManager {
private prompts: Map<string, MCPPrompt> = new Map();
private templateEngine: TemplateEngine;
constructor() {
this.templateEngine = new TemplateEngine();
}
// 注册提示模板
registerPrompt(prompt: MCPPrompt): void {
this.validatePrompt(prompt);
this.prompts.set(prompt.name, prompt);
console.log(`Prompt registered: ${prompt.name}`);
}
// 生成提示
async generatePrompt(name: string, args: Record<string, any>): Promise<PromptResult> {
const prompt = this.prompts.get(name);
if (!prompt) {
throw new Error(`Prompt not found: ${name}`);
}
// 验证参数
this.validateArguments(prompt, args);
try {
return await prompt.template.generate(args);
} catch (error) {
throw new Error(`Prompt generation failed: ${error.message}`);
}
}
// 列出提示模板
listPrompts(category?: string): MCPPrompt[] {
const prompts = Array.from(this.prompts.values());
if (category) {
return prompts.filter(p => p.metadata?.category === category);
}
return prompts;
}
private validatePrompt(prompt: MCPPrompt): void {
if (!prompt.name || typeof prompt.name !== 'string') {
throw new Error('Prompt name must be a non-empty string');
}
if (this.prompts.has(prompt.name)) {
throw new Error(`Prompt with name '${prompt.name}' already exists`);
}
if (!prompt.template || typeof prompt.template.generate !== 'function') {
throw new Error('Prompt must have a valid template with generate method');
}
}
private validateArguments(prompt: MCPPrompt, args: Record<string, any>): void {
if (!prompt.arguments) return;
for (const arg of prompt.arguments) {
if (arg.required && !(arg.name in args)) {
throw new Error(`Missing required argument: ${arg.name}`);
}
if (arg.name in args) {
this.validateArgumentValue(args[arg.name], arg);
}
}
}
private validateArgumentValue(value: any, arg: PromptArgument): void {
// 类型检查
if (arg.type === 'string' && typeof value !== 'string') {
throw new Error(`Argument '${arg.name}' must be a string`);
}
if (arg.type === 'number' && typeof value !== 'number') {
throw new Error(`Argument '${arg.name}' must be a number`);
}
if (arg.type === 'boolean' && typeof value !== 'boolean') {
throw new Error(`Argument '${arg.name}' must be a boolean`);
}
// 枚举检查
if (arg.enum && !arg.enum.includes(value)) {
throw new Error(`Argument '${arg.name}' must be one of: ${arg.enum.join(', ')}`);
}
// 验证规则检查
if (arg.validation) {
const validation = arg.validation;
if (typeof value === 'string') {
if (validation.pattern && !new RegExp(validation.pattern).test(value)) {
throw new Error(`Argument '${arg.name}' does not match pattern: ${validation.pattern}`);
}
if (validation.minLength && value.length < validation.minLength) {
throw new Error(`Argument '${arg.name}' is too short (minimum ${validation.minLength})`);
}
if (validation.maxLength && value.length > validation.maxLength) {
throw new Error(`Argument '${arg.name}' is too long (maximum ${validation.maxLength})`);
}
}
if (typeof value === 'number') {
if (validation.minimum && value < validation.minimum) {
throw new Error(`Argument '${arg.name}' is too small (minimum ${validation.minimum})`);
}
if (validation.maximum && value > validation.maximum) {
throw new Error(`Argument '${arg.name}' is too large (maximum ${validation.maximum})`);
}
}
}
}
}
// 模板引擎
class TemplateEngine {
// 简单的模板变量替换
processTemplate(template: string, variables: Record<string, any>): string {
let result = template;
// 替换 {{variable}} 格式的变量
result = result.replace(/\{\{(\w+)\}\}/g, (match, varName) => {
return variables[varName] !== undefined ? String(variables[varName]) : match;
});
// 替换 ${variable} 格式的变量
result = result.replace(/\$\{(\w+)\}/g, (match, varName) => {
return variables[varName] !== undefined ? String(variables[varName]) : match;
});
return result;
}
// 条件处理
processConditionals(template: string, variables: Record<string, any>): string {
// 处理 {{#if condition}} ... {{/if}} 格式
return template.replace(/\{\{#if\s+(\w+)\}\}([\s\S]*?)\{\{\/if\}\}/g, (match, condition, content) => {
return variables[condition] ? content : '';
});
}
// 循环处理
processLoops(template: string, variables: Record<string, any>): string {
// 处理 {{#each array}} ... {{/each}} 格式
return template.replace(/\{\{#each\s+(\w+)\}\}([\s\S]*?)\{\{\/each\}\}/g, (match, arrayName, content) => {
const array = variables[arrayName];
if (!Array.isArray(array)) return '';
return array.map(item => {
return this.processTemplate(content, { ...variables, this: item });
}).join('');
});
}
}
// 代码审查提示模板
class CodeReviewPromptTemplate implements PromptTemplate {
async generate(args: Record<string, any>): Promise<PromptResult> {
const { code, language = 'unknown', focusAreas = [] } = args;
let systemPrompt = `你是一个经验丰富的代码审查专家。请仔细审查以下${language}代码。`;
if (focusAreas.length > 0) {
systemPrompt += `\n\n请特别关注以下方面:\n${focusAreas.map((area: string) => `- ${area}`).join('\n')}`;
} else {
systemPrompt += `
请关注以下方面:
- 代码质量和可读性
- 潜在的bug和安全问题
- 性能优化建议
- 最佳实践遵循情况`;
}
systemPrompt += '\n\n请提供具体的改进建议和示例代码。';
return {
messages: [
{
role: 'system',
content: {
type: 'text',
text: systemPrompt
}
},
{
role: 'user',
content: {
type: 'text',
text: `请审查以下代码:
\`\`\`${language}
${code}
\`\`\``
}
}
],
metadata: {
language,
codeLength: code.length,
focusAreas
}
};
}
}
// API文档生成提示模板
class APIDocPromptTemplate implements PromptTemplate {
async generate(args: Record<string, any>): Promise<PromptResult> {
const { apiSpec, format = 'markdown', includeExamples = true } = args;
const systemPrompt = `你是一个技术写作专家,专门负责生成清晰、准确的API文档。
请根据提供的API规范生成${format}格式的文档。
${includeExamples ? '请包含详细的请求和响应示例。' : ''}
文档应该包括:
1. API概述和认证方式
2. 端点列表和详细说明
3. 请求/响应格式
4. 错误代码说明
5. 使用示例(如果需要)
请确保文档结构清晰,易于理解和使用。`;
return {
messages: [
{
role: 'system',
content: {
type: 'text',
text: systemPrompt
}
},
{
role: 'user',
content: {
type: 'text',
text: `请为以下API生成文档:
\`\`\`json
${JSON.stringify(apiSpec, null, 2)}
\`\`\``
}
}
],
metadata: {
format,
includeExamples,
specSize: JSON.stringify(apiSpec).length
}
};
}
}
// 测试用例生成提示模板
class TestCasePromptTemplate implements PromptTemplate {
async generate(args: Record<string, any>): Promise<PromptResult> {
const {
code,
language = 'javascript',
framework = 'jest',
testTypes = ['unit', 'integration']
} = args;
const systemPrompt = `你是一个测试专家,专门为代码编写高质量的测试用例。
请为提供的${language}代码生成${framework}测试框架的测试用例。
测试类型:${testTypes.join(', ')}
请确保测试用例:
1. 覆盖主要功能和边界情况
2. 包含正面和负面测试场景
3. 具有清晰的测试描述
4. 遵循测试最佳实践
5. 易于维护和理解
请生成完整的、可运行的测试代码。`;
return {
messages: [
{
role: 'system',
content: {
type: 'text',
text: systemPrompt
}
},
{
role: 'user',
content: {
type: 'text',
text: `请为以下代码生成测试用例:
\`\`\`${language}
${code}
\`\`\``
}
}
],
metadata: {
language,
framework,
testTypes,
codeLength: code.length
}
};
}
}
综合示例:注册所有组件
// 综合示例:创建完整的MCP服务器
async function createCompleteMCPServer(): Promise<MCPServer> {
const server = new MCPServer({
name: 'complete-mcp-server',
version: '1.0.0',
description: '完整功能的MCP服务器示例',
capabilities: {
tools: true,
resources: true,
prompts: true,
logging: true
}
});
// 工具注册
const toolRegistry = new MCPToolRegistry();
const fileTools = new FileSystemTools([process.cwd()]);
const httpTools = new HTTPTools();
toolRegistry.registerTool(fileTools.getReadFileTool());
toolRegistry.registerTool(fileTools.getWriteFileTool());
toolRegistry.registerTool(fileTools.getListDirectoryTool());
toolRegistry.registerTool(httpTools.getHTTPRequestTool());
toolRegistry.registerTool(httpTools.getWebScrapeTool());
// 资源注册
const resourceManager = new MCPResourceManager();
resourceManager.registerResource({
uri: 'config://server',
name: 'Server Configuration',
description: '服务器配置信息',
mimeType: 'application/json',
provider: new ConfigResourceProvider({
server: 'complete-mcp-server',
version: '1.0.0',
capabilities: ['tools', 'resources', 'prompts']
}),
metadata: {
category: 'system',
tags: ['config', 'server']
}
});
// 提示模板注册
const promptManager = new MCPPromptManager();
promptManager.registerPrompt({
name: 'code_review',
description: '代码审查提示模板',
arguments: [
{
name: 'code',
description: '要审查的代码',
type: 'string',
required: true
},
{
name: 'language',
description: '编程语言',
type: 'string',
required: false,
default: 'javascript'
},
{
name: 'focusAreas',
description: '关注的审查方面',
type: 'array',
required: false,
default: []
}
],
template: new CodeReviewPromptTemplate(),
metadata: {
category: 'development',
tags: ['code', 'review', 'quality']
}
});
promptManager.registerPrompt({
name: 'api_documentation',
description: 'API文档生成提示模板',
arguments: [
{
name: 'apiSpec',
description: 'API规范(OpenAPI/Swagger格式)',
type: 'object',
required: true
},
{
name: 'format',
description: '文档格式',
type: 'string',
enum: ['markdown', 'html', 'pdf'],
default: 'markdown'
}
],
template: new APIDocPromptTemplate(),
metadata: {
category: 'documentation',
tags: ['api', 'docs', 'openapi']
}
});
return server;
}
// 启动完整的MCP服务器
async function main() {
try {
const server = await createCompleteMCPServer();
await server.start();
console.log('Complete MCP Server is running with all features!');
} catch (error) {
console.error('Failed to start server:', error);
process.exit(1);
}
}
小结
通过这三章的学习,我们掌握了MCP的三大核心组件:
- Tools工具系统:实现了文件操作、网络请求等实用工具
- Resources资源管理:支持文件、HTTP、配置等多种资源类型
- Prompts模板系统:提供了可参数化的提示模板生成能力
这些组件构成了MCP Server的核心功能,为AI模型提供了丰富的外部交互能力。接下来的章节将学习服务器生命周期、错误处理、安全性等高级主题。