UNPKG

mongodb-memory-bank-mcp

Version:

FIXED: MongoDB Memory Bank MCP with bulletproof error handling, smart operations, and session state management. Eliminates [object Object] errors and user confusion.

126 lines (125 loc) 4.84 kB
import { serializeError } from "../helpers/serialize-error.js"; import { getProjectName } from "../../../../shared/services/project-context-manager.js"; /** * Intelligently serializes response body for MCP protocol * - Strings: returned as-is * - String arrays: joined with newlines for readability * - Complex objects/arrays: JSON stringified * - null/undefined: empty string */ const serializeResponseBody = (body) => { if (body === null || body === undefined) { return ""; } // Handle strings directly (most common case for memory bank) if (typeof body === "string") { return body; } // Handle string arrays (like original list_projects, list_project_files) if (Array.isArray(body) && body.every(item => typeof item === "string")) { return body.join("\n"); } // Handle complex objects and arrays (MongoDB enhanced features) return JSON.stringify(body, null, 2); }; /** * Universal MCP request adapter with multi-signal project detection * Implements universal project detection following MCP patterns and MongoDB best practices * Based on research from alioshr/memory-bank-mcp and MongoDB official MCP server */ export const adaptUniversalMcpRequestHandler = async (controller) => { return async (request) => { const { params } = request; let body = params?.arguments; try { // CRITICAL FIX: Use workingDirectory parameter if provided let projectName; // Check if project name is already provided in the request if (body && typeof body === 'object' && 'projectName' in body && body.projectName) { projectName = body.projectName; } else { // Use workingDirectory parameter if provided for project detection const workingDirectory = body && typeof body === 'object' && 'workingDirectory' in body ? body.workingDirectory : undefined; console.log(`[MCP-ADAPTER] Request body:`, JSON.stringify(body)); console.log(`[MCP-ADAPTER] Extracted workingDirectory: "${workingDirectory}"`); // Use master project context manager for 100% consistency console.log(`[MCP-ADAPTER] Using master project context manager`); projectName = await getProjectName(workingDirectory); } // Inject or override project name with detected value body = { ...(body || {}), projectName }; } catch (error) { console.error(`[UNIVERSAL-ADAPTER] Error detecting project:`, error); // Return error following MCP patterns return { tools: [], isError: true, content: [ { type: "text", text: JSON.stringify(serializeError(error)), }, ], }; } const response = await controller.handle({ body, }); const isError = response.statusCode < 200 || response.statusCode >= 300; return { tools: [], isError, content: [ { type: "text", text: isError ? JSON.stringify(serializeError(response.body)) : serializeResponseBody(response.body), }, ], }; }; }; /** * Path-based adapter (LEGACY - use adaptUniversalMcpRequestHandler) * Kept for backward compatibility during transition */ export const adaptPathBasedMcpRequestHandler = adaptUniversalMcpRequestHandler; /** * Project-aware adapter (LEGACY - use adaptUniversalMcpRequestHandler) * Kept for backward compatibility during transition */ export const adaptProjectAwareMcpRequestHandler = adaptUniversalMcpRequestHandler; /** * Standard MCP request adapter (without project detection) * Used for operations that don't involve project names (like list_projects) */ export const adaptMcpRequestHandler = async (controller) => { return async (request) => { const { params } = request; const body = params?.arguments; const response = await controller.handle({ body, }); const isError = response.statusCode < 200 || response.statusCode >= 300; return { tools: [], isError, content: [ { type: "text", text: isError ? JSON.stringify(serializeError(response.body)) : serializeResponseBody(response.body), }, ], }; }; };