step_into
Execute a single step into a function call during debugging to examine internal execution flow and identify issues in Python, JavaScript, or Rust code.
Instructions
Step into
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| sessionId | Yes |
Implementation Reference
- src/server.ts:431-486 (registration)Registration of the 'step_into' tool in the MCP server's listTools response, including schema definition (inputSchema requires sessionId).private registerTools(): void { this.server.setRequestHandler(ListToolsRequestSchema, async () => { this.logger.debug('Handling ListToolsRequest'); // Get supported languages dynamically - deferred until request time const supportedLanguages = await this.getSupportedLanguagesAsync(); // Generate dynamic descriptions for path parameters const fileDescription = this.getPathDescription('source file'); const scriptPathDescription = this.getPathDescription('script'); return { tools: [ { name: 'create_debug_session', description: 'Create a new debugging session', inputSchema: { type: 'object', properties: { language: { type: 'string', enum: supportedLanguages, description: 'Programming language for debugging' }, name: { type: 'string', description: 'Optional session name' }, executablePath: {type: 'string', description: 'Path to language executable (optional, will auto-detect if not provided)'} }, required: ['language'] } }, { name: 'list_supported_languages', description: 'List all supported debugging languages with metadata', inputSchema: { type: 'object', properties: {} } }, { name: 'list_debug_sessions', description: 'List all active debugging sessions', inputSchema: { type: 'object', properties: {} } }, { name: 'set_breakpoint', description: 'Set a breakpoint. Setting breakpoints on non-executable lines (structural, declarative) may lead to unexpected behavior', inputSchema: { type: 'object', properties: { sessionId: { type: 'string' }, file: { type: 'string', description: fileDescription }, line: { type: 'number', description: 'Line number where to set breakpoint. Executable statements (assignments, function calls, conditionals, returns) work best. Structural lines (function/class definitions), declarative lines (imports), or non-executable lines (comments, blank lines) may cause unexpected stepping behavior' }, condition: { type: 'string' } }, required: ['sessionId', 'file', 'line'] } }, { name: 'start_debugging', description: 'Start debugging a script', inputSchema: { type: 'object', properties: { sessionId: { type: 'string' }, scriptPath: { type: 'string', description: scriptPathDescription }, args: { type: 'array', items: { type: 'string' } }, dapLaunchArgs: { type: 'object', properties: { stopOnEntry: { type: 'boolean' }, justMyCode: { type: 'boolean' } }, additionalProperties: true }, dryRunSpawn: { type: 'boolean' }, adapterLaunchConfig: { type: 'object', description: 'Optional adapter-specific launch configuration overrides', additionalProperties: true } }, required: ['sessionId', 'scriptPath'] } }, { name: 'close_debug_session', description: 'Close a debugging session', inputSchema: { type: 'object', properties: { sessionId: { type: 'string' } }, required: ['sessionId'] } }, { name: 'step_over', description: 'Step over', inputSchema: { type: 'object', properties: { sessionId: { type: 'string' } }, required: ['sessionId'] } }, { name: 'step_into', description: 'Step into', inputSchema: { type: 'object', properties: { sessionId: { type: 'string' } }, required: ['sessionId'] } }, { name: 'step_out', description: 'Step out', inputSchema: { type: 'object', properties: { sessionId: { type: 'string' } }, required: ['sessionId'] } }, { name: 'continue_execution', description: 'Continue execution', inputSchema: { type: 'object', properties: { sessionId: { type: 'string' } }, required: ['sessionId'] } }, { name: 'pause_execution', description: 'Pause execution (Not Implemented)', inputSchema: { type: 'object', properties: { sessionId: { type: 'string' } }, required: ['sessionId'] } }, { name: 'get_variables', description: 'Get variables (scope is variablesReference: number)', inputSchema: { type: 'object', properties: { sessionId: { type: 'string' }, scope: { type: 'number', description: "The variablesReference number from a StackFrame or Variable" } }, required: ['sessionId', 'scope'] } }, { name: 'get_local_variables', description: 'Get local variables for the current stack frame. This is a convenience tool that returns just the local variables without needing to traverse stack->scopes->variables manually', inputSchema: { type: 'object', properties: { sessionId: { type: 'string' }, includeSpecial: { type: 'boolean', description: 'Include special/internal variables like this, __proto__, __builtins__, etc. Default: false' } }, required: ['sessionId'] } }, { name: 'get_stack_trace', description: 'Get stack trace', inputSchema: { type: 'object', properties: { sessionId: { type: 'string' }, includeInternals: { type: 'boolean', description: 'Include internal/framework frames (e.g., Node.js internals). Default: false for cleaner output.' } }, required: ['sessionId'] } }, { name: 'get_scopes', description: 'Get scopes for a stack frame', inputSchema: { type: 'object', properties: { sessionId: { type: 'string' }, frameId: { type: 'number', description: "The ID of the stack frame from a stackTrace response" } }, required: ['sessionId', 'frameId'] } }, { name: 'evaluate_expression', description: 'Evaluate expression in the current debug context. Expressions can read and modify program state', inputSchema: { type: 'object', properties: { sessionId: { type: 'string' }, expression: { type: 'string' }, frameId: { type: 'number', description: 'Optional stack frame ID for evaluation context. Must be a frame ID from a get_stack_trace response. If not provided, uses the current (top) frame automatically' } }, required: ['sessionId', 'expression'] } }, { name: 'get_source_context', description: 'Get source context around a specific line in a file', inputSchema: { type: 'object', properties: { sessionId: { type: 'string' }, file: { type: 'string', description: fileDescription }, line: { type: 'number', description: 'Line number to get context for' }, linesContext: { type: 'number', description: 'Number of lines before and after to include (default: 5)' } }, required: ['sessionId', 'file', 'line'] } }, ], }; });
- src/server.ts:474-475 (schema)Schema for 'step_into' tool: requires sessionId string.{ name: 'step_into', description: 'Step into', inputSchema: { type: 'object', properties: { sessionId: { type: 'string' } }, required: ['sessionId'] } }, { name: 'step_out', description: 'Step out', inputSchema: { type: 'object', properties: { sessionId: { type: 'string' } }, required: ['sessionId'] } },
- src/server.ts:692-764 (handler)MCP tool handler dispatch for 'step_into': validates sessionId, calls DebugMcpServer.stepInto() which delegates to SessionManager.stepInto().case 'step_over': case 'step_into': case 'step_out': { if (!args.sessionId) { throw new McpError(McpErrorCode.InvalidParams, 'Missing required sessionId'); } try { let stepResult: { success: boolean; state: string; error?: string; data?: unknown; }; if (toolName === 'step_over') { stepResult = await this.stepOver(args.sessionId); } else if (toolName === 'step_into') { stepResult = await this.stepInto(args.sessionId); } else { stepResult = await this.stepOut(args.sessionId); } // Build response with location and line context if available const stepType = toolName.replace('step_', '').replace('_', ' '); const response: Record<string, unknown> = { success: stepResult.success, message: `Stepped ${stepType}`, state: stepResult.state }; // Extract location from result data const resultData = stepResult.data as { message?: string; location?: { file: string; line: number; column?: number } } | undefined; const location = resultData?.location; if (location) { response.location = location; // Try to get line context try { const lineContext = await this.lineReader.getLineContext( location.file, location.line, { contextLines: 2 } ); if (lineContext) { response.context = { lineContent: lineContext.lineContent, surrounding: lineContext.surrounding }; } } catch (contextError) { // Log but don't fail if we can't get context this.logger.debug('Could not get line context for step result', { file: location.file, line: location.line, error: contextError }); } } result = { content: [{ type: 'text', text: JSON.stringify(response) }] }; } catch (error) { // Handle validation errors specifically if (error instanceof SessionTerminatedError || error instanceof SessionNotFoundError || error instanceof ProxyNotRunningError) { result = { content: [{ type: 'text', text: JSON.stringify({ success: false, error: error.message }) }] }; } else if (error instanceof Error) { // Handle other expected errors (like "Failed to step over") result = { content: [{ type: 'text', text: JSON.stringify({ success: false, error: error.message }) }] }; } else { // Re-throw unexpected errors throw error; } } break; }
- src/server.ts:332-338 (handler)DebugMcpServer.stepInto(): wrapper that validates session and calls SessionManager.stepInto.public async stepInto(sessionId: string): Promise<{ success: boolean; state: string; error?: string; data?: unknown; }> { this.validateSession(sessionId); const result = await this.sessionManager.stepInto(sessionId); if (!result.success) { throw new Error(result.error || 'Failed to step into'); } return result;
- SessionManagerOperations.stepInto(): core logic - sends DAP 'stepIn' request via proxyManager, waits for 'stopped' event.async stepInto(sessionId: string): Promise<DebugResult> { const session = this._getSessionById(sessionId); // Check if session is terminated if (session.sessionLifecycle === SessionLifecycleState.TERMINATED) { throw new SessionTerminatedError(sessionId); } const threadId = session.proxyManager?.getCurrentThreadId(); this.logger.info( `[SM stepInto ${sessionId}] Entered. Current state: ${session.state}, ThreadID: ${threadId}` ); if (!session.proxyManager || !session.proxyManager.isRunning()) { throw new ProxyNotRunningError(sessionId, 'step into'); } if (session.state !== SessionState.PAUSED) { this.logger.warn(`[SM stepInto ${sessionId}] Not paused. State: ${session.state}`); return { success: false, error: 'Not paused', state: session.state }; } if (typeof threadId !== 'number') { this.logger.warn(`[SM stepInto ${sessionId}] No current thread ID.`); return { success: false, error: 'No current thread ID', state: session.state }; } this.logger.info(`[SM stepInto ${sessionId}] Sending DAP 'stepIn' for threadId ${threadId}`); try { return await this._executeStepOperation(session, sessionId, { command: 'stepIn', threadId, logTag: 'stepInto', successMessage: 'Step into completed.', }); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); this.logger.error(`[SM stepInto ${sessionId}] Error during step:`, error); this._updateSessionState(session, SessionState.ERROR); return { success: false, error: errorMessage, state: session.state }; }