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.
- package/README.md +14 -0
- 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.d.ts +7 -0
- package/dist/mcp/servicenow-knowledge-catalog-mcp-enhanced.js +709 -0
- package/dist/mcp/shared/enhanced-base-mcp-server.d.ts +53 -0
- package/dist/mcp/shared/enhanced-base-mcp-server.js +168 -0
- package/dist/mcp/shared/mcp-logger.d.ts +80 -0
- package/dist/mcp/shared/mcp-logger.js +190 -0
- package/dist/utils/servicenow-client-with-tracking.d.ts +38 -0
- package/dist/utils/servicenow-client-with-tracking.js +137 -0
- package/package.json +2 -2
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enhanced Base MCP Server with Logging and Token Tracking
|
|
3
|
+
*/
|
|
4
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
5
|
+
import { ServiceNowClientWithTracking } from '../../utils/servicenow-client-with-tracking.js';
|
|
6
|
+
import { MCPLogger } from './mcp-logger.js';
|
|
7
|
+
import { SnowOAuth } from '../../utils/snow-oauth.js';
|
|
8
|
+
export interface MCPToolResult {
|
|
9
|
+
content: Array<{
|
|
10
|
+
type: string;
|
|
11
|
+
text: string;
|
|
12
|
+
}>;
|
|
13
|
+
}
|
|
14
|
+
export declare abstract class EnhancedBaseMCPServer {
|
|
15
|
+
protected server: Server;
|
|
16
|
+
protected client: ServiceNowClientWithTracking;
|
|
17
|
+
protected logger: MCPLogger;
|
|
18
|
+
protected oauth: SnowOAuth;
|
|
19
|
+
protected isAuthenticated: boolean;
|
|
20
|
+
constructor(name: string, version?: string);
|
|
21
|
+
/**
|
|
22
|
+
* Execute tool with enhanced tracking
|
|
23
|
+
*/
|
|
24
|
+
protected executeTool(toolName: string, handler: () => Promise<MCPToolResult>): Promise<MCPToolResult>;
|
|
25
|
+
/**
|
|
26
|
+
* Validate ServiceNow connection with progress
|
|
27
|
+
*/
|
|
28
|
+
protected validateConnection(): Promise<{
|
|
29
|
+
success: boolean;
|
|
30
|
+
error?: string;
|
|
31
|
+
}>;
|
|
32
|
+
/**
|
|
33
|
+
* Create standardized response with tracking
|
|
34
|
+
*/
|
|
35
|
+
protected createResponse(message: string, data?: any): MCPToolResult;
|
|
36
|
+
/**
|
|
37
|
+
* Query table with progress tracking
|
|
38
|
+
*/
|
|
39
|
+
protected queryTable(table: string, query: string, limit?: number): Promise<any>;
|
|
40
|
+
/**
|
|
41
|
+
* Create record with tracking
|
|
42
|
+
*/
|
|
43
|
+
protected createRecord(table: string, data: any): Promise<any>;
|
|
44
|
+
/**
|
|
45
|
+
* Get client for direct use
|
|
46
|
+
*/
|
|
47
|
+
getClient(): ServiceNowClientWithTracking;
|
|
48
|
+
/**
|
|
49
|
+
* Get logger for direct use
|
|
50
|
+
*/
|
|
51
|
+
getLogger(): MCPLogger;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=enhanced-base-mcp-server.d.ts.map
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Enhanced Base MCP Server with Logging and Token Tracking
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.EnhancedBaseMCPServer = void 0;
|
|
7
|
+
const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
|
|
8
|
+
const servicenow_client_with_tracking_js_1 = require("../../utils/servicenow-client-with-tracking.js");
|
|
9
|
+
const mcp_logger_js_1 = require("./mcp-logger.js");
|
|
10
|
+
const snow_oauth_js_1 = require("../../utils/snow-oauth.js");
|
|
11
|
+
const mcp_auth_middleware_js_1 = require("../../utils/mcp-auth-middleware.js");
|
|
12
|
+
class EnhancedBaseMCPServer {
|
|
13
|
+
constructor(name, version = '1.0.0') {
|
|
14
|
+
this.isAuthenticated = false;
|
|
15
|
+
// Create enhanced logger
|
|
16
|
+
this.logger = new mcp_logger_js_1.MCPLogger(name);
|
|
17
|
+
// Log startup
|
|
18
|
+
this.logger.info(`🚀 Starting ${name} MCP Server v${version}`);
|
|
19
|
+
// Create enhanced client with tracking
|
|
20
|
+
this.client = new servicenow_client_with_tracking_js_1.ServiceNowClientWithTracking(this.logger);
|
|
21
|
+
// Initialize OAuth
|
|
22
|
+
this.oauth = new snow_oauth_js_1.SnowOAuth();
|
|
23
|
+
// Create server with capabilities
|
|
24
|
+
this.server = new index_js_1.Server({
|
|
25
|
+
name,
|
|
26
|
+
version,
|
|
27
|
+
}, {
|
|
28
|
+
capabilities: {
|
|
29
|
+
tools: {},
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
// Report initialization
|
|
33
|
+
this.logger.info(`✅ ${name} initialized and ready`);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Execute tool with enhanced tracking
|
|
37
|
+
*/
|
|
38
|
+
async executeTool(toolName, handler) {
|
|
39
|
+
// Start operation tracking
|
|
40
|
+
this.logger.operationStart(toolName);
|
|
41
|
+
try {
|
|
42
|
+
// Ensure authentication
|
|
43
|
+
await mcp_auth_middleware_js_1.mcpAuth.ensureAuthenticated();
|
|
44
|
+
this.isAuthenticated = true;
|
|
45
|
+
// Execute the tool handler
|
|
46
|
+
const result = await handler();
|
|
47
|
+
// Log completion
|
|
48
|
+
this.logger.operationComplete(toolName);
|
|
49
|
+
// Send token usage summary if in Claude
|
|
50
|
+
if (process.send) {
|
|
51
|
+
const usage = this.logger.getTokenUsage();
|
|
52
|
+
process.send({
|
|
53
|
+
type: 'token_usage',
|
|
54
|
+
data: {
|
|
55
|
+
tool: toolName,
|
|
56
|
+
tokens: usage
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
return result;
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
this.logger.error(`Tool execution failed: ${toolName}`, error);
|
|
64
|
+
// Return error as tool result
|
|
65
|
+
return {
|
|
66
|
+
content: [{
|
|
67
|
+
type: 'text',
|
|
68
|
+
text: `❌ Error executing ${toolName}: ${error instanceof Error ? error.message : String(error)}`
|
|
69
|
+
}]
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Validate ServiceNow connection with progress
|
|
75
|
+
*/
|
|
76
|
+
async validateConnection() {
|
|
77
|
+
this.logger.progress('Validating ServiceNow connection...');
|
|
78
|
+
try {
|
|
79
|
+
// Check credentials
|
|
80
|
+
const credentials = await this.oauth.loadCredentials();
|
|
81
|
+
if (!credentials) {
|
|
82
|
+
return {
|
|
83
|
+
success: false,
|
|
84
|
+
error: 'No ServiceNow credentials found. Run "snow-flow auth login"'
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
// Check token
|
|
88
|
+
if (!credentials.accessToken) {
|
|
89
|
+
return {
|
|
90
|
+
success: false,
|
|
91
|
+
error: 'OAuth authentication required. Run "snow-flow auth login"'
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
// Test connection
|
|
95
|
+
this.logger.progress('Testing ServiceNow API connection...');
|
|
96
|
+
const connectionTest = await this.client.testConnection();
|
|
97
|
+
if (!connectionTest.success) {
|
|
98
|
+
return {
|
|
99
|
+
success: false,
|
|
100
|
+
error: `ServiceNow connection failed: ${connectionTest.error}`
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
this.logger.info('✅ ServiceNow connection validated');
|
|
104
|
+
return { success: true };
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
this.logger.error('Connection validation failed', error);
|
|
108
|
+
return {
|
|
109
|
+
success: false,
|
|
110
|
+
error: error instanceof Error ? error.message : String(error)
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Create standardized response with tracking
|
|
116
|
+
*/
|
|
117
|
+
createResponse(message, data) {
|
|
118
|
+
// Log the response
|
|
119
|
+
this.logger.debug('Tool response', { message, hasData: !!data });
|
|
120
|
+
// Format response
|
|
121
|
+
const response = {
|
|
122
|
+
content: [{
|
|
123
|
+
type: 'text',
|
|
124
|
+
text: message
|
|
125
|
+
}]
|
|
126
|
+
};
|
|
127
|
+
// Add data if provided
|
|
128
|
+
if (data) {
|
|
129
|
+
response.content[0].text += '\n\n' + JSON.stringify(data, null, 2);
|
|
130
|
+
}
|
|
131
|
+
return response;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Query table with progress tracking
|
|
135
|
+
*/
|
|
136
|
+
async queryTable(table, query, limit = 10) {
|
|
137
|
+
this.logger.progress(`Querying ${table} table (limit: ${limit})...`);
|
|
138
|
+
const result = await this.client.searchRecords(table, query, limit);
|
|
139
|
+
const recordCount = result?.data?.result?.length || 0;
|
|
140
|
+
this.logger.info(`Query completed: ${recordCount} records found`);
|
|
141
|
+
return result;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Create record with tracking
|
|
145
|
+
*/
|
|
146
|
+
async createRecord(table, data) {
|
|
147
|
+
this.logger.progress(`Creating ${table} record...`);
|
|
148
|
+
const result = await this.client.createRecord(table, data);
|
|
149
|
+
if (result?.success) {
|
|
150
|
+
this.logger.info(`✅ Created ${table} record: ${result.data?.result?.sys_id}`);
|
|
151
|
+
}
|
|
152
|
+
return result;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Get client for direct use
|
|
156
|
+
*/
|
|
157
|
+
getClient() {
|
|
158
|
+
return this.client;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Get logger for direct use
|
|
162
|
+
*/
|
|
163
|
+
getLogger() {
|
|
164
|
+
return this.logger;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
exports.EnhancedBaseMCPServer = EnhancedBaseMCPServer;
|
|
168
|
+
//# sourceMappingURL=enhanced-base-mcp-server.js.map
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enhanced MCP Logger with Token Tracking and Progress Reporting
|
|
3
|
+
* Sends logs to stderr so they appear in Claude Code console
|
|
4
|
+
*/
|
|
5
|
+
interface TokenUsage {
|
|
6
|
+
input: number;
|
|
7
|
+
output: number;
|
|
8
|
+
total: number;
|
|
9
|
+
}
|
|
10
|
+
export declare class MCPLogger {
|
|
11
|
+
private name;
|
|
12
|
+
private tokenUsage;
|
|
13
|
+
private startTime;
|
|
14
|
+
private lastProgressTime;
|
|
15
|
+
private progressInterval;
|
|
16
|
+
constructor(name: string);
|
|
17
|
+
/**
|
|
18
|
+
* Log to stderr with proper formatting
|
|
19
|
+
*/
|
|
20
|
+
private log;
|
|
21
|
+
/**
|
|
22
|
+
* Start progress indicator for long-running operations
|
|
23
|
+
*/
|
|
24
|
+
private startProgressIndicator;
|
|
25
|
+
/**
|
|
26
|
+
* Stop progress indicator
|
|
27
|
+
*/
|
|
28
|
+
stopProgress(): void;
|
|
29
|
+
/**
|
|
30
|
+
* Log info message
|
|
31
|
+
*/
|
|
32
|
+
info(message: string, data?: any): void;
|
|
33
|
+
/**
|
|
34
|
+
* Log warning message
|
|
35
|
+
*/
|
|
36
|
+
warn(message: string, data?: any): void;
|
|
37
|
+
/**
|
|
38
|
+
* Log error message
|
|
39
|
+
*/
|
|
40
|
+
error(message: string, error?: any): void;
|
|
41
|
+
/**
|
|
42
|
+
* Log debug message
|
|
43
|
+
*/
|
|
44
|
+
debug(message: string, data?: any): void;
|
|
45
|
+
/**
|
|
46
|
+
* Log progress update
|
|
47
|
+
*/
|
|
48
|
+
progress(message: string): void;
|
|
49
|
+
/**
|
|
50
|
+
* Track API call
|
|
51
|
+
*/
|
|
52
|
+
trackAPICall(operation: string, table?: string, recordCount?: number): void;
|
|
53
|
+
/**
|
|
54
|
+
* Add token usage
|
|
55
|
+
*/
|
|
56
|
+
addTokens(input: number, output: number): void;
|
|
57
|
+
/**
|
|
58
|
+
* Log operation start
|
|
59
|
+
*/
|
|
60
|
+
operationStart(operation: string, params?: any): void;
|
|
61
|
+
/**
|
|
62
|
+
* Log operation complete
|
|
63
|
+
*/
|
|
64
|
+
operationComplete(operation: string, result?: any): void;
|
|
65
|
+
/**
|
|
66
|
+
* Get token usage
|
|
67
|
+
*/
|
|
68
|
+
getTokenUsage(): TokenUsage;
|
|
69
|
+
/**
|
|
70
|
+
* Reset token usage
|
|
71
|
+
*/
|
|
72
|
+
resetTokens(): void;
|
|
73
|
+
}
|
|
74
|
+
export declare function getGlobalLogger(name?: string): MCPLogger;
|
|
75
|
+
/**
|
|
76
|
+
* Log formatter for consistent output
|
|
77
|
+
*/
|
|
78
|
+
export declare function formatLogMessage(level: string, message: string, data?: any): string;
|
|
79
|
+
export {};
|
|
80
|
+
//# sourceMappingURL=mcp-logger.d.ts.map
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Enhanced MCP Logger with Token Tracking and Progress Reporting
|
|
4
|
+
* Sends logs to stderr so they appear in Claude Code console
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.MCPLogger = void 0;
|
|
8
|
+
exports.getGlobalLogger = getGlobalLogger;
|
|
9
|
+
exports.formatLogMessage = formatLogMessage;
|
|
10
|
+
class MCPLogger {
|
|
11
|
+
constructor(name) {
|
|
12
|
+
this.tokenUsage = { input: 0, output: 0, total: 0 };
|
|
13
|
+
this.startTime = Date.now();
|
|
14
|
+
this.lastProgressTime = Date.now();
|
|
15
|
+
this.progressInterval = null;
|
|
16
|
+
this.name = name;
|
|
17
|
+
// Start progress indicator
|
|
18
|
+
this.startProgressIndicator();
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Log to stderr with proper formatting
|
|
22
|
+
*/
|
|
23
|
+
log(level, message, data) {
|
|
24
|
+
const timestamp = new Date().toISOString();
|
|
25
|
+
const logEntry = {
|
|
26
|
+
timestamp,
|
|
27
|
+
level,
|
|
28
|
+
service: this.name,
|
|
29
|
+
message,
|
|
30
|
+
data,
|
|
31
|
+
tokens: this.tokenUsage.total,
|
|
32
|
+
duration: Math.round((Date.now() - this.startTime) / 1000)
|
|
33
|
+
};
|
|
34
|
+
// Send to stderr so it appears in console
|
|
35
|
+
console.error(`[${this.name}] ${level}: ${message}`, data ? JSON.stringify(data, null, 2) : '');
|
|
36
|
+
// Also send structured log for potential parsing
|
|
37
|
+
if (process.send) {
|
|
38
|
+
process.send({
|
|
39
|
+
type: 'log',
|
|
40
|
+
data: logEntry
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Start progress indicator for long-running operations
|
|
46
|
+
*/
|
|
47
|
+
startProgressIndicator() {
|
|
48
|
+
// Send progress every 2 seconds
|
|
49
|
+
this.progressInterval = setInterval(() => {
|
|
50
|
+
const duration = Math.round((Date.now() - this.startTime) / 1000);
|
|
51
|
+
if (duration > 0) {
|
|
52
|
+
this.progress(`Operation in progress... (${duration}s elapsed, ${this.tokenUsage.total} tokens used)`);
|
|
53
|
+
}
|
|
54
|
+
}, 2000);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Stop progress indicator
|
|
58
|
+
*/
|
|
59
|
+
stopProgress() {
|
|
60
|
+
if (this.progressInterval) {
|
|
61
|
+
clearInterval(this.progressInterval);
|
|
62
|
+
this.progressInterval = null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Log info message
|
|
67
|
+
*/
|
|
68
|
+
info(message, data) {
|
|
69
|
+
this.log('INFO', message, data);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Log warning message
|
|
73
|
+
*/
|
|
74
|
+
warn(message, data) {
|
|
75
|
+
this.log('WARN', message, data);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Log error message
|
|
79
|
+
*/
|
|
80
|
+
error(message, error) {
|
|
81
|
+
const errorData = error instanceof Error ? {
|
|
82
|
+
message: error.message,
|
|
83
|
+
stack: error.stack,
|
|
84
|
+
name: error.name
|
|
85
|
+
} : error;
|
|
86
|
+
this.log('ERROR', message, errorData);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Log debug message
|
|
90
|
+
*/
|
|
91
|
+
debug(message, data) {
|
|
92
|
+
if (process.env.DEBUG === 'true' || process.env.NODE_ENV === 'development') {
|
|
93
|
+
this.log('DEBUG', message, data);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Log progress update
|
|
98
|
+
*/
|
|
99
|
+
progress(message) {
|
|
100
|
+
// Only log progress if enough time has passed
|
|
101
|
+
const now = Date.now();
|
|
102
|
+
if (now - this.lastProgressTime > 1000) {
|
|
103
|
+
this.lastProgressTime = now;
|
|
104
|
+
console.error(`⏳ [${this.name}] ${message}`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Track API call
|
|
109
|
+
*/
|
|
110
|
+
trackAPICall(operation, table, recordCount) {
|
|
111
|
+
const message = `🔄 API Call: ${operation}${table ? ` on ${table}` : ''}${recordCount ? ` (${recordCount} records)` : ''}`;
|
|
112
|
+
this.info(message);
|
|
113
|
+
// Estimate token usage (rough approximation)
|
|
114
|
+
const estimatedTokens = recordCount ? recordCount * 50 : 100;
|
|
115
|
+
this.addTokens(estimatedTokens, 50);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Add token usage
|
|
119
|
+
*/
|
|
120
|
+
addTokens(input, output) {
|
|
121
|
+
this.tokenUsage.input += input;
|
|
122
|
+
this.tokenUsage.output += output;
|
|
123
|
+
this.tokenUsage.total = this.tokenUsage.input + this.tokenUsage.output;
|
|
124
|
+
// Report token usage
|
|
125
|
+
if (this.tokenUsage.total > 0) {
|
|
126
|
+
console.error(`📊 [${this.name}] Tokens used: ${this.tokenUsage.total} (in: ${this.tokenUsage.input}, out: ${this.tokenUsage.output})`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Log operation start
|
|
131
|
+
*/
|
|
132
|
+
operationStart(operation, params) {
|
|
133
|
+
this.startTime = Date.now();
|
|
134
|
+
this.info(`🚀 Starting: ${operation}`, params);
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Log operation complete
|
|
138
|
+
*/
|
|
139
|
+
operationComplete(operation, result) {
|
|
140
|
+
const duration = Math.round((Date.now() - this.startTime) / 1000);
|
|
141
|
+
this.stopProgress();
|
|
142
|
+
this.info(`✅ Completed: ${operation} (${duration}s, ${this.tokenUsage.total} tokens)`, result);
|
|
143
|
+
// Send final token report
|
|
144
|
+
if (this.tokenUsage.total > 0) {
|
|
145
|
+
console.error(`
|
|
146
|
+
═══════════════════════════════════════════════════════════
|
|
147
|
+
📊 ${this.name} - Operation Complete
|
|
148
|
+
─────────────────────────────────────────────────────────
|
|
149
|
+
⏱️ Duration: ${duration} seconds
|
|
150
|
+
🔢 Tokens Used: ${this.tokenUsage.total}
|
|
151
|
+
├─ Input: ${this.tokenUsage.input}
|
|
152
|
+
└─ Output: ${this.tokenUsage.output}
|
|
153
|
+
🎯 Operation: ${operation}
|
|
154
|
+
═══════════════════════════════════════════════════════════
|
|
155
|
+
`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Get token usage
|
|
160
|
+
*/
|
|
161
|
+
getTokenUsage() {
|
|
162
|
+
return { ...this.tokenUsage };
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Reset token usage
|
|
166
|
+
*/
|
|
167
|
+
resetTokens() {
|
|
168
|
+
this.tokenUsage = { input: 0, output: 0, total: 0 };
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
exports.MCPLogger = MCPLogger;
|
|
172
|
+
/**
|
|
173
|
+
* Create a singleton logger instance for consistent logging
|
|
174
|
+
*/
|
|
175
|
+
let globalLogger = null;
|
|
176
|
+
function getGlobalLogger(name) {
|
|
177
|
+
if (!globalLogger) {
|
|
178
|
+
globalLogger = new MCPLogger(name || 'MCP-Server');
|
|
179
|
+
}
|
|
180
|
+
return globalLogger;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Log formatter for consistent output
|
|
184
|
+
*/
|
|
185
|
+
function formatLogMessage(level, message, data) {
|
|
186
|
+
const timestamp = new Date().toISOString().split('T')[1].split('.')[0];
|
|
187
|
+
const dataStr = data ? ` | ${JSON.stringify(data)}` : '';
|
|
188
|
+
return `[${timestamp}] ${level.padEnd(5)} | ${message}${dataStr}`;
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=mcp-logger.js.map
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ServiceNow Client Wrapper with Token & Progress Tracking
|
|
3
|
+
*/
|
|
4
|
+
import { ServiceNowClient } from './servicenow-client.js';
|
|
5
|
+
import { MCPLogger } from '../mcp/shared/mcp-logger.js';
|
|
6
|
+
export declare class ServiceNowClientWithTracking extends ServiceNowClient {
|
|
7
|
+
private mcpLogger;
|
|
8
|
+
constructor(logger?: MCPLogger);
|
|
9
|
+
/**
|
|
10
|
+
* Override makeRequest to add tracking
|
|
11
|
+
*/
|
|
12
|
+
makeRequest(config: any): Promise<any>;
|
|
13
|
+
/**
|
|
14
|
+
* Override searchRecords to add tracking
|
|
15
|
+
*/
|
|
16
|
+
searchRecords(table: string, query: string, limit?: number): Promise<any>;
|
|
17
|
+
/**
|
|
18
|
+
* Override createRecord to add tracking
|
|
19
|
+
*/
|
|
20
|
+
createRecord(table: string, data: any): Promise<any>;
|
|
21
|
+
/**
|
|
22
|
+
* Override updateRecord to add tracking
|
|
23
|
+
*/
|
|
24
|
+
updateRecord(table: string, sysId: string, data: any): Promise<any>;
|
|
25
|
+
/**
|
|
26
|
+
* Override getRecord to add tracking
|
|
27
|
+
*/
|
|
28
|
+
getRecord(table: string, sysId: string, fields?: string[]): Promise<any>;
|
|
29
|
+
/**
|
|
30
|
+
* Extract table name from URL
|
|
31
|
+
*/
|
|
32
|
+
private extractTableFromUrl;
|
|
33
|
+
/**
|
|
34
|
+
* Get logger for external use
|
|
35
|
+
*/
|
|
36
|
+
getLogger(): MCPLogger;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=servicenow-client-with-tracking.d.ts.map
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* ServiceNow Client Wrapper with Token & Progress Tracking
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ServiceNowClientWithTracking = void 0;
|
|
7
|
+
const servicenow_client_js_1 = require("./servicenow-client.js");
|
|
8
|
+
const mcp_logger_js_1 = require("../mcp/shared/mcp-logger.js");
|
|
9
|
+
class ServiceNowClientWithTracking extends servicenow_client_js_1.ServiceNowClient {
|
|
10
|
+
constructor(logger) {
|
|
11
|
+
super();
|
|
12
|
+
this.mcpLogger = logger || new mcp_logger_js_1.MCPLogger('ServiceNow-API');
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Override makeRequest to add tracking
|
|
16
|
+
*/
|
|
17
|
+
async makeRequest(config) {
|
|
18
|
+
const operation = `${config.method || 'GET'} ${config.url || config.endpoint}`;
|
|
19
|
+
const table = this.extractTableFromUrl(config.url || config.endpoint);
|
|
20
|
+
// Log API call start
|
|
21
|
+
this.mcpLogger.trackAPICall(operation, table);
|
|
22
|
+
this.mcpLogger.progress(`Calling ServiceNow API: ${operation}`);
|
|
23
|
+
try {
|
|
24
|
+
// Call parent method
|
|
25
|
+
const result = await super.makeRequest(config);
|
|
26
|
+
// Estimate tokens based on response size
|
|
27
|
+
if (result.data) {
|
|
28
|
+
const responseSize = JSON.stringify(result.data).length;
|
|
29
|
+
const estimatedTokens = Math.ceil(responseSize / 4); // Rough estimate: 4 chars per token
|
|
30
|
+
this.mcpLogger.addTokens(50, estimatedTokens); // 50 for request, response based on size
|
|
31
|
+
}
|
|
32
|
+
return result;
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
this.mcpLogger.error(`API call failed: ${operation}`, error);
|
|
36
|
+
throw error;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Override searchRecords to add tracking
|
|
41
|
+
*/
|
|
42
|
+
async searchRecords(table, query, limit = 10) {
|
|
43
|
+
this.mcpLogger.operationStart(`Search ${table}`, { query, limit });
|
|
44
|
+
try {
|
|
45
|
+
const result = await super.searchRecords(table, query, limit);
|
|
46
|
+
// Track record count
|
|
47
|
+
const recordCount = result?.data?.result?.length || 0;
|
|
48
|
+
this.mcpLogger.info(`Found ${recordCount} ${table} records`);
|
|
49
|
+
// Estimate tokens
|
|
50
|
+
if (result?.data?.result) {
|
|
51
|
+
const dataSize = JSON.stringify(result.data.result).length;
|
|
52
|
+
const estimatedTokens = Math.ceil(dataSize / 4);
|
|
53
|
+
this.mcpLogger.addTokens(100, estimatedTokens);
|
|
54
|
+
}
|
|
55
|
+
this.mcpLogger.operationComplete(`Search ${table}`, { count: recordCount });
|
|
56
|
+
return result;
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
this.mcpLogger.error(`Search failed for ${table}`, error);
|
|
60
|
+
throw error;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Override createRecord to add tracking
|
|
65
|
+
*/
|
|
66
|
+
async createRecord(table, data) {
|
|
67
|
+
this.mcpLogger.operationStart(`Create ${table} record`, { fields: Object.keys(data).length });
|
|
68
|
+
try {
|
|
69
|
+
const result = await super.createRecord(table, data);
|
|
70
|
+
// Estimate tokens
|
|
71
|
+
const requestSize = JSON.stringify(data).length;
|
|
72
|
+
const responseSize = JSON.stringify(result).length;
|
|
73
|
+
this.mcpLogger.addTokens(Math.ceil(requestSize / 4), Math.ceil(responseSize / 4));
|
|
74
|
+
this.mcpLogger.operationComplete(`Create ${table} record`, {
|
|
75
|
+
sys_id: result?.data?.result?.sys_id
|
|
76
|
+
});
|
|
77
|
+
return result;
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
this.mcpLogger.error(`Failed to create ${table} record`, error);
|
|
81
|
+
throw error;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Override updateRecord to add tracking
|
|
86
|
+
*/
|
|
87
|
+
async updateRecord(table, sysId, data) {
|
|
88
|
+
this.mcpLogger.operationStart(`Update ${table} record`, { sys_id: sysId });
|
|
89
|
+
try {
|
|
90
|
+
const result = await super.updateRecord(table, sysId, data);
|
|
91
|
+
// Estimate tokens
|
|
92
|
+
const requestSize = JSON.stringify(data).length;
|
|
93
|
+
const responseSize = JSON.stringify(result).length;
|
|
94
|
+
this.mcpLogger.addTokens(Math.ceil(requestSize / 4), Math.ceil(responseSize / 4));
|
|
95
|
+
this.mcpLogger.operationComplete(`Update ${table} record`);
|
|
96
|
+
return result;
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
this.mcpLogger.error(`Failed to update ${table} record`, error);
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Override getRecord to add tracking
|
|
105
|
+
*/
|
|
106
|
+
async getRecord(table, sysId, fields) {
|
|
107
|
+
this.mcpLogger.progress(`Fetching ${table} record: ${sysId}`);
|
|
108
|
+
try {
|
|
109
|
+
const result = await super.getRecord(table, sysId, fields);
|
|
110
|
+
// Estimate tokens
|
|
111
|
+
if (result?.data?.result) {
|
|
112
|
+
const responseSize = JSON.stringify(result.data.result).length;
|
|
113
|
+
this.mcpLogger.addTokens(50, Math.ceil(responseSize / 4));
|
|
114
|
+
}
|
|
115
|
+
return result;
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
this.mcpLogger.error(`Failed to get ${table} record`, error);
|
|
119
|
+
throw error;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Extract table name from URL
|
|
124
|
+
*/
|
|
125
|
+
extractTableFromUrl(url) {
|
|
126
|
+
const match = url.match(/\/table\/([^/?]+)/);
|
|
127
|
+
return match ? match[1] : undefined;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Get logger for external use
|
|
131
|
+
*/
|
|
132
|
+
getLogger() {
|
|
133
|
+
return this.mcpLogger;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
exports.ServiceNowClientWithTracking = ServiceNowClientWithTracking;
|
|
137
|
+
//# sourceMappingURL=servicenow-client-with-tracking.js.map
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "snow-flow",
|
|
3
|
-
"version": "3.
|
|
4
|
-
"description": "Snow-Flow v3.
|
|
3
|
+
"version": "3.3.1",
|
|
4
|
+
"description": "Snow-Flow v3.3.1: ServiceNow development platform with 180+ MCP tools. Enhanced MCP servers with real-time progress indicators, detailed token tracking, 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": {
|