inspect_variables
Inspect variables in current scope to debug NodeJS server code by examining local or global values during execution.
Instructions
Inspects variables in current scope
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| scope | No | Scope to inspect (local/global) |
Implementation Reference
- src/mcp-server.js:529-613 (handler)The handler function that implements the core logic of the 'inspect_variables' tool. It handles both global and local scope inspection using the Node.js debugger protocol. For local scopes when paused, it iterates through the scope chain of the top call frame, fetches properties using getProperties, and formats the variables for output.async ({ scope = 'local' }) => { try { // Ensure debugger is enabled if (!inspector.debuggerEnabled) { await inspector.enableDebugger(); } if (scope === 'global' || !inspector.paused) { // For global scope or when not paused, use Runtime.globalProperties const response = await inspector.send('Runtime.globalLexicalScopeNames', {}); // Get global object properties for a more complete picture const globalObjResponse = await inspector.send('Runtime.evaluate', { expression: 'this', contextId: 1, returnByValue: true }); return { content: [{ type: "text", text: JSON.stringify({ lexicalNames: response.names, globalThis: globalObjResponse.result.value }, null, 2) }] }; } else { // For local scope when paused, get variables from the current call frame if (inspector.currentCallFrames.length === 0) { return { content: [{ type: "text", text: "No active call frames. Debugger is not paused at a breakpoint." }] }; } const frame = inspector.currentCallFrames[0]; // Get top frame const scopeChain = frame.scopeChain; // Create a formatted output of variables in scope const result = {}; for (const scopeObj of scopeChain) { const { scope, type, name } = scopeObj; if (type === 'global') continue; // Skip global scope for local inspection const objProperties = await inspector.getProperties(scope.object.objectId); const variables = {}; for (const prop of objProperties.result) { if (prop.value && prop.configurable) { if (prop.value.type === 'object' && prop.value.subtype !== 'null') { variables[prop.name] = `[${prop.value.subtype || prop.value.type}]`; } else if (prop.value.type === 'function') { variables[prop.name] = '[function]'; } else if (prop.value.value !== undefined) { variables[prop.name] = prop.value.value; } else { variables[prop.name] = `[${prop.value.type}]`; } } } result[type] = variables; } return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] }; } } catch (err) { return { content: [{ type: "text", text: `Error inspecting variables: ${err.message}` }] }; } }
- src/mcp-server.js:523-614 (registration)The registration of the 'inspect_variables' tool using server.tool(), including name, description, input schema, and handler reference.server.tool( "inspect_variables", "Inspects variables in current scope", { scope: z.string().optional().describe("Scope to inspect (local/global)") }, async ({ scope = 'local' }) => { try { // Ensure debugger is enabled if (!inspector.debuggerEnabled) { await inspector.enableDebugger(); } if (scope === 'global' || !inspector.paused) { // For global scope or when not paused, use Runtime.globalProperties const response = await inspector.send('Runtime.globalLexicalScopeNames', {}); // Get global object properties for a more complete picture const globalObjResponse = await inspector.send('Runtime.evaluate', { expression: 'this', contextId: 1, returnByValue: true }); return { content: [{ type: "text", text: JSON.stringify({ lexicalNames: response.names, globalThis: globalObjResponse.result.value }, null, 2) }] }; } else { // For local scope when paused, get variables from the current call frame if (inspector.currentCallFrames.length === 0) { return { content: [{ type: "text", text: "No active call frames. Debugger is not paused at a breakpoint." }] }; } const frame = inspector.currentCallFrames[0]; // Get top frame const scopeChain = frame.scopeChain; // Create a formatted output of variables in scope const result = {}; for (const scopeObj of scopeChain) { const { scope, type, name } = scopeObj; if (type === 'global') continue; // Skip global scope for local inspection const objProperties = await inspector.getProperties(scope.object.objectId); const variables = {}; for (const prop of objProperties.result) { if (prop.value && prop.configurable) { if (prop.value.type === 'object' && prop.value.subtype !== 'null') { variables[prop.name] = `[${prop.value.subtype || prop.value.type}]`; } else if (prop.value.type === 'function') { variables[prop.name] = '[function]'; } else if (prop.value.value !== undefined) { variables[prop.name] = prop.value.value; } else { variables[prop.name] = `[${prop.value.type}]`; } } } result[type] = variables; } return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] }; } } catch (err) { return { content: [{ type: "text", text: `Error inspecting variables: ${err.message}` }] }; } } );
- src/mcp-server.js:526-528 (schema)Zod input schema defining the optional 'scope' parameter for local or global variable inspection.{ scope: z.string().optional().describe("Scope to inspect (local/global)") },
- src/mcp-server.js:307-318 (helper)Helper method in the Inspector class used by the tool to retrieve detailed properties of scope objects during local variable inspection.async getProperties(objectId, ownProperties = true) { try { return await this.send('Runtime.getProperties', { objectId, ownProperties, accessorPropertiesOnly: false, generatePreview: true }); } catch (err) { throw err; } }