Skip to main content
Glama
server.ts7.24 kB
/** * ByteBot MCP Server * * Main MCP server class that orchestrates all ByteBot integrations * and exposes tools via the Model Context Protocol */ import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema, Tool, } from '@modelcontextprotocol/sdk/types.js'; import { AgentClient } from './clients/agent-client.js'; import { DesktopClient } from './clients/desktop-client.js'; import { WebSocketClient } from './clients/websocket-client.js'; import { EnvironmentConfig, HealthCheckResult } from './types/mcp.js'; import { getAgentTools, handleAgentTool } from './tools/agent-tools.js'; import { getDesktopTools, handleDesktopTool } from './tools/desktop-tools.js'; import { getHybridTools, handleHybridTool, HybridOrchestrator, } from './tools/hybrid-tools.js'; import { validateEndpoint, validateWebSocketEndpoint } from './utils/error-handler.js'; /** * ByteBot MCP Server */ export class ByteBotMCPServer { private server: Server; private agentClient: AgentClient; private desktopClient: DesktopClient; private wsClient: WebSocketClient | null = null; private orchestrator: HybridOrchestrator; private config: EnvironmentConfig; private tools: Tool[] = []; constructor(config: EnvironmentConfig) { this.config = config; // Validate endpoints validateEndpoint(config.agentUrl, 'Agent API'); validateEndpoint(config.desktopUrl, 'Desktop API'); if (config.wsUrl && config.enableWebSocket) { validateWebSocketEndpoint(config.wsUrl); } // Initialize clients this.agentClient = new AgentClient(config); this.desktopClient = new DesktopClient(config); // Initialize WebSocket client if enabled if (config.enableWebSocket && config.wsUrl) { this.wsClient = new WebSocketClient(config); } // Initialize orchestrator this.orchestrator = new HybridOrchestrator( this.agentClient, this.desktopClient, this.wsClient, config ); // Initialize MCP server this.server = new Server( { name: config.serverName, version: '1.0.0', }, { capabilities: { tools: {}, }, } ); // Register all tools this.registerTools(); // Set up request handlers this.setupHandlers(); console.log(`[ByteBot MCP] Server initialized: ${config.serverName}`); } /** * Register all available tools */ private registerTools(): void { this.tools = [ ...getAgentTools(), ...getDesktopTools(), ...getHybridTools(), ] as Tool[]; console.log(`[ByteBot MCP] Registered ${this.tools.length} tools`); } /** * Set up MCP request handlers */ private setupHandlers(): void { // List tools handler this.server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: this.tools, }; }); // Call tool handler this.server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; console.log(`[ByteBot MCP] Tool called: ${name}`); try { // Route to appropriate handler based on tool name prefix if (name.startsWith('bytebot_create_and_monitor') || name.startsWith('bytebot_intervene') || name.startsWith('bytebot_execute_workflow') || name.startsWith('bytebot_monitor_task')) { return await handleHybridTool(name, args || {}, this.orchestrator); } else if ( name.startsWith('bytebot_create_task') || name.startsWith('bytebot_list_tasks') || name.startsWith('bytebot_get_task') || name.startsWith('bytebot_get_in_progress') || name.startsWith('bytebot_update_task') || name.startsWith('bytebot_delete_task') ) { return await handleAgentTool(name, args || {}, this.agentClient); } else { return await handleDesktopTool(name, args || {}, this.desktopClient); } } catch (error) { console.error(`[ByteBot MCP] Error handling tool ${name}:`, error); throw error; } }); } /** * Start the MCP server */ async start(): Promise<void> { console.log('[ByteBot MCP] Starting server...'); // Perform health checks const health = await this.healthCheck(); if (!health.agentApi) { console.warn('[ByteBot MCP] Warning: Agent API health check failed'); console.warn( `[ByteBot MCP] Make sure ByteBot is running at ${this.config.agentUrl}` ); } if (!health.desktopApi) { console.warn('[ByteBot MCP] Warning: Desktop API health check failed'); console.warn( `[ByteBot MCP] Make sure ByteBot is running at ${this.config.desktopUrl}` ); } // Connect WebSocket if enabled if (this.wsClient) { try { await this.wsClient.connect(); console.log('[ByteBot MCP] WebSocket connected'); // Subscribe to all task updates this.wsClient.subscribeToAllTasks(); } catch (error) { console.warn( '[ByteBot MCP] WebSocket connection failed. Falling back to polling:', error ); } } // Start stdio transport const transport = new StdioServerTransport(); await this.server.connect(transport); console.log('[ByteBot MCP] Server started on stdio transport'); console.log('[ByteBot MCP] Ready to accept MCP requests'); } /** * Stop the MCP server */ async stop(): Promise<void> { console.log('[ByteBot MCP] Stopping server...'); // Disconnect WebSocket if (this.wsClient) { this.wsClient.disconnect(); } // Clear caches this.agentClient.clearCache(); await this.server.close(); console.log('[ByteBot MCP] Server stopped'); } /** * Health check for all ByteBot endpoints */ async healthCheck(): Promise<HealthCheckResult> { const result: HealthCheckResult = { agentApi: false, desktopApi: false, timestamp: new Date().toISOString(), errors: [], }; // Check Agent API try { result.agentApi = await this.agentClient.healthCheck(); } catch (error) { result.errors.push( `Agent API: ${error instanceof Error ? error.message : String(error)}` ); } // Check Desktop API try { result.desktopApi = await this.desktopClient.healthCheck(); } catch (error) { result.errors.push( `Desktop API: ${error instanceof Error ? error.message : String(error)}` ); } // Check WebSocket if enabled if (this.wsClient) { result.webSocket = this.wsClient.isConnected(); } return result; } /** * Get server statistics */ getStats() { return { serverName: this.config.serverName, toolsRegistered: this.tools.length, agentApiUrl: this.config.agentUrl, desktopApiUrl: this.config.desktopUrl, webSocketEnabled: this.config.enableWebSocket, webSocketConnected: this.wsClient?.isConnected() || false, }; } }

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/sensuslab/spark-mcp'

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