UNPKG

bottlenecks-mcp-server

Version:

Model Context Protocol server for Bottlenecks database - enables AI agents like Claude to interact with bottleneck data

149 lines 5.24 kB
/** * MCP Server Implementation for Bottlenecks * Integrates with existing Vercel-deployed Next.js APIs */ 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 { createMCPTools, getToolDefinitions, TOOL_CATEGORIES, } from './tools/index.js'; /** * Bottlenecks MCP Server */ export class BottlenecksMCPServer { server; tools; config; constructor(config) { this.config = config; // Initialize the MCP server this.server = new Server({ name: 'bottlenecks-mcp', version: '1.0.0', }, { capabilities: { tools: {}, resources: {}, }, }); // Create tools (without API key initially) this.tools = createMCPTools(config); // Set up request handlers this.setupHandlers(); } /** * Set up MCP request handlers */ setupHandlers() { // List available tools this.server.setRequestHandler(ListToolsRequestSchema, async () => { const toolDefinitions = getToolDefinitions(); return { tools: toolDefinitions.map((tool) => ({ name: tool.name, description: tool.description, inputSchema: tool.inputSchema, })), }; }); // Handle tool calls this.server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; // Find the requested tool const tool = this.tools.find((t) => t.name === name); if (!tool) { throw new Error(`Unknown tool: ${name}`); } try { // Execute the tool const result = await tool.handler(args || {}); return { content: result.content, isError: result.isError || false, }; } catch (error) { // Handle tool execution errors const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred'; return { content: [ { type: 'text', text: `Error executing tool '${name}': ${errorMessage}`, }, ], isError: true, }; } }); } /** * Update the API key for authenticated requests */ setApiKey(apiKey) { // Recreate tools with the API key this.tools = createMCPTools(this.config, apiKey); } /** * Start the MCP server */ async start() { const transport = new StdioServerTransport(); await this.server.connect(transport); console.error('Bottlenecks MCP Server started successfully'); console.error(`Connected to API: ${this.config.apiBaseUrl}`); console.error(`Available tools: ${this.tools.length}`); // Log tool categories Object.entries(TOOL_CATEGORIES).forEach(([category, tools]) => { console.error(` ${category}: ${tools.length} tools`); }); } /** * Stop the MCP server */ async stop() { // The server will stop when the transport is closed console.error('Bottlenecks MCP Server stopping...'); } /** * Get server status */ getStatus() { return { name: 'bottlenecks-mcp', version: '1.0.0', apiBaseUrl: this.config.apiBaseUrl, toolCount: this.tools.length, categories: Object.fromEntries(Object.entries(TOOL_CATEGORIES).map(([category, tools]) => [ category, tools.length, ])), }; } } /** * Create and configure the MCP server */ export function createBottlenecksMCPServer(options = {}) { const config = { apiBaseUrl: options.apiBaseUrl || (process.env.VERCEL_URL ? `https://${process.env.VERCEL_URL}` : null) || process.env.NEXT_PUBLIC_SITE_URL || 'https://www.bottlenecksinstitute.com', supabaseUrl: options.supabaseUrl || process.env.NEXT_PUBLIC_SUPABASE_URL || '', supabaseKey: options.supabaseKey || process.env.SUPABASE_SERVICE_ROLE_KEY || '', defaultTimeout: options.defaultTimeout || 30000, }; // Validate required configuration only if we're actually going to use the database if (!config.supabaseUrl) { process.stderr.write('Warning: NEXT_PUBLIC_SUPABASE_URL not set. Database operations will fail.\n'); } if (!config.supabaseKey) { process.stderr.write('Warning: SUPABASE_SERVICE_ROLE_KEY not set. Database operations will fail.\n'); } return new BottlenecksMCPServer(config); } /** * Default export for easy importing */ export default BottlenecksMCPServer; //# sourceMappingURL=server.js.map