#!/usr/bin/env node /** * Validate and Clean MCP Tools Reference * Remove duplicates and ensure consistency */ import fs from 'fs'; import { ConfigManager } from './src/config/ConfigManager.js'; import { AuthManager } from './src/auth/AuthManager.js'; import { ApiClient } from './src/proxy/ApiClient.js'; import { ToolGenerator } from './src/tools/ToolGenerator.js'; class ReferenceValidator { constructor() { this.toolsByAuth = {}; this.totalTools = 0; this.authTypeStats = {}; this.uniqueTools = new Map(); } /** * Initialize and generate all tools */ async initialize() { console.log('๐Ÿ”ง Initializing MCP components...'); const config = new ConfigManager(); const authManager = new AuthManager(null, config.getAll(true)); const apiClient = new ApiClient(config.getAll(), authManager); this.toolGenerator = new ToolGenerator(apiClient); console.log('๐Ÿ“‹ Generating all tools...'); const allTools = this.toolGenerator.generateAllTools(); this.totalTools = allTools.length; console.log(`โœ… Generated ${this.totalTools} tools`); // Group tools by authentication type and remove duplicates this.groupAndDeduplicateTools(allTools); return true; } /** * Group tools by authentication type and remove duplicates */ groupAndDeduplicateTools(allTools) { console.log('๐Ÿ“Š Grouping tools and removing duplicates...'); this.toolsByAuth = { public: [], provider: [], patient: [], partner: [], affiliate: [], network: [] }; allTools.forEach(tool => { const toolImpl = this.toolGenerator.getTool(tool.name); if (toolImpl && toolImpl.authType) { const authType = toolImpl.authType.toLowerCase(); // Check for duplicates using tool name as key if (!this.uniqueTools.has(tool.name)) { this.uniqueTools.set(tool.name, { name: tool.name, description: tool.description, inputSchema: tool.inputSchema, endpoint: toolImpl.endpoint, authType: toolImpl.authType }); if (this.toolsByAuth[authType]) { this.toolsByAuth[authType].push(this.uniqueTools.get(tool.name)); } } else { console.log(`โš ๏ธ Duplicate tool found: ${tool.name}`); } } }); // Calculate statistics Object.keys(this.toolsByAuth).forEach(authType => { this.authTypeStats[authType] = this.toolsByAuth[authType].length; console.log(` ${authType.toUpperCase()}: ${this.authTypeStats[authType]} tools`); }); const totalUnique = Array.from(this.uniqueTools.keys()).length; console.log(`๐Ÿ“Š Total unique tools: ${totalUnique}`); console.log(`๐Ÿ“Š Duplicates removed: ${this.totalTools - totalUnique}`); } /** * Format parameter documentation */ formatParameterDoc(paramName, paramSpec) { const required = paramSpec.required ? '**Required**' : '*Optional*'; const type = paramSpec.type || 'string'; const description = paramSpec.description || 'Parameter'; let doc = `- **\`${paramName}\`** (${type}) - ${required} - ${description}`; // Add validation rules if available if (paramSpec.minLength || paramSpec.maxLength) { doc += `\n - Length: ${paramSpec.minLength || 0}-${paramSpec.maxLength || 'unlimited'} characters`; } if (paramSpec.pattern) { doc += `\n - Format: \`${paramSpec.pattern}\``; } if (paramSpec.enum) { doc += `\n - Allowed values: ${paramSpec.enum.map(v => `\`${v}\``).join(', ')}`; } if (paramSpec.example) { doc += `\n - Example: \`${paramSpec.example}\``; } return doc; } /** * Generate tool documentation section */ generateToolSection(tool) { let section = `### \`${tool.name}\`\n\n`; section += `**Description**: ${tool.description}\n\n`; section += `**Method**: ${tool.endpoint.method}\n\n`; section += `**Endpoint**: \`${tool.endpoint.path}\`\n\n`; // Parameters if (tool.inputSchema && tool.inputSchema.properties) { const properties = tool.inputSchema.properties; const required = tool.inputSchema.required || []; section += `**Parameters**:\n\n`; // Required parameters first const requiredParams = Object.entries(properties).filter(([name]) => required.includes(name)); const optionalParams = Object.entries(properties).filter(([name]) => !required.includes(name)); if (requiredParams.length > 0) { section += `**Required Parameters**:\n`; requiredParams.forEach(([name, spec]) => { section += this.formatParameterDoc(name, { ...spec, required: true }) + '\n'; }); section += '\n'; } if (optionalParams.length > 0) { section += `**Optional Parameters**:\n`; optionalParams.forEach(([name, spec]) => { section += this.formatParameterDoc(name, { ...spec, required: false }) + '\n'; }); section += '\n'; } } else { section += `**Parameters**: None\n\n`; } // Usage example section += `**Usage Example**:\n`; section += `\`\`\`javascript\n`; section += `await mcpClient.callTool('${tool.name}'`; if (tool.inputSchema && tool.inputSchema.properties) { const properties = tool.inputSchema.properties; const required = tool.inputSchema.required || []; if (Object.keys(properties).length > 0) { section += `, {\n`; Object.entries(properties).forEach(([name, spec], index, arr) => { const isRequired = required.includes(name); const example = this.generateExampleValue(name, spec); section += ` ${name}: ${example}`; if (index < arr.length - 1) section += ','; if (!isRequired) section += ' // optional'; section += '\n'; }); section += `}`; } } section += `);\n\`\`\`\n\n`; return section; } /** * Generate example value for parameter */ generateExampleValue(paramName, paramSpec) { if (paramSpec.example) { return typeof paramSpec.example === 'string' ? `"${paramSpec.example}"` : paramSpec.example; } const type = paramSpec.type || 'string'; const name = paramName.toLowerCase(); // Generate contextual examples based on parameter name if (name.includes('email')) return '"user@example.com"'; if (name.includes('password')) return '"password123"'; if (name.includes('phone')) return '"+1234567890"'; if (name.includes('date')) return '"2024-01-15"'; if (name.includes('id') || name.includes('Id')) return '123'; if (name.includes('name')) return '"John Doe"'; if (name.includes('address')) return '"123 Main St"'; if (name.includes('city')) return '"New York"'; if (name.includes('state')) return '"NY"'; if (name.includes('zip')) return '"10001"'; if (name.includes('age')) return '30'; if (name.includes('amount') || name.includes('price')) return '99.99'; if (name.includes('meeting')) return '"meeting-123"'; if (name.includes('call')) return '"consultation"'; // Default by type switch (type) { case 'integer': case 'number': return '123'; case 'boolean': return 'true'; case 'array': return '[]'; case 'object': return '{}'; default: return '"example_value"'; } } /** * Generate authentication type icon */ getAuthTypeIcon(authType) { const icons = { public: '๐ŸŒ', provider: '๐Ÿฅ', patient: '๐Ÿ‘ค', partner: '๐Ÿค', affiliate: '๐Ÿ”—', network: '๐ŸŒ' }; return icons[authType] || '๐Ÿ”ง'; } /** * Generate complete documentation */ generateCleanDocumentation() { console.log('๐Ÿ“ Generating clean documentation...'); const currentDate = new Date().toISOString().split('T')[0]; const totalUnique = Array.from(this.uniqueTools.keys()).length; let content = `# ๐Ÿ› ๏ธ Laravel Healthcare MCP Server - Complete Tools Reference ## ๐Ÿ“Š Overview This document provides a comprehensive reference for all MCP tools available in the Laravel Healthcare MCP Server, with exact tool names and complete parameter specifications. **Last Updated**: ${currentDate} **Total Tools**: ${totalUnique} **API Coverage**: 100% from comprehensive audit **Generated From**: Live ToolGenerator analysis (duplicates removed) ## ๐Ÿ“‹ Tool Distribution by Authentication Type | Authentication Type | Tool Count | Percentage | Description | |-------------------|------------|------------|-------------| `; // Add distribution table Object.entries(this.authTypeStats).forEach(([authType, count]) => { const percentage = ((count / totalUnique) * 100).toFixed(1); const icon = this.getAuthTypeIcon(authType); const description = this.getAuthTypeDescription(authType); content += `| ${icon} **${authType.charAt(0).toUpperCase() + authType.slice(1)}** | ${count} | ${percentage}% | ${description} |\n`; }); content += `\n**Total**: ${totalUnique} tools\n\n---\n\n`; // Generate sections for each auth type const authTypeOrder = ['public', 'provider', 'patient', 'partner', 'affiliate', 'network']; authTypeOrder.forEach(authType => { const tools = this.toolsByAuth[authType]; if (tools.length === 0) return; const authTypeTitle = authType.charAt(0).toUpperCase() + authType.slice(1); const authTypeIcon = this.getAuthTypeIcon(authType); content += `## ${authTypeIcon} ${authTypeTitle} Tools (${tools.length} tools)\n\n`; content += `### Authentication Requirements\n`; content += `- **Type**: ${authType === 'public' ? 'None (public access)' : `${authTypeTitle} authentication required`}\n`; content += `- **Security**: ${authType === 'public' ? 'Public endpoints' : 'Bearer token required'}\n`; content += `- **HIPAA Compliance**: ${authType === 'provider' ? 'Required for patient data' : 'Standard security'}\n\n`; // Sort tools alphabetically tools.sort((a, b) => a.name.localeCompare(b.name)); // Add tools tools.forEach(tool => { content += this.generateToolSection(tool); }); content += '---\n\n'; }); // Add footer content += this.generateFooter(); return content; } /** * Get authentication type description */ getAuthTypeDescription(authType) { const descriptions = { public: 'Login, registration, password management, webhooks', provider: 'Clinical data, EMR operations, patient management', patient: 'Patient portal operations', partner: 'Partner business operations', affiliate: 'Affiliate management', network: 'Network operations' }; return descriptions[authType] || 'API operations'; } /** * Generate documentation footer */ generateFooter() { return `## ๐Ÿ“š Usage Guidelines ### Basic Tool Usage \`\`\`javascript // Initialize MCP client const mcpClient = new MCPClient(); // Public tool (no authentication) await mcpClient.callTool('public_create_login', { username: 'user@example.com', password: 'password123' }); // Provider tool (requires authentication) await mcpClient.callTool('provider_get_emrpatientsList', { draw: 1, start: 0, length: 10 }); \`\`\` ### Authentication Flow \`\`\`javascript // 1. Login to get token const loginResult = await mcpClient.callTool('public_create_login', { username: 'provider@example.com', password: 'password123' }); // 2. Use authenticated endpoints const patients = await mcpClient.callTool('provider_get_emrpatientsList', { draw: 1, start: 0, length: 10 }); \`\`\` ### Video Call Features \`\`\`javascript // Start a video call await mcpClient.callTool('provider_get_createmeeting', { meeting_id: 'meeting-123' }); // Join a meeting await mcpClient.callTool('provider_get_joinmeeting', { meeting_id: 'meeting-123' }); // Start call with patient await mcpClient.callTool('provider_create_startCall', { patient_id: 123, agent_id: 456, appointment_id: 789, call_type: 'consultation' }); \`\`\` ## ๐Ÿ”’ Security Notes - **Public Tools**: No authentication required, rate-limited - **Provider Tools**: Require provider authentication, HIPAA-compliant - **Patient Tools**: Require patient authentication, access to own data only - **Partner/Affiliate/Network Tools**: Require respective authentication levels ## ๐Ÿ“– Additional Resources - [API Documentation](./README.md) - [Authentication Guide](./docs/authentication.md) - [HIPAA Compliance](./docs/hipaa-compliance.md) - [Error Handling](./docs/error-handling.md) --- *This reference was automatically generated from the live ToolGenerator with duplicates removed* *For the most up-to-date information, refer to the source code in \`src/config/endpoints.js\`* `; } /** * Run the validation and cleaning process */ async run() { try { console.log('๐Ÿš€ Starting Reference Validation and Cleaning\n'); await this.initialize(); const cleanDocumentation = this.generateCleanDocumentation(); // Write to file fs.writeFileSync('MCP-TOOLS-REFERENCE.md', cleanDocumentation); const totalUnique = Array.from(this.uniqueTools.keys()).length; console.log('\n๐Ÿ“„ Clean documentation generated successfully!'); console.log(`โœ… MCP-TOOLS-REFERENCE.md updated with ${totalUnique} unique tools`); console.log(`๐Ÿงน Removed ${this.totalTools - totalUnique} duplicate entries`); console.log('\n๐Ÿ“Š Final Statistics:'); Object.entries(this.authTypeStats).forEach(([authType, count]) => { const percentage = ((count / totalUnique) * 100).toFixed(1); console.log(` ${authType.toUpperCase()}: ${count} tools (${percentage}%)`); }); return true; } catch (error) { console.error('โŒ Error validating and cleaning documentation:', error.message); console.error('๐Ÿ“‹ Stack:', error.stack); return false; } } } // Run the validator const validator = new ReferenceValidator(); validator.run().then(success => { if (success) { console.log('\n๐ŸŽ‰ Reference validation and cleaning completed successfully!'); } else { console.log('\nโŒ Reference validation and cleaning failed'); process.exit(1); } });