UNPKG

@compligent-mcp/nice

Version:

Compligent MCP Client - NIST NICE Framework (SP 800-181 Rev 2) (connects to hosted compliance database)

196 lines • 8.16 kB
#!/usr/bin/env node /** * Compligent MCP Client - NIST NICE Framework * * This is a thin client that connects to the hosted NICE Framework service * on Railway, providing all 20 tools through the MCP protocol for SP 800-181 Rev 2. */ import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { CallToolRequestSchema, ListToolsRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema } from "@modelcontextprotocol/sdk/types.js"; import axios, { AxiosError } from "axios"; // Configuration const HOSTED_SERVICE_URL = "https://nice-mcp-server-production.up.railway.app"; const CLIENT_VERSION = "2.0.0"; const API_TIMEOUT = 30000; // 30 seconds class NICEClient { server; requestId = 1; constructor() { this.server = new Server({ name: "@compligent-mcp/nice", version: CLIENT_VERSION, }, { capabilities: { tools: {}, prompts: {}, }, }); this.setupHandlers(); } setupHandlers() { // List tools - proxy to hosted service this.server.setRequestHandler(ListToolsRequestSchema, async () => { try { const response = await this.proxyRequest({ jsonrpc: "2.0", method: "tools/list", id: this.requestId++, }); return { tools: response.result?.tools || [], }; } catch (error) { console.error("Failed to list tools:", error); return { tools: [] }; } }); // Call tool - proxy to hosted service this.server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { const response = await this.proxyRequest({ jsonrpc: "2.0", method: "tools/call", params: { name, arguments: args || {}, }, id: this.requestId++, }); if (response.error) { throw new Error(`Tool execution failed: ${response.error.message}`); } return response.result; } catch (error) { console.error(`Failed to call tool ${name}:`, error); // Return a user-friendly error message return { content: [ { type: "text", text: `Error: Unable to connect to NICE Framework service. Please check your internet connection and try again.\n\nTechnical details: ${error instanceof Error ? error.message : 'Unknown error'}`, }, ], }; } }); // List prompts - proxy to hosted service this.server.setRequestHandler(ListPromptsRequestSchema, async () => { try { const response = await this.proxyRequest({ jsonrpc: "2.0", method: "prompts/list", id: this.requestId++, }); return { prompts: response.result?.prompts || [], }; } catch (error) { console.error("Failed to list prompts:", error); return { prompts: [] }; } }); // Get prompt - proxy to hosted service this.server.setRequestHandler(GetPromptRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { const response = await this.proxyRequest({ jsonrpc: "2.0", method: "prompts/get", params: { name, arguments: args || {}, }, id: this.requestId++, }); if (response.error) { throw new Error(`Prompt execution failed: ${response.error.message}`); } return response.result; } catch (error) { console.error(`Failed to get prompt ${name}:`, error); // Return a user-friendly error message return { description: `Error: Unable to connect to NICE Framework service. Please check your internet connection and try again.`, messages: [ { role: "assistant", content: { type: "text", text: `Technical details: ${error instanceof Error ? error.message : 'Unknown error'}`, }, }, ], }; } }); } async proxyRequest(mcpRequest) { try { // For MCP protocol, we need to send the request via stdio to the hosted service // Since the hosted service expects MCP protocol over HTTP, we'll use the /mcp endpoint const response = await axios.post(`${HOSTED_SERVICE_URL}/mcp`, mcpRequest, { headers: { "Content-Type": "application/json", "Accept": "application/json, text/event-stream", "User-Agent": `@compligent-mcp/nice/${CLIENT_VERSION}`, // Add authentication header if API key is provided ...(process.env.COMPLIGENT_API_KEY && { Authorization: `Bearer ${process.env.COMPLIGENT_API_KEY}`, }), }, timeout: API_TIMEOUT, }); return response.data; } catch (error) { if (error instanceof AxiosError) { if (error.code === "ECONNREFUSED" || error.code === "ENOTFOUND") { throw new Error("Unable to connect to Compligent NICE Framework service. Please check your internet connection."); } if (error.response?.status === 401) { throw new Error("Authentication failed. Please check your COMPLIGENT_API_KEY environment variable."); } if (error.response?.status === 429) { throw new Error("Rate limit exceeded. Please try again later."); } throw new Error(`Service error (${error.response?.status || error.code}): ${error.message}`); } throw error; } } async start() { const transport = new StdioServerTransport(); await this.server.connect(transport); // Log startup info to stderr (won't interfere with MCP protocol on stdout) console.error(`šŸš€ Compligent NICE Framework MCP Client v${CLIENT_VERSION}`); console.error(` Connected to: ${HOSTED_SERVICE_URL}`); console.error(` Ready to serve 20 tools + 17 prompts via MCP protocol`); console.error(` ${process.env.COMPLIGENT_API_KEY ? "āœ“" : "⚠"} ${process.env.COMPLIGENT_API_KEY ? "Authenticated" : "Running without API key"}`); } } // Error handling process.on("SIGINT", async () => { console.error("\nšŸ‘‹ Shutting down Compligent NICE Framework client..."); process.exit(0); }); process.on("uncaughtException", (error) => { console.error("šŸ’„ Uncaught Exception:", error); process.exit(1); }); process.on("unhandledRejection", (reason) => { console.error("šŸ’„ Unhandled Rejection:", reason); process.exit(1); }); // Start the client const client = new NICEClient(); client.start().catch((error) => { console.error("Failed to start NICE Framework client:", error); process.exit(1); }); //# sourceMappingURL=index.js.map