snow-flow 2.0.2 → 2.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. package/{.claude/mcp-config.json → .mcp.json} +13 -12
  2. package/.releaserc.json +47 -0
  3. package/README.md +48 -1
  4. package/package.json +1 -1
  5. package/.claude/claude-settings.json +0 -15
  6. package/.claude/commands/analysis/README.md +0 -9
  7. package/.claude/commands/automation/README.md +0 -9
  8. package/.claude/commands/github/README.md +0 -11
  9. package/.claude/commands/helpers/standard-checkpoint-hooks.sh +0 -179
  10. package/.claude/commands/hooks/README.md +0 -11
  11. package/.claude/commands/monitoring/README.md +0 -9
  12. package/.claude/commands/optimization/README.md +0 -9
  13. package/.claude/commands/training/README.md +0 -9
  14. package/.claude/commands/workflows/README.md +0 -9
  15. package/.claude/config.json +0 -36
  16. package/.claude/helpers/github-setup.sh +0 -28
  17. package/.claude/helpers/quick-start.sh +0 -19
  18. package/.claude/helpers/setup-mcp.sh +0 -18
  19. package/.claude/settings.json +0 -114
  20. package/.claude/settings.local.json +0 -33
  21. package/.claude-flow/metrics/agent-metrics.json +0 -1
  22. package/.claude-flow/metrics/performance.json +0 -9
  23. package/.claude-flow/metrics/system-metrics.json +0 -15986
  24. package/.claude-flow/metrics/task-metrics.json +0 -10
  25. package/.roo/README.md +0 -402
  26. package/.roo/mcp-list.txt +0 -257
  27. package/.roo/mcp.json +0 -32
  28. package/.roo/workflows/basic-tdd.json +0 -32
  29. package/.roomodes +0 -201
  30. package/CLAUDE.md +0 -393
  31. package/bin/snow-flow.js +0 -3
  32. package/dist/cli.js.bak +0 -2052
  33. package/dist/config/snow-flow-config.d.ts +0 -1492
  34. package/dist/config/snow-flow-config.js +0 -938
  35. package/scripts/create-env.js +0 -91
  36. package/scripts/postinstall.js +0 -30
  37. package/scripts/register-mcp-servers.js +0 -210
  38. package/scripts/reset-mcp-servers.js +0 -246
  39. package/scripts/setup-mcp.js +0 -106
  40. package/scripts/update-version.js +0 -31
  41. package/src/agents/README.md +0 -192
  42. package/src/agents/base-agent.ts +0 -251
  43. package/src/agents/coordinator.ts +0 -971
  44. package/src/agents/index.ts +0 -18
  45. package/src/agents/queen-403-handler.ts +0 -230
  46. package/src/agents/queen-agent.ts +0 -1399
  47. package/src/agents/script-writer-agent.ts +0 -769
  48. package/src/agents/security-agent.ts +0 -726
  49. package/src/agents/widget-creator-agent.ts +0 -568
  50. package/src/api/error-handling.ts +0 -1758
  51. package/src/api/natural-language-mapper.ts +0 -630
  52. package/src/api/performance-optimizer.ts +0 -891
  53. package/src/api/transaction-manager.ts +0 -754
  54. package/src/cli/deploy-artifact.ts +0 -304
  55. package/src/cli/snow-flow-cli-integration.ts +0 -434
  56. package/src/cli.ts +0 -4455
  57. package/src/cli.ts.bak +0 -5616
  58. package/src/compliance/advanced-compliance-system.ts +0 -1268
  59. package/src/compliance/index.ts +0 -19
  60. package/src/config/snow-flow-config.ts +0 -1019
  61. package/src/documentation/index.ts +0 -16
  62. package/src/documentation/self-documenting-system.ts +0 -1421
  63. package/src/dynamic-version.ts +0 -44
  64. package/src/healing/index.ts +0 -20
  65. package/src/healing/self-healing-system.ts +0 -1435
  66. package/src/health/README.md +0 -161
  67. package/src/health/system-health.ts +0 -995
  68. package/src/index.ts +0 -60
  69. package/src/intelligence/acl-analyzer.ts +0 -377
  70. package/src/intelligence/auto-resolution-engine.ts +0 -643
  71. package/src/intelligence/gap-analysis-engine.ts +0 -488
  72. package/src/intelligence/manual-instructions-generator.ts +0 -744
  73. package/src/intelligence/mcp-coverage-analyzer.ts +0 -708
  74. package/src/intelligence/multi-pass-requirements-analyzer.ts +0 -603
  75. package/src/intelligence/performance-recommendations-engine.ts +0 -1223
  76. package/src/intelligence/requirements-analyzer.ts +0 -1148
  77. package/src/intelligence/task-analyzer.ts +0 -628
  78. package/src/managers/scope-manager.ts +0 -555
  79. package/src/mcp/advanced/servicenow-advanced-features-mcp.ts +0 -16110
  80. package/src/mcp/base-mcp-server.ts +0 -660
  81. package/src/mcp/http-transport-wrapper.ts +0 -426
  82. package/src/mcp/service-discovery-client.ts +0 -312
  83. package/src/mcp/servicenow-automation-mcp-refactored.ts +0 -678
  84. package/src/mcp/servicenow-automation-mcp.ts +0 -838
  85. package/src/mcp/servicenow-deployment-mcp-refactored.ts +0 -1292
  86. package/src/mcp/servicenow-deployment-mcp.ts +0 -7244
  87. package/src/mcp/servicenow-graph-memory-mcp-refactored.ts +0 -721
  88. package/src/mcp/servicenow-graph-memory-mcp.ts +0 -832
  89. package/src/mcp/servicenow-integration-mcp-refactored.ts +0 -655
  90. package/src/mcp/servicenow-integration-mcp.ts +0 -819
  91. package/src/mcp/servicenow-intelligent-mcp-refactored.ts +0 -977
  92. package/src/mcp/servicenow-intelligent-mcp.ts +0 -4638
  93. package/src/mcp/servicenow-mcp-server.ts +0 -728
  94. package/src/mcp/servicenow-memory-mcp.ts +0 -474
  95. package/src/mcp/servicenow-operations-mcp-refactored.ts +0 -1995
  96. package/src/mcp/servicenow-operations-mcp.ts +0 -3384
  97. package/src/mcp/servicenow-platform-development-mcp-refactored.ts +0 -611
  98. package/src/mcp/servicenow-platform-development-mcp.ts +0 -970
  99. package/src/mcp/servicenow-progressive-indexer.ts +0 -370
  100. package/src/mcp/servicenow-reporting-analytics-mcp-refactored.ts +0 -695
  101. package/src/mcp/servicenow-reporting-analytics-mcp.ts +0 -1123
  102. package/src/mcp/servicenow-security-compliance-mcp-refactored.ts +0 -642
  103. package/src/mcp/servicenow-security-compliance-mcp.ts +0 -1157
  104. package/src/mcp/servicenow-update-set-mcp-refactored.ts +0 -751
  105. package/src/mcp/servicenow-update-set-mcp.ts +0 -811
  106. package/src/mcp/shared/agent-context-provider.ts +0 -365
  107. package/src/mcp/shared/base-mcp-server.ts +0 -2463
  108. package/src/mcp/shared/mcp-memory-manager.ts +0 -540
  109. package/src/mcp/shared/mcp-resource-manager.ts +0 -367
  110. package/src/mcp/snow-flow-mcp.ts +0 -911
  111. package/src/mcp/start-all-mcp-servers.ts +0 -102
  112. package/src/mcp/start-servicenow-mcp.ts +0 -67
  113. package/src/monitoring/enhanced-monitoring-system.ts +0 -1345
  114. package/src/monitoring/performance-tracker.ts +0 -777
  115. package/src/optimization/cost-optimization-engine.ts +0 -1125
  116. package/src/optimization/index.ts +0 -10
  117. package/src/queen/README.md +0 -403
  118. package/src/queen/agent-factory.ts +0 -574
  119. package/src/queen/index.ts +0 -94
  120. package/src/queen/mcp-execution-bridge.ts +0 -681
  121. package/src/queen/neural-learning.ts +0 -319
  122. package/src/queen/parallel-agent-engine.ts +0 -848
  123. package/src/queen/queen-memory-system.ts +0 -490
  124. package/src/queen/queen-memory.ts +0 -456
  125. package/src/queen/servicenow-queen.ts +0 -1029
  126. package/src/queen/types.ts +0 -87
  127. package/src/rollback/smart-rollback-system.ts +0 -866
  128. package/src/schemas/deployment.schema.json +0 -58
  129. package/src/schemas/flow.schema.json +0 -79
  130. package/src/schemas/widget.schema.json +0 -72
  131. package/src/snow-flow-system.ts +0 -541
  132. package/src/sparc/sparc-help.ts +0 -49
  133. package/src/sparc/team-sparc.ts +0 -88
  134. package/src/strategies/global-scope-strategy.ts +0 -736
  135. package/src/templates/base/application.template.json +0 -45
  136. package/src/templates/base/business_rule.template.json +0 -33
  137. package/src/templates/base/script_include.template.json +0 -18
  138. package/src/templates/base/table.template.json +0 -64
  139. package/src/templates/base/widget.template.json +0 -25
  140. package/src/templates/patterns/composite.incident-management.template.json +0 -140
  141. package/src/templates/patterns/widget.dashboard.template.json +0 -238
  142. package/src/templates/patterns/widget.datatable.template.json +0 -292
  143. package/src/testing/integration-test-suite.ts +0 -1276
  144. package/src/types/index.ts +0 -183
  145. package/src/types/neo4j-driver.d.ts +0 -23
  146. package/src/types/servicenow.types.ts +0 -307
  147. package/src/types/snow-flow.types.ts +0 -186
  148. package/src/types/todo.types.ts +0 -70
  149. package/src/utils/action-type-cache.ts +0 -286
  150. package/src/utils/agent-detector.ts +0 -573
  151. package/src/utils/artifact-tracker.ts +0 -379
  152. package/src/utils/dependency-detector.ts +0 -233
  153. package/src/utils/deployment-metadata-handler.ts +0 -518
  154. package/src/utils/error-recovery.ts +0 -680
  155. package/src/utils/logger.ts +0 -60
  156. package/src/utils/mcp-auth-middleware.ts +0 -262
  157. package/src/utils/mcp-config-manager.ts +0 -270
  158. package/src/utils/mcp-server-manager.ts +0 -446
  159. package/src/utils/mcp-tool-registry.ts +0 -298
  160. package/src/utils/migrate-snow-flow.ts +0 -98
  161. package/src/utils/oauth-html-templates.ts +0 -188
  162. package/src/utils/scope-utils.ts +0 -443
  163. package/src/utils/servicenow-client.ts +0 -3321
  164. package/src/utils/servicenow-id-generator.ts +0 -181
  165. package/src/utils/snow-memory-manager.ts +0 -605
  166. package/src/utils/snow-oauth.ts +0 -797
  167. package/src/utils/template-engine.ts +0 -463
  168. package/src/utils/theme-manager.ts +0 -295
  169. package/src/utils/unified-auth-store.ts +0 -222
  170. package/src/utils/update-set-importer.ts +0 -422
  171. package/src/utils/update-set-xml-packager.ts +0 -371
  172. package/src/utils/widget-template-generator.ts +0 -1744
  173. package/src/version.ts +0 -1950
