UNPKG

sfcc-dev-mcp

Version:

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

168 lines 7.2 kB
/** * MCP Server for SFCC Development * * This module implements the Model Context Protocol (MCP) server for accessing * Salesforce B2C Commerce Cloud development features. It provides a standardized interface * for AI assistants to interact with SFCC development tools and data. */ import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js'; import { Logger } from '../utils/logger.js'; import { ConfigurationFactory } from '../config/configuration-factory.js'; import { SFCC_DOCUMENTATION_TOOLS, BEST_PRACTICES_TOOLS, SFRA_DOCUMENTATION_TOOLS, LOG_TOOLS, JOB_LOG_TOOLS, SYSTEM_OBJECT_TOOLS, CARTRIDGE_GENERATION_TOOLS, CODE_VERSION_TOOLS, } from './tool-definitions.js'; import { LogToolHandler } from './handlers/log-handler.js'; import { JobLogToolHandler } from './handlers/job-log-handler.js'; import { DocsToolHandler } from './handlers/docs-handler.js'; import { BestPracticesToolHandler } from './handlers/best-practices-handler.js'; import { SFRAToolHandler } from './handlers/sfra-handler.js'; import { SystemObjectToolHandler } from './handlers/system-object-handler.js'; import { CodeVersionToolHandler } from './handlers/code-version-handler.js'; import { CartridgeToolHandler } from './handlers/cartridge-handler.js'; /** * MCP Server implementation for SFCC development assistance * * This class sets up the MCP server, defines available tools, and handles * requests from MCP clients (like AI assistants) to interact with SFCC development features. */ export class SFCCDevServer { server; logger; config; capabilities; handlers = []; /** * Initialize the SFCC Development MCP Server * * @param config - SFCC configuration for connecting to the logging system */ constructor(config) { this.logger = Logger.getChildLogger('Server'); this.config = config; this.logMethodEntry('constructor', { hostname: config.hostname }); this.capabilities = ConfigurationFactory.getCapabilities(config); this.initializeServer(); this.registerHandlers(); this.setupToolHandlers(); this.logMethodExit('constructor'); } initializeServer() { this.server = new Server({ name: 'SFCC Development MCP Server', version: '1.0.14', // synced with package.json }, { capabilities: { tools: {}, }, }); } logMethodEntry(methodName, params) { this.logger.methodEntry(methodName, params); } logMethodExit(methodName, result) { this.logger.methodExit(methodName, result); } // Register modular handlers (each encapsulates its own responsibility) registerHandlers() { const context = { logger: this.logger, config: this.config, capabilities: this.capabilities, }; this.handlers = [ new LogToolHandler(context, 'Log'), new JobLogToolHandler(context, 'JobLog'), new DocsToolHandler(context, 'Docs'), new BestPracticesToolHandler(context, 'BestPractices'), new SFRAToolHandler(context, 'SFRA'), new SystemObjectToolHandler(context, 'SystemObjects'), new CodeVersionToolHandler(context, 'CodeVersions'), new CartridgeToolHandler(context, 'Cartridge'), ]; } /** * Set up MCP tool handlers for SFCC operations */ setupToolHandlers() { this.server.setRequestHandler(ListToolsRequestSchema, async () => { const tools = []; // Always available tools tools.push(...SFCC_DOCUMENTATION_TOOLS); tools.push(...BEST_PRACTICES_TOOLS); tools.push(...SFRA_DOCUMENTATION_TOOLS); tools.push(...CARTRIDGE_GENERATION_TOOLS); // Conditional tools based on available capabilities if (this.capabilities.canAccessLogs) { tools.push(...LOG_TOOLS); tools.push(...JOB_LOG_TOOLS); } if (this.capabilities.canAccessOCAPI) { tools.push(...SYSTEM_OBJECT_TOOLS); tools.push(...CODE_VERSION_TOOLS); } return { tools }; }); this.server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; const startTime = Date.now(); this.logger.methodEntry(`handleToolRequest:${name}`, args); try { const handler = this.handlers.find((h) => h.canHandle(name)); if (!handler) { this.logger.error(`Unknown tool requested: ${name}`); throw new Error(`Unknown tool: ${name}`); } const result = await handler.handle(name, args ?? {}, startTime); // Log the full response in debug mode this.logger.debug(`Full response for ${name}:`, { contentType: result.content?.[0]?.type, contentLength: result.content?.[0]?.text?.length ?? 0, responsePreview: result.content?.[0]?.text?.substring(0, 200) + (result.content?.[0]?.text?.length > 200 ? '...' : ''), fullResponse: result.content?.[0]?.text, }); return result; } catch (error) { this.logger.error(`Error handling tool "${name}":`, error); this.logger.timing(`${name}_error`, startTime); const errorResult = { content: [ { type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}`, }, ], isError: true, }; // Log error response in debug mode this.logger.debug(`Error response for ${name}:`, errorResult); return errorResult; } finally { this.logger.methodExit(`handleToolRequest:${name}`); } }); } /** * Start the MCP server */ async run() { const transport = new StdioServerTransport(); // Set up graceful shutdown process.on('SIGINT', () => this.shutdown()); process.on('SIGTERM', () => this.shutdown()); await this.server.connect(transport); this.logger.log('SFCC Development MCP server running on stdio'); } /** * Gracefully shutdown the server and dispose of resources */ async shutdown() { this.logger.log('Shutting down SFCC Development MCP server...'); // Dispose of all handlers await Promise.all(this.handlers.map(handler => handler.dispose())); this.logger.log('SFCC Development MCP server shutdown complete'); process.exit(0); } } //# sourceMappingURL=server.js.map