Skip to main content
Glama
index.ts4.98 kB
#!/usr/bin/env node import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, } from '@modelcontextprotocol/sdk/types.js'; import { zodToJsonSchema } from 'zod-to-json-schema'; import { readFileSync } from 'fs'; import { fileURLToPath } from 'url'; import { dirname, join } from 'path'; // Import the single source of truth for all tools and prompts import { TOOLS, TOOL_MAP, ToolResult, ToolContent } from './tools-registry.js'; import { PROMPTS, PROMPT_MAP } from './prompts-registry.js'; import { createMcpLogger } from './logger.js'; /* eslint-disable no-process-exit */ // Read version from package.json const currentDir = dirname(fileURLToPath(import.meta.url)); const packageJson = JSON.parse(readFileSync(join(currentDir, '..', 'package.json'), 'utf-8')); const VERSION = packageJson.version as string; const serverLogger = createMcpLogger('SERVER'); // Initialize server const server = new Server( { name: 'mcp-server-tauri', version: VERSION, }, { capabilities: { tools: {}, prompts: {}, }, } ); // Handle connection errors gracefully - don't crash on broken pipe server.onerror = (error) => { // Ignore broken pipe errors - they happen when the client disconnects const message = error instanceof Error ? error.message : String(error); if (message.includes('broken pipe') || message.includes('EPIPE')) { // Client disconnected, exit gracefully process.exit(0); } // For other errors, log to stderr (will be captured by MCP client) serverLogger.error(message); }; // Handle connection close - exit gracefully server.onclose = () => { process.exit(0); }; // Tool list handler - generated from registry server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: TOOLS.map((tool) => { return { name: tool.name, description: tool.description, inputSchema: zodToJsonSchema(tool.schema) as Record<string, unknown>, annotations: tool.annotations, }; }), }; }); /** * Convert a ToolResult to MCP content array. * Handles string (legacy), single content, and content arrays. */ function toolResultToContent(result: ToolResult): Array<{ type: string; text?: string; data?: string; mimeType?: string }> { // Legacy string result - convert to text content if (typeof result === 'string') { return [ { type: 'text', text: result } ]; } // Array of content items if (Array.isArray(result)) { return result.map(contentToMcp); } // Single content item return [ contentToMcp(result) ]; } /** * Convert a single ToolContent to MCP format. */ function contentToMcp(content: ToolContent): { type: string; text?: string; data?: string; mimeType?: string } { if (content.type === 'text') { return { type: 'text', text: content.text }; } // Image content return { type: 'image', data: content.data, mimeType: content.mimeType }; } // Tool call handler - generated from registry server.setRequestHandler(CallToolRequestSchema, async (request) => { try { const tool = TOOL_MAP.get(request.params.name); if (!tool) { throw new Error(`Unknown tool: ${request.params.name}`); } const output = await tool.handler(request.params.arguments); return { content: toolResultToContent(output) }; } catch(error: unknown) { const message = error instanceof Error ? error.message : String(error); return { content: [ { type: 'text', text: `Error: ${message}` } ], isError: true, }; } }); // Prompt list handler - generated from registry server.setRequestHandler(ListPromptsRequestSchema, async () => { return { prompts: PROMPTS.map((prompt) => { return { name: prompt.name, description: prompt.description, arguments: prompt.arguments, }; }), }; }); // Get prompt handler - returns prompt messages for a specific prompt server.setRequestHandler(GetPromptRequestSchema, async (request) => { const prompt = PROMPT_MAP.get(request.params.name); if (!prompt) { throw new Error(`Unknown prompt: ${request.params.name}`); } const args = (request.params.arguments || {}) as Record<string, string>; return { description: prompt.description, messages: prompt.handler(args), }; }); // Start server async function main(): Promise<void> { const transport = new StdioServerTransport(); await server.connect(transport); // Don't log to stderr - it interferes with MCP protocol } main().catch(() => { // Don't log errors to stderr - just exit silently // The error will be in the MCP response if needed process.exit(1); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/hypothesi/mcp-server-tauri'

If you have feedback or need assistance with the MCP directory API, please join our Discord server