UNPKG

storybook-mcp-server

Version:

MCP server for Storybook - provides AI assistants access to components, stories, properties and screenshots

271 lines 10.1 kB
#!/usr/bin/env node "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js"); const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js"); const types_js_1 = require("@modelcontextprotocol/sdk/types.js"); const storybook_client_js_1 = require("./storybook-client.js"); const screenshot_service_js_1 = require("./screenshot-service.js"); const logger_js_1 = require("./logger.js"); const config_js_1 = require("./config.js"); const args = (0, config_js_1.parseArgs)(); class StorybookMCPServer { server; storybookClient; screenshotService; constructor(storybookUrl) { this.server = new index_js_1.Server({ name: 'storybook-mcp-server', version: '0.1.0', }, { capabilities: { tools: {}, }, }); this.storybookClient = new storybook_client_js_1.StorybookClient(storybookUrl); this.screenshotService = new screenshot_service_js_1.ScreenshotService(); this.setupHandlers(); } setupHandlers() { this.server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({ tools: this.getToolDefinitions(), })); this.server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { switch (name) { case 'storybook_list_components': return await this.handleListComponents(); case 'storybook_list_stories': return await this.handleListStories(args); case 'storybook_get_story_details': return await this.handleGetStoryDetails(args); case 'storybook_get_component_props': return await this.handleGetComponentProps(args); case 'storybook_capture_screenshot': return await this.handleCaptureScreenshot(args); case 'storybook_capture_all_screenshots': return await this.handleCaptureAllScreenshots(args); default: throw new Error(`Unknown tool: ${name}`); } } catch (error) { logger_js_1.logger.error(`Error executing tool ${name}:`, error); return { content: [ { type: 'text', text: `Error: ${error instanceof Error ? error.message : 'Unknown error'}`, }, ], }; } }); } getToolDefinitions() { return [ { name: 'storybook_list_components', description: 'List all components available in the Storybook instance', inputSchema: { type: 'object', properties: {}, }, }, { name: 'storybook_list_stories', description: 'List all stories, optionally filtered by component', inputSchema: { type: 'object', properties: { componentId: { type: 'string', description: 'Optional component ID to filter stories', }, }, }, }, { name: 'storybook_get_story_details', description: 'Get detailed information about a specific story', inputSchema: { type: 'object', properties: { storyId: { type: 'string', description: 'The ID of the story', }, }, required: ['storyId'], }, }, { name: 'storybook_get_component_props', description: 'Get the props/properties definition for a component', inputSchema: { type: 'object', properties: { componentId: { type: 'string', description: 'The ID of the component', }, }, required: ['componentId'], }, }, { name: 'storybook_capture_screenshot', description: 'Capture a screenshot of a specific story', inputSchema: { type: 'object', properties: { storyId: { type: 'string', description: 'The ID of the story to capture', }, viewport: { type: 'object', properties: { width: { type: 'number', description: 'Viewport width in pixels', }, height: { type: 'number', description: 'Viewport height in pixels', }, }, description: 'Optional viewport dimensions', }, }, required: ['storyId'], }, }, { name: 'storybook_capture_all_screenshots', description: 'Capture screenshots of all stories', inputSchema: { type: 'object', properties: { viewport: { type: 'object', properties: { width: { type: 'number', description: 'Viewport width in pixels', }, height: { type: 'number', description: 'Viewport height in pixels', }, }, description: 'Optional viewport dimensions', }, }, }, }, ]; } async handleListComponents() { const components = await this.storybookClient.listComponents(); return { content: [ { type: 'text', text: JSON.stringify(components, null, 2), }, ], }; } async handleListStories(args) { const stories = await this.storybookClient.listStories(args.componentId); return { content: [ { type: 'text', text: JSON.stringify(stories, null, 2), }, ], }; } async handleGetStoryDetails(args) { const details = await this.storybookClient.getStoryDetails(args.storyId); return { content: [ { type: 'text', text: JSON.stringify(details, null, 2), }, ], }; } async handleGetComponentProps(args) { const props = await this.storybookClient.getComponentProps(args.componentId); return { content: [ { type: 'text', text: JSON.stringify(props, null, 2), }, ], }; } async handleCaptureScreenshot(args) { const screenshotPath = await this.screenshotService.captureStoryScreenshot(this.storybookClient.getStorybookUrl(), args.storyId, args.viewport); return { content: [ { type: 'text', text: `Screenshot captured: ${screenshotPath}`, }, ], }; } async handleCaptureAllScreenshots(args) { const stories = await this.storybookClient.listStories(); const screenshots = await this.screenshotService.captureAllScreenshots(this.storybookClient.getStorybookUrl(), stories.map((s) => s.id), args.viewport); return { content: [ { type: 'text', text: `Captured ${screenshots.length} screenshots:\n${screenshots.join('\n')}`, }, ], }; } async start() { logger_js_1.logger.info('Starting Storybook MCP Server...'); await this.storybookClient.initialize(); const transport = new stdio_js_1.StdioServerTransport(); await this.server.connect(transport); logger_js_1.logger.info('Storybook MCP Server started successfully'); } async stop() { await this.screenshotService.close(); logger_js_1.logger.info('Storybook MCP Server stopped'); } } async function main() { const server = new StorybookMCPServer(args.storybookUrl); process.on('SIGINT', async () => { await server.stop(); process.exit(0); }); process.on('SIGTERM', async () => { await server.stop(); process.exit(0); }); try { await server.start(); } catch (error) { logger_js_1.logger.error('Failed to start server:', error); process.exit(1); } } main().catch((error) => { logger_js_1.logger.error('Unhandled error:', error); process.exit(1); }); //# sourceMappingURL=index.js.map