#!/usr/bin/env node /** * Update MCP Tools Documentation Script * Generates complete MCP-TOOLS-REFERENCE.md with all tools and exact parameter details */ import fs from "fs"; import path from "path"; /** * Load endpoints from configuration */ function loadEndpoints() { try { const endpointsPath = path.join(process.cwd(), "src/config/endpoints.js"); const endpointsContent = fs.readFileSync(endpointsPath, "utf8"); // Extract endpoint arrays const endpoints = { PUBLIC: extractEndpointArray(endpointsContent, "PUBLIC_ENDPOINTS"), PROVIDER: extractEndpointArray(endpointsContent, "PROVIDER_ENDPOINTS"), PATIENT: extractEndpointArray(endpointsContent, "PATIENT_ENDPOINTS"), PARTNER: extractEndpointArray(endpointsContent, "PARTNER_ENDPOINTS"), AFFILIATE: extractEndpointArray(endpointsContent, "AFFILIATE_ENDPOINTS"), NETWORK: extractEndpointArray(endpointsContent, "NETWORK_ENDPOINTS"), }; return endpoints; } catch (error) { console.error("❌ Error loading endpoints:", error.message); process.exit(1); } } /** * Extract endpoint array from configuration text */ function extractEndpointArray(content, arrayName) { const regex = new RegExp( `export const ${arrayName} = \\[([\\s\\S]*?)\\];`, "g" ); const match = regex.exec(content); if (!match) { console.warn(`⚠️ Could not find ${arrayName} in configuration`); return []; } const arrayContent = match[1]; const endpoints = []; // Split array content by endpoint objects more carefully const endpointBlocks = []; let braceCount = 0; let currentBlock = ""; let inEndpoint = false; for (let i = 0; i < arrayContent.length; i++) { const char = arrayContent[i]; if (char === "{") { if (braceCount === 0) { inEndpoint = true; currentBlock = ""; } braceCount++; } if (inEndpoint) { currentBlock += char; } if (char === "}") { braceCount--; if (braceCount === 0 && inEndpoint) { endpointBlocks.push(currentBlock); inEndpoint = false; currentBlock = ""; } } } // Process each endpoint block endpointBlocks.forEach((block) => { if (!block.includes("path:")) return; // Extract path const pathMatch = block.match(/path:\s*["']([^"']+)["']/); if (!pathMatch) return; // Extract method const methodMatch = block.match(/method:\s*["']([^"']+)["']/); if (!methodMatch) return; // Extract description const descMatch = block.match(/description:\s*["']([^"']*?)["']/); const description = descMatch ? descMatch[1].trim() : "No description"; // Extract parameters - look for the parameters object with proper brace matching let parameters = []; const paramStartMatch = block.match(/parameters:\s*\{/); if (paramStartMatch) { const startIndex = paramStartMatch.index + paramStartMatch[0].length; let braceCount = 1; let endIndex = startIndex; for (let i = startIndex; i < block.length && braceCount > 0; i++) { if (block[i] === "{") braceCount++; if (block[i] === "}") braceCount--; endIndex = i; } const parametersText = block.slice(startIndex, endIndex); parameters = extractParameters(parametersText); } endpoints.push({ path: pathMatch[1].trim(), method: methodMatch[1].trim().toUpperCase(), description, parameters, }); }); return endpoints; } /** * Extract parameters from parameter object text */ function extractParameters(parametersText) { const parameters = []; if (!parametersText || parametersText.trim() === "") { return parameters; } // More robust parameter extraction - handle nested braces properly let braceCount = 0; let currentParam = ""; let paramName = ""; let inParam = false; for (let i = 0; i < parametersText.length; i++) { const char = parametersText[i]; // Look for parameter name followed by colon if (!inParam && /\w/.test(char)) { const remaining = parametersText.slice(i); const paramMatch = remaining.match(/^(\w+):\s*\{/); if (paramMatch) { paramName = paramMatch[1]; i += paramMatch[0].length - 1; // Skip to opening brace inParam = true; braceCount = 1; currentParam = ""; continue; } } if (inParam) { if (char === "{") braceCount++; if (char === "}") braceCount--; if (braceCount > 0) { currentParam += char; } else { // End of parameter, extract details const typeMatch = currentParam.match(/type:\s*["']([^"']+)["']/); const type = typeMatch ? typeMatch[1] : "string"; const requiredMatch = currentParam.match(/required:\s*(true|false)/); const required = requiredMatch ? requiredMatch[1] === "true" : false; const descMatch = currentParam.match( /description:\s*["']([^"']*?)["']/ ); const description = descMatch ? descMatch[1] : ""; parameters.push({ name: paramName.trim(), type: type.trim(), required, description: description.trim(), }); inParam = false; currentParam = ""; paramName = ""; } } } return parameters; } /** * Generate tool name from endpoint (matching ToolGenerator logic) */ function generateToolName(authType, method, path) { // Convert HTTP method to action (matching ToolGenerator._getActionFromMethod) const actions = { GET: "get", POST: "create", PUT: "update", PATCH: "update", DELETE: "delete", ANY: "manage", }; const action = actions[method.toUpperCase()] || "call"; // Convert path to resource name (matching ToolGenerator._getResourceFromPath) const resource = path .replace(/^\/api\//, "") .replace(/\{[^}]+\}/g, "id") .replace(/[\/\-]/g, "_") .replace(/[^a-zA-Z0-9_]/g, "") .toLowerCase(); if (authType === "PUBLIC") { return `public_${action}_${resource}`; } return `${authType.toLowerCase()}_${action}_${resource}`; } /** * Format parameters for documentation */ function formatParameters(parameters) { if (!parameters || parameters.length === 0) { return "No parameters"; } const required = parameters.filter((p) => p.required); const optional = parameters.filter((p) => !p.required); let result = ""; if (required.length > 0) { result += "**Required:** " + required.map((p) => `${p.name} (${p.type})`).join(", "); } if (optional.length > 0) { if (result) result += ", "; result += "**Optional:** " + optional.map((p) => `${p.name} (${p.type})`).join(", "); } return result; } /** * Generate documentation section for auth type */ function generateAuthTypeSection(authType, endpoints) { const authTypeNames = { PUBLIC: "Public Tools", PROVIDER: "Provider Tools", PATIENT: "Patient Tools", PARTNER: "Partner Tools", AFFILIATE: "Affiliate Tools", NETWORK: "Network Tools", }; const authDescriptions = { PUBLIC: "No authentication required. These tools handle login, registration, password management, and public data access.", PROVIDER: "Provider authentication required. These tools handle clinical data, EMR operations, and healthcare data requiring HIPAA compliance.", PATIENT: "Patient authentication required. These tools handle patient portal operations and personal health data access.", PARTNER: "Partner authentication required. These tools handle business operations and partner management.", AFFILIATE: "Affiliate authentication required. These tools handle affiliate management and referral operations.", NETWORK: "Network authentication required. These tools handle network operations and multi-partner management.", }; let section = `## ${authTypeNames[authType]} (${endpoints.length} tools)\n\n`; section += `*${authDescriptions[authType]}*\n\n`; section += `| Tool Name | Method | Endpoint | Description | Key Parameters |\n`; section += `| --------- | ------ | -------- | ----------- | -------------- |\n`; endpoints.forEach((endpoint) => { const toolName = generateToolName(authType, endpoint.method, endpoint.path); const parameters = formatParameters(endpoint.parameters); section += `| \`${toolName}\` | ${endpoint.method} | \`${endpoint.path}\` | ${endpoint.description} | ${parameters} |\n`; }); section += "\n---\n\n"; return section; } /** * Generate complete documentation */ function generateDocumentation(endpoints) { const totalTools = Object.values(endpoints).reduce( (sum, arr) => sum + arr.length, 0 ); const currentDate = new Date().toISOString().split("T")[0]; let doc = `# Laravel Healthcare MCP Server - Complete Tools Reference ## Overview This document provides a comprehensive reference for all MCP (Model Context Protocol) tools available in the Laravel Healthcare MCP Server. The server provides **${totalTools}** tools organized by authentication type and functionality (updated ${currentDate}). ## Authentication Types - **PUBLIC**: No authentication required (login, registration, public data) - **PROVIDER**: Provider authentication required (clinical data, EMR operations) - **PATIENT**: Patient authentication required (patient portal operations) - **PARTNER**: Partner authentication required (business operations) - **AFFILIATE**: Affiliate authentication required (affiliate management) - **NETWORK**: Network authentication required (network operations) ## Tool Naming Convention All tools follow the pattern: \`{auth_type}_{method}_{resource}\` - **auth_type**: Authentication type (public, provider, patient, etc.) - **method**: HTTP method (get, post, put, delete) - **resource**: API resource or endpoint identifier --- `; // Generate sections for each auth type const authTypes = [ "PUBLIC", "PROVIDER", "PATIENT", "PARTNER", "AFFILIATE", "NETWORK", ]; authTypes.forEach((authType) => { if (endpoints[authType] && endpoints[authType].length > 0) { doc += generateAuthTypeSection(authType, endpoints[authType]); } }); // Add summary doc += `## Summary | Authentication Type | Tool Count | Coverage | | ------------------- | ---------- | -------- | `; authTypes.forEach((authType) => { const count = endpoints[authType] ? endpoints[authType].length : 0; doc += `| ${authType} | ${count} | 100% |\n`; }); doc += `| **TOTAL** | **${totalTools}** | **100%** | --- *This documentation is automatically generated from the endpoint configuration and provides 100% coverage of all available MCP tools.* `; return doc; } /** * Main function */ function updateDocumentation() { console.log("📚 Updating MCP Tools Documentation...\n"); // Load endpoints console.log("📋 Loading endpoint configuration..."); const endpoints = loadEndpoints(); const totalEndpoints = Object.values(endpoints).reduce( (sum, arr) => sum + arr.length, 0 ); console.log(`✅ Loaded ${totalEndpoints} endpoints\n`); // Generate documentation console.log("📝 Generating documentation..."); const documentation = generateDocumentation(endpoints); // Save documentation const docPath = path.join(process.cwd(), "MCP-TOOLS-REFERENCE.md"); fs.writeFileSync(docPath, documentation); console.log(`✅ Documentation saved to: ${docPath}\n`); // Display summary console.log("📊 DOCUMENTATION SUMMARY:"); Object.keys(endpoints).forEach((authType) => { const count = endpoints[authType].length; console.log(`${authType}: ${count} tools`); }); console.log(`TOTAL: ${totalEndpoints} tools\n`); console.log("✅ Documentation update complete!"); } // Run if called directly if ( process.argv[1] && process.argv[1].endsWith("update-mcp-documentation.js") ) { updateDocumentation(); } export { updateDocumentation };