Skip to main content
Glama
cameronsjo

MCP Server Template

by cameronsjo
server.ts4.29 kB
/** * MCP Server implementation * * Core server using low-level MCP SDK Server API for fine-grained control. * Supports both stdio and HTTP transports via environment configuration. */ import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { ListToolsRequestSchema, CallToolRequestSchema, type CallToolResult, } from '@modelcontextprotocol/sdk/types.js'; import { createLogger } from './shared/logger.js'; import { getConfig } from './config/index.js'; import { getToolRegistry } from './tools/registry.js'; import { withSpan } from './shared/tracing.js'; import { sanitizeObject } from './shared/pii-sanitizer.js'; const logger = createLogger('server'); const config = getConfig(); /** * Create and configure the MCP server */ export function createServer(): Server { const server = new Server( { name: config.serverName, version: config.serverVersion, }, { capabilities: { tools: {}, // Enable resources and prompts when implemented // resources: {}, // prompts: {}, }, } ); // Handle list tools request server.setRequestHandler(ListToolsRequestSchema, async () => { const registry = getToolRegistry(); const tools = registry.getDefinitions(); logger.debug('Listed tools', { count: tools.length }); return { tools }; }); // Handle tool execution request server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; return withSpan( `tool.${name}`, async (span) => { span.setAttribute('mcp.tool.name', name); const registry = getToolRegistry(); const result = await registry.execute(name, args); if (result.success) { span.setAttribute('mcp.tool.success', true); // Format successful response const response: CallToolResult = { content: [ { type: 'text', text: JSON.stringify(sanitizeObject(result.data as Record<string, unknown>), null, 2), }, ], isError: false, }; return response; } else { span.setAttribute('mcp.tool.success', false); span.setAttribute('mcp.tool.error_code', result.error?.code ?? 'UNKNOWN'); // Format error response const response: CallToolResult = { content: [ { type: 'text', text: JSON.stringify(result.error, null, 2), }, ], isError: true, }; return response; } }, { attributes: { 'mcp.tool.name': name, }, } ); }); logger.info('MCP server created', { name: config.serverName, version: config.serverVersion, }); return server; } /** * Connect server to stdio transport and run */ export async function runStdioServer(server: Server): Promise<void> { const transport = new StdioServerTransport(); logger.info('Starting stdio transport'); await server.connect(transport); logger.info('MCP server running on stdio'); } /** * Graceful shutdown handler */ export function setupGracefulShutdown( server: Server, cleanup: () => Promise<void> ): void { const shutdown = async (signal: string): Promise<void> => { logger.info('Received shutdown signal', { signal }); try { await server.close(); await cleanup(); logger.info('Graceful shutdown complete'); process.exit(0); } catch (error) { logger.error('Error during shutdown', { error: String(error) }); process.exit(1); } }; process.on('SIGINT', () => void shutdown('SIGINT')); process.on('SIGTERM', () => void shutdown('SIGTERM')); // Handle uncaught errors process.on('uncaughtException', (error) => { logger.critical('Uncaught exception', { error: error.message, stack: error.stack }); void shutdown('uncaughtException'); }); process.on('unhandledRejection', (reason) => { logger.critical('Unhandled rejection', { reason: String(reason) }); void shutdown('unhandledRejection'); }); }

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/cameronsjo/mcp-server-template'

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