@debugg-ai/debugg-ai-mcp 1.0.52 → 1.0.53
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/index.js +85 -78
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -23,16 +23,13 @@ import { config } from "./config/index.js";
|
|
|
23
23
|
import { initTools, getTools, getTool } from "./tools/index.js";
|
|
24
24
|
import { resolveProjectContext } from "./services/projectContext.js";
|
|
25
25
|
import { Logger, validateInput, createErrorResponse, toMCPError, handleConfigurationError, Telemetry, TelemetryEvents, } from "./utils/index.js";
|
|
26
|
-
//
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
// Logger and server are initialized lazily in main() to avoid triggering
|
|
27
|
+
// config loading at module load time. If config validation fails (bad env vars),
|
|
28
|
+
// the error is caught by main()'s try-catch instead of crashing before any
|
|
29
|
+
// error handling is set up.
|
|
30
|
+
let logger;
|
|
31
|
+
let server;
|
|
31
32
|
function createMCPServer() {
|
|
32
|
-
logger.info('Initializing DebuggAI MCP Server', {
|
|
33
|
-
name: config.server.name,
|
|
34
|
-
version: config.server.version
|
|
35
|
-
});
|
|
36
33
|
return new Server({
|
|
37
34
|
name: config.server.name,
|
|
38
35
|
version: config.server.version,
|
|
@@ -45,7 +42,6 @@ function createMCPServer() {
|
|
|
45
42
|
},
|
|
46
43
|
});
|
|
47
44
|
}
|
|
48
|
-
const server = createMCPServer();
|
|
49
45
|
/**
|
|
50
46
|
* Create progress callback for tool execution
|
|
51
47
|
*/
|
|
@@ -76,75 +72,70 @@ function createProgressCallback(progressToken) {
|
|
|
76
72
|
};
|
|
77
73
|
}
|
|
78
74
|
/**
|
|
79
|
-
*
|
|
75
|
+
* Register MCP request handlers. Called in main() after server is created.
|
|
80
76
|
*/
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
const { name, arguments: args } = typedReq.params;
|
|
92
|
-
const progressToken = typedReq.params._meta?.progressToken;
|
|
93
|
-
// Unknown tool is a protocol error - throw directly so SDK returns JSON-RPC error
|
|
94
|
-
const tool = getTool(name);
|
|
95
|
-
if (!tool) {
|
|
96
|
-
requestLogger.warn(`Tool not found: ${name}`);
|
|
97
|
-
throw new Error(`Unknown tool: ${name}`);
|
|
98
|
-
}
|
|
99
|
-
try {
|
|
100
|
-
// Validate input using the tool's schema
|
|
101
|
-
const validatedInput = validateInput(tool.inputSchema, args, name);
|
|
102
|
-
// Create tool context
|
|
103
|
-
const context = {
|
|
104
|
-
progressToken: typeof progressToken === 'string' ? progressToken : undefined,
|
|
105
|
-
requestId,
|
|
106
|
-
timestamp: new Date(),
|
|
107
|
-
};
|
|
108
|
-
// Create progress callback
|
|
109
|
-
const progressCallback = createProgressCallback(typeof progressToken === 'string' || typeof progressToken === 'number' ? String(progressToken) : undefined);
|
|
110
|
-
// Execute tool handler with progress callback
|
|
111
|
-
requestLogger.info(`Executing tool: ${name}`);
|
|
112
|
-
const toolStart = Date.now();
|
|
113
|
-
const result = await tool.handler(validatedInput, context, progressCallback);
|
|
114
|
-
const toolDuration = Date.now() - toolStart;
|
|
115
|
-
requestLogger.info(`Tool execution completed: ${name}`);
|
|
116
|
-
Telemetry.capture(TelemetryEvents.TOOL_EXECUTED, { toolName: name, durationMs: toolDuration, success: true });
|
|
117
|
-
return result;
|
|
118
|
-
}
|
|
119
|
-
catch (error) {
|
|
120
|
-
// Validation and execution errors are tool execution errors (isError: true)
|
|
121
|
-
// so the model can self-correct
|
|
122
|
-
const mcpError = toMCPError(error, 'tool execution');
|
|
123
|
-
requestLogger.error('Tool execution failed', {
|
|
124
|
-
errorCode: mcpError.code,
|
|
125
|
-
message: mcpError.message,
|
|
126
|
-
data: mcpError.data
|
|
77
|
+
function registerHandlers() {
|
|
78
|
+
server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
79
|
+
const typedReq = req;
|
|
80
|
+
const requestId = `req_${Date.now()}`;
|
|
81
|
+
const requestLogger = logger.child({ requestId });
|
|
82
|
+
requestLogger.info("Received tool call request", {
|
|
83
|
+
toolName: typedReq.params.name,
|
|
84
|
+
hasProgressToken: !!typedReq.params._meta?.progressToken,
|
|
85
|
+
progressToken: typedReq.params._meta?.progressToken,
|
|
86
|
+
progressTokenType: typeof typedReq.params._meta?.progressToken
|
|
127
87
|
});
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
}
|
|
88
|
+
const { name, arguments: args } = typedReq.params;
|
|
89
|
+
const progressToken = typedReq.params._meta?.progressToken;
|
|
90
|
+
const tool = getTool(name);
|
|
91
|
+
if (!tool) {
|
|
92
|
+
requestLogger.warn(`Tool not found: ${name}`);
|
|
93
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
94
|
+
}
|
|
95
|
+
try {
|
|
96
|
+
const validatedInput = validateInput(tool.inputSchema, args, name);
|
|
97
|
+
const context = {
|
|
98
|
+
progressToken: typeof progressToken === 'string' ? progressToken : undefined,
|
|
99
|
+
requestId,
|
|
100
|
+
timestamp: new Date(),
|
|
101
|
+
};
|
|
102
|
+
const progressCallback = createProgressCallback(typeof progressToken === 'string' || typeof progressToken === 'number' ? String(progressToken) : undefined);
|
|
103
|
+
requestLogger.info(`Executing tool: ${name}`);
|
|
104
|
+
const toolStart = Date.now();
|
|
105
|
+
const result = await tool.handler(validatedInput, context, progressCallback);
|
|
106
|
+
const toolDuration = Date.now() - toolStart;
|
|
107
|
+
requestLogger.info(`Tool execution completed: ${name}`);
|
|
108
|
+
Telemetry.capture(TelemetryEvents.TOOL_EXECUTED, { toolName: name, durationMs: toolDuration, success: true });
|
|
109
|
+
return result;
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
const mcpError = toMCPError(error, 'tool execution');
|
|
113
|
+
requestLogger.error('Tool execution failed', {
|
|
114
|
+
errorCode: mcpError.code,
|
|
115
|
+
message: mcpError.message,
|
|
116
|
+
data: mcpError.data
|
|
117
|
+
});
|
|
118
|
+
Telemetry.capture(TelemetryEvents.TOOL_FAILED, { toolName: name, errorCode: mcpError.code });
|
|
119
|
+
return createErrorResponse(mcpError, typedReq.params.name);
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
123
|
+
const tools = getTools();
|
|
124
|
+
logger.info('Tools list requested', { toolCount: tools.length });
|
|
125
|
+
return { tools };
|
|
126
|
+
});
|
|
127
|
+
}
|
|
142
128
|
/**
|
|
143
129
|
* Main server initialization and startup
|
|
144
130
|
*/
|
|
145
131
|
async function main() {
|
|
146
132
|
try {
|
|
147
|
-
//
|
|
133
|
+
// Initialize logger and server here (not at module load time) so config
|
|
134
|
+
// validation errors are caught by this try-catch instead of crashing.
|
|
135
|
+
logger = new Logger({ module: 'main' });
|
|
136
|
+
server = createMCPServer();
|
|
137
|
+
// Register request handlers (they reference the `server` variable)
|
|
138
|
+
registerHandlers();
|
|
148
139
|
logger.info('Starting DebuggAI MCP Server', {
|
|
149
140
|
nodeVersion: process.version,
|
|
150
141
|
platform: process.platform,
|
|
@@ -198,27 +189,43 @@ async function main() {
|
|
|
198
189
|
throw handleConfigurationError(error);
|
|
199
190
|
}
|
|
200
191
|
}
|
|
192
|
+
/**
|
|
193
|
+
* Safe log helper — falls back to stderr if logger isn't initialized yet
|
|
194
|
+
* (e.g. config validation failed before logger was created).
|
|
195
|
+
*/
|
|
196
|
+
function safeLog(level, message, meta) {
|
|
197
|
+
try {
|
|
198
|
+
if (logger) {
|
|
199
|
+
logger[level](message, meta);
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
catch {
|
|
204
|
+
// Logger init failed (config validation error) — fall through to stderr
|
|
205
|
+
}
|
|
206
|
+
process.stderr.write(`[${level.toUpperCase()}] ${message} ${meta ? JSON.stringify(meta) : ''}\n`);
|
|
207
|
+
}
|
|
201
208
|
/**
|
|
202
209
|
* Handle graceful shutdown
|
|
203
210
|
*/
|
|
204
211
|
process.on('SIGINT', async () => {
|
|
205
|
-
|
|
212
|
+
safeLog('info', 'Received SIGINT, shutting down gracefully');
|
|
206
213
|
await Telemetry.shutdown();
|
|
207
214
|
process.exit(0);
|
|
208
215
|
});
|
|
209
216
|
process.on('SIGTERM', async () => {
|
|
210
|
-
|
|
217
|
+
safeLog('info', 'Received SIGTERM, shutting down gracefully');
|
|
211
218
|
await Telemetry.shutdown();
|
|
212
219
|
process.exit(0);
|
|
213
220
|
});
|
|
214
221
|
process.on('unhandledRejection', (reason) => {
|
|
215
|
-
|
|
222
|
+
safeLog('error', 'Unhandled promise rejection', {
|
|
216
223
|
error: reason instanceof Error ? reason.message : String(reason),
|
|
217
224
|
stack: reason instanceof Error ? reason.stack : undefined,
|
|
218
225
|
});
|
|
219
226
|
});
|
|
220
227
|
process.on('uncaughtException', (error) => {
|
|
221
|
-
|
|
228
|
+
safeLog('error', 'Uncaught exception', {
|
|
222
229
|
error: error.message,
|
|
223
230
|
stack: error.stack,
|
|
224
231
|
});
|
|
@@ -227,9 +234,9 @@ process.on('uncaughtException', (error) => {
|
|
|
227
234
|
* Start the server
|
|
228
235
|
*/
|
|
229
236
|
main().catch((error) => {
|
|
230
|
-
|
|
237
|
+
safeLog('error', 'Fatal error during startup', {
|
|
231
238
|
error: error instanceof Error ? error.message : String(error),
|
|
232
|
-
stack: error instanceof Error ? error.stack : undefined
|
|
239
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
233
240
|
});
|
|
234
241
|
process.exit(1);
|
|
235
242
|
});
|