UNPKG

sfcc-dev-mcp

Version:

MCP server for Salesforce B2C Commerce Cloud development assistance including logs, debugging, and development tools

172 lines 5.31 kB
import { Logger } from '../../utils/logger.js'; export class HandlerError extends Error { toolName; code; details; constructor(message, toolName, code = 'HANDLER_ERROR', details) { super(message); this.toolName = toolName; this.code = code; this.details = details; this.name = 'HandlerError'; } } export class BaseToolHandler { context; logger; _isInitialized = false; constructor(context, subLoggerName) { this.context = context; this.logger = Logger.getChildLogger(`Handler:${subLoggerName}`); } /** * Check if this handler can handle the given tool */ canHandle(toolName) { return this.getToolNameSet().has(toolName); } /** * Config-driven tool execution * Handles validation, defaults, execution, and logging uniformly */ async handle(toolName, args, startTime) { if (!this.canHandle(toolName)) { throw new Error(`Unsupported tool: ${toolName}`); } const toolConfig = this.getToolConfig(); const spec = toolConfig[toolName]; if (!spec) { throw new Error(`No configuration found for tool: ${toolName}`); } return this.executeWithLogging(toolName, startTime, () => this.dispatchTool(spec, args), spec.logMessage(this.applyDefaults(spec, args))); } /** * Generic tool dispatch using configuration * Handles validation, defaults, and execution */ async dispatchTool(spec, args) { const context = await this.createExecutionContext(); const processedArgs = this.createValidatedArgs(spec, args, 'tool'); return spec.exec(processedArgs, context); } /** * Apply default values to arguments */ applyDefaults(spec, args) { if (!spec.defaults) { return args; } const defaults = spec.defaults(args); return { ...args, ...defaults }; } /** * Create validated arguments with defaults applied */ createValidatedArgs(spec, args, toolName) { // Apply defaults first const processedArgs = this.applyDefaults(spec, args); // Validate if validator exists if (spec.validate) { spec.validate(processedArgs, toolName); } return processedArgs; } /** * Initialize the handler (lazy initialization) */ async initialize() { if (this._isInitialized) { return; } await this.onInitialize(); this._isInitialized = true; } /** * Override this method for custom initialization logic */ async onInitialize() { // Default: no-op } /** * Clean up resources when handler is destroyed */ async dispose() { await this.onDispose(); this._isInitialized = false; } /** * Override this method for custom cleanup logic */ async onDispose() { // Default: no-op } /** * Validate required arguments */ validateArgs(args, required, toolName) { for (const field of required) { if (!args?.[field]) { throw new HandlerError(`${field} is required`, toolName, 'MISSING_ARGUMENT', { required, provided: Object.keys(args || {}) }); } } } /** * Create a standardized response */ createResponse(data, stringify = true) { return { content: [ { type: 'text', text: stringify ? JSON.stringify(data, null, 2) : data }, ], isError: false, }; } /** * Create an error response */ createErrorResponse(error, toolName) { this.logger.error(`Error in ${toolName}:`, error); return { content: [ { type: 'text', text: error instanceof HandlerError ? `Error: ${error.message}` : `Error: ${error.message}`, }, ], isError: true, }; } /** * Execute a tool operation with standardized logging and error handling */ async executeWithLogging(toolName, startTime, operation, logMessage) { try { await this.initialize(); if (logMessage) { this.logger.debug(logMessage); } const result = await operation(); this.logger.timing(toolName, startTime); // Log result metadata for debugging this.logger.debug(`${toolName} completed successfully`, { resultType: typeof result, resultLength: Array.isArray(result) ? result.length : undefined, hasData: result != null, }); return this.createResponse(result); } catch (error) { this.logger.timing(`${toolName}_error`, startTime); return this.createErrorResponse(error, toolName); } } /** * @deprecated Use executeWithLogging instead */ async wrap(toolName, startTime, fn, logMessage) { return this.executeWithLogging(toolName, startTime, fn, logMessage); } } //# sourceMappingURL=base-handler.js.map