@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
JavaScript
/**
* 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