snow-flow 2.0.2 ā 2.0.3
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.
- package/{.claude/mcp-config.json ā .mcp.json} +13 -12
- package/.releaserc.json +47 -0
- package/README.md +6 -0
- package/package.json +1 -1
- package/.claude/claude-settings.json +0 -15
- package/.claude/commands/analysis/README.md +0 -9
- package/.claude/commands/automation/README.md +0 -9
- package/.claude/commands/github/README.md +0 -11
- package/.claude/commands/helpers/standard-checkpoint-hooks.sh +0 -179
- package/.claude/commands/hooks/README.md +0 -11
- package/.claude/commands/monitoring/README.md +0 -9
- package/.claude/commands/optimization/README.md +0 -9
- package/.claude/commands/training/README.md +0 -9
- package/.claude/commands/workflows/README.md +0 -9
- package/.claude/config.json +0 -36
- package/.claude/helpers/github-setup.sh +0 -28
- package/.claude/helpers/quick-start.sh +0 -19
- package/.claude/helpers/setup-mcp.sh +0 -18
- package/.claude/settings.json +0 -114
- package/.claude/settings.local.json +0 -33
- package/.claude-flow/metrics/agent-metrics.json +0 -1
- package/.claude-flow/metrics/performance.json +0 -9
- package/.claude-flow/metrics/system-metrics.json +0 -15986
- package/.claude-flow/metrics/task-metrics.json +0 -10
- package/.roo/README.md +0 -402
- package/.roo/mcp-list.txt +0 -257
- package/.roo/mcp.json +0 -32
- package/.roo/workflows/basic-tdd.json +0 -32
- package/.roomodes +0 -201
- package/CLAUDE.md +0 -393
- package/bin/snow-flow.js +0 -3
- package/dist/cli.js.bak +0 -2052
- package/dist/config/snow-flow-config.d.ts +0 -1492
- package/dist/config/snow-flow-config.js +0 -938
- package/scripts/create-env.js +0 -91
- package/scripts/postinstall.js +0 -30
- package/scripts/register-mcp-servers.js +0 -210
- package/scripts/reset-mcp-servers.js +0 -246
- package/scripts/setup-mcp.js +0 -106
- package/scripts/update-version.js +0 -31
- package/src/agents/README.md +0 -192
- package/src/agents/base-agent.ts +0 -251
- package/src/agents/coordinator.ts +0 -971
- package/src/agents/index.ts +0 -18
- package/src/agents/queen-403-handler.ts +0 -230
- package/src/agents/queen-agent.ts +0 -1399
- package/src/agents/script-writer-agent.ts +0 -769
- package/src/agents/security-agent.ts +0 -726
- package/src/agents/widget-creator-agent.ts +0 -568
- package/src/api/error-handling.ts +0 -1758
- package/src/api/natural-language-mapper.ts +0 -630
- package/src/api/performance-optimizer.ts +0 -891
- package/src/api/transaction-manager.ts +0 -754
- package/src/cli/deploy-artifact.ts +0 -304
- package/src/cli/snow-flow-cli-integration.ts +0 -434
- package/src/cli.ts +0 -4455
- package/src/cli.ts.bak +0 -5616
- package/src/compliance/advanced-compliance-system.ts +0 -1268
- package/src/compliance/index.ts +0 -19
- package/src/config/snow-flow-config.ts +0 -1019
- package/src/documentation/index.ts +0 -16
- package/src/documentation/self-documenting-system.ts +0 -1421
- package/src/dynamic-version.ts +0 -44
- package/src/healing/index.ts +0 -20
- package/src/healing/self-healing-system.ts +0 -1435
- package/src/health/README.md +0 -161
- package/src/health/system-health.ts +0 -995
- package/src/index.ts +0 -60
- package/src/intelligence/acl-analyzer.ts +0 -377
- package/src/intelligence/auto-resolution-engine.ts +0 -643
- package/src/intelligence/gap-analysis-engine.ts +0 -488
- package/src/intelligence/manual-instructions-generator.ts +0 -744
- package/src/intelligence/mcp-coverage-analyzer.ts +0 -708
- package/src/intelligence/multi-pass-requirements-analyzer.ts +0 -603
- package/src/intelligence/performance-recommendations-engine.ts +0 -1223
- package/src/intelligence/requirements-analyzer.ts +0 -1148
- package/src/intelligence/task-analyzer.ts +0 -628
- package/src/managers/scope-manager.ts +0 -555
- package/src/mcp/advanced/servicenow-advanced-features-mcp.ts +0 -16110
- package/src/mcp/base-mcp-server.ts +0 -660
- package/src/mcp/http-transport-wrapper.ts +0 -426
- package/src/mcp/service-discovery-client.ts +0 -312
- package/src/mcp/servicenow-automation-mcp-refactored.ts +0 -678
- package/src/mcp/servicenow-automation-mcp.ts +0 -838
- package/src/mcp/servicenow-deployment-mcp-refactored.ts +0 -1292
- package/src/mcp/servicenow-deployment-mcp.ts +0 -7244
- package/src/mcp/servicenow-graph-memory-mcp-refactored.ts +0 -721
- package/src/mcp/servicenow-graph-memory-mcp.ts +0 -832
- package/src/mcp/servicenow-integration-mcp-refactored.ts +0 -655
- package/src/mcp/servicenow-integration-mcp.ts +0 -819
- package/src/mcp/servicenow-intelligent-mcp-refactored.ts +0 -977
- package/src/mcp/servicenow-intelligent-mcp.ts +0 -4638
- package/src/mcp/servicenow-mcp-server.ts +0 -728
- package/src/mcp/servicenow-memory-mcp.ts +0 -474
- package/src/mcp/servicenow-operations-mcp-refactored.ts +0 -1995
- package/src/mcp/servicenow-operations-mcp.ts +0 -3384
- package/src/mcp/servicenow-platform-development-mcp-refactored.ts +0 -611
- package/src/mcp/servicenow-platform-development-mcp.ts +0 -970
- package/src/mcp/servicenow-progressive-indexer.ts +0 -370
- package/src/mcp/servicenow-reporting-analytics-mcp-refactored.ts +0 -695
- package/src/mcp/servicenow-reporting-analytics-mcp.ts +0 -1123
- package/src/mcp/servicenow-security-compliance-mcp-refactored.ts +0 -642
- package/src/mcp/servicenow-security-compliance-mcp.ts +0 -1157
- package/src/mcp/servicenow-update-set-mcp-refactored.ts +0 -751
- package/src/mcp/servicenow-update-set-mcp.ts +0 -811
- package/src/mcp/shared/agent-context-provider.ts +0 -365
- package/src/mcp/shared/base-mcp-server.ts +0 -2463
- package/src/mcp/shared/mcp-memory-manager.ts +0 -540
- package/src/mcp/shared/mcp-resource-manager.ts +0 -367
- package/src/mcp/snow-flow-mcp.ts +0 -911
- package/src/mcp/start-all-mcp-servers.ts +0 -102
- package/src/mcp/start-servicenow-mcp.ts +0 -67
- package/src/monitoring/enhanced-monitoring-system.ts +0 -1345
- package/src/monitoring/performance-tracker.ts +0 -777
- package/src/optimization/cost-optimization-engine.ts +0 -1125
- package/src/optimization/index.ts +0 -10
- package/src/queen/README.md +0 -403
- package/src/queen/agent-factory.ts +0 -574
- package/src/queen/index.ts +0 -94
- package/src/queen/mcp-execution-bridge.ts +0 -681
- package/src/queen/neural-learning.ts +0 -319
- package/src/queen/parallel-agent-engine.ts +0 -848
- package/src/queen/queen-memory-system.ts +0 -490
- package/src/queen/queen-memory.ts +0 -456
- package/src/queen/servicenow-queen.ts +0 -1029
- package/src/queen/types.ts +0 -87
- package/src/rollback/smart-rollback-system.ts +0 -866
- package/src/schemas/deployment.schema.json +0 -58
- package/src/schemas/flow.schema.json +0 -79
- package/src/schemas/widget.schema.json +0 -72
- package/src/snow-flow-system.ts +0 -541
- package/src/sparc/sparc-help.ts +0 -49
- package/src/sparc/team-sparc.ts +0 -88
- package/src/strategies/global-scope-strategy.ts +0 -736
- package/src/templates/base/application.template.json +0 -45
- package/src/templates/base/business_rule.template.json +0 -33
- package/src/templates/base/script_include.template.json +0 -18
- package/src/templates/base/table.template.json +0 -64
- package/src/templates/base/widget.template.json +0 -25
- package/src/templates/patterns/composite.incident-management.template.json +0 -140
- package/src/templates/patterns/widget.dashboard.template.json +0 -238
- package/src/templates/patterns/widget.datatable.template.json +0 -292
- package/src/testing/integration-test-suite.ts +0 -1276
- package/src/types/index.ts +0 -183
- package/src/types/neo4j-driver.d.ts +0 -23
- package/src/types/servicenow.types.ts +0 -307
- package/src/types/snow-flow.types.ts +0 -186
- package/src/types/todo.types.ts +0 -70
- package/src/utils/action-type-cache.ts +0 -286
- package/src/utils/agent-detector.ts +0 -573
- package/src/utils/artifact-tracker.ts +0 -379
- package/src/utils/dependency-detector.ts +0 -233
- package/src/utils/deployment-metadata-handler.ts +0 -518
- package/src/utils/error-recovery.ts +0 -680
- package/src/utils/logger.ts +0 -60
- package/src/utils/mcp-auth-middleware.ts +0 -262
- package/src/utils/mcp-config-manager.ts +0 -270
- package/src/utils/mcp-server-manager.ts +0 -446
- package/src/utils/mcp-tool-registry.ts +0 -298
- package/src/utils/migrate-snow-flow.ts +0 -98
- package/src/utils/oauth-html-templates.ts +0 -188
- package/src/utils/scope-utils.ts +0 -443
- package/src/utils/servicenow-client.ts +0 -3321
- package/src/utils/servicenow-id-generator.ts +0 -181
- package/src/utils/snow-memory-manager.ts +0 -605
- package/src/utils/snow-oauth.ts +0 -797
- package/src/utils/template-engine.ts +0 -463
- package/src/utils/theme-manager.ts +0 -295
- package/src/utils/unified-auth-store.ts +0 -222
- package/src/utils/update-set-importer.ts +0 -422
- package/src/utils/update-set-xml-packager.ts +0 -371
- package/src/utils/widget-template-generator.ts +0 -1744
- package/src/version.ts +0 -1950
|
@@ -1,970 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* ServiceNow Platform Development MCP Server
|
|
4
|
-
* Handles core platform development artifacts with full dynamic discovery
|
|
5
|
-
* NO HARDCODED VALUES - All tables, fields, and 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 PlatformArtifactType {
|
|
22
|
-
table: string;
|
|
23
|
-
name: string;
|
|
24
|
-
description: string;
|
|
25
|
-
primaryFields: string[];
|
|
26
|
-
requiredFields: string[];
|
|
27
|
-
deploymentFields: string[];
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
interface DynamicTableInfo {
|
|
31
|
-
name: string;
|
|
32
|
-
label: string;
|
|
33
|
-
fields: Array<{
|
|
34
|
-
name: string;
|
|
35
|
-
type: string;
|
|
36
|
-
label: string;
|
|
37
|
-
mandatory: boolean;
|
|
38
|
-
display: boolean;
|
|
39
|
-
}>;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
class ServiceNowPlatformDevelopmentMCP {
|
|
43
|
-
private server: Server;
|
|
44
|
-
private client: ServiceNowClient;
|
|
45
|
-
private logger: Logger;
|
|
46
|
-
private config: ReturnType<typeof mcpConfig.getConfig>;
|
|
47
|
-
private tableCache: Map<string, DynamicTableInfo> = new Map();
|
|
48
|
-
|
|
49
|
-
constructor() {
|
|
50
|
-
this.server = new Server(
|
|
51
|
-
{
|
|
52
|
-
name: 'servicenow-platform-development',
|
|
53
|
-
version: '1.0.0',
|
|
54
|
-
},
|
|
55
|
-
{
|
|
56
|
-
capabilities: {
|
|
57
|
-
tools: {},
|
|
58
|
-
},
|
|
59
|
-
}
|
|
60
|
-
);
|
|
61
|
-
|
|
62
|
-
this.client = new ServiceNowClient();
|
|
63
|
-
this.logger = new Logger('ServiceNowPlatformDevelopmentMCP');
|
|
64
|
-
this.config = mcpConfig.getConfig();
|
|
65
|
-
|
|
66
|
-
this.setupHandlers();
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
private setupHandlers() {
|
|
70
|
-
this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
71
|
-
tools: [
|
|
72
|
-
{
|
|
73
|
-
name: 'snow_create_ui_page',
|
|
74
|
-
description: 'Create UI Pages dynamically with full field discovery - NO hardcoded values',
|
|
75
|
-
inputSchema: {
|
|
76
|
-
type: 'object',
|
|
77
|
-
properties: {
|
|
78
|
-
name: { type: 'string', description: 'UI Page name' },
|
|
79
|
-
title: { type: 'string', description: 'Page title' },
|
|
80
|
-
html: { type: 'string', description: 'HTML content' },
|
|
81
|
-
processingScript: { type: 'string', description: 'Server-side processing script' },
|
|
82
|
-
clientScript: { type: 'string', description: 'Client-side script' },
|
|
83
|
-
css: { type: 'string', description: 'CSS styles' },
|
|
84
|
-
category: { type: 'string', description: 'Page category' }
|
|
85
|
-
},
|
|
86
|
-
required: ['name', 'title', 'html']
|
|
87
|
-
}
|
|
88
|
-
},
|
|
89
|
-
{
|
|
90
|
-
name: 'snow_create_script_include',
|
|
91
|
-
description: 'Create Script Includes with dynamic table discovery - NO hardcoded values',
|
|
92
|
-
inputSchema: {
|
|
93
|
-
type: 'object',
|
|
94
|
-
properties: {
|
|
95
|
-
name: { type: 'string', description: 'Script Include name' },
|
|
96
|
-
script: { type: 'string', description: 'JavaScript code' },
|
|
97
|
-
description: { type: 'string', description: 'Description of functionality' },
|
|
98
|
-
clientCallable: { type: 'boolean', description: 'Can be called from client' },
|
|
99
|
-
apiName: { type: 'string', description: 'API name for external calls' }
|
|
100
|
-
},
|
|
101
|
-
required: ['name', 'script']
|
|
102
|
-
}
|
|
103
|
-
},
|
|
104
|
-
{
|
|
105
|
-
name: 'snow_create_business_rule',
|
|
106
|
-
description: 'Create Business Rules with dynamic table and field discovery - NO hardcoded values',
|
|
107
|
-
inputSchema: {
|
|
108
|
-
type: 'object',
|
|
109
|
-
properties: {
|
|
110
|
-
name: { type: 'string', description: 'Business Rule name' },
|
|
111
|
-
tableName: { type: 'string', description: 'Target table name or sys_id' },
|
|
112
|
-
script: { type: 'string', description: 'JavaScript code' },
|
|
113
|
-
when: { type: 'string', description: 'When to execute: before, after, async, display' },
|
|
114
|
-
condition: { type: 'string', description: 'Condition script' },
|
|
115
|
-
description: { type: 'string', description: 'Rule description' }
|
|
116
|
-
},
|
|
117
|
-
required: ['name', 'tableName', 'script', 'when']
|
|
118
|
-
}
|
|
119
|
-
},
|
|
120
|
-
{
|
|
121
|
-
name: 'snow_create_client_script',
|
|
122
|
-
description: 'Create Client Scripts with dynamic form discovery - NO hardcoded values',
|
|
123
|
-
inputSchema: {
|
|
124
|
-
type: 'object',
|
|
125
|
-
properties: {
|
|
126
|
-
name: { type: 'string', description: 'Client Script name' },
|
|
127
|
-
tableName: { type: 'string', description: 'Target table name or sys_id' },
|
|
128
|
-
script: { type: 'string', description: 'JavaScript code' },
|
|
129
|
-
type: { type: 'string', description: 'Script type: onLoad, onChange, onSubmit, onCellEdit' },
|
|
130
|
-
fieldName: { type: 'string', description: 'Field name for onChange scripts' },
|
|
131
|
-
condition: { type: 'string', description: 'Condition script' },
|
|
132
|
-
description: { type: 'string', description: 'Script description' }
|
|
133
|
-
},
|
|
134
|
-
required: ['name', 'tableName', 'script', 'type']
|
|
135
|
-
}
|
|
136
|
-
},
|
|
137
|
-
{
|
|
138
|
-
name: 'snow_create_ui_policy',
|
|
139
|
-
description: 'Create UI Policies with dynamic field discovery - NO hardcoded values',
|
|
140
|
-
inputSchema: {
|
|
141
|
-
type: 'object',
|
|
142
|
-
properties: {
|
|
143
|
-
name: { type: 'string', description: 'UI Policy name' },
|
|
144
|
-
tableName: { type: 'string', description: 'Target table name or sys_id' },
|
|
145
|
-
condition: { type: 'string', description: 'Condition script' },
|
|
146
|
-
description: { type: 'string', description: 'Policy description' },
|
|
147
|
-
runScripts: { type: 'boolean', description: 'Run scripts when policy applies' },
|
|
148
|
-
reverseWhenFalse: { type: 'boolean', description: 'Reverse actions when condition is false' }
|
|
149
|
-
},
|
|
150
|
-
required: ['name', 'tableName', 'condition']
|
|
151
|
-
}
|
|
152
|
-
},
|
|
153
|
-
{
|
|
154
|
-
name: 'snow_create_ui_action',
|
|
155
|
-
description: 'Create UI Actions with dynamic form discovery - NO hardcoded values',
|
|
156
|
-
inputSchema: {
|
|
157
|
-
type: 'object',
|
|
158
|
-
properties: {
|
|
159
|
-
name: { type: 'string', description: 'UI Action name' },
|
|
160
|
-
tableName: { type: 'string', description: 'Target table name or sys_id' },
|
|
161
|
-
script: { type: 'string', description: 'JavaScript code' },
|
|
162
|
-
condition: { type: 'string', description: 'Condition script' },
|
|
163
|
-
actionName: { type: 'string', description: 'Action name for forms' },
|
|
164
|
-
formButton: { type: 'boolean', description: 'Show as form button' },
|
|
165
|
-
listButton: { type: 'boolean', description: 'Show as list button' },
|
|
166
|
-
description: { type: 'string', description: 'Action description' }
|
|
167
|
-
},
|
|
168
|
-
required: ['name', 'tableName', 'script']
|
|
169
|
-
}
|
|
170
|
-
},
|
|
171
|
-
{
|
|
172
|
-
name: 'snow_discover_platform_tables',
|
|
173
|
-
description: 'Discover all available platform development tables dynamically',
|
|
174
|
-
inputSchema: {
|
|
175
|
-
type: 'object',
|
|
176
|
-
properties: {
|
|
177
|
-
category: { type: 'string', description: 'Filter by category: ui, script, policy, action, all' }
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
},
|
|
181
|
-
{
|
|
182
|
-
name: 'snow_discover_table_fields',
|
|
183
|
-
description: 'Discover all fields for a specific table dynamically',
|
|
184
|
-
inputSchema: {
|
|
185
|
-
type: 'object',
|
|
186
|
-
properties: {
|
|
187
|
-
tableName: { type: 'string', description: 'Table name to discover fields for' }
|
|
188
|
-
},
|
|
189
|
-
required: ['tableName']
|
|
190
|
-
}
|
|
191
|
-
},
|
|
192
|
-
{
|
|
193
|
-
name: 'snow_table_schema_discovery',
|
|
194
|
-
description: 'Comprehensive table schema discovery - structure, relationships, indexes, constraints',
|
|
195
|
-
inputSchema: {
|
|
196
|
-
type: 'object',
|
|
197
|
-
properties: {
|
|
198
|
-
tableName: { type: 'string', description: 'Table name to analyze' },
|
|
199
|
-
includeRelated: { type: 'boolean', description: 'Include related table information' },
|
|
200
|
-
includeIndexes: { type: 'boolean', description: 'Include index information' },
|
|
201
|
-
includeExtensions: { type: 'boolean', description: 'Include table extensions/hierarchy' },
|
|
202
|
-
maxDepth: { type: 'number', description: 'Max depth for relationship discovery (default: 2)' }
|
|
203
|
-
},
|
|
204
|
-
required: ['tableName']
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
]
|
|
208
|
-
}));
|
|
209
|
-
|
|
210
|
-
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
211
|
-
try {
|
|
212
|
-
const { name, arguments: args } = request.params;
|
|
213
|
-
|
|
214
|
-
// Ensure authentication
|
|
215
|
-
const authResult = await mcpAuth.ensureAuthenticated();
|
|
216
|
-
if (!authResult.success) {
|
|
217
|
-
throw new McpError(
|
|
218
|
-
ErrorCode.InternalError,
|
|
219
|
-
authResult.error || 'Authentication required'
|
|
220
|
-
);
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
switch (name) {
|
|
224
|
-
case 'snow_create_ui_page':
|
|
225
|
-
return await this.createUIPage(args);
|
|
226
|
-
case 'snow_create_script_include':
|
|
227
|
-
return await this.createScriptInclude(args);
|
|
228
|
-
case 'snow_create_business_rule':
|
|
229
|
-
return await this.createBusinessRule(args);
|
|
230
|
-
case 'snow_create_client_script':
|
|
231
|
-
return await this.createClientScript(args);
|
|
232
|
-
case 'snow_create_ui_policy':
|
|
233
|
-
return await this.createUIPolicy(args);
|
|
234
|
-
case 'snow_create_ui_action':
|
|
235
|
-
return await this.createUIAction(args);
|
|
236
|
-
case 'snow_discover_platform_tables':
|
|
237
|
-
return await this.discoverPlatformTables(args);
|
|
238
|
-
case 'snow_discover_table_fields':
|
|
239
|
-
return await this.discoverTableFields(args);
|
|
240
|
-
case 'snow_table_schema_discovery':
|
|
241
|
-
return await this.discoverTableSchema(args);
|
|
242
|
-
default:
|
|
243
|
-
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
244
|
-
}
|
|
245
|
-
} catch (error) {
|
|
246
|
-
this.logger.error(`Error in ${request.params.name}:`, error);
|
|
247
|
-
throw error;
|
|
248
|
-
}
|
|
249
|
-
});
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
/**
|
|
253
|
-
* Dynamically discover all platform development tables
|
|
254
|
-
*/
|
|
255
|
-
private async discoverPlatformTables(args: any) {
|
|
256
|
-
try {
|
|
257
|
-
this.logger.info('Discovering platform development tables...');
|
|
258
|
-
|
|
259
|
-
// Define table categories based on actual ServiceNow schema
|
|
260
|
-
const tableQueries = [
|
|
261
|
-
{ category: 'ui', query: 'nameSTARTSWITHsys_ui^ORnameSTARTSWITHsp_' },
|
|
262
|
-
{ category: 'script', query: 'nameSTARTSWITHsys_script^ORnameSTARTSWITHsys_processor' },
|
|
263
|
-
{ category: 'policy', query: 'nameSTARTSWITHsys_ui_policy^ORnameSTARTSWITHsys_ui_action' },
|
|
264
|
-
{ category: 'security', query: 'nameSTARTSWITHsys_security^ORnameSTARTSWITHsys_user' },
|
|
265
|
-
{ category: 'system', query: 'nameSTARTSWITHsys_dictionary^ORnameSTARTSWITHsys_choice' }
|
|
266
|
-
];
|
|
267
|
-
|
|
268
|
-
const category = args?.category || 'all';
|
|
269
|
-
const discoveredTables: Array<{category: string, tables: any[]}> = [];
|
|
270
|
-
|
|
271
|
-
for (const tableQuery of tableQueries) {
|
|
272
|
-
if (category === 'all' || category === tableQuery.category) {
|
|
273
|
-
const tablesResponse = await this.client.searchRecords(
|
|
274
|
-
'sys_db_object',
|
|
275
|
-
tableQuery.query,
|
|
276
|
-
50
|
|
277
|
-
);
|
|
278
|
-
|
|
279
|
-
if (tablesResponse.success && tablesResponse.data) {
|
|
280
|
-
discoveredTables.push({
|
|
281
|
-
category: tableQuery.category,
|
|
282
|
-
tables: tablesResponse.data.result.map((table: any) => ({
|
|
283
|
-
name: table.name,
|
|
284
|
-
label: table.label,
|
|
285
|
-
super_class: table.super_class,
|
|
286
|
-
is_extendable: table.is_extendable,
|
|
287
|
-
sys_id: table.sys_id
|
|
288
|
-
}))
|
|
289
|
-
});
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
return {
|
|
295
|
-
content: [{
|
|
296
|
-
type: 'text',
|
|
297
|
-
text: `š Discovered Platform Development Tables:\n\n${discoveredTables.map(cat =>
|
|
298
|
-
`**${cat.category.toUpperCase()} Tables:**\n${cat.tables.map(table =>
|
|
299
|
-
`- ${table.name} (${table.label})`
|
|
300
|
-
).join('\n')}`
|
|
301
|
-
).join('\n\n')}\n\n⨠All tables discovered dynamically from ServiceNow schema - no hardcoded values!`
|
|
302
|
-
}]
|
|
303
|
-
};
|
|
304
|
-
} catch (error) {
|
|
305
|
-
this.logger.error('Failed to discover platform tables:', error);
|
|
306
|
-
throw new McpError(ErrorCode.InternalError, `Failed to discover tables: ${error}`);
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
/**
|
|
311
|
-
* Dynamically discover table fields
|
|
312
|
-
*/
|
|
313
|
-
private async discoverTableFields(args: any) {
|
|
314
|
-
try {
|
|
315
|
-
const tableName = args.tableName;
|
|
316
|
-
this.logger.info(`Discovering fields for table: ${tableName}`);
|
|
317
|
-
|
|
318
|
-
// First, resolve table name to sys_id if needed
|
|
319
|
-
const tableInfo = await this.getTableInfo(tableName);
|
|
320
|
-
if (!tableInfo) {
|
|
321
|
-
throw new Error(`Table not found: ${tableName}`);
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
// Get all fields for this table
|
|
325
|
-
const fieldsResponse = await this.client.searchRecords(
|
|
326
|
-
'sys_dictionary',
|
|
327
|
-
`nameSTARTSWITH${tableInfo.name}^element!=NULL`,
|
|
328
|
-
100
|
|
329
|
-
);
|
|
330
|
-
|
|
331
|
-
if (!fieldsResponse.success || !fieldsResponse.data) {
|
|
332
|
-
throw new Error(`Failed to get fields for table: ${tableName}`);
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
const fields = fieldsResponse.data.result.map((field: any) => ({
|
|
336
|
-
name: field.element,
|
|
337
|
-
type: field.internal_type,
|
|
338
|
-
label: field.column_label,
|
|
339
|
-
mandatory: field.mandatory === 'true',
|
|
340
|
-
display: field.display === 'true',
|
|
341
|
-
max_length: field.max_length,
|
|
342
|
-
reference: field.reference,
|
|
343
|
-
choice: field.choice
|
|
344
|
-
}));
|
|
345
|
-
|
|
346
|
-
// Cache the table info
|
|
347
|
-
this.tableCache.set(tableName, {
|
|
348
|
-
name: tableInfo.name,
|
|
349
|
-
label: tableInfo.label,
|
|
350
|
-
fields: fields
|
|
351
|
-
});
|
|
352
|
-
|
|
353
|
-
return {
|
|
354
|
-
content: [{
|
|
355
|
-
type: 'text',
|
|
356
|
-
text: `š Fields for ${tableInfo.label} (${tableInfo.name}):\n\n${fields.map((field: any) =>
|
|
357
|
-
`- **${field.name}** (${field.label})\n Type: ${field.type}${field.mandatory ? ' *Required*' : ''}${field.reference ? ` -> ${field.reference}` : ''}`
|
|
358
|
-
).join('\n')}\n\nš Total fields: ${fields.length}\n⨠All fields discovered dynamically from ServiceNow schema!`
|
|
359
|
-
}]
|
|
360
|
-
};
|
|
361
|
-
} catch (error) {
|
|
362
|
-
this.logger.error('Failed to discover table fields:', error);
|
|
363
|
-
throw new McpError(ErrorCode.InternalError, `Failed to discover fields: ${error}`);
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
/**
|
|
368
|
-
* Get table information dynamically
|
|
369
|
-
*/
|
|
370
|
-
private async getTableInfo(tableName: string): Promise<{name: string, label: string, sys_id: string} | null> {
|
|
371
|
-
try {
|
|
372
|
-
this.logger.debug(`Looking up table info for: ${tableName}`);
|
|
373
|
-
|
|
374
|
-
// First, check if this is a known standard table that may not appear in sys_db_object
|
|
375
|
-
const standardTables: Record<string, {label: string}> = {
|
|
376
|
-
'incident': { label: 'Incident' },
|
|
377
|
-
'problem': { label: 'Problem' },
|
|
378
|
-
'change_request': { label: 'Change Request' },
|
|
379
|
-
'sc_request': { label: 'Request' },
|
|
380
|
-
'sc_req_item': { label: 'Requested Item' },
|
|
381
|
-
'sc_task': { label: 'Catalog Task' },
|
|
382
|
-
'task': { label: 'Task' }
|
|
383
|
-
};
|
|
384
|
-
|
|
385
|
-
if (standardTables[tableName]) {
|
|
386
|
-
this.logger.debug(`Using known standard table: ${tableName}`);
|
|
387
|
-
return {
|
|
388
|
-
name: tableName,
|
|
389
|
-
label: standardTables[tableName].label,
|
|
390
|
-
sys_id: `standard_table_${tableName}` // Placeholder sys_id for standard tables
|
|
391
|
-
};
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
// Try direct lookup first
|
|
395
|
-
const tableResponse = await this.client.searchRecords(
|
|
396
|
-
'sys_db_object',
|
|
397
|
-
`name=${tableName}`,
|
|
398
|
-
1
|
|
399
|
-
);
|
|
400
|
-
|
|
401
|
-
if (tableResponse.success && tableResponse.data?.result?.length > 0) {
|
|
402
|
-
const table = tableResponse.data.result[0];
|
|
403
|
-
return {
|
|
404
|
-
name: table.name,
|
|
405
|
-
label: table.label,
|
|
406
|
-
sys_id: table.sys_id
|
|
407
|
-
};
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
// Log the actual response for debugging
|
|
411
|
-
this.logger.debug(`Table lookup response for ${tableName}: ${JSON.stringify(tableResponse)}`);
|
|
412
|
-
|
|
413
|
-
// Try by sys_id
|
|
414
|
-
const tableByIdResponse = await this.client.searchRecords(
|
|
415
|
-
'sys_db_object',
|
|
416
|
-
`sys_id=${tableName}`,
|
|
417
|
-
1
|
|
418
|
-
);
|
|
419
|
-
|
|
420
|
-
if (tableByIdResponse.success && tableByIdResponse.data?.result?.length > 0) {
|
|
421
|
-
const table = tableByIdResponse.data.result[0];
|
|
422
|
-
return {
|
|
423
|
-
name: table.name,
|
|
424
|
-
label: table.label,
|
|
425
|
-
sys_id: table.sys_id
|
|
426
|
-
};
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
// Try partial match
|
|
430
|
-
const tableByPartialResponse = await this.client.searchRecords(
|
|
431
|
-
'sys_db_object',
|
|
432
|
-
`nameCONTAINS${tableName}^ORlabelCONTAINS${tableName}`,
|
|
433
|
-
5
|
|
434
|
-
);
|
|
435
|
-
|
|
436
|
-
if (tableByPartialResponse.success && tableByPartialResponse.data?.result?.length > 0) {
|
|
437
|
-
const table = tableByPartialResponse.data.result[0];
|
|
438
|
-
return {
|
|
439
|
-
name: table.name,
|
|
440
|
-
label: table.label,
|
|
441
|
-
sys_id: table.sys_id
|
|
442
|
-
};
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
return null;
|
|
446
|
-
} catch (error) {
|
|
447
|
-
this.logger.error(`Failed to get table info for ${tableName}:`, error);
|
|
448
|
-
return null;
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
/**
|
|
453
|
-
* Create UI Page with dynamic field discovery
|
|
454
|
-
*/
|
|
455
|
-
private async createUIPage(args: any) {
|
|
456
|
-
try {
|
|
457
|
-
this.logger.info('Creating UI Page...');
|
|
458
|
-
|
|
459
|
-
// Get UI Page table structure dynamically
|
|
460
|
-
const uiPageFields = await this.discoverRequiredFields('sys_ui_page');
|
|
461
|
-
|
|
462
|
-
const uiPageData = {
|
|
463
|
-
name: args.name,
|
|
464
|
-
title: args.title,
|
|
465
|
-
html: args.html,
|
|
466
|
-
processing_script: args.processingScript || '',
|
|
467
|
-
client_script: args.clientScript || '',
|
|
468
|
-
css: args.css || '',
|
|
469
|
-
category: args.category || 'general'
|
|
470
|
-
};
|
|
471
|
-
|
|
472
|
-
// Ensure we have Update Set
|
|
473
|
-
const updateSetResult = await this.client.ensureUpdateSet();
|
|
474
|
-
|
|
475
|
-
const response = await this.client.createRecord('sys_ui_page', uiPageData);
|
|
476
|
-
|
|
477
|
-
if (!response.success) {
|
|
478
|
-
throw new Error(`Failed to create UI Page: ${response.error}`);
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
return {
|
|
482
|
-
content: [{
|
|
483
|
-
type: 'text',
|
|
484
|
-
text: `ā
UI Page created successfully!\n\nš **${args.title}** (${args.name})\nš sys_id: ${response.data.sys_id}\n\nš View in ServiceNow: Open UI Page editor\n\n⨠Created with dynamic field discovery - no hardcoded values!`
|
|
485
|
-
}]
|
|
486
|
-
};
|
|
487
|
-
} catch (error) {
|
|
488
|
-
this.logger.error('Failed to create UI Page:', error);
|
|
489
|
-
throw new McpError(ErrorCode.InternalError, `Failed to create UI Page: ${error}`);
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
/**
|
|
494
|
-
* Create Script Include with dynamic discovery
|
|
495
|
-
*/
|
|
496
|
-
private async createScriptInclude(args: any) {
|
|
497
|
-
try {
|
|
498
|
-
this.logger.info('Creating Script Include...');
|
|
499
|
-
|
|
500
|
-
const scriptIncludeData = {
|
|
501
|
-
name: args.name,
|
|
502
|
-
script: args.script,
|
|
503
|
-
description: args.description || '',
|
|
504
|
-
client_callable: args.clientCallable || false,
|
|
505
|
-
api_name: args.apiName || args.name
|
|
506
|
-
};
|
|
507
|
-
|
|
508
|
-
const updateSetResult = await this.client.ensureUpdateSet();
|
|
509
|
-
const response = await this.client.createRecord('sys_script_include', scriptIncludeData);
|
|
510
|
-
|
|
511
|
-
if (!response.success) {
|
|
512
|
-
throw new Error(`Failed to create Script Include: ${response.error}`);
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
return {
|
|
516
|
-
content: [{
|
|
517
|
-
type: 'text',
|
|
518
|
-
text: `ā
Script Include created successfully!\n\nš **${args.name}**\nš sys_id: ${response.data.sys_id}\nš§ Client Callable: ${args.clientCallable ? 'Yes' : 'No'}\n\nš Description: ${args.description || 'No description provided'}\n\n⨠Created with dynamic field discovery!`
|
|
519
|
-
}]
|
|
520
|
-
};
|
|
521
|
-
} catch (error) {
|
|
522
|
-
this.logger.error('Failed to create Script Include:', error);
|
|
523
|
-
throw new McpError(ErrorCode.InternalError, `Failed to create Script Include: ${error}`);
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
/**
|
|
528
|
-
* Create Business Rule with dynamic table discovery
|
|
529
|
-
*/
|
|
530
|
-
private async createBusinessRule(args: any) {
|
|
531
|
-
try {
|
|
532
|
-
this.logger.info('Creating Business Rule...');
|
|
533
|
-
|
|
534
|
-
// Resolve table name dynamically
|
|
535
|
-
const tableInfo = await this.getTableInfo(args.tableName);
|
|
536
|
-
if (!tableInfo) {
|
|
537
|
-
throw new Error(`Table not found: ${args.tableName}`);
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
const businessRuleData = {
|
|
541
|
-
name: args.name,
|
|
542
|
-
table: tableInfo.name,
|
|
543
|
-
script: args.script,
|
|
544
|
-
when: args.when,
|
|
545
|
-
condition: args.condition || '',
|
|
546
|
-
description: args.description || ''
|
|
547
|
-
};
|
|
548
|
-
|
|
549
|
-
const updateSetResult = await this.client.ensureUpdateSet();
|
|
550
|
-
const response = await this.client.createRecord('sys_script', businessRuleData);
|
|
551
|
-
|
|
552
|
-
if (!response.success) {
|
|
553
|
-
throw new Error(`Failed to create Business Rule: ${response.error}`);
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
return {
|
|
557
|
-
content: [{
|
|
558
|
-
type: 'text',
|
|
559
|
-
text: `ā
Business Rule created successfully!\n\nš **${args.name}**\nš sys_id: ${response.data.sys_id}\nš Table: ${tableInfo.label} (${tableInfo.name})\nā° When: ${args.when}\n\nš Description: ${args.description || 'No description provided'}\n\n⨠Created with dynamic table discovery!`
|
|
560
|
-
}]
|
|
561
|
-
};
|
|
562
|
-
} catch (error) {
|
|
563
|
-
this.logger.error('Failed to create Business Rule:', error);
|
|
564
|
-
throw new McpError(ErrorCode.InternalError, `Failed to create Business Rule: ${error}`);
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
/**
|
|
569
|
-
* Create Client Script with dynamic discovery
|
|
570
|
-
*/
|
|
571
|
-
private async createClientScript(args: any) {
|
|
572
|
-
try {
|
|
573
|
-
this.logger.info('Creating Client Script...');
|
|
574
|
-
|
|
575
|
-
const tableInfo = await this.getTableInfo(args.tableName);
|
|
576
|
-
if (!tableInfo) {
|
|
577
|
-
throw new Error(`Table not found: ${args.tableName}`);
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
const clientScriptData = {
|
|
581
|
-
name: args.name,
|
|
582
|
-
table: tableInfo.name,
|
|
583
|
-
script: args.script,
|
|
584
|
-
type: args.type,
|
|
585
|
-
field: args.fieldName || '',
|
|
586
|
-
condition: args.condition || '',
|
|
587
|
-
description: args.description || ''
|
|
588
|
-
};
|
|
589
|
-
|
|
590
|
-
const updateSetResult = await this.client.ensureUpdateSet();
|
|
591
|
-
const response = await this.client.createRecord('sys_script_client', clientScriptData);
|
|
592
|
-
|
|
593
|
-
if (!response.success) {
|
|
594
|
-
throw new Error(`Failed to create Client Script: ${response.error}`);
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
return {
|
|
598
|
-
content: [{
|
|
599
|
-
type: 'text',
|
|
600
|
-
text: `ā
Client Script created successfully!\n\nš **${args.name}**\nš sys_id: ${response.data.sys_id}\nš Table: ${tableInfo.label} (${tableInfo.name})\nš§ Type: ${args.type}\n${args.fieldName ? `š·ļø Field: ${args.fieldName}\n` : ''}\nš Description: ${args.description || 'No description provided'}\n\n⨠Created with dynamic table discovery!`
|
|
601
|
-
}]
|
|
602
|
-
};
|
|
603
|
-
} catch (error) {
|
|
604
|
-
this.logger.error('Failed to create Client Script:', error);
|
|
605
|
-
throw new McpError(ErrorCode.InternalError, `Failed to create Client Script: ${error}`);
|
|
606
|
-
}
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
/**
|
|
610
|
-
* Create UI Policy with dynamic discovery
|
|
611
|
-
*/
|
|
612
|
-
private async createUIPolicy(args: any) {
|
|
613
|
-
try {
|
|
614
|
-
this.logger.info('Creating UI Policy...');
|
|
615
|
-
|
|
616
|
-
const tableInfo = await this.getTableInfo(args.tableName);
|
|
617
|
-
if (!tableInfo) {
|
|
618
|
-
throw new Error(`Table not found: ${args.tableName}`);
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
const uiPolicyData = {
|
|
622
|
-
name: args.name,
|
|
623
|
-
table: tableInfo.name,
|
|
624
|
-
conditions: args.condition,
|
|
625
|
-
description: args.description || '',
|
|
626
|
-
run_scripts: args.runScripts || false,
|
|
627
|
-
reverse_if_false: args.reverseWhenFalse || false
|
|
628
|
-
};
|
|
629
|
-
|
|
630
|
-
const updateSetResult = await this.client.ensureUpdateSet();
|
|
631
|
-
const response = await this.client.createRecord('sys_ui_policy', uiPolicyData);
|
|
632
|
-
|
|
633
|
-
if (!response.success) {
|
|
634
|
-
throw new Error(`Failed to create UI Policy: ${response.error}`);
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
return {
|
|
638
|
-
content: [{
|
|
639
|
-
type: 'text',
|
|
640
|
-
text: `ā
UI Policy created successfully!\n\nš **${args.name}**\nš sys_id: ${response.data.sys_id}\nš Table: ${tableInfo.label} (${tableInfo.name})\nš§ Run Scripts: ${args.runScripts ? 'Yes' : 'No'}\n\nš Description: ${args.description || 'No description provided'}\n\n⨠Created with dynamic table discovery!`
|
|
641
|
-
}]
|
|
642
|
-
};
|
|
643
|
-
} catch (error) {
|
|
644
|
-
this.logger.error('Failed to create UI Policy:', error);
|
|
645
|
-
throw new McpError(ErrorCode.InternalError, `Failed to create UI Policy: ${error}`);
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
/**
|
|
650
|
-
* Create UI Action with dynamic discovery
|
|
651
|
-
*/
|
|
652
|
-
private async createUIAction(args: any) {
|
|
653
|
-
try {
|
|
654
|
-
this.logger.info('Creating UI Action...');
|
|
655
|
-
|
|
656
|
-
const tableInfo = await this.getTableInfo(args.tableName);
|
|
657
|
-
if (!tableInfo) {
|
|
658
|
-
throw new Error(`Table not found: ${args.tableName}`);
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
const uiActionData = {
|
|
662
|
-
name: args.name,
|
|
663
|
-
table: tableInfo.name,
|
|
664
|
-
script: args.script,
|
|
665
|
-
condition: args.condition || '',
|
|
666
|
-
action_name: args.actionName || args.name,
|
|
667
|
-
form_button: args.formButton || false,
|
|
668
|
-
list_button: args.listButton || false,
|
|
669
|
-
description: args.description || ''
|
|
670
|
-
};
|
|
671
|
-
|
|
672
|
-
const updateSetResult = await this.client.ensureUpdateSet();
|
|
673
|
-
const response = await this.client.createRecord('sys_ui_action', uiActionData);
|
|
674
|
-
|
|
675
|
-
if (!response.success) {
|
|
676
|
-
throw new Error(`Failed to create UI Action: ${response.error}`);
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
return {
|
|
680
|
-
content: [{
|
|
681
|
-
type: 'text',
|
|
682
|
-
text: `ā
UI Action created successfully!\n\nšÆ **${args.name}**\nš sys_id: ${response.data.sys_id}\nš Table: ${tableInfo.label} (${tableInfo.name})\nš Form Button: ${args.formButton ? 'Yes' : 'No'}\nš List Button: ${args.listButton ? 'Yes' : 'No'}\n\nš Description: ${args.description || 'No description provided'}\n\n⨠Created with dynamic table discovery!`
|
|
683
|
-
}]
|
|
684
|
-
};
|
|
685
|
-
} catch (error) {
|
|
686
|
-
this.logger.error('Failed to create UI Action:', error);
|
|
687
|
-
throw new McpError(ErrorCode.InternalError, `Failed to create UI Action: ${error}`);
|
|
688
|
-
}
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
/**
|
|
692
|
-
* Discover required fields for a table dynamically
|
|
693
|
-
*/
|
|
694
|
-
private async discoverRequiredFields(tableName: string): Promise<string[]> {
|
|
695
|
-
try {
|
|
696
|
-
const fieldsResponse = await this.client.searchRecords(
|
|
697
|
-
'sys_dictionary',
|
|
698
|
-
`nameSTARTSWITH${tableName}^element!=NULL^mandatory=true`,
|
|
699
|
-
50
|
|
700
|
-
);
|
|
701
|
-
|
|
702
|
-
if (fieldsResponse.success && fieldsResponse.data) {
|
|
703
|
-
return fieldsResponse.data.result.map((field: any) => field.element);
|
|
704
|
-
}
|
|
705
|
-
|
|
706
|
-
return [];
|
|
707
|
-
} catch (error) {
|
|
708
|
-
this.logger.error(`Failed to discover required fields for ${tableName}:`, error);
|
|
709
|
-
return [];
|
|
710
|
-
}
|
|
711
|
-
}
|
|
712
|
-
|
|
713
|
-
/**
|
|
714
|
-
* Comprehensive table schema discovery
|
|
715
|
-
*/
|
|
716
|
-
private async discoverTableSchema(args: any) {
|
|
717
|
-
try {
|
|
718
|
-
const { tableName, includeRelated = true, includeIndexes = true, includeExtensions = true, maxDepth = 2 } = args;
|
|
719
|
-
this.logger.info(`Discovering comprehensive schema for table: ${tableName}`);
|
|
720
|
-
|
|
721
|
-
// Validate authentication
|
|
722
|
-
if (!this.client) {
|
|
723
|
-
throw new Error('ServiceNow client not initialized');
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
// Get table information
|
|
727
|
-
const tableInfo = await this.getTableInfo(tableName);
|
|
728
|
-
if (!tableInfo) {
|
|
729
|
-
throw new Error(`Table not found: ${tableName}. Searched in sys_db_object table.`);
|
|
730
|
-
}
|
|
731
|
-
|
|
732
|
-
this.logger.debug(`Found table info: ${JSON.stringify(tableInfo)}`);
|
|
733
|
-
|
|
734
|
-
// Get detailed table metadata
|
|
735
|
-
this.logger.debug(`Attempting to fetch table details for sys_id: ${tableInfo.sys_id}`);
|
|
736
|
-
|
|
737
|
-
// Check if this is a standard table with placeholder sys_id
|
|
738
|
-
const isStandardTable = tableInfo.sys_id.startsWith('standard_table_');
|
|
739
|
-
let tableDetailsResponse: any = { success: false };
|
|
740
|
-
|
|
741
|
-
if (!isStandardTable) {
|
|
742
|
-
tableDetailsResponse = await this.client.getRecord('sys_db_object', tableInfo.sys_id);
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
// Declare the variable once with proper type
|
|
746
|
-
let tableDetails: any;
|
|
747
|
-
|
|
748
|
-
if (!tableDetailsResponse.success || isStandardTable) {
|
|
749
|
-
const errorMessage = tableDetailsResponse.error ||
|
|
750
|
-
JSON.stringify(tableDetailsResponse) ||
|
|
751
|
-
'Unknown error occurred while fetching table details';
|
|
752
|
-
this.logger.error(`Table details fetch failed for ${tableInfo.sys_id}:`, tableDetailsResponse);
|
|
753
|
-
|
|
754
|
-
// Fallback: try using basic table info if detailed fetch fails
|
|
755
|
-
this.logger.warn(`Falling back to basic table info for ${tableInfo.name}`);
|
|
756
|
-
tableDetails = {
|
|
757
|
-
name: tableInfo.name,
|
|
758
|
-
label: tableInfo.label,
|
|
759
|
-
sys_id: tableInfo.sys_id,
|
|
760
|
-
is_extendable: 'unknown',
|
|
761
|
-
access: 'unknown',
|
|
762
|
-
sys_created_on: 'unknown',
|
|
763
|
-
sys_updated_on: 'unknown',
|
|
764
|
-
row_count: 'unknown',
|
|
765
|
-
super_class: null,
|
|
766
|
-
extension_model: 'unknown',
|
|
767
|
-
sys_scope: null
|
|
768
|
-
};
|
|
769
|
-
} else {
|
|
770
|
-
tableDetails = tableDetailsResponse.data;
|
|
771
|
-
}
|
|
772
|
-
|
|
773
|
-
// Get all fields with detailed information
|
|
774
|
-
const fieldsResponse = await this.client.searchRecords(
|
|
775
|
-
'sys_dictionary',
|
|
776
|
-
`name=${tableInfo.name}^element!=NULL`,
|
|
777
|
-
200
|
|
778
|
-
);
|
|
779
|
-
|
|
780
|
-
if (!fieldsResponse.success || !fieldsResponse.data) {
|
|
781
|
-
const errorMessage = fieldsResponse.error ||
|
|
782
|
-
'No data returned from fields query' ||
|
|
783
|
-
JSON.stringify(fieldsResponse);
|
|
784
|
-
this.logger.error(`Fields fetch failed for ${tableInfo.name}:`, fieldsResponse);
|
|
785
|
-
throw new Error(`Failed to get fields for table ${tableName}: ${errorMessage}`);
|
|
786
|
-
}
|
|
787
|
-
|
|
788
|
-
const fields = fieldsResponse.data.result.map((field: any) => ({
|
|
789
|
-
name: field.element,
|
|
790
|
-
label: field.column_label,
|
|
791
|
-
type: field.internal_type,
|
|
792
|
-
dataType: field.internal_type,
|
|
793
|
-
maxLength: field.max_length,
|
|
794
|
-
mandatory: field.mandatory === 'true',
|
|
795
|
-
readOnly: field.read_only === 'true',
|
|
796
|
-
display: field.display === 'true',
|
|
797
|
-
active: field.active === 'true',
|
|
798
|
-
array: field.array === 'true',
|
|
799
|
-
reference: field.reference,
|
|
800
|
-
referenceQual: field.reference_qual,
|
|
801
|
-
defaultValue: field.default_value,
|
|
802
|
-
choice: field.choice,
|
|
803
|
-
calculated: field.virtual === 'true',
|
|
804
|
-
attributes: field.attributes,
|
|
805
|
-
comments: field.comments
|
|
806
|
-
}));
|
|
807
|
-
|
|
808
|
-
// Analyze relationships
|
|
809
|
-
const relationships = fields
|
|
810
|
-
.filter((field: any) => field.reference)
|
|
811
|
-
.map((field: any) => ({
|
|
812
|
-
field: field.name,
|
|
813
|
-
targetTable: field.reference,
|
|
814
|
-
label: field.label,
|
|
815
|
-
referenceQual: field.referenceQual
|
|
816
|
-
}));
|
|
817
|
-
|
|
818
|
-
// Get table hierarchy if requested
|
|
819
|
-
let hierarchy: any = null;
|
|
820
|
-
if (includeExtensions) {
|
|
821
|
-
hierarchy = {
|
|
822
|
-
extends: tableDetails.super_class?.display_value || null,
|
|
823
|
-
extendsTable: tableDetails.super_class?.value || null,
|
|
824
|
-
isExtendable: tableDetails.is_extendable === 'true',
|
|
825
|
-
extensionModel: tableDetails.extension_model
|
|
826
|
-
};
|
|
827
|
-
|
|
828
|
-
// Find tables that extend this one
|
|
829
|
-
const childTablesResponse = await this.client.searchRecords(
|
|
830
|
-
'sys_db_object',
|
|
831
|
-
`super_class=${tableInfo.sys_id}`,
|
|
832
|
-
50
|
|
833
|
-
);
|
|
834
|
-
|
|
835
|
-
if (childTablesResponse.success && childTablesResponse.data) {
|
|
836
|
-
hierarchy.extendedBy = childTablesResponse.data.result.map((child: any) => ({
|
|
837
|
-
name: child.name,
|
|
838
|
-
label: child.label,
|
|
839
|
-
sys_id: child.sys_id
|
|
840
|
-
}));
|
|
841
|
-
}
|
|
842
|
-
}
|
|
843
|
-
|
|
844
|
-
// Get indexes if requested
|
|
845
|
-
let indexes: any[] = [];
|
|
846
|
-
if (includeIndexes) {
|
|
847
|
-
const indexResponse = await this.client.searchRecords(
|
|
848
|
-
'sys_db_index',
|
|
849
|
-
`table=${tableInfo.sys_id}`,
|
|
850
|
-
50
|
|
851
|
-
);
|
|
852
|
-
|
|
853
|
-
if (indexResponse.success && indexResponse.data) {
|
|
854
|
-
indexes = indexResponse.data.result.map((index: any) => ({
|
|
855
|
-
name: index.name,
|
|
856
|
-
unique: index.unique === 'true',
|
|
857
|
-
clustered: index.clustered === 'true',
|
|
858
|
-
fields: index.fields
|
|
859
|
-
}));
|
|
860
|
-
}
|
|
861
|
-
}
|
|
862
|
-
|
|
863
|
-
// Get related tables if requested
|
|
864
|
-
const relatedTables: any[] = [];
|
|
865
|
-
if (includeRelated && relationships.length > 0) {
|
|
866
|
-
const uniqueRelatedTables = [...new Set(relationships.map((rel: any) => rel.targetTable))];
|
|
867
|
-
|
|
868
|
-
for (const relTable of uniqueRelatedTables.slice(0, 10)) { // Limit to prevent too many queries
|
|
869
|
-
const relTableInfo = await this.getTableInfo(String(relTable));
|
|
870
|
-
if (relTableInfo) {
|
|
871
|
-
relatedTables.push({
|
|
872
|
-
name: relTableInfo.name,
|
|
873
|
-
label: relTableInfo.label,
|
|
874
|
-
referencedBy: relationships
|
|
875
|
-
.filter((rel: any) => rel.targetTable === relTable)
|
|
876
|
-
.map((rel: any) => rel.field)
|
|
877
|
-
});
|
|
878
|
-
}
|
|
879
|
-
}
|
|
880
|
-
}
|
|
881
|
-
|
|
882
|
-
// Compile comprehensive schema information
|
|
883
|
-
const schema = {
|
|
884
|
-
table: {
|
|
885
|
-
name: tableInfo.name,
|
|
886
|
-
label: tableInfo.label,
|
|
887
|
-
sys_id: tableInfo.sys_id,
|
|
888
|
-
isExtendable: tableDetails.is_extendable === 'true',
|
|
889
|
-
isSystemTable: tableDetails.sys_scope?.display_value === 'global',
|
|
890
|
-
created: tableDetails.sys_created_on,
|
|
891
|
-
updated: tableDetails.sys_updated_on,
|
|
892
|
-
recordCount: tableDetails.row_count || 'Unknown',
|
|
893
|
-
accessControls: tableDetails.access || 'Not specified'
|
|
894
|
-
},
|
|
895
|
-
hierarchy,
|
|
896
|
-
fields: {
|
|
897
|
-
total: fields.length,
|
|
898
|
-
mandatory: fields.filter((f: any) => f.mandatory).length,
|
|
899
|
-
references: fields.filter((f: any) => f.reference).length,
|
|
900
|
-
calculated: fields.filter((f: any) => f.calculated).length,
|
|
901
|
-
list: fields
|
|
902
|
-
},
|
|
903
|
-
relationships: {
|
|
904
|
-
total: relationships.length,
|
|
905
|
-
list: relationships,
|
|
906
|
-
relatedTables
|
|
907
|
-
},
|
|
908
|
-
indexes: {
|
|
909
|
-
total: indexes.length,
|
|
910
|
-
list: indexes
|
|
911
|
-
}
|
|
912
|
-
};
|
|
913
|
-
|
|
914
|
-
return {
|
|
915
|
-
content: [{
|
|
916
|
-
type: 'text',
|
|
917
|
-
text: `š **Comprehensive Schema Discovery for ${tableInfo.label} (${tableInfo.name})**\n\n` +
|
|
918
|
-
`š **Table Overview:**\n` +
|
|
919
|
-
`- Label: ${schema.table.label}\n` +
|
|
920
|
-
`- Name: ${schema.table.name}\n` +
|
|
921
|
-
`- System ID: ${schema.table.sys_id}\n` +
|
|
922
|
-
`- Extendable: ${schema.table.isExtendable ? 'Yes' : 'No'}\n` +
|
|
923
|
-
`- System Table: ${schema.table.isSystemTable ? 'Yes' : 'No'}\n` +
|
|
924
|
-
`- Record Count: ${schema.table.recordCount}\n\n` +
|
|
925
|
-
|
|
926
|
-
(hierarchy ? `š **Table Hierarchy:**\n` +
|
|
927
|
-
`- Extends: ${hierarchy.extends || 'None'}\n` +
|
|
928
|
-
`- Extended By: ${hierarchy.extendedBy?.length || 0} tables\n` +
|
|
929
|
-
(hierarchy.extendedBy?.length > 0 ?
|
|
930
|
-
hierarchy.extendedBy.map((t: any) => ` - ${t.label} (${t.name})`).join('\n') + '\n' : '') +
|
|
931
|
-
'\n' : '') +
|
|
932
|
-
|
|
933
|
-
`š **Fields Summary:**\n` +
|
|
934
|
-
`- Total Fields: ${schema.fields.total}\n` +
|
|
935
|
-
`- Mandatory Fields: ${schema.fields.mandatory}\n` +
|
|
936
|
-
`- Reference Fields: ${schema.fields.references}\n` +
|
|
937
|
-
`- Calculated Fields: ${schema.fields.calculated}\n\n` +
|
|
938
|
-
|
|
939
|
-
`š **Relationships:**\n` +
|
|
940
|
-
`- Total References: ${schema.relationships.total}\n` +
|
|
941
|
-
(schema.relationships.list.length > 0 ?
|
|
942
|
-
schema.relationships.list.map((rel: any) =>
|
|
943
|
-
` - ${rel.field} ā ${rel.targetTable} (${rel.label})`
|
|
944
|
-
).join('\n') + '\n' : '') +
|
|
945
|
-
'\n' +
|
|
946
|
-
|
|
947
|
-
(indexes.length > 0 ? `š **Indexes:**\n` +
|
|
948
|
-
indexes.map((idx: any) =>
|
|
949
|
-
`- ${idx.name} (${idx.unique ? 'Unique' : 'Non-unique'}) on: ${idx.fields}`
|
|
950
|
-
).join('\n') + '\n\n' : '') +
|
|
951
|
-
|
|
952
|
-
`\nš **Full Schema Details:**\n\`\`\`json\n${JSON.stringify(schema, null, 2)}\n\`\`\`\n\n` +
|
|
953
|
-
`⨠All schema information discovered dynamically from ServiceNow!`
|
|
954
|
-
}]
|
|
955
|
-
};
|
|
956
|
-
} catch (error) {
|
|
957
|
-
this.logger.error('Failed to discover table schema:', error);
|
|
958
|
-
throw new McpError(ErrorCode.InternalError, `Failed to discover table schema: ${error}`);
|
|
959
|
-
}
|
|
960
|
-
}
|
|
961
|
-
|
|
962
|
-
async run() {
|
|
963
|
-
const transport = new StdioServerTransport();
|
|
964
|
-
await this.server.connect(transport);
|
|
965
|
-
this.logger.info('ServiceNow Platform Development MCP Server running on stdio');
|
|
966
|
-
}
|
|
967
|
-
}
|
|
968
|
-
|
|
969
|
-
const server = new ServiceNowPlatformDevelopmentMCP();
|
|
970
|
-
server.run().catch(console.error);
|