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

334 lines
14 KiB
JavaScript

/**
* @fileoverview Categorize API endpoints by authentication type and functional category
* Maps endpoints from api-docs.json to the Laravel Healthcare MCP Server structure
*/
import fs from 'fs';
import path from 'path';
/**
* Authentication types for endpoint categorization
*/
const AUTH_TYPES = {
PUBLIC: "public",
PROVIDER: "provider",
PATIENT: "patient",
PARTNER: "partner",
AFFILIATE: "affiliate",
NETWORK: "network"
};
/**
* Functional categories for endpoint organization
*/
const CATEGORIES = {
MEETINGS: "meetings",
APPOINTMENTS: "appointments",
PATIENTS: "patients",
DOCTORS: "doctors",
LABS: "labs",
NOTES: "notes",
FORMS: "forms",
DOCUMENTS: "documents",
AUTHENTICATION: "authentication",
USER_MANAGEMENT: "user_management",
MEDICAL_RECORDS: "medical_records",
PRESCRIPTIONS: "prescriptions",
INVENTORY: "inventory",
LOCATIONS: "locations",
INSURANCE: "insurance",
PAYMENTS: "payments",
VITALS: "vitals",
TASKS: "tasks",
TAGS: "tags",
PHONE_LOGS: "phone_logs",
PRODUCTS: "products",
COMPANY: "company",
TOKENS: "tokens",
EMAILS: "emails",
ASSISTANT: "assistant",
LIVEKIT: "livekit"
};
/**
* Categorize endpoints by authentication type and functional category
*/
function categorizeEndpoints() {
try {
// Read the analysis file
const analysisPath = path.join(process.cwd(), 'api-docs-analysis.json');
const analysisContent = fs.readFileSync(analysisPath, 'utf8');
const analysis = JSON.parse(analysisContent);
console.log('=== CATEGORIZING 184 ENDPOINTS ===');
console.log('');
const categorizedEndpoints = {
[AUTH_TYPES.PUBLIC]: [],
[AUTH_TYPES.PROVIDER]: [],
[AUTH_TYPES.PATIENT]: [],
[AUTH_TYPES.PARTNER]: [],
[AUTH_TYPES.AFFILIATE]: [],
[AUTH_TYPES.NETWORK]: []
};
// Process each endpoint
analysis.allEndpoints.forEach(endpoint => {
const authType = determineAuthType(endpoint);
const category = determineCategory(endpoint);
const categorizedEndpoint = {
...endpoint,
authType,
category,
toolName: generateToolName(endpoint, authType)
};
categorizedEndpoints[authType].push(categorizedEndpoint);
});
// Display categorization summary
console.log('=== CATEGORIZATION SUMMARY ===');
Object.keys(categorizedEndpoints).forEach(authType => {
const count = categorizedEndpoints[authType].length;
console.log(`${authType.toUpperCase()}: ${count} endpoints`);
});
console.log('');
// Display by functional categories
const byCategoryCount = {};
Object.values(categorizedEndpoints).flat().forEach(endpoint => {
byCategoryCount[endpoint.category] = (byCategoryCount[endpoint.category] || 0) + 1;
});
console.log('=== BY FUNCTIONAL CATEGORY ===');
Object.keys(byCategoryCount).sort().forEach(category => {
console.log(`${category}: ${byCategoryCount[category]} endpoints`);
});
console.log('');
// Save categorized endpoints
const outputPath = path.join(process.cwd(), 'categorized-endpoints.json');
fs.writeFileSync(outputPath, JSON.stringify(categorizedEndpoints, null, 2));
console.log(`Categorized endpoints saved to: ${outputPath}`);
// Display detailed categorization
console.log('');
console.log('=== DETAILED CATEGORIZATION ===');
Object.keys(categorizedEndpoints).forEach(authType => {
console.log(`\n--- ${authType.toUpperCase()} ENDPOINTS (${categorizedEndpoints[authType].length}) ---`);
categorizedEndpoints[authType].forEach((endpoint, index) => {
console.log(`${index + 1}. ${endpoint.toolName}`);
console.log(` ${endpoint.method} ${endpoint.path}`);
console.log(` Category: ${endpoint.category}`);
console.log(` Summary: ${endpoint.summary}`);
console.log('');
});
});
return categorizedEndpoints;
} catch (error) {
console.error('Error categorizing endpoints:', error);
throw error;
}
}
/**
* Determine authentication type based on endpoint characteristics
*/
function determineAuthType(endpoint) {
const path = endpoint.path.toLowerCase();
const tags = endpoint.tags.map(tag => tag.toLowerCase());
const requiresAuth = endpoint.requiresAuth;
// Public endpoints (no authentication required)
if (!requiresAuth) {
// Check for specific public patterns
if (path.includes('/login') || path.includes('/register') ||
path.includes('/forgot-password') || path.includes('/reset-password') ||
path.includes('/set-password') || path.includes('/check-user') ||
path.includes('/patient-order-create') || path.includes('/patient-book-appointment') ||
path.includes('/get-signed-patient-data') || path.includes('/get/document') ||
path.includes('/generate-permanent-token') || path.includes('/redirect-with-auth') ||
path.includes('/get-pdf-url') || path.includes('/download/pdf') ||
path.includes('/get-form-without-auth') || path.includes('/store-intake-form-data') ||
path.includes('/update-intake-form-data') || path.includes('/room-joined/event') ||
path.includes('/get-patient-summary') || path.includes('/update-patient-summary') ||
path.includes('/generate-patient-summary') || path.includes('/get-patient-full-details') ||
path.includes('/get-patient-forms-list') || path.includes('/user-list-profile') ||
path.includes('/available-slots') || path.includes('/check-email') ||
tags.includes('patient authentication') && !requiresAuth) {
return AUTH_TYPES.PUBLIC;
}
return AUTH_TYPES.PUBLIC;
}
// Provider endpoints (clinical/EMR data)
if (path.includes('/emr/') || path.includes('/api/emr/') || path.includes('/emr-api/') ||
path.includes('/provider') || path.includes('/practitioners') ||
path.includes('/assistant') || path.includes('/company') ||
tags.includes('provider') || tags.includes('assistant') || tags.includes('company') ||
// Clinical data endpoints
path.includes('/appointment') || path.includes('/patient') || path.includes('/medical') ||
path.includes('/prescription') || path.includes('/document') || path.includes('/form') ||
path.includes('/lab') || path.includes('/vital') || path.includes('/note') ||
path.includes('/task') || path.includes('/tag') || path.includes('/phone-log') ||
path.includes('/inventory') || path.includes('/location') || path.includes('/insurance') ||
path.includes('/email') || path.includes('/user') ||
// Meeting/call endpoints
path.includes('/meeting') || path.includes('/call') || path.includes('/token') ||
tags.includes('meetings') || tags.includes('appointments') || tags.includes('patients') ||
tags.includes('doctors') || tags.includes('labs') || tags.includes('forms') ||
tags.includes('documents') || tags.includes('notes') || tags.includes('vitals') ||
tags.includes('tasks') || tags.includes('tags') || tags.includes('phone logs') ||
tags.includes('inventory') || tags.includes('locations') || tags.includes('insurance') ||
tags.includes('emails') || tags.includes('user management') || tags.includes('medical problems') ||
tags.includes('forms management') || tags.includes('intake forms') || tags.includes('consent forms') ||
tags.includes('patient forms') || tags.includes('patient data') || tags.includes('patient medical') ||
tags.includes('patient profile') || tags.includes('patient subscription') || tags.includes('patient payment') ||
tags.includes('products') || tags.includes('product sync') || tags.includes('payments') ||
tags.includes('token management') || tags.includes('appointment reports')) {
return AUTH_TYPES.PROVIDER;
}
// Patient endpoints (patient portal)
if (path.includes('/patient/') && !path.includes('/api/patient/register-patient') ||
tags.includes('patient authentication') && requiresAuth) {
return AUTH_TYPES.PATIENT;
}
// Partner endpoints
if (path.includes('/partner/') || tags.includes('partner')) {
return AUTH_TYPES.PARTNER;
}
// Affiliate endpoints
if (path.includes('/affiliate/') || tags.includes('affiliate')) {
return AUTH_TYPES.AFFILIATE;
}
// Network endpoints
if (path.includes('/network/') || tags.includes('network')) {
return AUTH_TYPES.NETWORK;
}
// Default to provider for authenticated endpoints
return AUTH_TYPES.PROVIDER;
}
/**
* Determine functional category based on endpoint characteristics
*/
function determineCategory(endpoint) {
const path = endpoint.path.toLowerCase();
const tags = endpoint.tags.map(tag => tag.toLowerCase());
// Map based on tags first
if (tags.includes('meetings')) return CATEGORIES.MEETINGS;
if (tags.includes('appointments') || tags.includes('appointment') || tags.includes('appointment reports')) return CATEGORIES.APPOINTMENTS;
if (tags.includes('patients')) return CATEGORIES.PATIENTS;
if (tags.includes('doctors')) return CATEGORIES.DOCTORS;
if (tags.includes('labs')) return CATEGORIES.LABS;
if (tags.includes('notes')) return CATEGORIES.NOTES;
if (tags.includes('forms') || tags.includes('forms management') || tags.includes('intake forms') ||
tags.includes('consent forms') || tags.includes('patient forms')) return CATEGORIES.FORMS;
if (tags.includes('documents')) return CATEGORIES.DOCUMENTS;
if (tags.includes('authentication') || tags.includes('patient authentication')) return CATEGORIES.AUTHENTICATION;
if (tags.includes('user management')) return CATEGORIES.USER_MANAGEMENT;
if (tags.includes('medical problems') || tags.includes('patient medical')) return CATEGORIES.MEDICAL_RECORDS;
if (tags.includes('inventory')) return CATEGORIES.INVENTORY;
if (tags.includes('locations')) return CATEGORIES.LOCATIONS;
if (tags.includes('insurance')) return CATEGORIES.INSURANCE;
if (tags.includes('payments') || tags.includes('patient payment')) return CATEGORIES.PAYMENTS;
if (tags.includes('vitals')) return CATEGORIES.VITALS;
if (tags.includes('tasks')) return CATEGORIES.TASKS;
if (tags.includes('tags')) return CATEGORIES.TAGS;
if (tags.includes('phone logs')) return CATEGORIES.PHONE_LOGS;
if (tags.includes('products') || tags.includes('product sync')) return CATEGORIES.PRODUCTS;
if (tags.includes('company')) return CATEGORIES.COMPANY;
if (tags.includes('token management')) return CATEGORIES.TOKENS;
if (tags.includes('emails')) return CATEGORIES.EMAILS;
if (tags.includes('assistant')) return CATEGORIES.ASSISTANT;
if (tags.includes('livekit')) return CATEGORIES.LIVEKIT;
if (tags.includes('patient data') || tags.includes('patient profile') ||
tags.includes('patient subscription') || tags.includes('patient summary')) return CATEGORIES.PATIENTS;
if (tags.includes('provider')) return CATEGORIES.USER_MANAGEMENT;
// Map based on path patterns
if (path.includes('/meeting') || path.includes('/call')) return CATEGORIES.MEETINGS;
if (path.includes('/appointment')) return CATEGORIES.APPOINTMENTS;
if (path.includes('/patient')) return CATEGORIES.PATIENTS;
if (path.includes('/doctor')) return CATEGORIES.DOCTORS;
if (path.includes('/lab')) return CATEGORIES.LABS;
if (path.includes('/note')) return CATEGORIES.NOTES;
if (path.includes('/form')) return CATEGORIES.FORMS;
if (path.includes('/document')) return CATEGORIES.DOCUMENTS;
if (path.includes('/login') || path.includes('/register') || path.includes('/password') || path.includes('/token')) return CATEGORIES.AUTHENTICATION;
if (path.includes('/user')) return CATEGORIES.USER_MANAGEMENT;
if (path.includes('/medical') || path.includes('/prescription')) return CATEGORIES.MEDICAL_RECORDS;
if (path.includes('/inventory')) return CATEGORIES.INVENTORY;
if (path.includes('/location')) return CATEGORIES.LOCATIONS;
if (path.includes('/insurance')) return CATEGORIES.INSURANCE;
if (path.includes('/payment')) return CATEGORIES.PAYMENTS;
if (path.includes('/vital')) return CATEGORIES.VITALS;
if (path.includes('/task')) return CATEGORIES.TASKS;
if (path.includes('/tag')) return CATEGORIES.TAGS;
if (path.includes('/phone')) return CATEGORIES.PHONE_LOGS;
if (path.includes('/product')) return CATEGORIES.PRODUCTS;
if (path.includes('/company')) return CATEGORIES.COMPANY;
if (path.includes('/email')) return CATEGORIES.EMAILS;
if (path.includes('/assistant')) return CATEGORIES.ASSISTANT;
// Default category
return CATEGORIES.USER_MANAGEMENT;
}
/**
* Generate MCP tool name following the naming convention
*/
function generateToolName(endpoint, authType) {
const method = endpoint.method.toLowerCase();
const path = endpoint.path.toLowerCase();
// Extract meaningful parts from the path
let pathParts = path.split('/').filter(part => part && !part.startsWith('{') && !part.endsWith('}'));
// Remove common prefixes
pathParts = pathParts.filter(part => !['api', 'emr', 'emr-api'].includes(part));
// Create action from method and path
let action = method;
if (method === 'post' && (path.includes('/login') || path.includes('/register'))) {
action = 'create';
} else if (method === 'get') {
action = 'get';
} else if (method === 'put') {
action = 'update';
} else if (method === 'delete') {
action = 'delete';
} else if (method === 'post') {
action = 'create';
}
// Create resource name from path parts
let resource = pathParts.join('_').replace(/-/g, '_');
// Clean up resource name
resource = resource.replace(/[^a-z0-9_]/g, '');
// Ensure we have a resource name
if (!resource) {
resource = endpoint.operationId || 'unknown';
}
return `${authType}_${action}_${resource}`;
}
// Run the categorization
if (import.meta.url === `file://${process.argv[1]}`) {
categorizeEndpoints();
}
export { categorizeEndpoints };