UNPKG

osc-mcp-server

Version:

Model Context Protocol server for OSC (Open Sound Control) endpoint management

306 lines 13.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.OSCMCPServer = void 0; const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js"); const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js"); const types_js_1 = require("@modelcontextprotocol/sdk/types.js"); const manager_1 = require("./osc/manager"); const validation_1 = require("./errors/validation"); const index_1 = require("./errors/index"); class OSCMCPServer { server; oscManager; isRunning = false; constructor() { this.server = new index_js_1.Server({ name: 'osc-mcp-server', version: '1.0.0', }); this.oscManager = (0, manager_1.createOSCManager)(); this.setupToolHandlers(); this.setupEventHandlers(); } async start() { if (this.isRunning) { throw new Error('Server is already running'); } try { const transport = new stdio_js_1.StdioServerTransport(); await this.server.connect(transport); this.isRunning = true; console.error('OSC MCP Server started successfully'); } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; throw new Error(`Failed to start MCP server: ${errorMessage}`); } } async shutdown() { if (!this.isRunning) { return; } try { await this.oscManager.shutdown(); await this.server.close(); console.error('OSC MCP Server shut down successfully'); } catch (error) { console.error('Error during server shutdown:', error); } finally { this.isRunning = false; } } setupToolHandlers() { this.server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => { return { tools: [ { name: 'create_osc_endpoint', description: 'Create a new OSC endpoint to listen for incoming OSC messages', inputSchema: { type: 'object', properties: { port: { type: 'number', description: 'UDP port number to listen on (1024-65535)', minimum: 1024, maximum: 65535, }, bufferSize: { type: 'number', description: 'Maximum number of messages to store in buffer (default: 1000)', minimum: 1, maximum: 10000, default: 1000, }, addressFilters: { type: 'array', description: 'OSC address patterns to filter messages (optional)', items: { type: 'string', }, }, }, required: ['port'], }, }, { name: 'stop_osc_endpoint', description: 'Stop and remove an existing OSC endpoint', inputSchema: { type: 'object', properties: { endpointId: { type: 'string', description: 'ID of the endpoint to stop', }, }, required: ['endpointId'], }, }, { name: 'get_osc_messages', description: 'Query received OSC messages from endpoints', inputSchema: { type: 'object', properties: { endpointId: { type: 'string', description: 'Optional endpoint ID to query (if not provided, queries all endpoints)', }, addressPattern: { type: 'string', description: 'Optional OSC address pattern to filter messages', }, timeWindowSeconds: { type: 'number', description: 'Optional time window in seconds (from now backwards)', minimum: 1, }, limit: { type: 'number', description: 'Optional maximum number of messages to return', minimum: 1, maximum: 1000, }, }, required: [], }, }, { name: 'get_endpoint_status', description: 'Get status information for OSC endpoints', inputSchema: { type: 'object', properties: { endpointId: { type: 'string', description: 'Optional endpoint ID (if not provided, returns all endpoints)', }, }, required: [], }, }, ], }; }); this.server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { switch (name) { case 'create_osc_endpoint': return await this.handleCreateEndpoint(args); case 'stop_osc_endpoint': return await this.handleStopEndpoint(args); case 'get_osc_messages': return await this.handleGetMessages(args); case 'get_endpoint_status': return await this.handleGetEndpointStatus(args); default: throw new types_js_1.McpError(types_js_1.ErrorCode.MethodNotFound, `Unknown tool: ${name}`); } } catch (error) { if (error instanceof types_js_1.McpError) { throw error; } const errorMessage = error instanceof Error ? error.message : 'Unknown error'; throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, `Tool execution failed: ${errorMessage}`); } }); } setupEventHandlers() { this.oscManager.on('endpointCreated', endpointInfo => { console.error(`Endpoint created: ${endpointInfo.id} on port ${endpointInfo.port}`); }); this.oscManager.on('endpointStopped', endpointId => { console.error(`Endpoint stopped: ${endpointId}`); }); this.oscManager.on('endpointError', (endpointId, error) => { console.error(`Endpoint error (${endpointId}):`, error); }); this.oscManager.on('messageReceived', (endpointId, message) => { console.error(`Message received on ${endpointId}: ${message.address}`); }); } async handleCreateEndpoint(params) { const validation = validation_1.ParameterValidator.validateCreateEndpoint(params); if (!validation.isValid) { throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidParams, validation.error.message, validation.error.details); } const config = { port: params.port, bufferSize: params.bufferSize || 1000, addressFilters: params.addressFilters || [], }; try { const response = await this.oscManager.createEndpoint(config); if (response.status === 'error') { throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, response.message); } return { content: [ { type: 'text', text: JSON.stringify(response, null, 2), }, ], }; } catch (error) { if (error instanceof types_js_1.McpError) { throw error; } const oscError = index_1.OperationErrors.operationFailed('create_osc_endpoint', error instanceof Error ? error.message : 'Unknown error'); throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, oscError.message, oscError.details); } } async handleStopEndpoint(params) { const validation = validation_1.ParameterValidator.validateStopEndpoint(params); if (!validation.isValid) { throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidParams, validation.error.message, validation.error.details); } try { const response = await this.oscManager.stopEndpoint(params.endpointId); return { content: [ { type: 'text', text: JSON.stringify(response, null, 2), }, ], }; } catch (error) { const oscError = index_1.OperationErrors.operationFailed('stop_osc_endpoint', error instanceof Error ? error.message : 'Unknown error'); throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, oscError.message, oscError.details); } } async handleGetMessages(params) { const validation = validation_1.ParameterValidator.validateGetMessages(params); if (!validation.isValid) { throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidParams, validation.error.message, validation.error.details); } try { const query = {}; if (params.addressPattern) { query.addressPattern = params.addressPattern; } if (params.timeWindowSeconds) { query.since = new Date(Date.now() - params.timeWindowSeconds * 1000); } if (params.limit) { query.limit = params.limit; } const response = this.oscManager.getMessages(params.endpointId, query); return { content: [ { type: 'text', text: JSON.stringify(response, this.dateReplacer, 2), }, ], }; } catch (error) { const oscError = index_1.OperationErrors.operationFailed('get_osc_messages', error instanceof Error ? error.message : 'Unknown error'); throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, oscError.message, oscError.details); } } async handleGetEndpointStatus(params) { const validation = validation_1.ParameterValidator.validateGetEndpointStatus(params); if (!validation.isValid) { throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidParams, validation.error.message, validation.error.details); } try { const response = this.oscManager.getEndpointStatus(params.endpointId); return { content: [ { type: 'text', text: JSON.stringify(response, this.dateReplacer, 2), }, ], }; } catch (error) { const oscError = index_1.OperationErrors.operationFailed('get_endpoint_status', error instanceof Error ? error.message : 'Unknown error'); throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, oscError.message, oscError.details); } } isServerRunning() { return this.isRunning; } getOSCManager() { return this.oscManager; } dateReplacer(_key, value) { if (value instanceof Date) { return value.toISOString(); } return value; } } exports.OSCMCPServer = OSCMCPServer; //# sourceMappingURL=server.js.map