snow-flow 3.3.0 ā 3.3.2
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/dist/dynamic-version.js +1 -1
- package/dist/mcp/servicenow-change-virtualagent-pa-mcp-enhanced.d.ts +7 -0
- package/dist/mcp/servicenow-change-virtualagent-pa-mcp-enhanced.js +816 -0
- package/dist/mcp/servicenow-cmdb-event-hr-csm-devops-mcp-enhanced.d.ts +7 -0
- package/dist/mcp/servicenow-cmdb-event-hr-csm-devops-mcp-enhanced.js +1112 -0
- package/dist/mcp/servicenow-flow-workspace-mobile-mcp-enhanced.d.ts +7 -0
- package/dist/mcp/servicenow-flow-workspace-mobile-mcp-enhanced.js +860 -0
- package/dist/mcp/servicenow-knowledge-catalog-mcp-enhanced.js +503 -1
- package/dist/mcp/shared/enhanced-base-mcp-server.d.ts +8 -0
- package/dist/mcp/shared/enhanced-base-mcp-server.js +24 -0
- package/dist/mcp/shared/mcp-logger.js +2 -1
- package/package.json +2 -2
|
@@ -55,7 +55,177 @@ class ServiceNowKnowledgeCatalogMCPEnhanced extends enhanced_base_mcp_server_js_
|
|
|
55
55
|
required: ['query']
|
|
56
56
|
}
|
|
57
57
|
},
|
|
58
|
-
|
|
58
|
+
{
|
|
59
|
+
name: 'snow_update_knowledge_article',
|
|
60
|
+
description: 'Updates existing knowledge article in kb_knowledge table.',
|
|
61
|
+
inputSchema: {
|
|
62
|
+
type: 'object',
|
|
63
|
+
properties: {
|
|
64
|
+
sys_id: { type: 'string', description: 'Article sys_id to update' },
|
|
65
|
+
short_description: { type: 'string', description: 'Article title' },
|
|
66
|
+
text: { type: 'string', description: 'Article content' },
|
|
67
|
+
workflow_state: { type: 'string', description: 'State: draft, review, published' },
|
|
68
|
+
valid_to: { type: 'string', description: 'Expiration date' },
|
|
69
|
+
keywords: { type: 'array', items: { type: 'string' } }
|
|
70
|
+
},
|
|
71
|
+
required: ['sys_id']
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
name: 'snow_retire_knowledge_article',
|
|
76
|
+
description: 'Retires knowledge article by setting workflow_state to retired in kb_knowledge table.',
|
|
77
|
+
inputSchema: {
|
|
78
|
+
type: 'object',
|
|
79
|
+
properties: {
|
|
80
|
+
sys_id: { type: 'string', description: 'Article sys_id' },
|
|
81
|
+
retirement_reason: { type: 'string', description: 'Reason for retirement' }
|
|
82
|
+
},
|
|
83
|
+
required: ['sys_id']
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
name: 'snow_create_knowledge_base',
|
|
88
|
+
description: 'Creates new knowledge base using kb_knowledge_base table.',
|
|
89
|
+
inputSchema: {
|
|
90
|
+
type: 'object',
|
|
91
|
+
properties: {
|
|
92
|
+
title: { type: 'string', description: 'Knowledge base name' },
|
|
93
|
+
description: { type: 'string', description: 'KB description' },
|
|
94
|
+
owner: { type: 'string', description: 'Owner user/group' },
|
|
95
|
+
kb_managers: { type: 'array', items: { type: 'string' } }
|
|
96
|
+
},
|
|
97
|
+
required: ['title']
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
name: 'snow_discover_knowledge_bases',
|
|
102
|
+
description: 'Lists all knowledge bases from kb_knowledge_base table.',
|
|
103
|
+
inputSchema: {
|
|
104
|
+
type: 'object',
|
|
105
|
+
properties: {
|
|
106
|
+
active_only: { type: 'boolean', default: true }
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
name: 'snow_get_knowledge_stats',
|
|
112
|
+
description: 'Gets statistics for knowledge articles from kb_knowledge table.',
|
|
113
|
+
inputSchema: {
|
|
114
|
+
type: 'object',
|
|
115
|
+
properties: {
|
|
116
|
+
kb_knowledge_base: { type: 'string', description: 'Filter by KB' },
|
|
117
|
+
date_range: { type: 'string', description: 'Date range filter' }
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
name: 'snow_knowledge_feedback',
|
|
123
|
+
description: 'Manages feedback for knowledge articles using kb_feedback table.',
|
|
124
|
+
inputSchema: {
|
|
125
|
+
type: 'object',
|
|
126
|
+
properties: {
|
|
127
|
+
article_id: { type: 'string', description: 'Article sys_id' },
|
|
128
|
+
rating: { type: 'number', description: 'Rating 1-5' },
|
|
129
|
+
comments: { type: 'string', description: 'Feedback comments' }
|
|
130
|
+
},
|
|
131
|
+
required: ['article_id']
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
// Service Catalog Tools
|
|
135
|
+
{
|
|
136
|
+
name: 'snow_create_catalog_item',
|
|
137
|
+
description: 'Creates service catalog item using sc_cat_item table.',
|
|
138
|
+
inputSchema: {
|
|
139
|
+
type: 'object',
|
|
140
|
+
properties: {
|
|
141
|
+
name: { type: 'string', description: 'Catalog item name' },
|
|
142
|
+
short_description: { type: 'string', description: 'Brief description' },
|
|
143
|
+
category: { type: 'string', description: 'Category sys_id' },
|
|
144
|
+
price: { type: 'string', description: 'Item price' },
|
|
145
|
+
workflow: { type: 'string', description: 'Fulfillment workflow' }
|
|
146
|
+
},
|
|
147
|
+
required: ['name', 'short_description']
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
name: 'snow_create_catalog_variable',
|
|
152
|
+
description: 'Creates variables for catalog items using item_option_new table.',
|
|
153
|
+
inputSchema: {
|
|
154
|
+
type: 'object',
|
|
155
|
+
properties: {
|
|
156
|
+
cat_item: { type: 'string', description: 'Catalog item sys_id' },
|
|
157
|
+
name: { type: 'string', description: 'Variable name' },
|
|
158
|
+
question_text: { type: 'string', description: 'Question to display' },
|
|
159
|
+
type: { type: 'string', description: 'Variable type' },
|
|
160
|
+
mandatory: { type: 'boolean', default: false }
|
|
161
|
+
},
|
|
162
|
+
required: ['cat_item', 'name', 'question_text']
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
name: 'snow_create_catalog_ui_policy',
|
|
167
|
+
description: 'Creates UI policies for catalog items using catalog_ui_policy table.',
|
|
168
|
+
inputSchema: {
|
|
169
|
+
type: 'object',
|
|
170
|
+
properties: {
|
|
171
|
+
cat_item: { type: 'string', description: 'Catalog item sys_id' },
|
|
172
|
+
short_description: { type: 'string', description: 'Policy name' },
|
|
173
|
+
condition: { type: 'string', description: 'When to apply' },
|
|
174
|
+
actions: { type: 'array', items: { type: 'object' } }
|
|
175
|
+
},
|
|
176
|
+
required: ['cat_item', 'short_description']
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
name: 'snow_order_catalog_item',
|
|
181
|
+
description: 'Submits catalog item order using sc_req_item table.',
|
|
182
|
+
inputSchema: {
|
|
183
|
+
type: 'object',
|
|
184
|
+
properties: {
|
|
185
|
+
cat_item: { type: 'string', description: 'Catalog item sys_id' },
|
|
186
|
+
requested_for: { type: 'string', description: 'User sys_id' },
|
|
187
|
+
variables: { type: 'object', description: 'Variable values' },
|
|
188
|
+
quantity: { type: 'number', default: 1 }
|
|
189
|
+
},
|
|
190
|
+
required: ['cat_item']
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
name: 'snow_search_catalog',
|
|
195
|
+
description: 'Searches service catalog items in sc_cat_item table.',
|
|
196
|
+
inputSchema: {
|
|
197
|
+
type: 'object',
|
|
198
|
+
properties: {
|
|
199
|
+
query: { type: 'string', description: 'Search text' },
|
|
200
|
+
category: { type: 'string', description: 'Filter by category' },
|
|
201
|
+
active_only: { type: 'boolean', default: true },
|
|
202
|
+
limit: { type: 'number', default: 10 }
|
|
203
|
+
},
|
|
204
|
+
required: ['query']
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
name: 'snow_get_catalog_item_details',
|
|
209
|
+
description: 'Gets full details of catalog item from sc_cat_item table.',
|
|
210
|
+
inputSchema: {
|
|
211
|
+
type: 'object',
|
|
212
|
+
properties: {
|
|
213
|
+
sys_id: { type: 'string', description: 'Catalog item sys_id' },
|
|
214
|
+
include_variables: { type: 'boolean', default: true }
|
|
215
|
+
},
|
|
216
|
+
required: ['sys_id']
|
|
217
|
+
}
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
name: 'snow_discover_catalogs',
|
|
221
|
+
description: 'Discovers catalog structure from sc_catalog table.',
|
|
222
|
+
inputSchema: {
|
|
223
|
+
type: 'object',
|
|
224
|
+
properties: {
|
|
225
|
+
include_categories: { type: 'boolean', default: true }
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
59
229
|
]
|
|
60
230
|
}));
|
|
61
231
|
this.server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
@@ -68,6 +238,32 @@ class ServiceNowKnowledgeCatalogMCPEnhanced extends enhanced_base_mcp_server_js_
|
|
|
68
238
|
return await this.createKnowledgeArticle(args);
|
|
69
239
|
case 'snow_search_knowledge':
|
|
70
240
|
return await this.searchKnowledge(args);
|
|
241
|
+
case 'snow_update_knowledge_article':
|
|
242
|
+
return await this.updateKnowledgeArticle(args);
|
|
243
|
+
case 'snow_retire_knowledge_article':
|
|
244
|
+
return await this.retireKnowledgeArticle(args);
|
|
245
|
+
case 'snow_create_knowledge_base':
|
|
246
|
+
return await this.createKnowledgeBase(args);
|
|
247
|
+
case 'snow_discover_knowledge_bases':
|
|
248
|
+
return await this.discoverKnowledgeBases(args);
|
|
249
|
+
case 'snow_get_knowledge_stats':
|
|
250
|
+
return await this.getKnowledgeStats(args);
|
|
251
|
+
case 'snow_knowledge_feedback':
|
|
252
|
+
return await this.knowledgeFeedback(args);
|
|
253
|
+
case 'snow_create_catalog_item':
|
|
254
|
+
return await this.createCatalogItem(args);
|
|
255
|
+
case 'snow_create_catalog_variable':
|
|
256
|
+
return await this.createCatalogVariable(args);
|
|
257
|
+
case 'snow_create_catalog_ui_policy':
|
|
258
|
+
return await this.createCatalogUIPolicy(args);
|
|
259
|
+
case 'snow_order_catalog_item':
|
|
260
|
+
return await this.orderCatalogItem(args);
|
|
261
|
+
case 'snow_search_catalog':
|
|
262
|
+
return await this.searchCatalog(args);
|
|
263
|
+
case 'snow_get_catalog_item_details':
|
|
264
|
+
return await this.getCatalogItemDetails(args);
|
|
265
|
+
case 'snow_discover_catalogs':
|
|
266
|
+
return await this.discoverCatalogs(args);
|
|
71
267
|
default:
|
|
72
268
|
throw new types_js_1.McpError(types_js_1.ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
73
269
|
}
|
|
@@ -189,6 +385,312 @@ ${articleList}
|
|
|
189
385
|
|
|
190
386
|
⨠Found ${articles.length} article(s)`);
|
|
191
387
|
}
|
|
388
|
+
/**
|
|
389
|
+
* Update Knowledge Article
|
|
390
|
+
*/
|
|
391
|
+
async updateKnowledgeArticle(args) {
|
|
392
|
+
this.logger.info('Updating knowledge article...', { sys_id: args.sys_id });
|
|
393
|
+
const updateData = {};
|
|
394
|
+
if (args.short_description)
|
|
395
|
+
updateData.short_description = args.short_description;
|
|
396
|
+
if (args.text)
|
|
397
|
+
updateData.text = args.text;
|
|
398
|
+
if (args.workflow_state)
|
|
399
|
+
updateData.workflow_state = args.workflow_state;
|
|
400
|
+
if (args.valid_to)
|
|
401
|
+
updateData.valid_to = args.valid_to;
|
|
402
|
+
if (args.keywords)
|
|
403
|
+
updateData.keywords = args.keywords.join(',');
|
|
404
|
+
this.logger.progress('Updating article in ServiceNow...');
|
|
405
|
+
const response = await this.updateRecord('kb_knowledge', args.sys_id, updateData);
|
|
406
|
+
if (!response.success) {
|
|
407
|
+
return this.createResponse(`ā Failed to update article: ${response.error}`);
|
|
408
|
+
}
|
|
409
|
+
this.logger.info('ā
Article updated successfully');
|
|
410
|
+
return this.createResponse(`ā
Knowledge article updated successfully!\nš sys_id: ${args.sys_id}`);
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Retire Knowledge Article
|
|
414
|
+
*/
|
|
415
|
+
async retireKnowledgeArticle(args) {
|
|
416
|
+
this.logger.info('Retiring knowledge article...', { sys_id: args.sys_id });
|
|
417
|
+
const updateData = {
|
|
418
|
+
workflow_state: 'retired',
|
|
419
|
+
u_retirement_reason: args.retirement_reason || 'Retired via API'
|
|
420
|
+
};
|
|
421
|
+
const response = await this.updateRecord('kb_knowledge', args.sys_id, updateData);
|
|
422
|
+
if (!response.success) {
|
|
423
|
+
return this.createResponse(`ā Failed to retire article: ${response.error}`);
|
|
424
|
+
}
|
|
425
|
+
this.logger.info('ā
Article retired successfully');
|
|
426
|
+
return this.createResponse(`ā
Knowledge article retired!\nš sys_id: ${args.sys_id}`);
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* Create Knowledge Base
|
|
430
|
+
*/
|
|
431
|
+
async createKnowledgeBase(args) {
|
|
432
|
+
this.logger.info('Creating knowledge base...', { title: args.title });
|
|
433
|
+
const kbData = {
|
|
434
|
+
title: args.title,
|
|
435
|
+
description: args.description || '',
|
|
436
|
+
owner: args.owner || '',
|
|
437
|
+
kb_managers: args.kb_managers?.join(',') || ''
|
|
438
|
+
};
|
|
439
|
+
this.logger.progress('Creating KB in ServiceNow...');
|
|
440
|
+
const response = await this.createRecord('kb_knowledge_base', kbData);
|
|
441
|
+
if (!response.success) {
|
|
442
|
+
return this.createResponse(`ā Failed to create KB: ${response.error}`);
|
|
443
|
+
}
|
|
444
|
+
const result = response.data;
|
|
445
|
+
this.logger.info('ā
Knowledge base created', { sys_id: result.sys_id });
|
|
446
|
+
return this.createResponse(`ā
Knowledge Base created!\nš **${args.title}**\nš sys_id: ${result.sys_id}`);
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* Discover Knowledge Bases
|
|
450
|
+
*/
|
|
451
|
+
async discoverKnowledgeBases(args) {
|
|
452
|
+
this.logger.info('Discovering knowledge bases...');
|
|
453
|
+
const query = args.active_only ? 'active=true' : '';
|
|
454
|
+
const response = await this.queryTable('kb_knowledge_base', query, 50);
|
|
455
|
+
if (!response.success) {
|
|
456
|
+
return this.createResponse(`ā Failed to discover KBs: ${response.error}`);
|
|
457
|
+
}
|
|
458
|
+
const kbs = response.data.result;
|
|
459
|
+
this.logger.info(`Found ${kbs.length} knowledge bases`);
|
|
460
|
+
const kbList = kbs.map((kb) => `š **${kb.title}**\nš ${kb.sys_id}\nš ${kb.description || 'No description'}`).join('\n\n');
|
|
461
|
+
return this.createResponse(`š Knowledge Bases Found:\n\n${kbList}\n\n⨠Total: ${kbs.length} knowledge base(s)`);
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* Get Knowledge Stats
|
|
465
|
+
*/
|
|
466
|
+
async getKnowledgeStats(args) {
|
|
467
|
+
this.logger.info('Getting knowledge statistics...');
|
|
468
|
+
let query = 'active=true';
|
|
469
|
+
if (args.kb_knowledge_base) {
|
|
470
|
+
query += `^kb_knowledge_base=${args.kb_knowledge_base}`;
|
|
471
|
+
}
|
|
472
|
+
this.logger.progress('Gathering statistics...');
|
|
473
|
+
// Get article counts by state
|
|
474
|
+
const states = ['draft', 'review', 'published', 'retired'];
|
|
475
|
+
const stats = { total: 0, by_state: {} };
|
|
476
|
+
for (const state of states) {
|
|
477
|
+
const stateQuery = `${query}^workflow_state=${state}`;
|
|
478
|
+
const response = await this.queryTable('kb_knowledge', stateQuery, 1);
|
|
479
|
+
if (response.success && response.data.headers) {
|
|
480
|
+
const count = parseInt(response.data.headers['x-total-count'] || '0');
|
|
481
|
+
stats.by_state[state] = count;
|
|
482
|
+
stats.total += count;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
this.logger.info('ā
Statistics gathered', stats);
|
|
486
|
+
return this.createResponse(`š Knowledge Base Statistics:\n\n` +
|
|
487
|
+
`š Total Articles: ${stats.total}\n` +
|
|
488
|
+
`š Draft: ${stats.by_state.draft || 0}\n` +
|
|
489
|
+
`šļø In Review: ${stats.by_state.review || 0}\n` +
|
|
490
|
+
`ā
Published: ${stats.by_state.published || 0}\n` +
|
|
491
|
+
`šļø Retired: ${stats.by_state.retired || 0}`);
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* Knowledge Feedback
|
|
495
|
+
*/
|
|
496
|
+
async knowledgeFeedback(args) {
|
|
497
|
+
this.logger.info('Managing knowledge feedback...', { article_id: args.article_id });
|
|
498
|
+
if (args.rating || args.comments) {
|
|
499
|
+
// Create feedback
|
|
500
|
+
const feedbackData = {
|
|
501
|
+
article: args.article_id,
|
|
502
|
+
rating: args.rating || 0,
|
|
503
|
+
comments: args.comments || '',
|
|
504
|
+
user: 'api_user'
|
|
505
|
+
};
|
|
506
|
+
this.logger.progress('Submitting feedback...');
|
|
507
|
+
const response = await this.createRecord('kb_feedback', feedbackData);
|
|
508
|
+
if (!response.success) {
|
|
509
|
+
return this.createResponse(`ā Failed to submit feedback: ${response.error}`);
|
|
510
|
+
}
|
|
511
|
+
this.logger.info('ā
Feedback submitted');
|
|
512
|
+
return this.createResponse(`ā
Feedback submitted!\nā Rating: ${args.rating || 'N/A'}`);
|
|
513
|
+
}
|
|
514
|
+
else {
|
|
515
|
+
// Get feedback for article
|
|
516
|
+
const query = `article=${args.article_id}`;
|
|
517
|
+
const response = await this.queryTable('kb_feedback', query, 10);
|
|
518
|
+
if (!response.success) {
|
|
519
|
+
return this.createResponse(`ā Failed to get feedback: ${response.error}`);
|
|
520
|
+
}
|
|
521
|
+
const feedback = response.data.result;
|
|
522
|
+
const avgRating = feedback.length > 0 ?
|
|
523
|
+
(feedback.reduce((sum, f) => sum + (f.rating || 0), 0) / feedback.length).toFixed(1) :
|
|
524
|
+
'N/A';
|
|
525
|
+
return this.createResponse(`š Article Feedback:\nā Average Rating: ${avgRating}\nš¬ ${feedback.length} feedback entries`);
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* Create Catalog Item
|
|
530
|
+
*/
|
|
531
|
+
async createCatalogItem(args) {
|
|
532
|
+
this.logger.info('Creating catalog item...', { name: args.name });
|
|
533
|
+
const itemData = {
|
|
534
|
+
name: args.name,
|
|
535
|
+
short_description: args.short_description,
|
|
536
|
+
category: args.category || '',
|
|
537
|
+
price: args.price || '0',
|
|
538
|
+
workflow: args.workflow || '',
|
|
539
|
+
active: true
|
|
540
|
+
};
|
|
541
|
+
this.logger.progress('Creating item in ServiceNow...');
|
|
542
|
+
const response = await this.createRecord('sc_cat_item', itemData);
|
|
543
|
+
if (!response.success) {
|
|
544
|
+
return this.createResponse(`ā Failed to create catalog item: ${response.error}`);
|
|
545
|
+
}
|
|
546
|
+
const result = response.data;
|
|
547
|
+
this.logger.info('ā
Catalog item created', { sys_id: result.sys_id });
|
|
548
|
+
return this.createResponse(`ā
Catalog Item created!\nšļø **${args.name}**\nš sys_id: ${result.sys_id}\nš° Price: ${args.price || '0'}`);
|
|
549
|
+
}
|
|
550
|
+
/**
|
|
551
|
+
* Create Catalog Variable
|
|
552
|
+
*/
|
|
553
|
+
async createCatalogVariable(args) {
|
|
554
|
+
this.logger.info('Creating catalog variable...', { name: args.name });
|
|
555
|
+
const varData = {
|
|
556
|
+
cat_item: args.cat_item,
|
|
557
|
+
name: args.name,
|
|
558
|
+
question_text: args.question_text,
|
|
559
|
+
type: args.type || '6', // Single line text
|
|
560
|
+
mandatory: args.mandatory || false,
|
|
561
|
+
order: 100
|
|
562
|
+
};
|
|
563
|
+
this.logger.progress('Creating variable...');
|
|
564
|
+
const response = await this.createRecord('item_option_new', varData);
|
|
565
|
+
if (!response.success) {
|
|
566
|
+
return this.createResponse(`ā Failed to create variable: ${response.error}`);
|
|
567
|
+
}
|
|
568
|
+
this.logger.info('ā
Variable created');
|
|
569
|
+
return this.createResponse(`ā
Catalog variable created!\nš ${args.question_text}\nš¤ Name: ${args.name}`);
|
|
570
|
+
}
|
|
571
|
+
/**
|
|
572
|
+
* Create Catalog UI Policy
|
|
573
|
+
*/
|
|
574
|
+
async createCatalogUIPolicy(args) {
|
|
575
|
+
this.logger.info('Creating catalog UI policy...', { short_description: args.short_description });
|
|
576
|
+
const policyData = {
|
|
577
|
+
cat_item: args.cat_item,
|
|
578
|
+
short_description: args.short_description,
|
|
579
|
+
condition: args.condition || '',
|
|
580
|
+
active: true
|
|
581
|
+
};
|
|
582
|
+
this.logger.progress('Creating UI policy...');
|
|
583
|
+
const response = await this.createRecord('catalog_ui_policy', policyData);
|
|
584
|
+
if (!response.success) {
|
|
585
|
+
return this.createResponse(`ā Failed to create UI policy: ${response.error}`);
|
|
586
|
+
}
|
|
587
|
+
this.logger.info('ā
UI policy created');
|
|
588
|
+
return this.createResponse(`ā
Catalog UI Policy created!\nš ${args.short_description}\nš sys_id: ${response.data.sys_id}`);
|
|
589
|
+
}
|
|
590
|
+
/**
|
|
591
|
+
* Order Catalog Item
|
|
592
|
+
*/
|
|
593
|
+
async orderCatalogItem(args) {
|
|
594
|
+
this.logger.info('Ordering catalog item...', { cat_item: args.cat_item });
|
|
595
|
+
const orderData = {
|
|
596
|
+
cat_item: args.cat_item,
|
|
597
|
+
requested_for: args.requested_for || 'current_user',
|
|
598
|
+
quantity: args.quantity || 1,
|
|
599
|
+
variables: JSON.stringify(args.variables || {})
|
|
600
|
+
};
|
|
601
|
+
this.logger.progress('Submitting order...');
|
|
602
|
+
const response = await this.createRecord('sc_req_item', orderData);
|
|
603
|
+
if (!response.success) {
|
|
604
|
+
return this.createResponse(`ā Failed to order item: ${response.error}`);
|
|
605
|
+
}
|
|
606
|
+
const result = response.data;
|
|
607
|
+
this.logger.info('ā
Order submitted', { number: result.number });
|
|
608
|
+
return this.createResponse(`ā
Catalog item ordered!\nš¦ Request: ${result.number}\nš sys_id: ${result.sys_id}\nš Status: ${result.state || 'Submitted'}`);
|
|
609
|
+
}
|
|
610
|
+
/**
|
|
611
|
+
* Search Catalog
|
|
612
|
+
*/
|
|
613
|
+
async searchCatalog(args) {
|
|
614
|
+
this.logger.info('Searching service catalog...', { query: args.query });
|
|
615
|
+
let query = `nameLIKE${args.query}^ORshort_descriptionLIKE${args.query}`;
|
|
616
|
+
if (args.category) {
|
|
617
|
+
query += `^category=${args.category}`;
|
|
618
|
+
}
|
|
619
|
+
if (args.active_only) {
|
|
620
|
+
query += '^active=true';
|
|
621
|
+
}
|
|
622
|
+
this.logger.progress('Searching catalog...');
|
|
623
|
+
const response = await this.queryTable('sc_cat_item', query, args.limit || 10);
|
|
624
|
+
if (!response.success) {
|
|
625
|
+
return this.createResponse(`ā Search failed: ${response.error}`);
|
|
626
|
+
}
|
|
627
|
+
const items = response.data.result;
|
|
628
|
+
if (!items.length) {
|
|
629
|
+
return this.createResponse(`ā No catalog items found matching "${args.query}"`);
|
|
630
|
+
}
|
|
631
|
+
this.logger.info(`Found ${items.length} catalog items`);
|
|
632
|
+
const itemList = items.map((item) => `šļø **${item.name}**\nš ${item.short_description}\nš° ${item.price || '0'}\nš ${item.sys_id}`).join('\n\n');
|
|
633
|
+
return this.createResponse(`š Catalog Search Results:\n\n${itemList}\n\n⨠Found ${items.length} item(s)`);
|
|
634
|
+
}
|
|
635
|
+
/**
|
|
636
|
+
* Get Catalog Item Details
|
|
637
|
+
*/
|
|
638
|
+
async getCatalogItemDetails(args) {
|
|
639
|
+
this.logger.info('Getting catalog item details...', { sys_id: args.sys_id });
|
|
640
|
+
const response = await this.getRecord('sc_cat_item', args.sys_id);
|
|
641
|
+
if (!response.success) {
|
|
642
|
+
return this.createResponse(`ā Failed to get item details: ${response.error}`);
|
|
643
|
+
}
|
|
644
|
+
const item = response.data;
|
|
645
|
+
let details = `šļø **${item.name}**\n` +
|
|
646
|
+
`š ${item.short_description}\n` +
|
|
647
|
+
`š° Price: ${item.price || '0'}\n` +
|
|
648
|
+
`š Active: ${item.active}\n` +
|
|
649
|
+
`š sys_id: ${item.sys_id}`;
|
|
650
|
+
if (args.include_variables) {
|
|
651
|
+
// Get variables
|
|
652
|
+
const varQuery = `cat_item=${args.sys_id}`;
|
|
653
|
+
const varResponse = await this.queryTable('item_option_new', varQuery, 50);
|
|
654
|
+
if (varResponse.success && varResponse.data.result.length > 0) {
|
|
655
|
+
const variables = varResponse.data.result;
|
|
656
|
+
details += `\n\nš Variables (${variables.length}):\n`;
|
|
657
|
+
variables.forEach((v) => {
|
|
658
|
+
details += ` ⢠${v.question_text} (${v.name})\n`;
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
this.logger.info('ā
Retrieved item details');
|
|
663
|
+
return this.createResponse(details);
|
|
664
|
+
}
|
|
665
|
+
/**
|
|
666
|
+
* Discover Catalogs
|
|
667
|
+
*/
|
|
668
|
+
async discoverCatalogs(args) {
|
|
669
|
+
this.logger.info('Discovering service catalogs...');
|
|
670
|
+
const response = await this.queryTable('sc_catalog', 'active=true', 20);
|
|
671
|
+
if (!response.success) {
|
|
672
|
+
return this.createResponse(`ā Failed to discover catalogs: ${response.error}`);
|
|
673
|
+
}
|
|
674
|
+
const catalogs = response.data.result;
|
|
675
|
+
this.logger.info(`Found ${catalogs.length} catalogs`);
|
|
676
|
+
let catalogInfo = `š Service Catalogs:\n\n`;
|
|
677
|
+
for (const catalog of catalogs) {
|
|
678
|
+
catalogInfo += `šļø **${catalog.title}**\nš ${catalog.sys_id}\n`;
|
|
679
|
+
if (args.include_categories) {
|
|
680
|
+
// Get categories for this catalog
|
|
681
|
+
const catQuery = `sc_catalog=${catalog.sys_id}^active=true`;
|
|
682
|
+
const catResponse = await this.queryTable('sc_category', catQuery, 10);
|
|
683
|
+
if (catResponse.success && catResponse.data.result.length > 0) {
|
|
684
|
+
catalogInfo += `š Categories:\n`;
|
|
685
|
+
catResponse.data.result.forEach((cat) => {
|
|
686
|
+
catalogInfo += ` ⢠${cat.title}\n`;
|
|
687
|
+
});
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
catalogInfo += '\n';
|
|
691
|
+
}
|
|
692
|
+
return this.createResponse(`${catalogInfo}⨠Total: ${catalogs.length} catalog(s) discovered`);
|
|
693
|
+
}
|
|
192
694
|
async start() {
|
|
193
695
|
const transport = new stdio_js_1.StdioServerTransport();
|
|
194
696
|
await this.server.connect(transport);
|
|
@@ -41,6 +41,14 @@ export declare abstract class EnhancedBaseMCPServer {
|
|
|
41
41
|
* Create record with tracking
|
|
42
42
|
*/
|
|
43
43
|
protected createRecord(table: string, data: any): Promise<any>;
|
|
44
|
+
/**
|
|
45
|
+
* Update record with tracking
|
|
46
|
+
*/
|
|
47
|
+
protected updateRecord(table: string, sysId: string, data: any): Promise<any>;
|
|
48
|
+
/**
|
|
49
|
+
* Get record with tracking
|
|
50
|
+
*/
|
|
51
|
+
protected getRecord(table: string, sysId: string): Promise<any>;
|
|
44
52
|
/**
|
|
45
53
|
* Get client for direct use
|
|
46
54
|
*/
|
|
@@ -36,6 +36,8 @@ class EnhancedBaseMCPServer {
|
|
|
36
36
|
* Execute tool with enhanced tracking
|
|
37
37
|
*/
|
|
38
38
|
async executeTool(toolName, handler) {
|
|
39
|
+
// Reset tokens at start of each operation to avoid accumulation
|
|
40
|
+
this.logger.resetTokens();
|
|
39
41
|
// Start operation tracking
|
|
40
42
|
this.logger.operationStart(toolName);
|
|
41
43
|
try {
|
|
@@ -151,6 +153,28 @@ class EnhancedBaseMCPServer {
|
|
|
151
153
|
}
|
|
152
154
|
return result;
|
|
153
155
|
}
|
|
156
|
+
/**
|
|
157
|
+
* Update record with tracking
|
|
158
|
+
*/
|
|
159
|
+
async updateRecord(table, sysId, data) {
|
|
160
|
+
this.logger.progress(`Updating ${table} record ${sysId}...`);
|
|
161
|
+
const result = await this.client.updateRecord(table, sysId, data);
|
|
162
|
+
if (result?.success) {
|
|
163
|
+
this.logger.info(`ā
Updated ${table} record: ${sysId}`);
|
|
164
|
+
}
|
|
165
|
+
return result;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Get record with tracking
|
|
169
|
+
*/
|
|
170
|
+
async getRecord(table, sysId) {
|
|
171
|
+
this.logger.progress(`Getting ${table} record ${sysId}...`);
|
|
172
|
+
const result = await this.client.getRecord(table, sysId);
|
|
173
|
+
if (result?.success) {
|
|
174
|
+
this.logger.info(`ā
Retrieved ${table} record: ${sysId}`);
|
|
175
|
+
}
|
|
176
|
+
return result;
|
|
177
|
+
}
|
|
154
178
|
/**
|
|
155
179
|
* Get client for direct use
|
|
156
180
|
*/
|
|
@@ -131,7 +131,7 @@ class MCPLogger {
|
|
|
131
131
|
*/
|
|
132
132
|
operationStart(operation, params) {
|
|
133
133
|
this.startTime = Date.now();
|
|
134
|
-
this.info(`š Starting: ${operation}`, params);
|
|
134
|
+
this.info(`š Starting: ${operation} (tokens reset)`, params);
|
|
135
135
|
}
|
|
136
136
|
/**
|
|
137
137
|
* Log operation complete
|
|
@@ -166,6 +166,7 @@ class MCPLogger {
|
|
|
166
166
|
*/
|
|
167
167
|
resetTokens() {
|
|
168
168
|
this.tokenUsage = { input: 0, output: 0, total: 0 };
|
|
169
|
+
console.error(`š [${this.name}] Token counter reset for new operation`);
|
|
169
170
|
}
|
|
170
171
|
}
|
|
171
172
|
exports.MCPLogger = MCPLogger;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "snow-flow",
|
|
3
|
-
"version": "3.3.
|
|
4
|
-
"description": "Snow-Flow v3.3.
|
|
3
|
+
"version": "3.3.2",
|
|
4
|
+
"description": "Snow-Flow v3.3.2: ServiceNow development platform with 180+ MCP tools. Enhanced MCP servers with real-time progress indicators, per-operation token tracking (tokens reset per call), and comprehensive operation logging. Supports ATF Testing, Knowledge Management, Service Catalog, Change Management, Virtual Agent, Performance Analytics, Flow Designer, Agent Workspace, Mobile, CMDB/Discovery, Event Management, HR Service Delivery, Customer Service Management, and DevOps integration. All tools use official ServiceNow REST APIs across 17 specialized MCP servers with full visibility into API operations.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "commonjs",
|
|
7
7
|
"bin": {
|