Skip to main content
Glama
by wsapi-chat
server.ts6.05 kB
import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema, CallToolResult, ListToolsResult, } from '@modelcontextprotocol/sdk/types.js'; import { createLogger } from './utils/logger.js'; import { handleError, getUserFriendlyMessage } from './utils/errors.js'; import { wsapiClient } from './client/index.js'; import { config } from './config/index.js'; // Import tool handlers import { messagingTools } from './tools/messaging.js'; import { contactTools } from './tools/contacts.js'; import { groupTools } from './tools/groups.js'; import { chatTools } from './tools/chats.js'; import { sessionTools } from './tools/session.js'; import { instanceTools } from './tools/instance.js'; import { accountTools } from './tools/account.js'; const logger = createLogger('mcp-server'); export interface ToolHandler { name: string; description: string; inputSchema: any; handler: (args: any) => Promise<any>; } export class WSAPIMCPServer { private server: Server; private tools: Map<string, ToolHandler> = new Map(); constructor() { this.server = new Server( { name: 'wsapi-mcp-server', version: '1.0.0', }, { capabilities: { tools: {}, }, } ); this.setupToolHandlers(); this.setupServerHandlers(); } private setupToolHandlers(): void { logger.info('Setting up tool handlers'); // Register all tool categories const toolCategories = [ messagingTools, contactTools, groupTools, chatTools, sessionTools, instanceTools, accountTools, ]; toolCategories.forEach(category => { Object.values(category).forEach(tool => { if (this.tools.has(tool.name)) { logger.warn(`Tool ${tool.name} already registered, skipping`); return; } this.tools.set(tool.name, tool); logger.debug(`Registered tool: ${tool.name}`); }); }); logger.info(`Registered ${this.tools.size} tools`); } private setupServerHandlers(): void { // Handle tool listing this.server.setRequestHandler(ListToolsRequestSchema, async (): Promise<ListToolsResult> => { logger.debug('Handling list_tools request'); const tools = Array.from(this.tools.values()).map(tool => ({ name: tool.name, description: tool.description, inputSchema: tool.inputSchema, })); logger.debug(`Returning ${tools.length} tools`); return { tools }; }); // Handle tool calls this.server.setRequestHandler(CallToolRequestSchema, async (request): Promise<CallToolResult> => { const { name, arguments: args } = request.params; logger.info(`Executing tool: ${name}`, { args: this.sanitizeArgs(args) }); try { const tool = this.tools.get(name); if (!tool) { throw new Error(`Unknown tool: ${name}`); } // Execute the tool const result = await tool.handler(args || {}); logger.info(`Tool ${name} executed successfully`); return { content: [ { type: 'text', text: typeof result === 'string' ? result : JSON.stringify(result, null, 2), }, ], }; } catch (error) { const wsapiError = handleError(error, { tool: name, args: this.sanitizeArgs(args) }); const userMessage = getUserFriendlyMessage(wsapiError); logger.error(`Tool ${name} failed`, { error: wsapiError.message }); return { content: [ { type: 'text', text: `Error: ${userMessage}`, }, ], isError: true, }; } }); // Error handling this.server.onerror = (error) => { logger.error('Server error', { error: error.message, stack: error.stack }); }; logger.info('Server handlers setup complete'); } // Sanitize arguments for logging (remove sensitive data) private sanitizeArgs(args: any): any { if (!args || typeof args !== 'object') { return args; } const sanitized = { ...args }; // Remove sensitive fields const sensitiveFields = ['apiKey', 'token', 'password', 'imageBase64', 'videoBase64', 'audioBase64', 'voiceBase64', 'documentBase64', 'stickerBase64']; sensitiveFields.forEach(field => { if (sanitized[field]) { sanitized[field] = '[REDACTED]'; } }); return sanitized; } async start(): Promise<void> { logger.info('Starting WSAPI MCP Server', { environment: config.environment, instanceId: config.wsapi.instanceId, toolCount: this.tools.size, }); // Health check try { const isHealthy = await wsapiClient.healthCheck(); if (!isHealthy) { logger.warn('API health check failed, but continuing startup'); } else { logger.info('API health check passed'); } } catch (error) { logger.warn('Could not perform health check', { error: (error as Error).message }); } // Start the server const transport = new StdioServerTransport(); await this.server.connect(transport); logger.info('WSAPI MCP Server started successfully'); } async stop(): Promise<void> { logger.info('Stopping WSAPI MCP Server'); await this.server.close(); logger.info('WSAPI MCP Server stopped'); } // Get server info getServerInfo(): object { return { name: 'wsapi-mcp-server', version: '1.0.0', toolCount: this.tools.size, tools: Array.from(this.tools.keys()), config: { environment: config.environment, instanceId: config.wsapi.instanceId, baseUrl: config.wsapi.baseUrl, }, }; } } // Create and export server instance export const mcpServer = new WSAPIMCPServer(); // Default export for the main entry point export default mcpServer;

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/wsapi-chat/wsapi-mcp'

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