Files
mcp-tool/update-mcp-documentation.js
nasir@endelospay.com 8c74b0e23f first
2025-07-11 20:22:12 +05:00

424 lines
12 KiB
JavaScript

#!/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 };