evaluate
Evaluate JavaScript expressions in the current NodeJS context to inspect values, test code snippets, or debug issues directly within the MCP NodeJS Debugger.
Instructions
Evaluates a JavaScript expression in the current context
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| expression | Yes | JavaScript expression to evaluate |
Implementation Reference
- src/mcp-server.js:855-1007 (handler)The complete handler implementation for the 'evaluate' tool. It wraps the expression in try-catch, evaluates it using CDP Debugger.evaluateOnCallFrame if paused or Runtime.evaluate otherwise, captures console output, formats the result including complex objects, and returns structured content.server.tool( "evaluate", "Evaluates a JavaScript expression in the current context", { expression: z.string().describe("JavaScript expression to evaluate") }, async ({ expression }) => { try { // Ensure debugger is enabled if (!inspector.debuggerEnabled) { await inspector.enableDebugger(); } // Capture the current console output length to know where to start capturing new output const consoleStartIndex = inspector.consoleOutput.length; // Wrap the expression in a try-catch to better handle errors const wrappedExpression = ` try { ${expression} } catch (e) { e; // Return the error } `; let result; if (inspector.paused && inspector.currentCallFrames.length > 0) { // When paused at a breakpoint, evaluate in the context of the call frame const frame = inspector.currentCallFrames[0]; result = await inspector.evaluateOnCallFrame(frame.callFrameId, wrappedExpression); } else { // Otherwise, evaluate in the global context result = await inspector.send('Runtime.evaluate', { expression: wrappedExpression, contextId: 1, objectGroup: 'console', includeCommandLineAPI: true, silent: false, returnByValue: true, generatePreview: true, awaitPromise: true // This will wait for promises to resolve }); } // Give some time for console logs to be processed await new Promise(resolve => setTimeout(resolve, 200)); // Get any console output that was generated during execution const consoleOutputs = inspector.consoleOutput.slice(consoleStartIndex); const consoleText = consoleOutputs.map(output => `[${output.type}] ${output.message}` ).join('\n'); let valueRepresentation; if (result.result) { if (result.result.type === 'object') { if (result.result.value) { // If we have a value, use it valueRepresentation = JSON.stringify(result.result.value, null, 2); } else if (result.result.objectId) { // If we have an objectId but no value, the object was too complex to serialize directly // Get more details about the object try { const objectProps = await inspector.getProperties(result.result.objectId); const formattedObject = {}; for (const prop of objectProps.result) { if (prop.value) { if (prop.value.type === 'object' && prop.value.subtype !== 'null') { // For nested objects, try to get their details too if (prop.value.objectId) { try { const nestedProps = await inspector.getProperties(prop.value.objectId); const nestedObj = {}; for (const nestedProp of nestedProps.result) { if (nestedProp.value) { if (nestedProp.value.value !== undefined) { nestedObj[nestedProp.name] = nestedProp.value.value; } else { nestedObj[nestedProp.name] = nestedProp.value.description || `[${nestedProp.value.subtype || nestedProp.value.type}]`; } } } formattedObject[prop.name] = nestedObj; } catch (nestedErr) { formattedObject[prop.name] = prop.value.description || `[${prop.value.subtype || prop.value.type}]`; } } else { formattedObject[prop.name] = prop.value.description || `[${prop.value.subtype || prop.value.type}]`; } } else if (prop.value.type === 'function') { formattedObject[prop.name] = '[function]'; } else if (prop.value.value !== undefined) { formattedObject[prop.name] = prop.value.value; } else { formattedObject[prop.name] = `[${prop.value.type}]`; } } } valueRepresentation = JSON.stringify(formattedObject, null, 2); } catch (propErr) { // If we can't get properties, at least show the object description valueRepresentation = result.result.description || `[${result.result.subtype || result.result.type}]`; } } else { // Fallback for objects without value or objectId valueRepresentation = result.result.description || `[${result.result.subtype || result.result.type}]`; } } else if (result.result.type === 'undefined') { valueRepresentation = 'undefined'; } else if (result.result.value !== undefined) { valueRepresentation = result.result.value.toString(); } else { valueRepresentation = `[${result.result.type}]`; } } else { valueRepresentation = 'No result'; } // Prepare the response content let responseContent = []; // Add console output if there was any if (consoleText.length > 0) { responseContent.push({ type: "text", text: `Console output:\n${consoleText}` }); } // Add the evaluation result responseContent.push({ type: "text", text: `Evaluation result: ${valueRepresentation}` }); return { content: responseContent }; } catch (err) { return { content: [{ type: "text", text: `Error evaluating expression: ${err.message}` }] }; } } );
- src/mcp-server.js:858-860 (schema)Zod schema for the 'evaluate' tool input, requiring a string 'expression'.{ expression: z.string().describe("JavaScript expression to evaluate") },
- src/mcp-server.js:855-857 (registration)Registration of the 'evaluate' tool using server.tool with name and description.server.tool( "evaluate", "Evaluates a JavaScript expression in the current context",
- src/mcp-server.js:287-305 (helper)Helper method 'evaluateOnCallFrame' on the Inspector class, used by the evaluate tool handler when the debugger is paused at a breakpoint.async evaluateOnCallFrame(callFrameId, expression) { if (!this.paused) { throw new Error('Debugger is not paused'); } try { return await this.send('Debugger.evaluateOnCallFrame', { callFrameId, expression, objectGroup: 'console', includeCommandLineAPI: true, silent: false, returnByValue: true, generatePreview: true }); } catch (err) { throw err; } }