UNPKG

mcp-magma-handbook

Version:

Enhanced MCP server with multi-query search, hybrid search, and collections for MAGMA computational algebra system

202 lines 8.18 kB
// Polyfill fetch for Node.js import fetch from 'node-fetch'; // @ts-ignore global.fetch = fetch; 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 { z } from 'zod'; import { config } from 'dotenv'; import { SupabaseMagmaKnowledgeBase } from './supabase-knowledge-base.js'; // Load environment variables config(); // Tool schemas const SearchMagmaSchema = z.object({ query: z.string().describe('Search query for MAGMA handbook content'), limit: z.number().optional().default(5).describe('Maximum number of results to return'), category: z.enum(['syntax', 'function', 'algorithm', 'example', 'theory', 'all']) .optional() .default('all') .describe('Category of content to search') }); const GetMagmaExampleSchema = z.object({ topic: z.string().describe('Mathematical topic or MAGMA function name'), complexity: z.enum(['basic', 'intermediate', 'advanced']) .optional() .default('basic') .describe('Complexity level of examples') }); const ExplainMagmaCodeSchema = z.object({ code: z.string().describe('MAGMA code to explain'), context: z.string().optional().describe('Additional context about the code') }); export class MagmaHandbookServer { server; knowledgeBase; constructor() { this.server = new Server({ name: 'mcp-magma-handbook', version: '1.0.0', }, { capabilities: { tools: {}, }, }); this.knowledgeBase = new SupabaseMagmaKnowledgeBase(); this.setupHandlers(); } setupHandlers() { // List available tools this.server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: [ { name: 'search_magma', description: 'Search MAGMA handbook for specific topics, functions, or algorithms', inputSchema: { type: 'object', properties: { query: { type: 'string' }, limit: { type: 'number' }, category: { type: 'string', enum: ['syntax', 'function', 'algorithm', 'example', 'theory', 'all'] } }, required: ['query'] } }, { name: 'get_magma_example', description: 'Get MAGMA code examples for specific mathematical topics', inputSchema: { type: 'object', properties: { topic: { type: 'string' }, complexity: { type: 'string', enum: ['basic', 'intermediate', 'advanced'] } }, required: ['topic'] } }, { name: 'explain_magma_code', description: 'Explain what a piece of MAGMA code does', inputSchema: { type: 'object', properties: { code: { type: 'string' }, context: { type: 'string' } }, required: ['code'] } } ], })); // Handle tool calls this.server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { switch (name) { case 'search_magma': { const params = SearchMagmaSchema.parse(args); const results = await this.knowledgeBase.search(params.query, params.limit, params.category); return { content: [ { type: 'text', text: this.formatSearchResults(results, params.query), }, ], }; } case 'get_magma_example': { const params = GetMagmaExampleSchema.parse(args); const examples = await this.knowledgeBase.getExamples(params.topic, params.complexity); return { content: [ { type: 'text', text: this.formatExamples(examples, params.topic), }, ], }; } case 'explain_magma_code': { const params = ExplainMagmaCodeSchema.parse(args); const explanation = await this.knowledgeBase.explainCode(params.code, params.context); return { content: [ { type: 'text', text: explanation, }, ], }; } default: throw new Error(`Unknown tool: ${name}`); } } catch (error) { return { content: [ { type: 'text', text: `Error: ${error instanceof Error ? error.message : 'Unknown error'}`, }, ], }; } }); } formatSearchResults(results, query) { if (results.length === 0) { return `No results found for query: "${query}"`; } let output = `Found ${results.length} results for "${query}":\n\n`; results.forEach((result, index) => { output += `## Result ${index + 1}\n`; output += `**Source**: ${result.metadata.source} (Page ${result.metadata.page})\n`; output += `**Category**: ${result.metadata.category}\n`; output += `**Relevance Score**: ${result.score.toFixed(3)}\n\n`; output += `${result.content}\n\n`; output += '---\n\n'; }); return output; } formatExamples(examples, topic) { if (examples.length === 0) { return `No examples found for topic: "${topic}"`; } let output = `# MAGMA Examples for "${topic}"\n\n`; examples.forEach((example, index) => { output += `## Example ${index + 1}: ${example.title}\n`; output += `**Level**: ${example.complexity}\n\n`; output += '```magma\n'; output += example.code; output += '\n```\n\n'; if (example.explanation) { output += `**Explanation**: ${example.explanation}\n\n`; } if (example.output) { output += `**Expected Output**:\n\`\`\`\n${example.output}\n\`\`\`\n\n`; } output += '---\n\n'; }); return output; } async start() { // Initialize knowledge base await this.knowledgeBase.initialize(); // Start server const transport = new StdioServerTransport(); await this.server.connect(transport); console.error('MAGMA Handbook MCP server started'); } } // Start the server const server = new MagmaHandbookServer(); server.start().catch(console.error); //# sourceMappingURL=index.js.map