@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.
Files changed (2) hide show
  1. package/dist/index.js +85 -78
  2. 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
- // Initialize logger
27
- const logger = new Logger({ module: 'main' });
28
- /**
29
- * Initialize MCP Server with configuration
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
- * Handle tool execution requests with proper validation and error handling
75
+ * Register MCP request handlers. Called in main() after server is created.
80
76
  */
81
- server.setRequestHandler(CallToolRequestSchema, async (req) => {
82
- const typedReq = req;
83
- const requestId = `req_${Date.now()}`;
84
- const requestLogger = logger.child({ requestId });
85
- requestLogger.info("Received tool call request", {
86
- toolName: typedReq.params.name,
87
- hasProgressToken: !!typedReq.params._meta?.progressToken,
88
- progressToken: typedReq.params._meta?.progressToken,
89
- progressTokenType: typeof typedReq.params._meta?.progressToken
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
- Telemetry.capture(TelemetryEvents.TOOL_FAILED, { toolName: name, errorCode: mcpError.code });
129
- return createErrorResponse(mcpError, typedReq.params.name);
130
- }
131
- });
132
- /**
133
- * Handle list tools requests
134
- */
135
- server.setRequestHandler(ListToolsRequestSchema, async () => {
136
- const tools = getTools();
137
- logger.info('Tools list requested', { toolCount: tools.length });
138
- return {
139
- tools: tools,
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
- // Log startup information
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
- logger.info('Received SIGINT, shutting down gracefully');
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
- logger.info('Received SIGTERM, shutting down gracefully');
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
- logger.error('Unhandled promise rejection', {
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
- logger.error('Uncaught exception', {
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
- logger.error('Fatal error during startup', {
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
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@debugg-ai/debugg-ai-mcp",
3
- "version": "1.0.52",
3
+ "version": "1.0.53",
4
4
  "description": "Zero-Config, Fully AI-Managed End-to-End Testing for all code gen platforms.",
5
5
  "type": "module",
6
6
  "bin": {