snow-flow 3.2.3 → 3.3.1

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.
@@ -0,0 +1,709 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * ServiceNow Knowledge Management & Service Catalog MCP Server - ENHANCED VERSION
5
+ * With logging, token tracking, and progress indicators
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
9
+ const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
10
+ const enhanced_base_mcp_server_js_1 = require("./shared/enhanced-base-mcp-server.js");
11
+ const mcp_config_manager_js_1 = require("../utils/mcp-config-manager.js");
12
+ class ServiceNowKnowledgeCatalogMCPEnhanced extends enhanced_base_mcp_server_js_1.EnhancedBaseMCPServer {
13
+ constructor() {
14
+ super('servicenow-knowledge-catalog-enhanced', '2.0.0');
15
+ this.config = mcp_config_manager_js_1.mcpConfig.getConfig();
16
+ this.setupHandlers();
17
+ }
18
+ setupHandlers() {
19
+ this.server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({
20
+ tools: [
21
+ // Knowledge Management Tools
22
+ {
23
+ name: 'snow_create_knowledge_article',
24
+ description: 'Creates a knowledge article in ServiceNow Knowledge Base using kb_knowledge table.',
25
+ inputSchema: {
26
+ type: 'object',
27
+ properties: {
28
+ short_description: { type: 'string', description: 'Article title' },
29
+ text: { type: 'string', description: 'Article content (HTML supported)' },
30
+ kb_knowledge_base: { type: 'string', description: 'Knowledge base sys_id or name' },
31
+ kb_category: { type: 'string', description: 'Category sys_id or name' },
32
+ article_type: { type: 'string', description: 'Type: text, html, wiki' },
33
+ workflow_state: { type: 'string', description: 'State: draft, review, published, retired' },
34
+ valid_to: { type: 'string', description: 'Expiration date (YYYY-MM-DD)' },
35
+ meta_description: { type: 'string', description: 'SEO meta description' },
36
+ keywords: { type: 'array', items: { type: 'string' }, description: 'Search keywords' },
37
+ author: { type: 'string', description: 'Author user sys_id or username' }
38
+ },
39
+ required: ['short_description', 'text']
40
+ }
41
+ },
42
+ {
43
+ name: 'snow_search_knowledge',
44
+ description: 'Searches knowledge articles in kb_knowledge table with full-text search.',
45
+ inputSchema: {
46
+ type: 'object',
47
+ properties: {
48
+ query: { type: 'string', description: 'Search query text' },
49
+ kb_knowledge_base: { type: 'string', description: 'Filter by knowledge base' },
50
+ kb_category: { type: 'string', description: 'Filter by category' },
51
+ workflow_state: { type: 'string', description: 'Filter by state (published, draft, etc.)' },
52
+ limit: { type: 'number', description: 'Maximum results to return', default: 10 },
53
+ include_content: { type: 'boolean', description: 'Include full article content', default: false }
54
+ },
55
+ required: ['query']
56
+ }
57
+ },
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
+ }
229
+ ]
230
+ }));
231
+ this.server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
232
+ try {
233
+ const { name, arguments: args } = request.params;
234
+ // Execute with enhanced tracking
235
+ return await this.executeTool(name, async () => {
236
+ switch (name) {
237
+ case 'snow_create_knowledge_article':
238
+ return await this.createKnowledgeArticle(args);
239
+ case 'snow_search_knowledge':
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);
267
+ default:
268
+ throw new types_js_1.McpError(types_js_1.ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
269
+ }
270
+ });
271
+ }
272
+ catch (error) {
273
+ if (error instanceof types_js_1.McpError)
274
+ throw error;
275
+ throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, `Tool execution failed: ${error}`);
276
+ }
277
+ });
278
+ }
279
+ /**
280
+ * Create Knowledge Article with enhanced tracking
281
+ */
282
+ async createKnowledgeArticle(args) {
283
+ this.logger.info('Creating knowledge article...', {
284
+ title: args.short_description,
285
+ hasContent: !!args.text,
286
+ contentLength: args.text?.length
287
+ });
288
+ // Validate connection
289
+ const connCheck = await this.validateConnection();
290
+ if (!connCheck.success) {
291
+ return this.createResponse(`❌ Connection failed: ${connCheck.error}`);
292
+ }
293
+ // Progress indicator
294
+ this.logger.progress('Building knowledge article data...');
295
+ const articleData = {
296
+ short_description: args.short_description,
297
+ text: args.text,
298
+ kb_knowledge_base: args.kb_knowledge_base || '',
299
+ kb_category: args.kb_category || '',
300
+ article_type: args.article_type || 'text',
301
+ workflow_state: args.workflow_state || 'draft',
302
+ valid_to: args.valid_to || '',
303
+ meta_description: args.meta_description || '',
304
+ keywords: args.keywords?.join(',') || '',
305
+ author: args.author || ''
306
+ };
307
+ this.logger.progress('Creating article in ServiceNow...');
308
+ // Create with tracking
309
+ const response = await this.createRecord('kb_knowledge', articleData);
310
+ if (!response.success) {
311
+ this.logger.error('Failed to create knowledge article', response.error);
312
+ return this.createResponse(`❌ Failed to create article: ${response.error}`);
313
+ }
314
+ // Success with details
315
+ const result = response.data;
316
+ this.logger.info('✅ Knowledge article created successfully', {
317
+ sys_id: result.sys_id,
318
+ number: result.number,
319
+ title: args.short_description
320
+ });
321
+ return this.createResponse(`✅ Knowledge Article created successfully!
322
+
323
+ 📚 **${args.short_description}**
324
+ 🆔 sys_id: ${result.sys_id}
325
+ 📋 Number: ${result.number}
326
+ 📊 State: ${args.workflow_state || 'draft'}
327
+ 📝 Type: ${args.article_type || 'text'}
328
+ ${args.kb_knowledge_base ? `📁 Knowledge Base: ${args.kb_knowledge_base}` : ''}
329
+ ${args.kb_category ? `🏷️ Category: ${args.kb_category}` : ''}
330
+ ${args.valid_to ? `📅 Valid Until: ${args.valid_to}` : ''}
331
+
332
+ ✨ Article created and ready for review!`);
333
+ }
334
+ /**
335
+ * Search Knowledge with enhanced tracking
336
+ */
337
+ async searchKnowledge(args) {
338
+ this.logger.info('Searching knowledge articles...', {
339
+ query: args.query,
340
+ limit: args.limit || 10,
341
+ includeContent: args.include_content
342
+ });
343
+ // Build query
344
+ let query = `short_descriptionLIKE${args.query}^ORtextLIKE${args.query}`;
345
+ if (args.kb_knowledge_base) {
346
+ query += `^kb_knowledge_base=${args.kb_knowledge_base}`;
347
+ }
348
+ if (args.kb_category) {
349
+ query += `^kb_category=${args.kb_category}`;
350
+ }
351
+ if (args.workflow_state) {
352
+ query += `^workflow_state=${args.workflow_state}`;
353
+ }
354
+ else {
355
+ query += '^workflow_state=published'; // Default to published only
356
+ }
357
+ this.logger.progress(`Searching kb_knowledge table for: "${args.query}"...`);
358
+ // Search with tracking
359
+ const limit = args.limit || 10;
360
+ const response = await this.queryTable('kb_knowledge', query, limit);
361
+ if (!response.success) {
362
+ this.logger.error('Knowledge search failed', response.error);
363
+ return this.createResponse(`❌ Search failed: ${response.error}`);
364
+ }
365
+ const articles = response.data.result;
366
+ if (!articles.length) {
367
+ this.logger.info('No articles found', { query: args.query });
368
+ return this.createResponse(`❌ No knowledge articles found matching "${args.query}"`);
369
+ }
370
+ this.logger.info(`Found ${articles.length} knowledge articles`);
371
+ // Format results
372
+ const articleList = articles.map((article) => {
373
+ const snippet = args.include_content ?
374
+ article.text?.substring(0, 200) + '...' :
375
+ article.short_description;
376
+ return `📄 **${article.short_description}**
377
+ 🆔 ${article.sys_id}
378
+ 📊 State: ${article.workflow_state}
379
+ 📅 Updated: ${article.sys_updated_on}
380
+ ${args.include_content ? `📝 ${snippet}` : ''}`;
381
+ }).join('\n\n');
382
+ return this.createResponse(`🔍 Knowledge Search Results for "${args.query}":
383
+
384
+ ${articleList}
385
+
386
+ ✨ Found ${articles.length} article(s)`);
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
+ }
694
+ async start() {
695
+ const transport = new stdio_js_1.StdioServerTransport();
696
+ await this.server.connect(transport);
697
+ // Log ready state
698
+ this.logger.info('🚀 ServiceNow Knowledge & Catalog MCP Server (Enhanced) running');
699
+ this.logger.info('📊 Token tracking enabled');
700
+ this.logger.info('⏳ Progress indicators active');
701
+ }
702
+ }
703
+ // Start the enhanced server
704
+ const server = new ServiceNowKnowledgeCatalogMCPEnhanced();
705
+ server.start().catch((error) => {
706
+ console.error('Failed to start enhanced server:', error);
707
+ process.exit(1);
708
+ });
709
+ //# sourceMappingURL=servicenow-knowledge-catalog-mcp-enhanced.js.map