/** * @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 };