424 lines
12 KiB
JavaScript
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 };
|