UNPKG

@cortexguardai/mcp

Version:

A Node.js-based MCP adapter for seamless integration with AI development environments.

236 lines 8.84 kB
import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { ListToolsRequestSchema, CallToolRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema } from '@modelcontextprotocol/sdk/types.js'; import axios from 'axios'; export class MCPServer { server; transport = null; httpClient; config; logger; constructor(config, logger) { this.config = config; this.logger = logger; this.httpClient = axios.create({ baseURL: config.serverUrl, headers: { 'Authorization': `Bearer ${config.authToken}`, 'Content-Type': 'application/json' } }); this.server = new Server({ name: 'cortex-context-mcp', version: '1.0.0' }, { capabilities: { tools: {}, resources: {} } }); // Setup process handlers // process.on('SIGINT', () => this.stop()); // process.on('SIGTERM', () => this.stop()); } /** * Start the MCP server */ async start() { try { // Setup request handlers this.setupHandlers(); // Create transport and connect this.transport = new StdioServerTransport(); await this.server.connect(this.transport); } catch (error) { throw error; } } /** * Stop the MCP server */ async stop() { try { if (this.transport) { await this.transport.close(); this.transport = null; } } catch (error) { throw error; } } registerResources() { if (!this.server) return; // Resources are now handled in setupHandlers() } /** * Setup MCP request handlers */ setupHandlers() { // Handle tools/list requests this.server.setRequestHandler(ListToolsRequestSchema, async () => { const tools = [ { name: 'get_contexts', description: 'Get all contexts for the configured project', inputSchema: { "type": "object", "properties": {}, "additionalProperties": false } }, { name: 'get_file', description: 'Get a specific file from the project context', inputSchema: { "type": "object", "properties": { "file_id": { "type": "string", "description": "File UUID" } }, "required": ["file_id"], "additionalProperties": false } }, { name: 'add_file', description: 'Add a new file to the project context', inputSchema: { "type": "object", "properties": { "filename": { "type": "string", "description": "Name of the file to add" }, "content": { "type": "string", "description": "Content of the file" }, "file_type": { "type": "string", "description": "Logical file type (e.g., javascript, text, json)" } }, "required": ["filename", "content"], "additionalProperties": false } } ]; return { tools }; }); // Handle tools/call requests this.server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; switch (name) { case 'get_contexts': return await this.handleGetContexts(args); case 'get_file': return await this.handleGetFile(args); case 'add_file': return await this.handleAddFile(args); default: throw new Error(`Unknown tool: ${name}`); } }); // Handle resources/list requests this.server.setRequestHandler(ListResourcesRequestSchema, async () => { const resources = [{ uri: `cortex://project/${this.config.projectId}`, name: 'Project Context', description: 'Access to project context files and information', mimeType: 'application/json' }]; return { resources }; }); // Handle resources/read requests this.server.setRequestHandler(ReadResourceRequestSchema, async (request) => { const { uri } = request.params; const projectUri = `cortex://project/${this.config.projectId}`; if (uri !== projectUri) { throw new Error(`Resource '${uri}' not found`); } try { const response = await this.httpClient.get(`/api/mcp/contexts/${this.config.projectId}`); const contexts = response.data?.result?.contexts || response.data?.contexts || response.data; return { contents: [{ uri: uri, text: JSON.stringify(contexts, null, 2) }] }; } catch (error) { throw new Error(`Failed to read resource: ${error?.message || 'unknown error'}`); } }); } registerTools() { // This method is kept for compatibility but tools are now handled in setupHandlers } async handleGetContexts(args) { try { const response = await this.httpClient.get(`/api/mcp/contexts/${this.config.projectId}`); const contexts = response.data?.result?.contexts || []; return { content: [{ type: 'text', text: JSON.stringify(contexts, null, 2) }] }; } catch (error) { this.logger.error('Error getting contexts:', error); return { content: [{ type: 'text', text: `Error getting contexts: ${error instanceof Error ? error.message : 'Unknown error'}` }], isError: true }; } } async handleGetFile({ file_id }) { try { const response = await this.httpClient.get(`/api/mcp/contexts/${this.config.projectId}/files/${file_id}`); const file = response.data?.result?.file || response.data?.file || response.data; const text = typeof file?.content === 'string' ? file.content : JSON.stringify(file, null, 2); return { content: [{ type: 'text', text }] }; } catch (error) { return { content: [{ type: 'text', text: `Error getting file: ${error.message}` }], isError: true }; } } async handleAddFile({ filename, content, file_type }) { try { const payload = { filename, content }; if (file_type) payload.file_type = file_type; const response = await this.httpClient.post(`/api/mcp/contexts/${this.config.projectId}/files`, payload); const created = response.data?.result?.file || response.data?.file || response.data; const fileId = created?.id || 'unknown'; return { content: [{ type: 'text', text: `File added successfully: ${filename} (${fileId})` }] }; } catch (error) { return { content: [{ type: 'text', text: `Error adding file: ${error.message}` }], isError: true }; } } } // Factory function for creating server instances export function createMCPServer(config, logger) { return new MCPServer(config, logger); } //# sourceMappingURL=server.js.map