first
This commit is contained in:
423
update-mcp-documentation.js
Normal file
423
update-mcp-documentation.js
Normal file
@@ -0,0 +1,423 @@
|
||||
#!/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 };
|
Reference in New Issue
Block a user