UNPKG

cursor-background-agent-mcp-server

Version:

MCP Server for Cursor Background Agents API - run autonomous coding agents from any MCP client

223 lines 8.17 kB
#!/usr/bin/env node "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.MCPStdioServer = void 0; const process_1 = require("process"); const cursorApiClient_1 = require("./infrastructure/cursorApiClient"); const toolExecutionService_1 = require("./application/toolExecutionService"); const toolInvocationController_1 = require("./presentation/toolInvocationController"); const manifestController_1 = require("./presentation/manifestController"); const toolInvocationController_2 = require("./presentation/toolInvocationController"); const resourceAccessController_1 = require("./presentation/resourceAccessController"); const errors_1 = require("./domain/errors"); class MCPStdioServer { constructor() { this.initialized = false; this.setupDependencies(); this.setupStdio(); } setupDependencies() { const apiKey = process.env.CURSOR_API_KEY; if (!apiKey) { this.writeError('CURSOR_API_KEY environment variable is required'); process.exit(1); } const cursorClient = new cursorApiClient_1.HttpCursorApiClient(apiKey); const toolExecutionService = new toolExecutionService_1.CursorToolExecutionService(cursorClient); (0, toolInvocationController_1.setToolExecutor)(toolExecutionService); } setupStdio() { let buffer = ''; process_1.stdin.setEncoding('utf8'); process_1.stdin.on('data', (chunk) => { buffer += chunk; const messages = buffer.split('\n'); buffer = messages.pop() || ''; messages.forEach(message => { if (message.trim()) { this.handleMessage(message.trim()); } }); }); process_1.stdin.on('end', () => { process.exit(0); }); process.on('SIGTERM', () => { process.exit(0); }); process.on('SIGINT', () => { process.exit(0); }); } async handleMessage(message) { try { const request = JSON.parse(message); if (!request.jsonrpc || request.jsonrpc !== '2.0') { this.sendError(request.id, -32600, 'Invalid Request', 'Invalid JSON-RPC version'); return; } await this.processRequest(request); } catch (error) { this.sendError(undefined, -32700, 'Parse error', 'Invalid JSON'); } } async processRequest(request) { try { switch (request.method) { case 'initialize': await this.handleInitialize(request); break; case 'initialized': this.handleInitialized(request); break; case 'tools/list': await this.handleToolsList(request); break; case 'tools/call': await this.handleToolCall(request); break; case 'resources/list': await this.handleResourcesList(request); break; case 'resources/read': await this.handleResourceRead(request); break; case 'ping': this.sendResponse(request.id, {}); break; default: this.sendError(request.id, -32601, 'Method not found', `Unknown method: ${request.method}`); } } catch (error) { const errorResponse = (0, errors_1.createMCPErrorResponse)(error); this.sendError(request.id, -32603, 'Internal error', errorResponse.error); } } async handleInitialize(request) { const { params } = request; this.sendResponse(request.id, { protocolVersion: '2024-11-05', capabilities: { tools: {}, resources: {} }, serverInfo: { name: 'cursor-background-agents-mcp', version: '1.0.0' } }); } handleInitialized(request) { this.initialized = true; } async handleToolsList(request) { try { const manifest = (await (0, manifestController_1.getManifest)()); const tools = manifest.tools.map(tool => ({ name: tool.name, description: tool.description, inputSchema: tool.inputSchema })); this.sendResponse(request.id, { tools }); } catch (error) { const errorResponse = (0, errors_1.createMCPErrorResponse)(error); this.sendError(request.id, -32603, 'Failed to list tools', errorResponse.error); } } async handleToolCall(request) { try { const { name, arguments: args } = request.params; if (!name || typeof name !== 'string') { this.sendError(request.id, -32602, 'Invalid params', 'Tool name is required'); return; } const result = await (0, toolInvocationController_2.invokeTool)(name, args || {}); this.sendResponse(request.id, { content: [ { type: 'text', text: JSON.stringify(result, null, 2) } ] }); } catch (error) { const errorResponse = (0, errors_1.createMCPErrorResponse)(error); this.sendError(request.id, -32603, 'Tool execution failed', errorResponse.error); } } async handleResourcesList(request) { try { const manifest = (await (0, manifestController_1.getManifest)()); const resources = manifest.resources.map(resource => ({ uri: `cursor://${resource.name}`, name: resource.name, description: resource.description, mimeType: 'application/json' })); this.sendResponse(request.id, { resources }); } catch (error) { const errorResponse = (0, errors_1.createMCPErrorResponse)(error); this.sendError(request.id, -32603, 'Failed to list resources', errorResponse.error); } } async handleResourceRead(request) { try { const { uri } = request.params; if (!uri || typeof uri !== 'string') { this.sendError(request.id, -32602, 'Invalid params', 'Resource URI is required'); return; } const resourceName = uri.replace('cursor://', ''); const result = await (0, resourceAccessController_1.accessResource)(resourceName); this.sendResponse(request.id, { contents: [ { uri, mimeType: 'application/json', text: JSON.stringify(result, null, 2) } ] }); } catch (error) { const errorResponse = (0, errors_1.createMCPErrorResponse)(error); this.sendError(request.id, -32603, 'Failed to read resource', errorResponse.error); } } sendResponse(id, result) { const response = { jsonrpc: '2.0', id, result }; this.writeMessage(JSON.stringify(response)); } sendError(id, code, message, data) { const response = { jsonrpc: '2.0', id, error: { code, message, data } }; this.writeMessage(JSON.stringify(response)); } writeMessage(message) { process_1.stdout.write(message + '\n'); } writeError(message) { process_1.stderr.write(`Error: ${message}\n`); } } exports.MCPStdioServer = MCPStdioServer; if (require.main === module) { new MCPStdioServer(); } //# sourceMappingURL=mcpStdioServer.js.map