/** * @fileoverview Create new tools for missing API endpoints * Generate new MCP tools for any API endpoints that don't have corresponding tools, * following naming conventions and including all parameters with exact specifications. */ import fs from 'fs'; import path from 'path'; /** * Create new tools for missing API endpoints */ function createMissingTools() { try { console.log('=== CREATING NEW TOOLS FOR MISSING API ENDPOINTS ==='); console.log(''); // Read the audit results const auditResultsPath = path.join(process.cwd(), 'mcp-tools-audit-results.json'); const auditResultsContent = fs.readFileSync(auditResultsPath, 'utf8'); const auditResults = JSON.parse(auditResultsContent); // Read the complete API parameters const apiParametersPath = path.join(process.cwd(), 'complete-api-parameters.json'); const apiParametersContent = fs.readFileSync(apiParametersPath, 'utf8'); const apiEndpoints = JSON.parse(apiParametersContent); // Read the endpoints configuration const endpointsConfigPath = path.join(process.cwd(), 'src/config/endpoints.js'); const endpointsConfigContent = fs.readFileSync(endpointsConfigPath, 'utf8'); console.log(`🔍 Found ${auditResults.missingTools.length} missing tools to create`); console.log(''); // Group missing tools by authentication type const missingToolsByAuth = groupMissingToolsByAuth(auditResults.missingTools, apiEndpoints); // Generate new tool definitions const newToolDefinitions = generateNewToolDefinitions(missingToolsByAuth, apiEndpoints); // Update the endpoints configuration const updatedContent = addNewToolsToConfig(endpointsConfigContent, newToolDefinitions); // Save the updated configuration if (Object.keys(newToolDefinitions).length > 0) { // Create backup const backupPath = path.join(process.cwd(), 'src/config/endpoints_backup_missing_' + Date.now() + '.js'); fs.writeFileSync(backupPath, endpointsConfigContent); console.log(`📁 Backup created: ${backupPath}`); // Save updated file fs.writeFileSync(endpointsConfigPath, updatedContent); console.log(`💾 Updated endpoints configuration saved`); } // Generate summary const totalNewTools = Object.values(newToolDefinitions).reduce((sum, tools) => sum + tools.length, 0); console.log(''); console.log('=== NEW TOOLS CREATION SUMMARY ==='); Object.keys(newToolDefinitions).forEach(authType => { console.log(`${authType.toUpperCase()}: ${newToolDefinitions[authType].length} new tools`); }); console.log(`Total new tools created: ${totalNewTools}`); console.log(`Backup created: ${totalNewTools > 0 ? 'Yes' : 'No'}`); return { newToolsByAuth: newToolDefinitions, totalNewTools, backupCreated: totalNewTools > 0 }; } catch (error) { console.error('Error creating missing tools:', error); throw error; } } /** * Group missing tools by authentication type */ function groupMissingToolsByAuth(missingTools, apiEndpoints) { const grouped = { public: [], provider: [], patient: [], partner: [], affiliate: [], network: [] }; missingTools.forEach(missingTool => { // Find the corresponding API endpoint const apiEndpoint = apiEndpoints.find(ep => ep.path === missingTool.path && ep.method === missingTool.method ); if (apiEndpoint) { const authType = determineAuthType(apiEndpoint); if (grouped[authType]) { grouped[authType].push({ missingTool, apiEndpoint }); } } }); return grouped; } /** * Determine authentication type for an API endpoint */ function determineAuthType(apiEndpoint) { // Check if endpoint requires authentication if (!apiEndpoint.requiresAuth || !apiEndpoint.security || apiEndpoint.security.length === 0) { return 'public'; } // Determine specific auth type based on path patterns const path = apiEndpoint.path; if (path.includes('/api/frontend/patient') || path.includes('/patient/')) { return 'patient'; } else if (path.includes('/partner/')) { return 'partner'; } else if (path.includes('/affiliate/')) { return 'affiliate'; } else if (path.includes('/network/')) { return 'network'; } else { // Default authenticated endpoints to provider return 'provider'; } } /** * Generate new tool definitions */ function generateNewToolDefinitions(missingToolsByAuth, apiEndpoints) { const newToolDefinitions = {}; Object.keys(missingToolsByAuth).forEach(authType => { const tools = missingToolsByAuth[authType]; newToolDefinitions[authType] = []; tools.forEach(({ missingTool, apiEndpoint }) => { const toolDefinition = generateToolDefinition(apiEndpoint, authType); if (toolDefinition) { newToolDefinitions[authType].push(toolDefinition); console.log(`📝 Generated ${authType} tool: ${toolDefinition.path} (${toolDefinition.method})`); } }); }); return newToolDefinitions; } /** * Generate a single tool definition */ function generateToolDefinition(apiEndpoint, authType) { const parameters = {}; // Add path parameters if (apiEndpoint.parameters?.path) { apiEndpoint.parameters.path.forEach(param => { parameters[param.name] = { type: param.type || 'string', required: param.required || true, // Path parameters are usually required description: param.description || `${param.name} parameter` }; }); } // Add query parameters if (apiEndpoint.parameters?.query) { apiEndpoint.parameters.query.forEach(param => { parameters[param.name] = { type: param.type || 'string', required: param.required || false, description: param.description || `${param.name} parameter` }; }); } // Add body parameters if (apiEndpoint.parameters?.body) { apiEndpoint.parameters.body.forEach(param => { parameters[param.name] = { type: param.type || 'string', required: param.required || false, description: param.description || `${param.name} parameter` }; }); } return { path: apiEndpoint.path, method: apiEndpoint.method, controller: generateControllerName(apiEndpoint), category: determineCategoryFromTags(apiEndpoint.tags), description: apiEndpoint.summary || apiEndpoint.description || `${apiEndpoint.method} ${apiEndpoint.path}`, parameters: Object.keys(parameters).length > 0 ? parameters : undefined }; } /** * Generate controller name from endpoint */ function generateControllerName(apiEndpoint) { const operationId = apiEndpoint.operationId; if (operationId) { return `ApiController@${operationId}`; } // Generate from path and method const pathParts = apiEndpoint.path.split('/').filter(part => part && !part.startsWith('{')); const resource = pathParts[pathParts.length - 1] || 'api'; const action = apiEndpoint.method.toLowerCase(); return `ApiController@${action}${resource.charAt(0).toUpperCase() + resource.slice(1)}`; } /** * Determine category from tags */ function determineCategoryFromTags(tags) { if (!tags || tags.length === 0) return 'GENERAL'; const tagMap = { 'Appointments': 'APPOINTMENT_SCHEDULING', 'Appointment': 'APPOINTMENT_SCHEDULING', 'Patients': 'PATIENT_MANAGEMENT', 'Patient': 'PATIENT_MANAGEMENT', 'Forms': 'FORMS_QUESTIONNAIRES', 'Documents': 'DOCUMENT_MANAGEMENT', 'User Management': 'USER_MANAGEMENT', 'Authentication': 'USER_MANAGEMENT', 'Locations': 'LOCATION_MANAGEMENT', 'Inventory': 'INVENTORY', 'Tasks': 'USER_MANAGEMENT', 'Emails': 'MESSAGING', 'Phone Logs': 'MESSAGING', 'Vitals': 'MEDICAL_RECORDS', 'Medical Problems': 'MEDICAL_RECORDS', 'Insurance': 'PATIENT_MANAGEMENT', 'Products': 'BUSINESS_OPERATIONS', 'Payments': 'BILLING_ORDERS', 'Meetings': 'AI_INTEGRATION', 'Provider': 'PROVIDER_MANAGEMENT' }; const primaryTag = tags[0]; return tagMap[primaryTag] || 'GENERAL'; } /** * Add new tools to configuration */ function addNewToolsToConfig(configContent, newToolDefinitions) { let updatedContent = configContent; Object.keys(newToolDefinitions).forEach(authType => { const tools = newToolDefinitions[authType]; if (tools.length === 0) return; const sectionName = `${authType.toUpperCase()}_ENDPOINTS`; const toolsCode = tools.map(tool => generateToolCode(tool)).join(',\n\n'); // Find the section and add tools const sectionRegex = new RegExp(`(export const ${sectionName}\\s*=\\s*\\[)([\\s\\S]*?)(\\];)`, 'g'); const match = sectionRegex.exec(updatedContent); if (match) { const beforeSection = match[1]; const existingContent = match[2]; const afterSection = match[3]; // Add new tools at the end of the section const newContent = existingContent.trim() ? `${existingContent.trimEnd()},\n\n // ===== NEW TOOLS FROM API DOCUMENTATION =====\n ${toolsCode}\n` : `\n // ===== NEW TOOLS FROM API DOCUMENTATION =====\n ${toolsCode}\n`; updatedContent = updatedContent.replace( sectionRegex, `${beforeSection}${newContent}${afterSection}` ); } }); return updatedContent; } /** * Generate code for a single tool */ function generateToolCode(tool) { let code = ` {\n`; code += ` path: "${tool.path}",\n`; code += ` method: "${tool.method}",\n`; code += ` controller: "${tool.controller}",\n`; code += ` category: ENDPOINT_CATEGORIES.${tool.category},\n`; code += ` description: "${tool.description}",\n`; if (tool.parameters && Object.keys(tool.parameters).length > 0) { code += ` parameters: {\n`; Object.keys(tool.parameters).forEach(paramName => { const param = tool.parameters[paramName]; code += ` ${paramName}: { type: "${param.type}", required: ${param.required}, description: "${param.description}" },\n`; }); code += ` },\n`; } code += ` }`; return code; } // Run the creation if (import.meta.url === `file://${process.argv[1]}`) { createMissingTools(); } export { createMissingTools };