/** * MCP Outline PostgreSQL - Register Handlers * Shared handler registration for all transport types * @author Descomplicar® | @link descomplicar.pt | @copyright 2026 */ import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { ListToolsRequestSchema, CallToolRequestSchema, ListResourcesRequestSchema, ListPromptsRequestSchema } from '@modelcontextprotocol/sdk/types.js'; import { Pool } from 'pg'; import { BaseTool } from '../types/tools.js'; import { checkRateLimit } from '../utils/security.js'; import { logger } from '../utils/logger.js'; /** * Register all MCP handlers on a server instance */ export function registerHandlers( server: Server, pgPool: Pool, tools: BaseTool[] ): void { // Register tools list handler server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: tools.map((tool) => ({ name: tool.name, description: tool.description, inputSchema: tool.inputSchema })) })); // Register resources handler (required even if empty) server.setRequestHandler(ListResourcesRequestSchema, async () => { logger.debug('Resources list requested'); return { resources: [] }; }); // Register prompts handler (required even if empty) server.setRequestHandler(ListPromptsRequestSchema, async () => { logger.debug('Prompts list requested'); return { prompts: [] }; }); // Register tool call handler server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; // Rate limiting (using 'default' as clientId for now) const clientId = process.env.CLIENT_ID || 'default'; if (!checkRateLimit('api', clientId)) { return { content: [ { type: 'text', text: 'Too Many Requests: rate limit exceeded. Try again later.' } ] }; } // Find the tool handler const tool = tools.find((t) => t.name === name); if (!tool) { return { content: [ { type: 'text', text: `Tool '${name}' not found` } ] }; } try { return await tool.handler(args as Record, pgPool); } catch (error) { logger.error(`Error in tool ${name}:`, { error: error instanceof Error ? error.message : String(error) }); return { content: [ { type: 'text', text: `Error in tool ${name}: ${error instanceof Error ? error.message : String(error)}` } ] }; } }); }