Chapters 4-6: Detailed Core Component Development
Chapters 4-6: Detailed Core Component Development
Chapter 4: Tools Development
Learning Objectives
- Understand the concept and mechanism of Tools
- Learn to define tool schema and parameters
- Master tool execution and result return
- Implement common tool types (file operations, network requests, etc.)
- Learn tool error handling and validation
4.1 Tool System Architecture
// Core interface for tool definition
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>;
}
// Tool registration and management system
class MCPToolRegistry {
private tools: Map<string, MCPTool> = new Map();
private categories: Map<string, string[]> = new Map();
// Register a tool
registerTool(tool: MCPTool): void {
this.validateTool(tool);
this.tools.set(tool.name, tool);
// Organize by category
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})`);
}
// Get a tool
getTool(name: string): MCPTool | undefined {
return this.tools.get(name);
}
// List all tools
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());
}
// Search for tools
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))
);
}
// Validate tool definition
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');
}
// Check for name conflicts
if (this.tools.has(tool.name)) {
throw new Error(`Tool with name '${tool.name}' already exists`);
}
}
// Execute a tool
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}`);
}
// Validate arguments
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 {
// Simplified argument validation
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 {
// Ensure result format is correct
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 File System Operation Tools
// File system toolset
import { promises as fs } from 'fs';
import path from 'path';
class FileSystemTools {
private allowedPaths: string[];
constructor(allowedPaths: string[] = [process.cwd()]) {
this.allowedPaths = allowedPaths;
}
// Validate path security
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;
}
// Read file tool
getReadFileTool(): MCPTool {
return {
name: 'read_file',
description: 'Reads the content of a specified file',
inputSchema: {
type: 'object',
properties: {
path: {
type: 'string',
description: 'File path'
},
encoding: {
type: 'string',
description: 'File encoding',
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']
}
};
}
// Write file tool
getWriteFileTool(): MCPTool {
return {
name: 'write_file',
description: 'Writes content to a specified file',
inputSchema: {
type: 'object',
properties: {
path: {
type: 'string',
description: 'File path'
},
content: {
type: 'string',
description: 'Content to write'
},
encoding: {
type: 'string',
description: 'File encoding',
enum: ['utf8', 'ascii', 'base64', 'hex'],
default: 'utf8'
},
createDirectories: {
type: 'boolean',
description: 'Whether to automatically create non-existent directories',
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']
}
};
}
// List directory tool
getListDirectoryTool(): MCPTool {
return {
name: 'list_directory',
description: 'Lists files and folders in a directory',
inputSchema: {
type: 'object',
properties: {
path: {
type: 'string',
description: 'Directory path'
},
recursive: {
type: 'boolean',
description: 'Whether to recursively list subdirectories',
default: false
},
includeHidden: {
type: 'boolean',
description: 'Whether to include hidden files',
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 Network Request Tools
// HTTP client tool
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: 'Sends an HTTP request',
inputSchema: {
type: 'object',
properties: {
url: {
type: 'string',
description: 'Request URL'
},
method: {
type: 'string',
description: 'HTTP method',
enum: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'],
default: 'GET'
},
headers: {
type: 'object',
description: 'Request headers',
additionalProperties: { type: 'string' }
},
body: {
type: 'string',
description: 'Request body (for POST/PUT etc.)'
},
timeout: {
type: 'number',
description: 'Timeout in milliseconds',
minimum: 1000,
maximum: 60000,
default: 30000
}
},
required: ['url']
},
handler: async (args) => {
const { url, method = 'GET', headers = {}, body, timeout = this.timeout } = args;
try {
// Use 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: 'Scrapes web page content and extracts text',
inputSchema: {
type: 'object',
properties: {
url: {
type: 'string',
description: 'URL of the web page to scrape'
},
selector: {
type: 'string',
description: 'CSS selector (optional)'
},
extractText: {
type: 'boolean',
description: 'Whether to extract text content only',
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();
// Simplified HTML text extraction (should use JSDOM or similar library in practice)
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 {
// Simplified HTML tag removal
return html
.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '')
.replace(/<style\b[^<]*(?:(?!<\/style>)<[^<]*)*<\/style>/gi, '')
.replace(/<[^>]+>/g, ' ')
.replace(/\s+/g, ' ')
.trim();
}
}
Chapter 5: Resources Management
Learning Objectives
- Understand the concept and usage of Resources
- Learn to create and manage various resource types
- Master resource reading, updating, and listening mechanisms
- Implement resource providers for file systems, databases, etc.
- Learn resource permissions and security control
5.1 Resource Management System
// Resource definition interface
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>;
}
// Resource manager
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();
// Register a resource
registerResource(resource: MCPResource): void {
this.validateResource(resource);
this.resources.set(resource.uri, resource);
// Set up watching
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}`);
}
// Read a resource
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}`);
}
}
// List resources
listResources(category?: string): MCPResource[] {
const resources = Array.from(this.resources.values());
if (category) {
return resources.filter(r => r.metadata?.category === category);
}
return resources;
}
// Subscribe to resource changes
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
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);
}
}
}
// Notify subscribers
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`);
}
}
}
// File system resource provider
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 {
// Use file system watcher
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 resource provider
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}`);
}
}
}
// Config resource provider
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()
}
};
}
}
Chapter 6: Prompts Template System
Learning Objectives
- Understand the role and design principles of Prompts
- Learn to create reusable prompt templates
- Master the implementation of parameterized prompts
- Learn prompt version management and optimization
- Implement a dynamic prompt generation system
6.1 Prompt Template System
// Prompt template interface
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;
};
}
// Prompt template manager
class MCPPromptManager {
private prompts: Map<string, MCPPrompt> = new Map();
private templateEngine: TemplateEngine;
constructor() {
this.templateEngine = new TemplateEngine();
}
// Register a prompt template
registerPrompt(prompt: MCPPrompt): void {
this.validatePrompt(prompt);
this.prompts.set(prompt.name, prompt);
console.log(`Prompt registered: ${prompt.name}`);
}
// Generate a prompt
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}`);
}
// Validate arguments
this.validateArguments(prompt, args);
try {
return await prompt.template.generate(args);
} catch (error) {
throw new Error(`Prompt generation failed: ${error.message}`);
}
}
// List prompt templates
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 {
// Type checking
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`);
}
// Enum checking
if (arg.enum && !arg.enum.includes(value)) {
throw new Error(`Argument '${arg.name}' must be one of: ${arg.enum.join(', ')}`);
}
// Validation rules checking
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})`);
}
}
}
}
}
// Template engine
class TemplateEngine {
// Simple template variable replacement
processTemplate(template: string, variables: Record<string, any>): string {
let result = template;
// Replace {{variable}} format variables
result = result.replace(/\{\{(\w+)\}\}/g, (match, varName) => {
return variables[varName] !== undefined ? String(variables[varName]) : match;
});
// Replace ${variable} format variables
result = result.replace(/\$\{(\w+)\}/g, (match, varName) => {
return variables[varName] !== undefined ? String(variables[varName]) : match;
});
return result;
}
// Conditional processing
processConditionals(template: string, variables: Record<string, any>): string {
// Process {{#if condition}} ... {{/if}} format
return template.replace(/\{\{\\#if\s+(\w+)\\}\} ([\s\S]*?)\{\{\\/if\}\}/g, (match, condition, content) => {
return variables[condition] ? content : '';
});
}
// Loop processing
processLoops(template: string, variables: Record<string, any>): string {
// Process {{#each array}} ... {{/each}} format
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('');
});
}
}
// Code review prompt template
class CodeReviewPromptTemplate implements PromptTemplate {
async generate(args: Record<string, any>): Promise<PromptResult> {
const { code, language = 'unknown', focusAreas = [] } = args;
let systemPrompt = `You are an experienced code review expert. Please carefully review the following ${language} code.`;
if (focusAreas.length > 0) {
systemPrompt += `\n\nPlease pay special attention to the following aspects:\n${focusAreas.map((area: string) => `- ${area}`).join('\n')}`;
} else {
systemPrompt += `
Please pay attention to the following aspects:
- Code quality and readability
- Potential bugs and security issues
- Performance optimization suggestions
- Adherence to best practices`;
}
systemPrompt += '\nPlease provide specific improvement suggestions and example code.';
return {
messages: [
{
role: 'system',
content: {
type: 'text',
text: systemPrompt
}
},
{
role: 'user',
content: {
type: 'text',
text: `Please review the following code:
\
```${language}
${code}
` } } ], metadata: { language, codeLength: code.length, focusAreas } }; } }
// API documentation generation prompt template
class APIDocPromptTemplate implements PromptTemplate {
async generate(args: Record<string, any>): Promise
const systemPrompt = `You are a technical writing expert specializing in generating clear, accurate API documentation.
Please generate documentation in ${format} format based on the provided API specification.
${includeExamples ? ‘Please include detailed request and response examples.’ : ”}
The documentation should include:
- API overview and authentication methods
- List of endpoints and detailed descriptions
- Request/response formats
- Error code descriptions
- Usage examples (if needed)
Please ensure the documentation is clearly structured, easy to understand and use.`;
return {
messages: [
{
role: 'system',
content: {
type: 'text',
text: systemPrompt
}
},
{
role: 'user',
content: {
type: 'text',
text: `Please generate documentation for the following API:
\
${JSON.stringify(apiSpec, null, 2)}
` } } ], metadata: { format, includeExamples, specSize: JSON.stringify(apiSpec).length } }; } }
// Test case generation prompt template
class TestCasePromptTemplate implements PromptTemplate {
async generate(args: Record<string, any>): Promise
const systemPrompt = `You are a testing expert specializing in writing high-quality test cases for code.
Please generate test cases for the provided {framework} testing framework.
Test types: ${testTypes.join(’, ’)}
Please ensure the test cases:
- Cover main functions and edge cases
- Include positive and negative test scenarios
- Have clear test descriptions
- Follow testing best practices
- Are easy to maintain and understand
Please generate complete, runnable test code.`;
return {
messages: [
{
role: 'system',
content: {
type: 'text',
text: systemPrompt
}
},
{
role: 'user',
content: {
type: 'text',
text: `Please generate test cases for the following code:
\
${code}
` } } ], metadata: { language, framework, testTypes, codeLength: code.length } }; } }
### Comprehensive Example: Register All Components
```typescript
// Comprehensive Example: Creating a complete MCP server
async function createCompleteMCPServer(): Promise<MCPServer> {
const server = new MCPServer({
name: 'complete-mcp-server',
version: '1.0.0',
description: 'Example of a fully functional MCP server',
capabilities: {
tools: true,
resources: true,
prompts: true,
logging: true
}
});
// Tool registration
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());
// Resource registration
const resourceManager = new MCPResourceManager();
resourceManager.registerResource({
uri: 'config://server',
name: 'Server Configuration',
description: 'Server configuration information',
mimeType: 'application/json',
provider: new ConfigResourceProvider({
server: 'complete-mcp-server',
version: '1.0.0',
capabilities: ['tools', 'resources', 'prompts']
}),
metadata: {
category: 'system',
tags: ['config', 'server']
}
});
// Prompt template registration
const promptManager = new MCPPromptManager();
promptManager.registerPrompt({
name: 'code_review',
description: 'Code review prompt template',
arguments: [
{
name: 'code',
description: 'Code to review',
type: 'string',
required: true
},
{
name: 'language',
description: 'Programming language',
type: 'string',
required: false,
default: 'javascript'
},
{
name: 'focusAreas',
description: 'Review focus areas',
type: 'array',
required: false,
default: []
}
],
template: new CodeReviewPromptTemplate(),
metadata: {
category: 'development',
tags: ['code', 'review', 'quality']
}
});
promptManager.registerPrompt({
name: 'api_documentation',
description: 'API documentation generation prompt template',
arguments: [
{
name: 'apiSpec',
description: 'API specification (OpenAPI/Swagger format)',
type: 'object',
required: true
},
{
name: 'format',
description: 'Document format',
type: 'string',
enum: ['markdown', 'html', 'pdf'],
default: 'markdown'
}
],
template: new APIDocPromptTemplate(),
metadata: {
category: 'documentation',
tags: ['api', 'docs', 'openapi']
}
});
return server;
}
// Start the complete MCP server
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);
}
}
Summary
Through these three chapters, we have mastered the three core components of MCP:
- Tools System: Implemented practical tools for file operations, network requests, etc.
- Resources Management: Supported various resource types such as files, HTTP, and configuration
- Prompts Template System: Provided a parameterized prompt template generation capability
These components form the core functionality of the MCP Server, providing rich external interaction capabilities for AI models. The following chapters will cover advanced topics such as server lifecycle, error handling, and security.