@emmahyde/thought-patterns
Version:
MCP server combining systematic thinking, mental models, debugging approaches, and stochastic algorithms for comprehensive cognitive pattern support
147 lines (146 loc) • 4.58 kB
JavaScript
import { z } from 'zod';
/**
* Abstract base class for all tool servers
* Provides standardized validation, error handling, and response formatting
*/
export class BaseToolServer {
/**
* Constructor that accepts a Zod schema for input validation
* @param schema - Zod schema for validating input data
*/
constructor(schema) {
this.schema = schema;
}
/**
* Validates input using the provided Zod schema
* @param input - Raw input data to validate
* @returns Validated and typed input data
* @throws Error if validation fails
*/
validate(input) {
try {
return this.schema.parse(input);
}
catch (error) {
if (error instanceof z.ZodError) {
const errorMessages = error.errors.map(err => `${err.path.join('.')}: ${err.message}`).join(', ');
throw new Error(`Validation failed: ${errorMessages}`);
}
throw error;
}
}
/**
* Standardized process method for unified server interface
* Default implementation delegates to handle method for backward compatibility
* Servers can override this to provide standardized processing interface
* @param validInput - Validated input data
* @returns Processed output data
*/
process(validInput) {
return this.handle(validInput);
}
/**
* Main entry point that wraps validation, processing, and error handling
* Provides standardized {content, isError} envelope response
* @param rawInput - Raw input data from MCP request
* @returns Standardized MCP response
*/
run(rawInput) {
try {
// Validate input using schema
const validatedInput = this.validate(rawInput);
// Process with concrete implementation
const result = this.handle(validatedInput);
// Format successful response
return {
content: [{
type: "text",
text: JSON.stringify(result, null, 2)
}]
};
}
catch (error) {
// Format error response
return {
content: [{
type: "text",
text: JSON.stringify({
error: error instanceof Error ? error.message : String(error),
status: 'failed',
timestamp: new Date().toISOString()
}, null, 2)
}],
isError: true
};
}
}
/**
* Optional method for servers that need custom response formatting
* @param result - Result from handle method
* @returns Formatted response content
*/
formatResponse(result) {
return [{
type: "text",
text: JSON.stringify(result, null, 2)
}];
}
/**
* Optional method for servers that need custom error formatting
* @param error - Error that occurred during processing
* @returns Formatted error response content
*/
formatError(error) {
return [{
type: "text",
text: JSON.stringify({
error: error.message,
status: 'failed',
timestamp: new Date().toISOString()
}, null, 2)
}];
}
}
/**
* Tool registry for managing all available tools
*/
export class ToolRegistry {
/**
* Register a new tool
* @param entry - Tool registry entry
*/
static register(entry) {
this.tools.push(entry);
}
/**
* Find a tool by name
* @param name - Tool name
* @returns Tool registry entry or undefined
*/
static findTool(name) {
return this.tools.find(tool => tool.name === name);
}
/**
* Get all registered tools
* @returns Array of all tool registry entries
*/
static getAllTools() {
return [...this.tools];
}
/**
* Get tool names for MCP ListTools response
* @returns Array of tool definitions for MCP
*/
static getToolDefinitions() {
return this.tools.map(tool => ({
name: tool.name,
description: tool.description || `Tool for ${tool.name} operations`,
inputSchema: {
type: "object",
properties: {},
required: []
}
}));
}
}
ToolRegistry.tools = [];