UNPKG

cook-mcp-windy

Version:

HowToCook MCP Server - Intelligent Chinese recipe management and meal planning for AI assistants

226 lines 7.51 kB
#!/usr/bin/env node 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 { allTools, toolHandlers, toolInfo } from './tools/index.js'; /** * HowToCook MCP Server * * A Model Context Protocol server for recipe management and meal planning. * Provides tools for recipe retrieval, meal planning, and dish combination recommendations. */ class HowToCookMCPServer { server; constructor() { this.server = new Server({ name: 'howtocook-mcp', version: '1.0.0', }, { capabilities: { tools: {}, }, }); this.setupToolHandlers(); this.setupErrorHandling(); } /** * Set up tool handlers */ setupToolHandlers() { // Handle tool listing this.server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: allTools, }; }); // Handle tool calls this.server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { // Validate tool exists if (!toolHandlers[name]) { throw new Error(`Unknown tool: ${name}`); } // Call the appropriate tool handler const handler = toolHandlers[name]; const result = await handler(args || {}); // Format response for MCP return { content: [ { type: 'text', text: this.formatToolResponse(name, result), }, ], }; } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred'; return { content: [ { type: 'text', text: JSON.stringify({ success: false, error: `Tool execution failed: ${errorMessage}`, tool: name, timestamp: new Date().toISOString() }, null, 2), }, ], isError: true, }; } }); } /** * Set up error handling */ setupErrorHandling() { this.server.onerror = (error) => { console.error('[MCP Server Error]', error); }; process.on('SIGINT', async () => { await this.server.close(); process.exit(0); }); process.on('SIGTERM', async () => { await this.server.close(); process.exit(0); }); } /** * Format tool response for MCP client */ formatToolResponse(toolName, response) { const timestamp = new Date().toISOString(); if (response.success) { return JSON.stringify({ success: true, tool: toolName, message: response.message, data: response.data, timestamp, // Add helpful metadata metadata: { toolCategory: this.getToolCategory(toolName), dataType: this.getDataType(response.data), recordCount: this.getRecordCount(response.data) } }, null, 2); } else { return JSON.stringify({ success: false, tool: toolName, error: response.error, details: response.details, timestamp, // Add troubleshooting info troubleshooting: this.getTroubleshootingInfo(toolName, response.error) }, null, 2); } } /** * Get tool category for metadata */ getToolCategory(toolName) { const info = toolInfo[toolName]; return info?.category || 'Unknown'; } /** * Get data type for metadata */ getDataType(data) { if (!data) return 'none'; if (Array.isArray(data)) return 'array'; if (data.items && Array.isArray(data.items)) return 'paginated'; if (data.recipe) return 'recipe'; if (data.mealPlan) return 'meal_plan'; if (data.combination) return 'dish_combination'; return 'object'; } /** * Get record count for metadata */ getRecordCount(data) { if (!data) return 0; if (Array.isArray(data)) return data.length; if (data.items && Array.isArray(data.items)) return data.items.length; if (data.totalCount) return data.totalCount; return 1; } /** * Get troubleshooting information */ getTroubleshootingInfo(toolName, error) { const tips = []; if (error.includes('not found')) { tips.push('Check if the identifier exists in the database'); tips.push('Try using a different search method (ID vs name)'); } if (error.includes('validation')) { tips.push('Verify all required parameters are provided'); tips.push('Check parameter types and value ranges'); } if (error.includes('empty')) { tips.push('Ensure the recipe database is properly loaded'); tips.push('Try with different filter criteria'); } // Tool-specific tips switch (toolName) { case 'get_recipes_by_category': tips.push('Valid categories: 水产, 早餐, 调味料, 甜品, 饮品, 荤菜, 半成品, 汤羹, 主食, 素菜'); break; case 'recommend_meal_plan': tips.push('Ensure numberOfPeople is between 1 and 20'); tips.push('Check dietary restrictions are from the valid list'); break; case 'recommend_dish_combination': tips.push('Ensure minDishes <= maxDishes'); tips.push('Check that occasion is from the valid list'); break; } return tips; } /** * Start the server */ async start() { const transport = new StdioServerTransport(); await this.server.connect(transport); console.error('HowToCook MCP Server started successfully'); console.error(`Available tools: ${allTools.map(t => t.name).join(', ')}`); } } /** * Main entry point */ async function main() { try { const server = new HowToCookMCPServer(); await server.start(); } catch (error) { console.error('Failed to start HowToCook MCP Server:', error); process.exit(1); } } // Start the server if this file is run directly if (import.meta.url === `file://${process.argv[1]}`) { main().catch((error) => { console.error('Unhandled error:', error); process.exit(1); }); } //# sourceMappingURL=index.js.map