UNPKG

snow-flow

Version:

Snow-Flow v3.2.0: Complete ServiceNow Enterprise Suite with 180+ MCP Tools. ATF Testing, Knowledge Management, Service Catalog, Change Management with CAB scheduling, Virtual Agent chatbots with NLU, Performance Analytics KPIs, Flow Designer automation, A

909 lines (908 loc) • 206 kB
#!/usr/bin/env node "use strict"; /** * ServiceNow Development Assistant MCP Server * Natural language artifact management and development orchestration for ServiceNow */ Object.defineProperty(exports, "__esModule", { value: true }); exports.ServiceNowDevelopmentAssistantMCP = void 0; const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js"); const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js"); const types_js_1 = require("@modelcontextprotocol/sdk/types.js"); const servicenow_client_js_1 = require("../utils/servicenow-client.js"); const mcp_auth_middleware_js_1 = require("../utils/mcp-auth-middleware.js"); const mcp_config_manager_js_1 = require("../utils/mcp-config-manager.js"); const logger_js_1 = require("../utils/logger.js"); const widget_template_generator_js_1 = require("../utils/widget-template-generator.js"); const fs_1 = require("fs"); const path_1 = require("path"); const self_documenting_system_js_1 = require("../documentation/self-documenting-system.js"); const cost_optimization_engine_js_1 = require("../optimization/cost-optimization-engine.js"); const advanced_compliance_system_js_1 = require("../compliance/advanced-compliance-system.js"); const self_healing_system_js_1 = require("../healing/self-healing-system.js"); const memory_system_js_1 = require("../memory/memory-system.js"); class ServiceNowDevelopmentAssistantMCP { constructor() { this.memoryIndex = new Map(); this.server = new index_js_1.Server({ name: 'servicenow-development-assistant', version: '1.0.0', }, { capabilities: { tools: {}, }, }); this.client = new servicenow_client_js_1.ServiceNowClient(); this.logger = new logger_js_1.Logger('ServiceNowDevelopmentAssistantMCP'); this.config = mcp_config_manager_js_1.mcpConfig.getMemoryConfig(); this.memoryPath = this.config.path || (0, path_1.join)(process.cwd(), 'memory', 'servicenow_artifacts'); this.setupHandlers(); } async initializeSystems() { try { // Initialize systems synchronously during server startup this.memorySystem = new memory_system_js_1.MemorySystem({ dbPath: './.snow-flow/data/intelligent-mcp.db', cache: { enabled: true, maxSize: 100, ttl: 3600 }, ttl: { default: 3600, session: 7200, artifact: 86400, metric: 604800 } }); await this.memorySystem.initialize(); this.logger.info('Memory system initialized'); this.documentationSystem = new self_documenting_system_js_1.SelfDocumentingSystem(this.client, this.memorySystem); this.costOptimizationEngine = new cost_optimization_engine_js_1.CostOptimizationEngine(this.client, this.memorySystem); this.complianceSystem = new advanced_compliance_system_js_1.AdvancedComplianceSystem(this.client, this.memorySystem); this.selfHealingSystem = new self_healing_system_js_1.SelfHealingSystem(this.client, this.memorySystem); this.logger.info('All systems initialized successfully'); } catch (error) { this.logger.error('Failed to initialize systems:', error); // Initialize minimal fallback systems this.memorySystem = new memory_system_js_1.MemorySystem({ dbPath: './.snow-flow/data/intelligent-mcp.db' }); await this.memorySystem.initialize(); } } setupHandlers() { this.server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({ tools: [ { name: 'snow_find_artifact', description: 'Finds ServiceNow artifacts using natural language queries. Searches cached memory first for performance, then queries ServiceNow directly if needed.', inputSchema: { type: 'object', properties: { query: { type: 'string', description: 'Natural language query (e.g., "the widget that shows incidents on homepage")' }, type: { type: 'string', enum: ['widget', 'flow', 'script', 'application', 'any'], description: 'Artifact type filter' }, }, required: ['query'], }, }, { name: 'snow_edit_artifact', description: 'Modifies ServiceNow artifacts using natural language instructions. Includes automatic error handling, retry logic, and validation of changes.', inputSchema: { type: 'object', properties: { query: { type: 'string', description: 'Natural language edit instruction (e.g., "pas de flow aan met de naam approval request flow en zorg dat er na de approval stap een mailtje naar test@admin.nl wordt gestuurd")' }, }, required: ['query'], }, }, { name: 'snow_get_by_sysid', description: 'Retrieves artifacts by sys_id for precise, fast lookups. More reliable than text-based searches when sys_id is known.', inputSchema: { type: 'object', properties: { sys_id: { type: 'string', description: 'System ID of the artifact' }, table: { type: 'string', description: 'ServiceNow table name (e.g., sp_widget, wf_workflow, sys_script_include)' }, }, required: ['sys_id', 'table'], }, }, { name: 'snow_edit_by_sysid', description: 'Updates specific fields of an artifact using sys_id. Provides direct field-level modifications with validation.', inputSchema: { type: 'object', properties: { sys_id: { type: 'string', description: 'System ID of the artifact to edit' }, table: { type: 'string', description: 'ServiceNow table name' }, field: { type: 'string', description: 'Field name to update (e.g., script, server_script, template)' }, value: { type: 'string', description: 'New value for the field' }, }, required: ['sys_id', 'table', 'field', 'value'], }, }, { name: 'snow_analyze_artifact', description: 'Performs comprehensive analysis of artifacts including dependencies, usage patterns, and optimization opportunities. Caches results for improved performance.', inputSchema: { type: 'object', properties: { sys_id: { type: 'string', description: 'System ID of the artifact' }, table: { type: 'string', description: 'ServiceNow table name' }, }, required: ['sys_id', 'table'], }, }, { name: 'snow_memory_search', description: 'Searches cached ServiceNow artifacts in local memory for instant results without API calls.', inputSchema: { type: 'object', properties: { query: { type: 'string', description: 'Search query' }, type: { type: 'string', enum: ['widget', 'flow', 'script', 'application'], description: 'Artifact type' }, }, required: ['query'], }, }, { name: 'snow_comprehensive_search', description: 'Searches across multiple ServiceNow tables simultaneously to find artifacts. Includes inactive records and cross-table relationships.', inputSchema: { type: 'object', properties: { query: { type: 'string', description: 'Natural language search query' }, include_inactive: { type: 'boolean', description: 'Include inactive records', default: false }, }, required: ['query'], }, }, { name: 'snow_sync_data_consistency', description: 'Synchronizes cached data with ServiceNow, validates sys_id mappings, and repairs consistency issues. Includes automatic cache refresh and reindexing.', inputSchema: { type: 'object', properties: { operation: { type: 'string', enum: ['refresh_cache', 'validate_sysids', 'reindex_artifacts', 'full_sync'], description: 'Type of sync operation' }, sys_id: { type: 'string', description: 'Specific sys_id to validate (optional)' }, table: { type: 'string', description: 'Specific table to sync (optional)' }, }, required: ['operation'], }, }, { name: 'snow_validate_live_connection', description: 'Validates ServiceNow connection status, authentication tokens, and user permissions. Returns detailed diagnostics with response times.', inputSchema: { type: 'object', properties: { test_level: { type: 'string', enum: ['basic', 'full', 'permissions'], description: 'Level of validation (basic=ping, full=read test, permissions=write test)', default: 'basic' }, include_performance: { type: 'boolean', description: 'Include response time metrics', default: false }, }, }, }, { name: 'batch_deployment_validator', description: 'Validates multiple artifacts before deployment. Checks dependencies, identifies conflicts, and provides remediation recommendations.', inputSchema: { type: 'object', properties: { artifacts: { type: 'array', items: { type: 'object', properties: { type: { type: 'string' }, sys_id: { type: 'string' }, table: { type: 'string' } } }, description: 'List of artifacts to validate' }, validation_level: { type: 'string', enum: ['syntax', 'dependencies', 'full'], description: 'Level of validation', default: 'full' }, check_conflicts: { type: 'boolean', description: 'Check for conflicts between artifacts', default: true }, }, required: ['artifacts'], }, }, { name: 'snow_escalate_permissions', description: 'Requests temporary elevated permissions for development operations. Manages role requirements and provides audit trail.', inputSchema: { type: 'object', properties: { required_roles: { type: 'array', items: { type: 'string' }, description: 'Required roles (admin, app_creator, system_administrator)' }, duration: { type: 'string', enum: ['session', 'temporary', 'workflow'], description: 'Duration of elevation', default: 'session' }, reason: { type: 'string', description: 'Reason for permission escalation' }, workflow_context: { type: 'string', description: 'Context of the development workflow requiring elevation' }, }, required: ['required_roles', 'reason'], }, }, { name: 'snow_analyze_requirements', description: 'Analyzes development requirements to identify dependencies, suggest reusable components, and create implementation roadmaps.', inputSchema: { type: 'object', properties: { objective: { type: 'string', description: 'Development objective (e.g., "iPhone provisioning for new users")' }, auto_discover_dependencies: { type: 'boolean', description: 'Automatically discover required dependencies', default: true }, suggest_existing_components: { type: 'boolean', description: 'Suggest reuse of existing components', default: true }, create_dependency_map: { type: 'boolean', description: 'Create visual dependency map', default: true }, scope_preference: { type: 'string', enum: ['global', 'scoped', 'auto'], description: 'Deployment scope preference', default: 'auto' }, }, required: ['objective'], }, }, { name: 'snow_orchestrate_development', description: 'Orchestrates complex development workflows with intelligent agent coordination, shared memory, and real-time progress tracking.', inputSchema: { type: 'object', properties: { objective: { type: 'string', description: 'Development objective (e.g., "iPhone provisioning workflow")' }, auto_spawn_agents: { type: 'boolean', description: 'Automatically spawn required agents', default: true }, shared_memory: { type: 'boolean', description: 'Enable shared memory between agents', default: true }, parallel_execution: { type: 'boolean', description: 'Enable parallel execution', default: true }, progress_monitoring: { type: 'boolean', description: 'Real-time progress monitoring', default: true }, auto_permissions: { type: 'boolean', description: 'Automatic permission escalation', default: false }, smart_discovery: { type: 'boolean', description: 'Smart artifact discovery and reuse', default: true }, live_testing: { type: 'boolean', description: 'Enable live testing during development', default: true }, auto_deploy: { type: 'boolean', description: 'Automatic deployment when ready', default: false }, }, required: ['objective'], }, }, ], })); // Register tool handlers this.server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { // Authenticate if needed const authResult = await mcp_auth_middleware_js_1.mcpAuth.ensureAuthenticated(); if (!authResult.success) { throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, authResult.error || 'Authentication required'); } switch (name) { case 'snow_find_artifact': return await this.findArtifact(args); case 'snow_edit_artifact': return await this.editArtifact(args); case 'snow_get_by_sysid': return await this.getBySysId(args); case 'snow_edit_by_sysid': return await this.editBySysId(args); case 'snow_analyze_artifact': return await this.analyzeArtifact(args); case 'snow_memory_search': return await this.searchMemory(args); case 'snow_comprehensive_search': return await this.comprehensiveSearch(args); case 'snow_sync_data_consistency': return await this.syncDataConsistency(args); case 'snow_validate_live_connection': return await this.validateLiveConnection(args); case 'batch_deployment_validator': return await this.batchDeploymentValidator(args); case 'snow_escalate_permissions': return await this.escalatePermissions(args); case 'snow_analyze_requirements': return await this.analyzeRequirements(args); case 'snow_orchestrate_development': return await this.orchestrateDevelopment(args); case 'snow_verify_artifact_searchable': return await this.verifyArtifactSearchable(args); case 'snow_generate_documentation': return await this.generateDocumentation(args); case 'snow_documentation_suggestions': return await this.getDocumentationSuggestions(args); case 'snow_start_continuous_documentation': return await this.startContinuousDocumentation(args); case 'snow_analyze_costs': const costRequest = { scope: args.scope || 'all', auto_implement: args.auto_implement || false, target_reduction: args.target_reduction, testing_enabled: args.testing_enabled !== false }; const costResult = await this.costOptimizationEngine.analyzeCosts(costRequest); return { content: [ { type: 'text', text: JSON.stringify(costResult, null, 2) } ] }; case 'snow_cost_dashboard': const dashboardResult = await this.costOptimizationEngine.getCostDashboard(); return { content: [ { type: 'text', text: JSON.stringify(dashboardResult, null, 2) } ] }; case 'snow_start_autonomous_cost_optimization': const startResult = await this.costOptimizationEngine.startAutonomousOptimization(args); return { content: [ { type: 'text', text: JSON.stringify(startResult, null, 2) } ] }; case 'snow_implement_cost_optimization': const implementResult = await this.costOptimizationEngine.implementOptimization(String(args.optimization_id)); return { content: [ { type: 'text', text: JSON.stringify(implementResult, null, 2) } ] }; case 'snow_assess_compliance': const complianceResult = await this.complianceSystem.assessCompliance(args); return { content: [ { type: 'text', text: JSON.stringify(complianceResult, null, 2) } ] }; case 'snow_compliance_dashboard': const complianceDashboard = await this.complianceSystem.getComplianceDashboard(); return { content: [ { type: 'text', text: JSON.stringify(complianceDashboard, null, 2) } ] }; case 'snow_start_compliance_monitoring': const monitoringResult = await this.complianceSystem.startContinuousMonitoring(args); return { content: [ { type: 'text', text: 'āœ… Compliance monitoring started successfully' } ] }; case 'snow_execute_corrective_action': const actionResult = await this.complianceSystem.executeCorrectiveAction(String(args.action_id), args); return { content: [ { type: 'text', text: JSON.stringify(actionResult, null, 2) } ] }; case 'snow_health_check': const healthResult = await this.selfHealingSystem.performHealthCheck(args); return { content: [ { type: 'text', text: JSON.stringify(healthResult, null, 2) } ] }; case 'snow_health_dashboard': const healthDashboard = await this.selfHealingSystem.getHealthDashboard(); return { content: [ { type: 'text', text: JSON.stringify(healthDashboard, null, 2) } ] }; case 'snow_start_autonomous_healing': const healingStartResult = await this.selfHealingSystem.startAutonomousHealing(args); return { content: [ { type: 'text', text: 'āœ… Autonomous healing started successfully' } ] }; case 'snow_execute_healing_action': const healingResult = await this.selfHealingSystem.executeHealingAction(String(args.action_id), args); return { content: [ { type: 'text', text: JSON.stringify(healingResult, null, 2) } ] }; default: throw new Error(`Unknown tool: ${name}`); } } catch (error) { this.logger.error(`Tool execution failed: ${name}`, error); throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, error instanceof Error ? error.message : String(error)); } }); } async findArtifact(args) { // Check authentication first const authResult = await mcp_auth_middleware_js_1.mcpAuth.ensureAuthenticated(); if (!authResult.success) { return { content: [ { type: 'text', text: authResult.error || 'āŒ Not authenticated with ServiceNow.\n\nPlease run: snow-flow auth login\n\nOr configure your .env file with ServiceNow OAuth credentials.', }, ], }; } try { this.logger.info('šŸ”“ SNOW-002 FIX: Finding ServiceNow artifact with retry logic', { query: args.query }); // 1. Parse natural language intent const intent = await this.parseIntent(args.query); // 2. Search in memory first const memoryResults = await this.searchInMemory(intent); if (memoryResults.length > 0) { return { content: [ { type: 'text', text: `🧠 Found in memory:\n\n${this.formatResults(memoryResults)}\n\nšŸ’” Using cached intelligent index for optimal performance.`, }, ], }; } // šŸ”“ CRITICAL FIX: Search ServiceNow with retry logic for newly created artifacts this.logger.info(`šŸ” Searching ServiceNow with retry logic for: ${intent.identifier} (type: ${intent.artifactType})`); const liveResults = await this.searchServiceNowWithRetry(intent); this.logger.info(`āœ… ServiceNow search with retry returned ${liveResults?.length || 0} results`); // Debug log if (liveResults && liveResults.length > 0) { this.logger.info(`First result: ${JSON.stringify(liveResults[0])}`); } // 4. Index results for future use (only if we have results) // Skip indexing - causes timeouts /* if (liveResults && liveResults.length > 0) { this.logger.info('Indexing found artifacts for future use...'); for (const result of liveResults) { await this.intelligentlyIndex(result); } } */ const instanceInfo = await mcp_auth_middleware_js_1.mcpAuth.getInstanceInfo(); const resultText = this.formatResults(liveResults); this.logger.info(`Formatted result text: ${resultText.substring(0, 200)}...`); const editSuggestion = this.generateEditSuggestion(liveResults?.[0]); return { content: [ { type: 'text', text: `šŸ” ServiceNow Search Results:\n\n${resultText}\n\nšŸ”— ServiceNow Instance: ${instanceInfo.instance}\n\n${editSuggestion}`, }, ], }; } catch (error) { throw new Error(`Artifact search failed: ${error instanceof Error ? error.message : String(error)}`); } } async editArtifact(args) { // Check authentication first const authResult = await mcp_auth_middleware_js_1.mcpAuth.ensureAuthenticated(); if (!authResult.success) { return { content: [ { type: 'text', text: authResult.error || 'āŒ Not authenticated with ServiceNow.\n\nPlease run: snow-flow auth login\n\nOr configure your .env file with ServiceNow OAuth credentials.', }, ], }; } try { this.logger.info('Editing ServiceNow artifact', { query: args.query }); // 1. Parse edit instruction const editIntent = await this.parseEditIntent(args.query); // 2. Find target artifact const artifact = await this.findTargetArtifact(editIntent); // 3. Analyze modification requirements const modification = await this.analyzeModification(editIntent, artifact); // 4. Apply intelligent modification const editedArtifact = await this.applyModification(artifact, modification); // 5. Deploy back to ServiceNow const deployResult = await this.deployArtifact(editedArtifact); // 6. Update memory with changes await this.updateMemoryIndex(editedArtifact, modification); const instanceInfo = await mcp_auth_middleware_js_1.mcpAuth.getInstanceInfo(); return { content: [ { type: 'text', text: `āœ… ServiceNow artifact successfully modified!\n\nšŸŽÆ Modification Details:\n- Artifact: ${artifact.name}\n- Type: ${artifact.type}\n- Changes: ${modification.description}\n\nšŸ”— View in ServiceNow: ${instanceInfo.instance}/nav_to.do?uri=${this.getArtifactUrl(artifact)}\n\nšŸ“ The artifact has been intelligently indexed and is now available for future natural language queries.`, }, ], }; } catch (error) { throw new Error(`Artifact editing failed: ${error instanceof Error ? error.message : String(error)}`); } } async analyzeArtifact(args) { // Check authentication first const authResult = await mcp_auth_middleware_js_1.mcpAuth.ensureAuthenticated(); if (!authResult.success) { return { content: [ { type: 'text', text: authResult.error || 'āŒ Not authenticated with ServiceNow.\n\nPlease run: snow-flow auth login\n\nOr configure your .env file with ServiceNow OAuth credentials.', }, ], }; } try { this.logger.info('Analyzing ServiceNow artifact', { sys_id: args.sys_id }); // Fetch complete artifact from ServiceNow const artifact = await this.client.getRecord(args.table, args.sys_id); // Skip indexing - causes timeouts /* // Perform intelligent indexing const indexedArtifact = await this.intelligentlyIndex(artifact); // Store in memory await this.storeInMemory(indexedArtifact); */ // Create minimal indexed artifact for response const indexedArtifact = { meta: { sys_id: artifact.sys_id, name: artifact.name || artifact.title || 'Unknown', type: artifact.sys_class_name || 'unknown', }, claudeSummary: `${artifact.name || artifact.title} is a ${artifact.sys_class_name || 'artifact'} in ServiceNow.`, structure: {}, context: {}, relationships: [], modificationPoints: [] }; return { content: [ { type: 'text', text: `🧠 Artifact Analysis Complete!\n\nšŸ“‹ Summary:\n${indexedArtifact.claudeSummary}\n\nšŸ—ļø Structure:\n${JSON.stringify(indexedArtifact.structure, null, 2)}\n\nšŸŽÆ Modification Points:\n${indexedArtifact.modificationPoints.map(p => `- ${p.description}`).join('\n')}\n\nšŸ’¾ Artifact has been intelligently indexed and stored in memory for future natural language interactions.`, }, ], }; } catch (error) { throw new Error(`Artifact _analysis failed: ${error instanceof Error ? error.message : String(error)}`); } } async searchMemory(args) { try { const results = await this.searchInMemory({ identifier: args.query, artifactType: args.type || 'any', action: 'find', confidence: 0.8 }); return { content: [ { type: 'text', text: `🧠 Memory Search Results:\n\n${this.formatMemoryResults(results)}\n\nšŸ’” All results are from the intelligent index for instant access.`, }, ], }; } catch (error) { throw new Error(`Memory search failed: ${error instanceof Error ? error.message : String(error)}`); } } async comprehensiveSearch(args) { // Check authentication first const authResult = await mcp_auth_middleware_js_1.mcpAuth.ensureAuthenticated(); if (!authResult.success) { return { content: [ { type: 'text', text: authResult.error || 'āŒ Not authenticated with ServiceNow.\n\nPlease run: snow-flow auth login\n\nOr configure your .env file with ServiceNow OAuth credentials.', }, ], }; } try { this.logger.info('Starting comprehensive search', { query: args.query }); // Define tables to search with their descriptions const searchTables = [ { name: 'sys_script', desc: 'Business Rules', type: 'business_rule' }, { name: 'sys_script_include', desc: 'Script Includes', type: 'script_include' }, { name: 'sys_script_client', desc: 'Client Scripts', type: 'client_script' }, { name: 'sys_ui_script', desc: 'UI Scripts', type: 'ui_script' }, { name: 'sp_widget', desc: 'Service Portal Widgets', type: 'widget' }, { name: 'sys_hub_flow', desc: 'Flow Designer Flows', type: 'flow' }, { name: 'wf_workflow', desc: 'Workflows', type: 'workflow' }, { name: 'sys_ui_action', desc: 'UI Actions', type: 'ui_action' }, { name: 'sys_ui_policy', desc: 'UI Policies', type: 'ui_policy' }, { name: 'sys_data_policy', desc: 'Data Policies', type: 'data_policy' }, { name: 'sys_app_application', desc: 'Applications', type: 'application' }, { name: 'sys_db_object', desc: 'Tables', type: 'table' }, { name: 'sys_dictionary', desc: 'Dictionary/Fields', type: 'field' }, { name: 'sysevent_email_action', desc: 'Notifications', type: 'notification' }, { name: 'sys_transform_map', desc: 'Transform Maps', type: 'transform_map' }, { name: 'sys_ws_definition', desc: 'REST APIs', type: 'rest_api' }, { name: 'sc_cat_item', desc: 'Catalog Items', type: 'catalog_item' }, { name: 'sc_catalog', desc: 'Service Catalogs', type: 'catalog' }, { name: 'sc_category', desc: 'Catalog Categories', type: 'catalog_category' }, { name: 'item_option_new', desc: 'Catalog Variables', type: 'catalog_variable' }, ]; const searchString = args.query.trim(); const allResults = []; // Generate multiple search strategies like Claude Code did const searchStrategies = [ { query: `name=${searchString}`, desc: 'Exact name match' }, { query: `nameLIKE${searchString}`, desc: 'Name contains' }, { query: `short_descriptionLIKE${searchString}`, desc: 'Description contains' }, { query: `nameLIKE${searchString}^ORshort_descriptionLIKE${searchString}`, desc: 'Name or description' }, ]; // Add wildcard searches if multiple words const words = searchString.split(' ').filter((w) => w.length > 2); if (words.length > 1) { const firstWord = words[0]; const lastWord = words[words.length - 1]; searchStrategies.push({ query: `nameLIKE*${firstWord}*${lastWord}*`, desc: 'First and last word match' }); } // šŸ”“ SNOW-002 FIX: Apply retry logic to comprehensive search as well for (const table of searchTables) { this.logger.info(`šŸ”“ SNOW-002 FIX: Searching ${table.desc} (${table.name}) with retry logic...`); // Try search with retry logic for each table const tableResults = []; const maxTableRetries = 3; // Shorter retry for comprehensive search for (let attempt = 1; attempt <= maxTableRetries; attempt++) { let foundResults = false; for (const strategy of searchStrategies) { try { const activeFilter = args.include_inactive ? '' : '^active=true'; const fullQuery = `${strategy.query}${activeFilter}^LIMIT5`; const results = await this.client.searchRecords(table.name, fullQuery); if (results && results.success && results.data.result.length > 0) { // Add metadata to results const enhancedResults = results.data.result.map((result) => ({ ...result, artifact_type: table.type, table_name: table.name, table_description: table.desc, search_strategy: strategy.desc, retry_attempt: attempt })); tableResults.push(...enhancedResults); foundResults = true; // Stop searching this table if we found results break; } } catch (error) { this.logger.warn(`Error searching ${table.name} (attempt ${attempt}):`, error); } } // If we found results, stop retrying this table if (foundResults) { break; } // If no results and not the last attempt, wait before retry if (attempt < maxTableRetries) { const delay = 800 * attempt; // Shorter delays: 800ms, 1600ms this.logger.info(`šŸ”„ No results for ${table.name}, waiting ${delay}ms before retry...`); await this.sleep(delay); } } // Add any results found for this table allResults.push(...tableResults); } // Remove duplicates by sys_id const uniqueResults = allResults.filter((result, index, self) => index === self.findIndex(r => r.sys_id === result.sys_id)); const instanceInfo = await mcp_auth_middleware_js_1.mcpAuth.getInstanceInfo(); const resultText = this.formatComprehensiveResults(uniqueResults); return { content: [ { type: 'text', text: `šŸ” Comprehensive ServiceNow Search Results:\n\n${resultText}\n\nšŸ”— ServiceNow Instance: ${instanceInfo.instance}\n\nšŸ’” Searched across ${searchTables.length} table types with multiple strategies.`, }, ], }; } catch (error) { throw new Error(`Comprehensive search failed: ${error instanceof Error ? error.message : String(error)}`); } } async parseIntent(query) { // Enhanced intent parsing with comprehensive type detection const lowercaseQuery = query.toLowerCase(); let artifactType = 'any'; // Default to searching all types // Check for specific artifact types (order matters - most specific first) // Service Portal if (lowercaseQuery.includes('widget')) artifactType = 'widget'; else if (lowercaseQuery.includes('portal')) artifactType = 'portal'; else if (lowercaseQuery.includes('page') && lowercaseQuery.includes('service')) artifactType = 'page'; else if (lowercaseQuery.includes('theme')) artifactType = 'theme'; // Flow Designer & Workflow else if (lowercaseQuery.includes('flow designer') || lowercaseQuery.includes('sys_hub_flow')) artifactType = 'flow'; else if (lowercaseQuery.includes('workflow') && !lowercaseQuery.includes('orchestration')) artifactType = 'workflow'; else if (lowercaseQuery.includes('workflow activity')) artifactType = 'workflow_activity'; else if (lowercaseQuery.includes('flow')) artifactType = 'flow'; // Scripts & Automation (most specific first) else if (lowercaseQuery.includes('script include')) artifactType = 'script_include'; else if (lowercaseQuery.includes('business rule')) artifactType = 'business_rule'; else if (lowercaseQuery.includes('client script')) artifactType = 'client_script'; else if (lowercaseQuery.includes('ui script')) artifactType = 'ui_script'; else if (lowercaseQuery.includes('ui action')) artifactType = 'ui_action'; else if (lowercaseQuery.includes('ui policy action')) artifactType = 'ui_policy_action'; else if (lowercaseQuery.includes('ui policy')) artifactType = 'ui_policy'; else if (lowercaseQuery.includes('data policy rule')) artifactType = 'data_policy_rule'; else if (lowercaseQuery.includes('data policy')) artifactType = 'data_policy'; // Applications else if (lowercaseQuery.includes('scoped app')) artifactType = 'scoped_app'; else if (lowercaseQuery.includes('application') || lowercaseQuery.includes('app')) artifactType = 'application'; // Tables & Fields else if (lowercaseQuery.includes('field') || lowercaseQuery.includes('dictionary')) artifactType = 'field'; else if (lowercaseQuery.includes('table')) artifactType = 'table'; // Forms & UI else if (lowercaseQuery.includes('form section')) artifactType = 'form_section'; else if (lowercaseQuery.includes('list control')) artifactType = 'list_control'; else if (lowercaseQuery.includes('related list')) artifactType = 'related_list'; else if (lowercaseQuery.includes('form')) artifactType = 'form'; else if (lowercaseQuery.includes('list')) artifactType = 'list'; else if (lowercaseQuery.includes('view')) artifactType = 'view'; else if (lowercaseQuery.includes('formatter')) artifactType = 'formatter'; // Reports & Dashboards else if (lowercaseQuery.includes('pa dashboard')) artifactType = 'pa_dashboard'; else if (lowercaseQuery.includes('pa widget')) artifactType = 'pa_widget'; else if (lowercaseQuery.includes('dashboard')) artifactType = 'dashboard'; else if (lowercaseQuery.includes('report')) artifactType = 'report'; else if (lowercaseQuery.includes('gauge')) artifactType = 'gauge'; else if (lowercaseQuery.includes('chart')) artifactType = 'chart'; else if (lowercaseQuery.includes('indicator')) artifactType = 'indicator'; // Security & Access Control else if (lowercaseQuery.includes('acl') || lowercaseQuery.includes('access control')) artifactType = 'acl'; else if (lowercaseQuery.includes('role')) artifactType = 'role'; else if (lowercaseQuery.includes('group')) artifactType = 'group'; // Notifications & Communication else if (lowercaseQuery.includes('email template')) artifactType = 'email_template'; else if (lowercaseQuery.includes('notification')) artifactType = 'notification'; // Import & Export else if (lowercaseQuery.includes('import set')) artifactType = 'import_set'; else if (lowercaseQuery.includes('transform map')) artifactType = 'transform_map'; // Web Services else if (lowercaseQuery.includes('rest api') || lowercaseQuery.includes('rest')) artifactType = 'rest_api'; else if (lowercaseQuery.includes('soap api') || lowercaseQuery.includes('soap')) artifactType = 'soap_api'; // Scheduled Jobs else if (lowercaseQuery.includes('scheduled job')) artifactType = 'scheduled_job'; else if (lowercaseQuery.includes('scheduled import')) artifactType = 'scheduled_import'; // Knowledge Management else if (lowercaseQuery.includes('knowledge base')) artifactType = 'knowledge_base'; else if (lowercaseQuery.includes('knowledge article') || lowercaseQuery.includes('knowledge')) artifactType = 'knowledge_article'; // System Administration else if (lowercaseQuery.includes('system property') || lowercaseQuery.includes('property')) artifactType = 'property'; // Mobile else if (lowercaseQuery.includes('mobile app') || lowercaseQuery.includes('mobile')) artifactType = 'mobile_app'; // Catalog else if (lowercaseQuery.includes('catalog item')) artifactType = 'catalog_item'; else if (lowercaseQuery.includes('catalog variable')) artifactType = 'catalog_variable'; else if (lowercaseQuery.includes('catalog')) artifactType = 'catalog'; // SLA & Metrics else if (lowercaseQuery.includes('sla')) artifactType = 'sla'; else if (lowercaseQuery.includes('metric')) artifactType = 'metric'; // Other common types else if (lowercaseQuery.includes('attachment')) artifactType = 'attachment'; else if (lowercaseQuery.includes('language')) artifactType = 'language'; else if (lowercaseQuery.includes('translation')) artifactType = 'translated_text'; else if (lowercaseQuery.includes('processor')) artifactType = 'processor'; else if (lowercaseQuery.includes('update set')) artifactType = 'update_set'; else if (lowercaseQuery.includes('ml model') || lowercaseQuery.includes('machine learning')) artifactType = 'ml_model'; else if (lowercaseQuery.includes('spoke')) artifactType = 'spoke'; else if (lowercaseQuery.includes('connection')) artifactType = 'connection'; else if (lowercaseQuery.includes('virtual agent') || lowercaseQuery.includes('chatbot')) artifactType = 'virtual_agent'; else if (lowercaseQuery.includes('event rule')) artifactType = 'event_rule'; else if (lowercaseQuery.includes('alert')) artifactType = 'alert'; else if (lowercaseQuery.includes('discovery')) artifactType = 'discovery_schedule'; else if (lowercaseQuery.includes('ci class')) artifactType = 'ci_class'; else if (lowercaseQuery.includes('relationship')) artifactType = 'relationship_type'; else if (lowercaseQuery.includes('service map')) artifactType = 'service_map'; else if (lowercaseQuery.includes('orchestration workflow')) artifactType = 'orchestration_workflow'; else if (lowercaseQuery.includes('pipeline')) artifactType = 'pipeline'; else if (lowercaseQuery.includes('deployment')) artifactType = 'deployment'; // Generic fallbacks else if (lowercaseQuery.includes('script')) artifactType = 'script_include'; // Smart identifier extraction - remove artifact type keywords and get the actual name const identifier = this.extractIdentifier(query, artifactType); return { action: 'find', artifactType, identifier, confidence: 0.9, }; } extractIdentifier(query, artifactType) { // Smart extraction of actual artifact name by removing type keywords let identifier = query.toLowerCase().trim(); // Remove common artifact type keywords const typeKeywords = [ 'widget', 'portal', 'page', 'theme', 'flow designer', 'sys_hub_flow', 'workflow', 'workflow activity', 'flow', 'script include', 'business rule', 'client script', 'ui script', 'ui action', 'ui policy action', 'ui policy', 'data policy rule', 'data policy', 'scoped app', 'application', 'app', 'field', 'dictionary', 'table', 'form sec