475 lines
13 KiB
JavaScript
475 lines
13 KiB
JavaScript
/**
|
|
* @fileoverview Final comprehensive parameter accuracy validation and duplicate removal
|
|
* Cross-validate that every API endpoint has a corresponding MCP tool with exactly matching parameters
|
|
* and that documentation accurately reflects all specifications.
|
|
* Also removes duplicate parameters from endpoints.js
|
|
*/
|
|
|
|
import fs from "fs";
|
|
import path from "path";
|
|
|
|
/**
|
|
* Perform final comprehensive parameter validation
|
|
*/
|
|
function finalParameterValidation() {
|
|
try {
|
|
console.log("=== FINAL COMPREHENSIVE PARAMETER ACCURACY VALIDATION ===");
|
|
console.log("");
|
|
|
|
// Read all necessary files
|
|
const apiParametersPath = path.join(
|
|
process.cwd(),
|
|
"complete-api-parameters.json"
|
|
);
|
|
const apiParametersContent = fs.readFileSync(apiParametersPath, "utf8");
|
|
const apiEndpoints = JSON.parse(apiParametersContent);
|
|
|
|
const endpointsConfigPath = path.join(
|
|
process.cwd(),
|
|
"src/config/endpoints.js"
|
|
);
|
|
const endpointsConfigContent = fs.readFileSync(endpointsConfigPath, "utf8");
|
|
|
|
const docPath = path.join(process.cwd(), "MCP-TOOLS-REFERENCE.md");
|
|
const docContent = fs.readFileSync(docPath, "utf8");
|
|
|
|
console.log(`📊 API Endpoints: ${apiEndpoints.length}`);
|
|
console.log("");
|
|
|
|
// Extract tools from configuration
|
|
const configTools = extractToolsFromConfig(endpointsConfigContent);
|
|
console.log(`🔧 Configuration Tools: ${configTools.length}`);
|
|
|
|
// Extract tools from documentation
|
|
const docTools = extractToolsFromDocumentation(docContent);
|
|
console.log(`📚 Documentation Tools: ${docTools.length}`);
|
|
console.log("");
|
|
|
|
// Perform comprehensive validation
|
|
const validationResults = performComprehensiveValidation(
|
|
apiEndpoints,
|
|
configTools,
|
|
docTools
|
|
);
|
|
|
|
// Generate final report
|
|
generateFinalValidationReport(validationResults);
|
|
|
|
// Save validation results
|
|
const validationOutputPath = path.join(
|
|
process.cwd(),
|
|
"final-parameter-validation-results.json"
|
|
);
|
|
fs.writeFileSync(
|
|
validationOutputPath,
|
|
JSON.stringify(validationResults, null, 2)
|
|
);
|
|
|
|
console.log(
|
|
`✅ Final validation completed. Results saved to: ${validationOutputPath}`
|
|
);
|
|
|
|
return validationResults;
|
|
} catch (error) {
|
|
console.error("Error in final parameter validation:", error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Extract tools from configuration
|
|
*/
|
|
function extractToolsFromConfig(configContent) {
|
|
const tools = [];
|
|
|
|
const endpointSections = [
|
|
"PUBLIC_ENDPOINTS",
|
|
"PROVIDER_ENDPOINTS",
|
|
"PATIENT_ENDPOINTS",
|
|
"PARTNER_ENDPOINTS",
|
|
"AFFILIATE_ENDPOINTS",
|
|
"NETWORK_ENDPOINTS",
|
|
];
|
|
|
|
endpointSections.forEach((sectionName) => {
|
|
const authType = sectionName.replace("_ENDPOINTS", "").toLowerCase();
|
|
const sectionRegex = new RegExp(
|
|
`export const ${sectionName}\\s*=\\s*\\[([\\s\\S]*?)\\];`,
|
|
"g"
|
|
);
|
|
const match = sectionRegex.exec(configContent);
|
|
|
|
if (match) {
|
|
const sectionContent = match[1];
|
|
const endpointRegex = /\{[\s\S]*?\}/g;
|
|
let endpointMatch;
|
|
|
|
while ((endpointMatch = endpointRegex.exec(sectionContent)) !== null) {
|
|
const endpointStr = endpointMatch[0];
|
|
|
|
const pathMatch = endpointStr.match(/path:\s*["']([^"']+)["']/);
|
|
const methodMatch = endpointStr.match(/method:\s*["']([^"']+)["']/);
|
|
|
|
if (pathMatch && methodMatch) {
|
|
const tool = {
|
|
authType: authType,
|
|
path: pathMatch[1],
|
|
method: methodMatch[1].toUpperCase(),
|
|
parameters: extractParametersFromEndpoint(endpointStr),
|
|
};
|
|
|
|
tools.push(tool);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
return tools;
|
|
}
|
|
|
|
/**
|
|
* Extract parameters from endpoint string
|
|
*/
|
|
function extractParametersFromEndpoint(endpointStr) {
|
|
const parameters = [];
|
|
|
|
const paramMatch = endpointStr.match(/parameters:\s*\{([\s\S]*?)\}/);
|
|
if (paramMatch) {
|
|
const paramContent = paramMatch[1];
|
|
const paramRegex = /(\w+):\s*\{([^}]+)\}/g;
|
|
let match;
|
|
|
|
while ((match = paramRegex.exec(paramContent)) !== null) {
|
|
const paramName = match[1];
|
|
const paramDef = match[2];
|
|
|
|
const typeMatch = paramDef.match(/type:\s*["']([^"']+)["']/);
|
|
const requiredMatch = paramDef.match(/required:\s*(true|false)/);
|
|
const descMatch = paramDef.match(/description:\s*["']([^"']+)["']/);
|
|
|
|
parameters.push({
|
|
name: paramName,
|
|
type: typeMatch ? typeMatch[1] : "string",
|
|
required: requiredMatch ? requiredMatch[1] === "true" : false,
|
|
description: descMatch ? descMatch[1] : "",
|
|
});
|
|
}
|
|
}
|
|
|
|
return parameters;
|
|
}
|
|
|
|
/**
|
|
* Extract tools from documentation
|
|
*/
|
|
function extractToolsFromDocumentation(docContent) {
|
|
const tools = [];
|
|
|
|
// Extract tool entries from markdown tables
|
|
const toolRegex = /\|\s*`([^`]+)`\s*\|\s*(\w+)\s*\|\s*`([^`]+)`\s*\|/g;
|
|
let match;
|
|
|
|
while ((match = toolRegex.exec(docContent)) !== null) {
|
|
const toolName = match[1];
|
|
const method = match[2];
|
|
const path = match[3];
|
|
|
|
// Determine auth type from tool name
|
|
const authType = toolName.split("_")[0];
|
|
|
|
tools.push({
|
|
name: toolName,
|
|
authType: authType,
|
|
method: method,
|
|
path: path,
|
|
});
|
|
}
|
|
|
|
return tools;
|
|
}
|
|
|
|
/**
|
|
* Perform comprehensive validation
|
|
*/
|
|
function performComprehensiveValidation(apiEndpoints, configTools, docTools) {
|
|
const results = {
|
|
apiEndpointCount: apiEndpoints.length,
|
|
configToolCount: configTools.length,
|
|
docToolCount: docTools.length,
|
|
coverage: {
|
|
apiToConfig: 0,
|
|
configToDoc: 0,
|
|
apiToDoc: 0,
|
|
},
|
|
missingFromConfig: [],
|
|
missingFromDoc: [],
|
|
parameterMismatches: [],
|
|
exactMatches: 0,
|
|
issues: [],
|
|
};
|
|
|
|
// Check API to Config coverage
|
|
apiEndpoints.forEach((apiEndpoint) => {
|
|
const configTool = configTools.find(
|
|
(tool) =>
|
|
tool.path === apiEndpoint.path && tool.method === apiEndpoint.method
|
|
);
|
|
|
|
if (configTool) {
|
|
results.coverage.apiToConfig++;
|
|
|
|
// Validate parameters
|
|
const parameterValidation = validateParameters(apiEndpoint, configTool);
|
|
if (parameterValidation.hasIssues) {
|
|
results.parameterMismatches.push({
|
|
endpoint: `${apiEndpoint.method} ${apiEndpoint.path}`,
|
|
issues: parameterValidation.issues,
|
|
});
|
|
} else {
|
|
results.exactMatches++;
|
|
}
|
|
} else {
|
|
results.missingFromConfig.push({
|
|
path: apiEndpoint.path,
|
|
method: apiEndpoint.method,
|
|
summary: apiEndpoint.summary,
|
|
});
|
|
}
|
|
});
|
|
|
|
// Check Config to Doc coverage
|
|
configTools.forEach((configTool) => {
|
|
const docTool = docTools.find(
|
|
(tool) =>
|
|
tool.path === configTool.path && tool.method === configTool.method
|
|
);
|
|
|
|
if (docTool) {
|
|
results.coverage.configToDoc++;
|
|
} else {
|
|
results.missingFromDoc.push({
|
|
path: configTool.path,
|
|
method: configTool.method,
|
|
authType: configTool.authType,
|
|
});
|
|
}
|
|
});
|
|
|
|
// Check API to Doc coverage
|
|
apiEndpoints.forEach((apiEndpoint) => {
|
|
const docTool = docTools.find(
|
|
(tool) =>
|
|
tool.path === apiEndpoint.path && tool.method === apiEndpoint.method
|
|
);
|
|
|
|
if (docTool) {
|
|
results.coverage.apiToDoc++;
|
|
}
|
|
});
|
|
|
|
// Calculate coverage percentages
|
|
results.coverage.apiToConfigPercent = (
|
|
(results.coverage.apiToConfig / results.apiEndpointCount) *
|
|
100
|
|
).toFixed(1);
|
|
results.coverage.configToDocPercent = (
|
|
(results.coverage.configToDoc / results.configToolCount) *
|
|
100
|
|
).toFixed(1);
|
|
results.coverage.apiToDocPercent = (
|
|
(results.coverage.apiToDoc / results.apiEndpointCount) *
|
|
100
|
|
).toFixed(1);
|
|
|
|
return results;
|
|
}
|
|
|
|
/**
|
|
* Validate parameters between API endpoint and config tool
|
|
*/
|
|
function validateParameters(apiEndpoint, configTool) {
|
|
const validation = {
|
|
hasIssues: false,
|
|
issues: [],
|
|
};
|
|
|
|
// Get all API parameters
|
|
const apiParams = [];
|
|
if (apiEndpoint.parameters?.path)
|
|
apiParams.push(...apiEndpoint.parameters.path);
|
|
if (apiEndpoint.parameters?.query)
|
|
apiParams.push(...apiEndpoint.parameters.query);
|
|
if (apiEndpoint.parameters?.body)
|
|
apiParams.push(...apiEndpoint.parameters.body);
|
|
|
|
const configParams = configTool.parameters || [];
|
|
|
|
// Check for missing parameters in config
|
|
apiParams.forEach((apiParam) => {
|
|
const configParam = configParams.find((cp) => cp.name === apiParam.name);
|
|
if (!configParam) {
|
|
validation.hasIssues = true;
|
|
validation.issues.push({
|
|
type: "missing_in_config",
|
|
parameter: apiParam.name,
|
|
apiType: apiParam.type,
|
|
apiRequired: apiParam.required,
|
|
});
|
|
} else {
|
|
// Check type mismatch
|
|
if (configParam.type !== apiParam.type) {
|
|
validation.hasIssues = true;
|
|
validation.issues.push({
|
|
type: "type_mismatch",
|
|
parameter: apiParam.name,
|
|
apiType: apiParam.type,
|
|
configType: configParam.type,
|
|
});
|
|
}
|
|
|
|
// Check requirement mismatch
|
|
if (configParam.required !== apiParam.required) {
|
|
validation.hasIssues = true;
|
|
validation.issues.push({
|
|
type: "requirement_mismatch",
|
|
parameter: apiParam.name,
|
|
apiRequired: apiParam.required,
|
|
configRequired: configParam.required,
|
|
});
|
|
}
|
|
}
|
|
});
|
|
|
|
// Check for extra parameters in config
|
|
configParams.forEach((configParam) => {
|
|
const apiParam = apiParams.find((ap) => ap.name === configParam.name);
|
|
if (!apiParam) {
|
|
validation.hasIssues = true;
|
|
validation.issues.push({
|
|
type: "extra_in_config",
|
|
parameter: configParam.name,
|
|
configType: configParam.type,
|
|
configRequired: configParam.required,
|
|
});
|
|
}
|
|
});
|
|
|
|
return validation;
|
|
}
|
|
|
|
/**
|
|
* Generate final validation report
|
|
*/
|
|
function generateFinalValidationReport(results) {
|
|
console.log("=== FINAL PARAMETER ACCURACY VALIDATION REPORT ===");
|
|
console.log("");
|
|
|
|
console.log("📊 COVERAGE STATISTICS:");
|
|
console.log(`API Endpoints: ${results.apiEndpointCount}`);
|
|
console.log(`Configuration Tools: ${results.configToolCount}`);
|
|
console.log(`Documentation Tools: ${results.docToolCount}`);
|
|
console.log("");
|
|
|
|
console.log("📈 COVERAGE PERCENTAGES:");
|
|
console.log(
|
|
`API → Configuration: ${results.coverage.apiToConfigPercent}% (${results.coverage.apiToConfig}/${results.apiEndpointCount})`
|
|
);
|
|
console.log(
|
|
`Configuration → Documentation: ${results.coverage.configToDocPercent}% (${results.coverage.configToDoc}/${results.configToolCount})`
|
|
);
|
|
console.log(
|
|
`API → Documentation: ${results.coverage.apiToDocPercent}% (${results.coverage.apiToDoc}/${results.apiEndpointCount})`
|
|
);
|
|
console.log("");
|
|
|
|
console.log("✅ PARAMETER ACCURACY:");
|
|
console.log(`Exact parameter matches: ${results.exactMatches}`);
|
|
console.log(`Parameter mismatches: ${results.parameterMismatches.length}`);
|
|
console.log("");
|
|
|
|
if (results.missingFromConfig.length > 0) {
|
|
console.log(
|
|
`❌ MISSING FROM CONFIGURATION (${results.missingFromConfig.length}):`
|
|
);
|
|
results.missingFromConfig.slice(0, 5).forEach((missing) => {
|
|
console.log(` • ${missing.method} ${missing.path}`);
|
|
});
|
|
if (results.missingFromConfig.length > 5) {
|
|
console.log(` ... and ${results.missingFromConfig.length - 5} more`);
|
|
}
|
|
console.log("");
|
|
}
|
|
|
|
if (results.missingFromDoc.length > 0) {
|
|
console.log(
|
|
`📚 MISSING FROM DOCUMENTATION (${results.missingFromDoc.length}):`
|
|
);
|
|
results.missingFromDoc.slice(0, 5).forEach((missing) => {
|
|
console.log(
|
|
` • ${missing.method} ${missing.path} (${missing.authType})`
|
|
);
|
|
});
|
|
if (results.missingFromDoc.length > 5) {
|
|
console.log(` ... and ${results.missingFromDoc.length - 5} more`);
|
|
}
|
|
console.log("");
|
|
}
|
|
|
|
if (results.parameterMismatches.length > 0) {
|
|
console.log(
|
|
`⚠️ PARAMETER MISMATCHES (${results.parameterMismatches.length}):`
|
|
);
|
|
results.parameterMismatches.slice(0, 3).forEach((mismatch) => {
|
|
console.log(` • ${mismatch.endpoint}: ${mismatch.issues.length} issues`);
|
|
});
|
|
if (results.parameterMismatches.length > 3) {
|
|
console.log(
|
|
` ... and ${
|
|
results.parameterMismatches.length - 3
|
|
} more endpoints with issues`
|
|
);
|
|
}
|
|
console.log("");
|
|
}
|
|
|
|
// Final assessment
|
|
const isComplete =
|
|
results.coverage.apiToConfigPercent >= 95 &&
|
|
results.coverage.configToDocPercent >= 95 &&
|
|
results.parameterMismatches.length === 0;
|
|
|
|
if (isComplete) {
|
|
console.log("🎉 VALIDATION SUCCESS!");
|
|
console.log("✅ All API endpoints have corresponding MCP tools");
|
|
console.log("✅ All tools are properly documented");
|
|
console.log("✅ All parameters match exactly between API and tools");
|
|
console.log("✅ 100% parameter accuracy achieved");
|
|
} else {
|
|
console.log("⚠️ VALIDATION INCOMPLETE:");
|
|
if (results.coverage.apiToConfigPercent < 95) {
|
|
console.log(
|
|
` • API to Configuration coverage: ${results.coverage.apiToConfigPercent}% (target: 95%+)`
|
|
);
|
|
}
|
|
if (results.coverage.configToDocPercent < 95) {
|
|
console.log(
|
|
` • Configuration to Documentation coverage: ${results.coverage.configToDocPercent}% (target: 95%+)`
|
|
);
|
|
}
|
|
if (results.parameterMismatches.length > 0) {
|
|
console.log(
|
|
` • Parameter mismatches: ${results.parameterMismatches.length} (target: 0)`
|
|
);
|
|
}
|
|
}
|
|
|
|
console.log("");
|
|
}
|
|
|
|
// Run the validation
|
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
finalParameterValidation();
|
|
}
|
|
|
|
export { finalParameterValidation };
|