Skip to main content
Glama
unified-server.js5.89 kB
#!/usr/bin/env node import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { randomUUID } from "node:crypto"; import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; import { ToolRegistry } from "./registry/tool-registry.js"; import { SessionManager } from "./state/SessionManager.js"; import { instrumentServer, } from "@shinzolabs/instrumentation-mcp"; // Lazy tool module map (single unified tool) const TOOL_MODULES = { unifiedreasoning: () => import("./tools/unified-reasoning.js"), }; export class ClearThoughtUnifiedServer { mcpServer; sessionManager; toolRegistry; options; constructor(options = {}) { this.options = { transport: options.transport || this.detectTransport(), port: options.port || parseInt(process.env.PORT || "3000"), config: options.config, }; this.toolRegistry = ToolRegistry.getInstance(); this.sessionManager = new SessionManager(this.options.config); // Create MCP server this.mcpServer = new Server({ name: "clear-thought", version: "1.0.0", }, { capabilities: { tools: {}, }, }); // Use TelemetryConfig to set configuration options const telemetryConfig = { serverName: "clear-thought", serverVersion: "1.0.0", exporterEndpoint: process.env.OTEL_EXPORTER_OTLP_ENDPOINT || "http://localhost:4318/v1", // OpenTelemetry collector endpoint - /trace and /metrics are added automatically exporterAuth: process.env.OTEL_AUTH_TOKEN ? { type: "bearer", token: process.env.OTEL_AUTH_TOKEN } : undefined, samplingRate: parseFloat(process.env.OTEL_SAMPLING_RATE || "1.0"), enableArgumentCollection: true // Enable argument collection for telemetry }; // Initialize telemetry const telemetry = instrumentServer(this.mcpServer, telemetryConfig); // Setup handlers this.setupHandlers(); } detectTransport() { // Prefer stdio by default; only use HTTP when explicitly requested if (process.env.TRANSPORT === "http") { return "http"; } return "stdio"; } setupHandlers() { // Tool execution handler - unified for all tools (lazy-load per call) this.mcpServer.setRequestHandler(CallToolRequestSchema, async (request) => { // 1. Check tool arguments for sessionId first (client-provided) const toolSessionId = request.params.arguments?.sessionId; // 2. Fall back to generating new session if not provided const sessionId = (typeof toolSessionId === "string" && toolSessionId) || randomUUID(); // 3. Get or create session (existing logic) const session = this.sessionManager.getOrCreateSession(sessionId); // Ensure the requested tool's module is loaded (self-registers on import) const toolName = request.params.name; const loader = TOOL_MODULES[toolName]; if (loader && !this.toolRegistry.has(toolName)) { await loader(); } // 4. Execute through registry const result = await this.toolRegistry.execute(request.params.name, request.params.arguments, session.state); // 5. Inject sessionId into response content for client continuation return { ...result, content: result.content.map((item) => { if (item.type === "text") { const data = JSON.parse(item.text); data.sessionContext = { ...data.sessionContext, sessionId: sessionId, // Ensure sessionId is always returned continuationInstructions: `To continue this reasoning session, include "sessionId": "${sessionId}" in your next tool call`, }; return { ...item, text: JSON.stringify(data) }; } return item; }), }; }); // List tools from registry (lazy-load modules at list time) this.mcpServer.setRequestHandler(ListToolsRequestSchema, async () => { // Load all tool modules so schemas are available to list await Promise.all(Object.values(TOOL_MODULES).map((fn) => fn())); return { tools: this.toolRegistry.toMCPTools() }; }); } async start() { switch (this.options.transport) { case "stdio": await this.startStdio(); break; case "http": // For HTTP, return the MCP server and let the host environment provide the HTTP transport return this.mcpServer; } } async startStdio() { const transport = new StdioServerTransport(); await this.mcpServer.connect(transport); console.error("Clear Thought MCP Server (stdio) started"); } // For Smithery export getMcpServer() { return this.mcpServer; } } // Factory function for different environments export default function createServer(options) { const server = new ClearThoughtUnifiedServer(options); return server; } // Auto-start if main module if (process.argv[1]?.endsWith("unified-server.ts") || process.argv[1]?.endsWith("unified-server.js")) { const server = createServer(); server.start().catch((error) => { console.error("Failed to start server:", error); process.exit(1); }); } //# sourceMappingURL=unified-server.js.map

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/waldzellai/clearthought-onepointfive'

If you have feedback or need assistance with the MCP directory API, please join our Discord server