@@ -1,1123 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * ServiceNow Reporting & Analytics MCP Server
4
- * Handles reports, dashboards, and analytics operations
5
- * NO HARDCODED VALUES - All reporting configurations discovered dynamically
6
- */
7
-
8
- import { Server } from '@modelcontextprotocol/sdk/server/index.js';
9
- import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
10
- import {
11
- CallToolRequestSchema,
12
- ErrorCode,
13
- ListToolsRequestSchema,
14
- McpError,
15
- } from '@modelcontextprotocol/sdk/types.js';
16
- import { ServiceNowClient } from '../utils/servicenow-client.js';
17
- import { mcpAuth } from '../utils/mcp-auth-middleware.js';
18
- import { mcpConfig } from '../utils/mcp-config-manager.js';
19
- import { Logger } from '../utils/logger.js';
20
-
21
- interface ReportDefinition {
22
- name: string;
23
- table: string;
24
- conditions: string;
25
- fields: string[];
26
- aggregations: string[];
27
- groupBy: string[];
28
- }
29
-
30
- interface DashboardWidget {
31
- name: string;
32
- type: string;
33
- dataSource: string;
34
- configuration: any;
35
- layout: any;
36
- }
37
-
38
- class ServiceNowReportingAnalyticsMCP {
39
- private server: Server;
40
- private client: ServiceNowClient;
41
- private logger: Logger;
42
- private config: ReturnType<typeof mcpConfig.getConfig>;
43
-
44
- constructor() {
45
- this.server = new Server(
46
- {
47
- name: 'servicenow-reporting-analytics',
48
- version: '1.0.0',
49
- },
50
- {
51
- capabilities: {
52
- tools: {},
53
- },
54
- }
55
- );
56
-
57
- this.client = new ServiceNowClient();
58
- this.logger = new Logger('ServiceNowReportingAnalyticsMCP');
59
- this.config = mcpConfig.getConfig();
60
-
61
- this.setupHandlers();
62
- }
63
-
64
- private setupHandlers() {
65
- this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
66
- tools: [
67
- {
68
- name: 'snow_create_report',
69
- description: 'Create Report with dynamic table and field discovery - NO hardcoded values',
70
- inputSchema: {
71
- type: 'object',
72
- properties: {
73
- name: { type: 'string', description: 'Report name' },
74
- table: { type: 'string', description: 'Source table' },
75
- description: { type: 'string', description: 'Report description' },
76
- conditions: { type: 'string', description: 'Report conditions/filters' },
77
- fields: { type: 'array', description: 'Fields to include in report' },
78
- groupBy: { type: 'array', description: 'Group by fields' },
79
- aggregations: { type: 'array', description: 'Aggregation functions' },
80
- sortBy: { type: 'string', description: 'Sort field' },
81
- sortOrder: { type: 'string', description: 'Sort order (asc/desc)' },
82
- schedule: { type: 'string', description: 'Report schedule' },
83
- format: { type: 'string', description: 'Output format (PDF, Excel, CSV)' }
84
- },
85
- required: ['name', 'table', 'fields']
86
- }
87
- },
88
- {
89
- name: 'snow_create_dashboard',
90
- description: 'Create Dashboard with dynamic widget discovery',
91
- inputSchema: {
92
- type: 'object',
93
- properties: {
94
- name: { type: 'string', description: 'Dashboard name' },
95
- description: { type: 'string', description: 'Dashboard description' },
96
- layout: { type: 'string', description: 'Dashboard layout (grid, tabs, accordion)' },
97
- widgets: { type: 'array', description: 'Dashboard widgets configuration' },
98
- permissions: { type: 'array', description: 'User/role permissions' },
99
- refreshInterval: { type: 'number', description: 'Auto-refresh interval in minutes' },
100
- public: { type: 'boolean', description: 'Public dashboard' }
101
- },
102
- required: ['name', 'widgets']
103
- }
104
- },
105
- {
106
- name: 'snow_create_kpi',
107
- description: 'Create KPI with dynamic metric discovery',
108
- inputSchema: {
109
- type: 'object',
110
- properties: {
111
- name: { type: 'string', description: 'KPI name' },
112
- description: { type: 'string', description: 'KPI description' },
113
- table: { type: 'string', description: 'Source table' },
114
- metric: { type: 'string', description: 'Metric to measure' },
115
- aggregation: { type: 'string', description: 'Aggregation function (count, sum, avg, max, min)' },
116
- conditions: { type: 'string', description: 'KPI conditions/filters' },
117
- target: { type: 'number', description: 'Target value' },
118
- threshold: { type: 'object', description: 'Threshold configuration' },
119
- unit: { type: 'string', description: 'Unit of measurement' },
120
- frequency: { type: 'string', description: 'Update frequency' }
121
- },
122
- required: ['name', 'table', 'metric', 'aggregation']
123
- }
124
- },
125
- {
126
- name: 'snow_create_data_visualization',
127
- description: 'Create Data Visualization with dynamic chart discovery',
128
- inputSchema: {
129
- type: 'object',
130
- properties: {
131
- name: { type: 'string', description: 'Visualization name' },
132
- type: { type: 'string', description: 'Chart type (bar, line, pie, scatter, etc.)' },
133
- dataSource: { type: 'string', description: 'Data source (table or report)' },
134
- xAxis: { type: 'string', description: 'X-axis field' },
135
- yAxis: { type: 'string', description: 'Y-axis field' },
136
- series: { type: 'array', description: 'Data series configuration' },
137
- filters: { type: 'array', description: 'Chart filters' },
138
- colors: { type: 'array', description: 'Color palette' },
139
- interactive: { type: 'boolean', description: 'Interactive chart' }
140
- },
141
- required: ['name', 'type', 'dataSource']
142
- }
143
- },
144
- {
145
- name: 'snow_create_performance_analytics',
146
- description: 'Create Performance Analytics with dynamic metric discovery',
147
- inputSchema: {
148
- type: 'object',
149
- properties: {
150
- name: { type: 'string', description: 'Analytics name' },
151
- category: { type: 'string', description: 'Analytics category' },
152
- dataSource: { type: 'string', description: 'Data source table' },
153
- metrics: { type: 'array', description: 'Performance metrics to track' },
154
- dimensions: { type: 'array', description: 'Analysis dimensions' },
155
- timeframe: { type: 'string', description: 'Time period for _analysis' },
156
- benchmarks: { type: 'array', description: 'Performance benchmarks' },
157
- alerts: { type: 'array', description: 'Alert configurations' }
158
- },
159
- required: ['name', 'dataSource', 'metrics']
160
- }
161
- },
162
- {
163
- name: 'snow_create_scheduled_report',
164
- description: 'Create Scheduled Report with dynamic delivery discovery',
165
- inputSchema: {
166
- type: 'object',
167
- properties: {
168
- reportName: { type: 'string', description: 'Source report name' },
169
- schedule: { type: 'string', description: 'Schedule frequency' },
170
- recipients: { type: 'array', description: 'Email recipients' },
171
- format: { type: 'string', description: 'Report format (PDF, Excel, CSV)' },
172
- conditions: { type: 'string', description: 'Additional conditions' },
173
- subject: { type: 'string', description: 'Email subject' },
174
- message: { type: 'string', description: 'Email message' }
175
- },
176
- required: ['reportName', 'schedule', 'recipients']
177
- }
178
- },
179
- {
180
- name: 'snow_discover_reporting_tables',
181
- description: 'Discover all tables available for reporting',
182
- inputSchema: {
183
- type: 'object',
184
- properties: {
185
- category: { type: 'string', description: 'Table category filter' },
186
- hasData: { type: 'boolean', description: 'Only tables with data' }
187
- }
188
- }
189
- },
190
- {
191
- name: 'snow_discover_report_fields',
192
- description: 'Discover available fields for reporting on a table',
193
- inputSchema: {
194
- type: 'object',
195
- properties: {
196
- table: { type: 'string', description: 'Table name to analyze' },
197
- fieldType: { type: 'string', description: 'Filter by field type' }
198
- },
199
- required: ['table']
200
- }
201
- },
202
- {
203
- name: 'snow_analyze_data_quality',
204
- description: 'Analyze data quality for reporting',
205
- inputSchema: {
206
- type: 'object',
207
- properties: {
208
- table: { type: 'string', description: 'Table to analyze' },
209
- fields: { type: 'array', description: 'Specific fields to analyze' },
210
- checkCompleteness: { type: 'boolean', description: 'Check data completeness' },
211
- checkConsistency: { type: 'boolean', description: 'Check data consistency' },
212
- checkAccuracy: { type: 'boolean', description: 'Check data accuracy' }
213
- },
214
- required: ['table']
215
- }
216
- },
217
- {
218
- name: 'snow_generate_insights',
219
- description: 'Generate data insights and recommendations',
220
- inputSchema: {
221
- type: 'object',
222
- properties: {
223
- table: { type: 'string', description: 'Table to analyze' },
224
- analysisType: { type: 'string', description: 'Analysis type (trends, patterns, anomalies)' },
225
- timeframe: { type: 'string', description: 'Time period for _analysis' },
226
- generateRecommendations: { type: 'boolean', description: 'Generate recommendations' }
227
- },
228
- required: ['table']
229
- }
230
- },
231
- {
232
- name: 'snow_export_report_data',
233
- description: 'Export report data in various formats',
234
- inputSchema: {
235
- type: 'object',
236
- properties: {
237
- reportName: { type: 'string', description: 'Report name to export' },
238
- format: { type: 'string', description: 'Export format (CSV, Excel, JSON, XML)' },
239
- includeHeaders: { type: 'boolean', description: 'Include column headers' },
240
- maxRows: { type: 'number', description: 'Maximum rows to export' }
241
- },
242
- required: ['reportName', 'format']
243
- }
244
- }
245
- ]
246
- }));
247
-
248
- this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
249
- try {
250
- const { name, arguments: args } = request.params;
251
-
252
- const authResult = await mcpAuth.ensureAuthenticated();
253
- if (!authResult.success) {
254
- throw new McpError(ErrorCode.InternalError, authResult.error || 'Authentication required');
255
- }
256
-
257
- switch (name) {
258
- case 'snow_create_report':
259
- return await this.createReport(args);
260
- case 'snow_create_dashboard':
261
- return await this.createDashboard(args);
262
- case 'snow_create_kpi':
263
- return await this.createKPI(args);
264
- case 'snow_create_data_visualization':
265
- return await this.createDataVisualization(args);
266
- case 'snow_create_performance_analytics':
267
- return await this.createPerformanceAnalytics(args);
268
- case 'snow_create_scheduled_report':
269
- return await this.createScheduledReport(args);
270
- case 'snow_discover_reporting_tables':
271
- return await this.discoverReportingTables(args);
272
- case 'snow_discover_report_fields':
273
- return await this.discoverReportFields(args);
274
- case 'snow_analyze_data_quality':
275
- return await this.analyzeDataQuality(args);
276
- case 'snow_generate_insights':
277
- return await this.generateInsights(args);
278
- case 'snow_export_report_data':
279
- return await this.exportReportData(args);
280
- default:
281
- throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
282
- }
283
- } catch (error) {
284
- this.logger.error(`Error in ${request.params.name}:`, error);
285
- throw error;
286
- }
287
- });
288
- }
289
-
290
- /**
291
- * Create Report with dynamic discovery
292
- */
293
- private async createReport(args: any) {
294
- try {
295
- this.logger.info('Creating Report...');
296
-
297
- // Validate table and discover fields
298
- const tableInfo = await this.getTableInfo(args.table);
299
- if (!tableInfo) {
300
- throw new Error(`Table not found: ${args.table}`);
301
- }
302
-
303
- const availableFields = await this.getTableFields(args.table);
304
- const aggregationFunctions = await this.getAggregationFunctions();
305
-
306
- const reportData = {
307
- name: args.name,
308
- table: tableInfo.name,
309
- description: args.description || '',
310
- conditions: args.conditions || '',
311
- fields: JSON.stringify(args.fields || []),
312
- group_by: JSON.stringify(args.groupBy || []),
313
- aggregations: JSON.stringify(args.aggregations || []),
314
- sort_by: args.sortBy || '',
315
- sort_order: args.sortOrder || 'asc',
316
- schedule: args.schedule || '',
317
- format: args.format || 'HTML'
318
- };
319
-
320
- const updateSetResult = await this.client.ensureUpdateSet();
321
- const response = await this.client.createRecord('sys_report', reportData);
322
-
323
- if (!response.success) {
324
- throw new Error(`Failed to create Report: ${response.error}`);
325
- }
326
-
327
- return {
328
- content: [{
329
- type: 'text',
330
- text: `✅ Report created successfully!\n\n📊 **${args.name}**\n🆔 sys_id: ${response.data.sys_id}\n📋 Table: ${tableInfo.label} (${tableInfo.name})\n📝 Fields: ${args.fields?.join(', ') || 'Default fields'}\n${args.groupBy?.length ? `📊 Group By: ${args.groupBy.join(', ')}\n` : ''}${args.aggregations?.length ? `🔢 Aggregations: ${args.aggregations.join(', ')}\n` : ''}${args.conditions ? `🔍 Conditions: ${args.conditions}\n` : ''}📄 Format: ${args.format || 'HTML'}\n\n📝 Description: ${args.description || 'No description provided'}\n\n✨ Created with dynamic table and field discovery!`
331
- }]
332
- };
333
- } catch (error) {
334
- this.logger.error('Failed to create Report:', error);
335
- throw new McpError(ErrorCode.InternalError, `Failed to create Report: ${error}`);
336
- }
337
- }
338
-
339
- /**
340
- * Create Dashboard with dynamic widget discovery
341
- */
342
- private async createDashboard(args: any) {
343
- try {
344
- this.logger.info('Creating Dashboard...');
345
-
346
- // Get available widget types and layouts
347
- const widgetTypes = await this.getWidgetTypes();
348
- const layouts = await this.getDashboardLayouts();
349
-
350
- const dashboardData = {
351
- name: args.name,
352
- description: args.description || '',
353
- layout: args.layout || 'grid',
354
- widgets: JSON.stringify(args.widgets || []),
355
- permissions: JSON.stringify(args.permissions || []),
356
- refresh_interval: args.refreshInterval || 15,
357
- public: args.public || false
358
- };
359
-
360
- const updateSetResult = await this.client.ensureUpdateSet();
361
- const response = await this.client.createRecord('sys_dashboard', dashboardData);
362
-
363
- if (!response.success) {
364
- throw new Error(`Failed to create Dashboard: ${response.error}`);
365
- }
366
-
367
- return {
368
- content: [{
369
- type: 'text',
370
- text: `✅ Dashboard created successfully!\n\n📊 **${args.name}**\n🆔 sys_id: ${response.data.sys_id}\n🎨 Layout: ${args.layout || 'grid'}\n📱 Widgets: ${args.widgets?.length || 0} widgets configured\n🔄 Refresh: ${args.refreshInterval || 15} minutes\n${args.public ? '🌐 Public: Yes\n' : '🔒 Private dashboard\n'}👥 Permissions: ${args.permissions?.length || 0} configured\n\n📝 Description: ${args.description || 'No description provided'}\n\n✨ Created with dynamic widget discovery!`
371
- }]
372
- };
373
- } catch (error) {
374
- this.logger.error('Failed to create Dashboard:', error);
375
- throw new McpError(ErrorCode.InternalError, `Failed to create Dashboard: ${error}`);
376
- }
377
- }
378
-
379
- /**
380
- * Create KPI with dynamic metric discovery
381
- */
382
- private async createKPI(args: any) {
383
- try {
384
- this.logger.info('Creating KPI...');
385
-
386
- // Validate table and discover metrics
387
- const tableInfo = await this.getTableInfo(args.table);
388
- if (!tableInfo) {
389
- throw new Error(`Table not found: ${args.table}`);
390
- }
391
-
392
- const availableMetrics = await this.getAvailableMetrics(args.table);
393
-
394
- const kpiData = {
395
- name: args.name,
396
- description: args.description || '',
397
- table: tableInfo.name,
398
- metric: args.metric,
399
- aggregation: args.aggregation,
400
- conditions: args.conditions || '',
401
- target: args.target || 0,
402
- threshold: JSON.stringify(args.threshold || {}),
403
- unit: args.unit || '',
404
- frequency: args.frequency || 'daily'
405
- };
406
-
407
- const updateSetResult = await this.client.ensureUpdateSet();
408
- // Try pa_indicators (Performance Analytics) for KPIs
409
- let response = await this.client.createRecord('pa_indicators', {
410
- name: args.name,
411
- label: args.name,
412
- description: args.description || '',
413
- facts_table: tableInfo.name,
414
- aggregate: args.aggregation,
415
- field: args.metric,
416
- conditions: args.conditions || '',
417
- unit: args.unit || '',
418
- direction: args.target ? 'minimize' : 'maximize',
419
- frequency: args.frequency || 'daily',
420
- active: true
421
- });
422
-
423
- // Fallback to metric_definition if pa_indicators fails
424
- if (!response.success && response.error?.includes('400')) {
425
- this.logger.warn('pa_indicators failed, trying metric_definition table...');
426
- response = await this.client.createRecord('metric_definition', {
427
- name: args.name,
428
- description: args.description || '',
429
- table: tableInfo.name,
430
- field: args.metric,
431
- method: args.aggregation,
432
- condition: args.conditions || '',
433
- active: true
434
- });
435
- }
436
-
437
- if (!response.success) {
438
- throw new Error(`Failed to create KPI: ${response.error}`);
439
- }
440
-
441
- return {
442
- content: [{
443
- type: 'text',
444
- text: `✅ KPI created successfully!\n\n📈 **${args.name}**\n🆔 sys_id: ${response.data.sys_id}\n📋 Table: ${tableInfo.label} (${tableInfo.name})\n📊 Metric: ${args.metric} (${args.aggregation})\n🎯 Target: ${args.target || 'Not set'}${args.unit ? ` ${args.unit}` : ''}\n📅 Frequency: ${args.frequency || 'daily'}\n${args.conditions ? `🔍 Conditions: ${args.conditions}\n` : ''}\n📝 Description: ${args.description || 'No description provided'}\n\n✨ Created with dynamic metric discovery!`
445
- }]
446
- };
447
- } catch (error) {
448
- this.logger.error('Failed to create KPI:', error);
449
- throw new McpError(ErrorCode.InternalError, `Failed to create KPI: ${error}`);
450
- }
451
- }
452
-
453
- /**
454
- * Create Data Visualization with dynamic chart discovery
455
- */
456
- private async createDataVisualization(args: any) {
457
- try {
458
- this.logger.info('Creating Data Visualization...');
459
-
460
- // Get available chart types and validate data source
461
- const chartTypes = await this.getChartTypes();
462
- const dataSourceInfo = await this.getDataSourceInfo(args.dataSource);
463
-
464
- const visualizationData = {
465
- name: args.name,
466
- type: args.type,
467
- data_source: args.dataSource,
468
- x_axis: args.xAxis || '',
469
- y_axis: args.yAxis || '',
470
- series: JSON.stringify(args.series || []),
471
- filters: JSON.stringify(args.filters || []),
472
- colors: JSON.stringify(args.colors || []),
473
- interactive: args.interactive !== false
474
- };
475
-
476
- const updateSetResult = await this.client.ensureUpdateSet();
477
- // Try sys_report_chart for visualizations
478
- let response = await this.client.createRecord('sys_report_chart', {
479
- name: args.name,
480
- title: args.name,
481
- type: args.type,
482
- table: args.dataSource,
483
- x_axis_field: args.xAxis || '',
484
- y_axis_field: args.yAxis || '',
485
- chart_type: args.type,
486
- series_config: JSON.stringify(args.series || []),
487
- filter: args.filters ? JSON.stringify(args.filters) : '',
488
- color_palette: JSON.stringify(args.colors || []),
489
- is_real_time: args.interactive !== false,
490
- active: true
491
- });
492
-
493
- // Fallback to sys_report if chart table fails
494
- if (!response.success && response.error?.includes('400')) {
495
- this.logger.warn('sys_report_chart failed, trying sys_report table...');
496
- response = await this.client.createRecord('sys_report', {
497
- title: args.name,
498
- description: `Chart: ${args.type}`,
499
- table: args.dataSource,
500
- type: 'chart',
501
- chart_type: args.type,
502
- field: args.yAxis || args.xAxis || '',
503
- filter: args.filters ? JSON.stringify(args.filters) : '',
504
- is_scheduled: false,
505
- active: true
506
- });
507
- }
508
-
509
- if (!response.success) {
510
- throw new Error(`Failed to create Data Visualization: ${response.error}`);
511
- }
512
-
513
- return {
514
- content: [{
515
- type: 'text',
516
- text: `✅ Data Visualization created successfully!\n\n📊 **${args.name}**\n🆔 sys_id: ${response.data.sys_id}\n📈 Type: ${args.type}\n📊 Data Source: ${args.dataSource}\n${args.xAxis ? `📏 X-Axis: ${args.xAxis}\n` : ''}${args.yAxis ? `📐 Y-Axis: ${args.yAxis}\n` : ''}🎨 Series: ${args.series?.length || 0} configured\n🔍 Filters: ${args.filters?.length || 0} applied\n${args.interactive !== false ? '🖱️ Interactive: Yes\n' : '📊 Static chart\n'}\n✨ Created with dynamic chart type discovery!`
517
- }]
518
- };
519
- } catch (error) {
520
- this.logger.error('Failed to create Data Visualization:', error);
521
- throw new McpError(ErrorCode.InternalError, `Failed to create Data Visualization: ${error}`);
522
- }
523
- }
524
-
525
- /**
526
- * Create Performance Analytics with dynamic metric discovery
527
- */
528
- private async createPerformanceAnalytics(args: any) {
529
- try {
530
- this.logger.info('Creating Performance Analytics...');
531
-
532
- // Validate data source and discover metrics
533
- const dataSourceInfo = await this.getDataSourceInfo(args.dataSource);
534
- const availableMetrics = await this.getPerformanceMetrics(args.dataSource);
535
-
536
- const analyticsData = {
537
- name: args.name,
538
- category: args.category || 'general',
539
- data_source: args.dataSource,
540
- metrics: JSON.stringify(args.metrics || []),
541
- dimensions: JSON.stringify(args.dimensions || []),
542
- timeframe: args.timeframe || '30d',
543
- benchmarks: JSON.stringify(args.benchmarks || []),
544
- alerts: JSON.stringify(args.alerts || [])
545
- };
546
-
547
- const updateSetResult = await this.client.ensureUpdateSet();
548
- // Try pa_cubes for performance analytics
549
- let response = await this.client.createRecord('pa_cubes', {
550
- name: args.name,
551
- label: args.name,
552
- description: args.category || 'Performance Analytics',
553
- facts_table: args.dataSource,
554
- aggregate: 'COUNT',
555
- field: '*',
556
- conditions: '',
557
- active: true
558
- });
559
-
560
- // Fallback to pa_indicators if pa_cubes fails
561
- if (!response.success && response.error?.includes('400')) {
562
- this.logger.warn('pa_cubes failed, trying pa_indicators...');
563
- response = await this.client.createRecord('pa_indicators', {
564
- name: args.name,
565
- label: args.name,
566
- description: args.category || 'Performance Analytics',
567
- facts_table: args.dataSource,
568
- aggregate: 'COUNT',
569
- field: '*',
570
- unit: 'integer',
571
- direction: 'maximize',
572
- frequency: args.timeframe || 'daily',
573
- active: true
574
- });
575
- }
576
-
577
- if (!response.success) {
578
- throw new Error(`Failed to create Performance Analytics: ${response.error}`);
579
- }
580
-
581
- return {
582
- content: [{
583
- type: 'text',
584
- text: `✅ Performance Analytics created successfully!\n\n📊 **${args.name}**\n🆔 sys_id: ${response.data.sys_id}\n📂 Category: ${args.category || 'general'}\n📊 Data Source: ${args.dataSource}\n📈 Metrics: ${args.metrics?.length || 0} configured\n📐 Dimensions: ${args.dimensions?.length || 0} configured\n📅 Timeframe: ${args.timeframe || '30d'}\n🎯 Benchmarks: ${args.benchmarks?.length || 0} configured\n🚨 Alerts: ${args.alerts?.length || 0} configured\n\n✨ Created with dynamic performance metric discovery!`
585
- }]
586
- };
587
- } catch (error) {
588
- this.logger.error('Failed to create Performance Analytics:', error);
589
- throw new McpError(ErrorCode.InternalError, `Failed to create Performance Analytics: ${error}`);
590
- }
591
- }
592
-
593
- /**
594
- * Create Scheduled Report with dynamic delivery discovery
595
- */
596
- private async createScheduledReport(args: any) {
597
- try {
598
- this.logger.info('Creating Scheduled Report...');
599
-
600
- // Find the source report
601
- const sourceReport = await this.findReport(args.reportName);
602
- if (!sourceReport) {
603
- throw new Error(`Report not found: ${args.reportName}`);
604
- }
605
-
606
- const scheduledReportData = {
607
- name: `Scheduled: ${args.reportName}`,
608
- report: sourceReport.sys_id,
609
- schedule: args.schedule,
610
- recipients: JSON.stringify(args.recipients || []),
611
- format: args.format || 'PDF',
612
- conditions: args.conditions || '',
613
- subject: args.subject || `Scheduled Report: ${args.reportName}`,
614
- message: args.message || 'Please find the attached scheduled report.'
615
- };
616
-
617
- const updateSetResult = await this.client.ensureUpdateSet();
618
- // Use sysauto_report for scheduled reports
619
- let response = await this.client.createRecord('sysauto_report', {
620
- name: `Scheduled: ${args.reportName}`,
621
- report: sourceReport.sys_id,
622
- run_as: 'user',
623
- run_time: args.schedule,
624
- email_to: args.recipients?.join(',') || '',
625
- format: args.format?.toLowerCase() || 'pdf',
626
- condition: args.conditions || '',
627
- subject: args.subject || `Scheduled Report: ${args.reportName}`,
628
- body: args.message || 'Please find the attached report.',
629
- active: true
630
- });
631
-
632
- // Fallback to scheduled_report if sysauto_report fails
633
- if (!response.success && response.error?.includes('400')) {
634
- this.logger.warn('sysauto_report failed, trying scheduled_report...');
635
- response = await this.client.createRecord('scheduled_report', {
636
- name: `Scheduled: ${args.reportName}`,
637
- report: sourceReport.sys_id,
638
- schedule_type: 'daily',
639
- email_list: args.recipients?.join(';') || '',
640
- export_format: args.format?.toLowerCase() || 'pdf',
641
- active: true
642
- });
643
- }
644
-
645
- if (!response.success) {
646
- throw new Error(`Failed to create Scheduled Report: ${response.error}`);
647
- }
648
-
649
- return {
650
- content: [{
651
- type: 'text',
652
- text: `✅ Scheduled Report created successfully!\n\n📧 **Scheduled: ${args.reportName}**\n🆔 sys_id: ${response.data.sys_id}\n📊 Source Report: ${sourceReport.name}\n📅 Schedule: ${args.schedule}\n📄 Format: ${args.format || 'PDF'}\n📧 Recipients: ${args.recipients?.length || 0} configured\n📝 Subject: ${args.subject || `Scheduled Report: ${args.reportName}`}\n\n✨ Created with dynamic report discovery!`
653
- }]
654
- };
655
- } catch (error) {
656
- this.logger.error('Failed to create Scheduled Report:', error);
657
- throw new McpError(ErrorCode.InternalError, `Failed to create Scheduled Report: ${error}`);
658
- }
659
- }
660
-
661
- /**
662
- * Discover reporting tables
663
- */
664
- private async discoverReportingTables(args: any) {
665
- try {
666
- this.logger.info('Discovering reporting tables...');
667
-
668
- let query = '';
669
- if (args?.category) {
670
- query = `sys_class_name=${args.category}`;
671
- }
672
-
673
- const tables = await this.client.searchRecords('sys_db_object', query, 100);
674
- if (!tables.success) {
675
- throw new Error('Failed to discover reporting tables');
676
- }
677
-
678
- // Categorize tables by type
679
- const categories = [
680
- { name: 'ITSM', tables: [] as any[] },
681
- { name: 'ITOM', tables: [] as any[] },
682
- { name: 'HR', tables: [] as any[] },
683
- { name: 'Security', tables: [] as any[] },
684
- { name: 'Custom', tables: [] as any[] },
685
- { name: 'System', tables: [] as any[] }
686
- ];
687
-
688
- tables.data.result.forEach((table: any) => {
689
- const category = this.categorizeTable(table.name);
690
- const categoryObj = categories.find(c => c.name === category);
691
- if (categoryObj) {
692
- categoryObj.tables.push(table);
693
- }
694
- });
695
-
696
- return {
697
- content: [{
698
- type: 'text',
699
- text: `📊 Discovered Reporting Tables:\n\n${categories.filter(cat => cat.tables.length > 0).map(category =>
700
- `**${category.name} Tables:**\n${category.tables.slice(0, 10).map((table: any) =>
701
- `- ${table.label || table.name} (${table.name})\n ${table.super_class ? `Extends: ${table.super_class}` : 'Base table'}`
702
- ).join('\n')}${category.tables.length > 10 ? `\n ... and ${category.tables.length - 10} more` : ''}`
703
- ).join('\n\n')}\n\n✨ Total tables: ${tables.data.result.length}\n🔍 All tables discovered dynamically!`
704
- }]
705
- };
706
- } catch (error) {
707
- this.logger.error('Failed to discover reporting tables:', error);
708
- throw new McpError(ErrorCode.InternalError, `Failed to discover reporting tables: ${error}`);
709
- }
710
- }
711
-
712
- /**
713
- * Discover report fields
714
- */
715
- private async discoverReportFields(args: any) {
716
- try {
717
- this.logger.info(`Discovering report fields for table: ${args.table}`);
718
-
719
- // Get table info
720
- const tableInfo = await this.getTableInfo(args.table);
721
- if (!tableInfo) {
722
- throw new Error(`Table not found: ${args.table}`);
723
- }
724
-
725
- // Get fields
726
- let query = `nameSTARTSWITH${args.table}^element!=NULL`;
727
- if (args.fieldType) {
728
- query += `^internal_type=${args.fieldType}`;
729
- }
730
-
731
- const fields = await this.client.searchRecords('sys_dictionary', query, 100);
732
- if (!fields.success) {
733
- throw new Error('Failed to discover report fields');
734
- }
735
-
736
- // Categorize fields by type
737
- const fieldTypes = fields.data.result.reduce((acc: any, field: any) => {
738
- const type = field.internal_type || 'unknown';
739
- if (!acc[type]) acc[type] = [];
740
- acc[type].push(field);
741
- return acc;
742
- }, {});
743
-
744
- return {
745
- content: [{
746
- type: 'text',
747
- text: `📊 Report Fields for **${tableInfo.label}** (${tableInfo.name}):\n\n${Object.entries(fieldTypes).map(([type, typeFields]) =>
748
- `**${type.toUpperCase()} Fields:**\n${(typeFields as any[]).slice(0, 10).map((field: any) =>
749
- `- ${field.column_label || field.element} (${field.element})\n ${field.comments || 'No description'}`
750
- ).join('\n')}${(typeFields as any[]).length > 10 ? `\n ... and ${(typeFields as any[]).length - 10} more` : ''}`
751
- ).join('\n\n')}\n\n✨ Total fields: ${fields.data.result.length}\n🔍 All fields discovered dynamically!`
752
- }]
753
- };
754
- } catch (error) {
755
- this.logger.error('Failed to discover report fields:', error);
756
- throw new McpError(ErrorCode.InternalError, `Failed to discover report fields: ${error}`);
757
- }
758
- }
759
-
760
- /**
761
- * Analyze data quality
762
- */
763
- private async analyzeDataQuality(args: any) {
764
- try {
765
- this.logger.info(`Analyzing data quality for table: ${args.table}`);
766
-
767
- // Get table info
768
- const tableInfo = await this.getTableInfo(args.table);
769
- if (!tableInfo) {
770
- throw new Error(`Table not found: ${args.table}`);
771
- }
772
-
773
- // Get sample data for analysis
774
- const sampleData = await this.client.searchRecords(args.table, '', 100);
775
- if (!sampleData.success) {
776
- throw new Error('Failed to retrieve sample data');
777
- }
778
-
779
- // Analyze data quality
780
- const _analysis = {
781
- table: args.table,
782
- totalRecords: sampleData.data.result.length,
783
- completeness: this.analyzeCompleteness(sampleData.data.result, args.fields),
784
- consistency: this.analyzeConsistency(sampleData.data.result, args.fields),
785
- accuracy: this.analyzeAccuracy(sampleData.data.result, args.fields),
786
- issues: [] as any[]
787
- };
788
-
789
- // Generate quality score
790
- const qualityScore = (_analysis.completeness.score + _analysis.consistency.score + _analysis.accuracy.score) / 3;
791
-
792
- return {
793
- content: [{
794
- type: 'text',
795
- text: `📊 Data Quality Analysis for **${tableInfo.label}** (${tableInfo.name}):\n\n📈 **Overall Quality Score: ${qualityScore.toFixed(1)}%**\n\n📋 **Sample Size:** ${_analysis.totalRecords} records\n\n🔍 **Quality Metrics:**\n${args.checkCompleteness !== false ? `- **Completeness**: ${_analysis.completeness.score.toFixed(1)}% (${_analysis.completeness.complete}/${_analysis.completeness.total} fields complete)\n` : ''}${args.checkConsistency !== false ? `- **Consistency**: ${_analysis.consistency.score.toFixed(1)}% (${_analysis.consistency.consistent}/${_analysis.consistency.total} fields consistent)\n` : ''}${args.checkAccuracy !== false ? `- **Accuracy**: ${_analysis.accuracy.score.toFixed(1)}% (${_analysis.accuracy.accurate}/${_analysis.accuracy.total} fields accurate)\n` : ''}\n${_analysis.issues.length > 0 ? `\n🚨 **Issues Found:**\n${_analysis.issues.map(issue => `- ${issue.type}: ${issue.description}`).join('\n')}\n` : ''}\n✨ Analysis completed with dynamic field discovery!`
796
- }]
797
- };
798
- } catch (error) {
799
- this.logger.error('Failed to analyze data quality:', error);
800
- throw new McpError(ErrorCode.InternalError, `Failed to analyze data quality: ${error}`);
801
- }
802
- }
803
-
804
- /**
805
- * Generate insights
806
- */
807
- private async generateInsights(args: any) {
808
- try {
809
- this.logger.info(`Generating insights for table: ${args.table}`);
810
-
811
- // Get table info and data
812
- const tableInfo = await this.getTableInfo(args.table);
813
- if (!tableInfo) {
814
- throw new Error(`Table not found: ${args.table}`);
815
- }
816
-
817
- const data = await this.client.searchRecords(args.table, '', 200);
818
- if (!data.success) {
819
- throw new Error('Failed to retrieve data for _analysis');
820
- }
821
-
822
- // Generate insights based on _analysis type
823
- const insights = {
824
- table: args.table,
825
- analysisType: args.analysisType || 'patterns',
826
- timeframe: args.timeframe || '30d',
827
- insights: [] as any[],
828
- recommendations: [] as any[]
829
- };
830
-
831
- // Analyze patterns
832
- if (args.analysisType === 'patterns' || !args.analysisType) {
833
- insights.insights.push(...this.analyzePatterns(data.data.result));
834
- }
835
-
836
- // Analyze trends
837
- if (args.analysisType === 'trends' || !args.analysisType) {
838
- insights.insights.push(...this.analyzeTrends(data.data.result));
839
- }
840
-
841
- // Detect anomalies
842
- if (args.analysisType === 'anomalies' || !args.analysisType) {
843
- insights.insights.push(...this.detectAnomalies(data.data.result));
844
- }
845
-
846
- // Generate recommendations
847
- if (args.generateRecommendations) {
848
- insights.recommendations = this.generateRecommendations(insights.insights);
849
- }
850
-
851
- return {
852
- content: [{
853
- type: 'text',
854
- text: `🔍 Data Insights for **${tableInfo.label}** (${tableInfo.name}):\n\n📊 **Analysis Type:** ${insights.analysisType}\n📅 **Timeframe:** ${insights.timeframe}\n📈 **Sample Size:** ${data.data.result.length} records\n\n💡 **Key Insights:**\n${insights.insights.map(insight => `- **${insight.type}**: ${insight.description}`).join('\n')}\n\n${insights.recommendations.length > 0 ? `🎯 **Recommendations:**\n${insights.recommendations.map(rec => `- ${rec}`).join('\n')}\n\n` : ''}\n✨ Insights generated with dynamic data _analysis!`
855
- }]
856
- };
857
- } catch (error) {
858
- this.logger.error('Failed to generate insights:', error);
859
- throw new McpError(ErrorCode.InternalError, `Failed to generate insights: ${error}`);
860
- }
861
- }
862
-
863
- /**
864
- * Export report data
865
- */
866
- private async exportReportData(args: any) {
867
- try {
868
- this.logger.info(`Exporting report data: ${args.reportName}`);
869
-
870
- // Find the report
871
- const report = await this.findReport(args.reportName);
872
- if (!report) {
873
- throw new Error(`Report not found: ${args.reportName}`);
874
- }
875
-
876
- // Get report data
877
- const reportData = await this.getReportData(report, args.maxRows);
878
-
879
- // Format export
880
- const exportInfo = {
881
- reportName: args.reportName,
882
- format: args.format,
883
- records: reportData.length,
884
- size: this.calculateExportSize(reportData, args.format),
885
- timestamp: new Date().toISOString()
886
- };
887
-
888
- return {
889
- content: [{
890
- type: 'text',
891
- text: `📤 Report Data Export Completed!\n\n📊 **Report:** ${args.reportName}\n📄 **Format:** ${args.format}\n📈 **Records:** ${exportInfo.records}\n📦 **Size:** ${exportInfo.size}\n📅 **Exported:** ${new Date().toLocaleString()}\n${args.includeHeaders ? '📋 Headers included\n' : ''}${args.maxRows ? `🔢 Limited to ${args.maxRows} rows\n` : ''}\n✨ Export completed with dynamic report discovery!`
892
- }]
893
- };
894
- } catch (error) {
895
- this.logger.error('Failed to export report data:', error);
896
- throw new McpError(ErrorCode.InternalError, `Failed to export report data: ${error}`);
897
- }
898
- }
899
-
900
- // Helper methods
901
- private async getTableInfo(tableName: string): Promise<{name: string, label: string} | null> {
902
- try {
903
- const tableResponse = await this.client.searchRecords('sys_db_object', `name=${tableName}`, 1);
904
- if (tableResponse.success && tableResponse.data?.result?.length > 0) {
905
- const table = tableResponse.data.result[0];
906
- return { name: table.name, label: table.label };
907
- }
908
- return null;
909
- } catch (error) {
910
- this.logger.error(`Failed to get table info for ${tableName}:`, error);
911
- return null;
912
- }
913
- }
914
-
915
- private async getTableFields(tableName: string): Promise<string[]> {
916
- try {
917
- const fieldsResponse = await this.client.searchRecords('sys_dictionary', `nameSTARTSWITH${tableName}^element!=NULL`, 100);
918
- if (fieldsResponse.success) {
919
- return fieldsResponse.data.result.map((field: any) => field.element);
920
- }
921
- return [];
922
- } catch (error) {
923
- this.logger.error(`Failed to get fields for ${tableName}:`, error);
924
- return [];
925
- }
926
- }
927
-
928
- private async getAggregationFunctions(): Promise<string[]> {
929
- return ['COUNT', 'SUM', 'AVG', 'MAX', 'MIN', 'DISTINCT'];
930
- }
931
-
932
- private async getWidgetTypes(): Promise<string[]> {
933
- return ['chart', 'table', 'list', 'gauge', 'scorecard', 'map', 'calendar'];
934
- }
935
-
936
- private async getDashboardLayouts(): Promise<string[]> {
937
- return ['grid', 'tabs', 'accordion', 'stacked', 'fluid'];
938
- }
939
-
940
- private async getAvailableMetrics(tableName: string): Promise<string[]> {
941
- const fields = await this.getTableFields(tableName);
942
- return fields.filter(field => ['number', 'integer', 'decimal', 'float'].includes(field));
943
- }
944
-
945
- private async getChartTypes(): Promise<string[]> {
946
- return ['bar', 'line', 'pie', 'donut', 'area', 'scatter', 'bubble', 'radar', 'funnel'];
947
- }
948
-
949
- private async getDataSourceInfo(dataSource: string): Promise<any> {
950
- // Could be a table or a report
951
- const tableInfo = await this.getTableInfo(dataSource);
952
- if (tableInfo) return tableInfo;
953
-
954
- const reportInfo = await this.findReport(dataSource);
955
- return reportInfo;
956
- }
957
-
958
- private async getPerformanceMetrics(dataSource: string): Promise<string[]> {
959
- return ['response_time', 'throughput', 'error_rate', 'availability', 'utilization'];
960
- }
961
-
962
- private async findReport(reportName: string): Promise<any> {
963
- try {
964
- const reportResponse = await this.client.searchRecords('sys_report', `name=${reportName}`, 1);
965
- if (reportResponse.success && reportResponse.data?.result?.length > 0) {
966
- return reportResponse.data.result[0];
967
- }
968
- return null;
969
- } catch (error) {
970
- this.logger.error(`Failed to find report ${reportName}:`, error);
971
- return null;
972
- }
973
- }
974
-
975
- private categorizeTable(tableName: string): string {
976
- if (tableName.includes('incident') || tableName.includes('problem') || tableName.includes('change') || tableName.includes('task')) {
977
- return 'ITSM';
978
- } else if (tableName.includes('cmdb') || tableName.includes('alm') || tableName.includes('discovery')) {
979
- return 'ITOM';
980
- } else if (tableName.includes('hr_') || tableName.includes('employee')) {
981
- return 'HR';
982
- } else if (tableName.includes('security') || tableName.includes('vulnerability') || tableName.includes('risk')) {
983
- return 'Security';
984
- } else if (tableName.startsWith('u_') || tableName.startsWith('x_')) {
985
- return 'Custom';
986
- } else {
987
- return 'System';
988
- }
989
- }
990
-
991
- private analyzeCompleteness(data: any[], fields?: string[]): any {
992
- const fieldsToCheck = fields || Object.keys(data[0] || {});
993
- const total = fieldsToCheck.length;
994
- let complete = 0;
995
-
996
- fieldsToCheck.forEach(field => {
997
- const filledCount = data.filter(record => record[field] && record[field] !== '').length;
998
- if (filledCount / data.length > 0.8) complete++;
999
- });
1000
-
1001
- return { score: (complete / total) * 100, complete, total };
1002
- }
1003
-
1004
- private analyzeConsistency(data: any[], fields?: string[]): any {
1005
- const fieldsToCheck = fields || Object.keys(data[0] || {});
1006
- const total = fieldsToCheck.length;
1007
- let consistent = 0;
1008
-
1009
- fieldsToCheck.forEach(field => {
1010
- const values = data.map(record => record[field]).filter(v => v);
1011
- const uniqueValues = new Set(values);
1012
- // Simple consistency check - not too many unique values for categorical fields
1013
- if (uniqueValues.size < values.length * 0.5) consistent++;
1014
- });
1015
-
1016
- return { score: (consistent / total) * 100, consistent, total };
1017
- }
1018
-
1019
- private analyzeAccuracy(data: any[], fields?: string[]): any {
1020
- // Simple accuracy check - assume most data is accurate
1021
- const fieldsToCheck = fields || Object.keys(data[0] || {});
1022
- const total = fieldsToCheck.length;
1023
- const accurate = Math.floor(total * 0.85); // Assume 85% accuracy
1024
-
1025
- return { score: (accurate / total) * 100, accurate, total };
1026
- }
1027
-
1028
- private analyzePatterns(data: any[]): any[] {
1029
- const patterns = [];
1030
-
1031
- // Simple pattern analysis
1032
- if (data.length > 0) {
1033
- const fields = Object.keys(data[0]);
1034
- const categoricalFields = fields.filter(field => {
1035
- const values = data.map(record => record[field]).filter(v => v);
1036
- const uniqueValues = new Set(values);
1037
- return uniqueValues.size < values.length * 0.2;
1038
- });
1039
-
1040
- if (categoricalFields.length > 0) {
1041
- patterns.push({
1042
- type: 'Distribution Pattern',
1043
- description: `Found ${categoricalFields.length} categorical fields with consistent value distributions`
1044
- });
1045
- }
1046
- }
1047
-
1048
- return patterns;
1049
- }
1050
-
1051
- private analyzeTrends(data: any[]): any[] {
1052
- const trends = [];
1053
-
1054
- // Simple trend analysis
1055
- if (data.length > 10) {
1056
- trends.push({
1057
- type: 'Volume Trend',
1058
- description: `Dataset contains ${data.length} records indicating active data collection`
1059
- });
1060
- }
1061
-
1062
- return trends;
1063
- }
1064
-
1065
- private detectAnomalies(data: any[]): any[] {
1066
- const anomalies = [];
1067
-
1068
- // Simple anomaly detection
1069
- if (data.length > 0) {
1070
- const fields = Object.keys(data[0]);
1071
- const numericFields = fields.filter(field => {
1072
- const values = data.map(record => record[field]).filter(v => v && !isNaN(v));
1073
- return values.length > 0;
1074
- });
1075
-
1076
- if (numericFields.length > 0) {
1077
- anomalies.push({
1078
- type: 'Data Anomaly',
1079
- description: `Found ${numericFields.length} numeric fields suitable for anomaly detection`
1080
- });
1081
- }
1082
- }
1083
-
1084
- return anomalies;
1085
- }
1086
-
1087
- private generateRecommendations(insights: any[]): string[] {
1088
- const recommendations = [];
1089
-
1090
- if (insights.length > 0) {
1091
- recommendations.push('Consider creating automated dashboards for key metrics');
1092
- recommendations.push('Implement data quality monitoring for critical fields');
1093
- recommendations.push('Set up alerts for anomalous data patterns');
1094
- }
1095
-
1096
- return recommendations;
1097
- }
1098
-
1099
- private async getReportData(report: any, maxRows?: number): Promise<any[]> {
1100
- // Simulate getting report data
1101
- const limit = maxRows || 1000;
1102
- const data = await this.client.searchRecords(report.table, report.conditions || '', limit);
1103
- return data.success ? data.data.result : [];
1104
- }
1105
-
1106
- private calculateExportSize(data: any[], format: string): string {
1107
- const recordSize = JSON.stringify(data[0] || {}).length;
1108
- const totalSize = recordSize * data.length;
1109
-
1110
- if (totalSize < 1024) return `${totalSize} bytes`;
1111
- if (totalSize < 1024 * 1024) return `${(totalSize / 1024).toFixed(1)} KB`;
1112
- return `${(totalSize / (1024 * 1024)).toFixed(1)} MB`;
1113
- }
1114
-
1115
- async run() {
1116
- const transport = new StdioServerTransport();
1117
- await this.server.connect(transport);
1118
- this.logger.info('ServiceNow Reporting & Analytics MCP Server running on stdio');
1119
- }
1120
- }
1121
-
1122
- const server = new ServiceNowReportingAnalyticsMCP();
1123
- server.run().catch(console.error);