sessions_create
Start a Python debugging session to set breakpoints, step through code execution, and inspect variables for script analysis.
Instructions
Create a new debug session for a Python script
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| entry | Yes | Project-relative path to Python script | |
| pythonPath | Yes | Absolute path to Python interpreter (must have debugpy installed) | |
| args | No | Command-line arguments for the script | |
| env | No | Environment variables |
Implementation Reference
- src/mcp_debug_tool/server.py:60-87 (registration)Registration of the 'sessions_create' tool in list_tools(), including input schema definition and description.Tool( name="sessions_create", description="Create a new debug session for a Python script", inputSchema={ "type": "object", "properties": { "entry": { "type": "string", "description": "Project-relative path to Python script", }, "pythonPath": { "type": "string", "description": "Absolute path to Python interpreter (must have debugpy installed)", }, "args": { "type": "array", "items": {"type": "string"}, "description": "Command-line arguments for the script", }, "env": { "type": "object", "additionalProperties": {"type": "string"}, "description": "Environment variables", }, }, "required": ["entry", "pythonPath"], }, ),
- src/mcp_debug_tool/server.py:252-306 (handler)MCP tool handler _handle_sessions_create: validates input with StartSessionRequest, calls SessionManager.create_session_async, returns sessionId or error.async def _handle_sessions_create(self, arguments: dict) -> list[TextContent]: """ Handler for sessions_create tool. Creates a new debug session for a Python script. """ try: request = StartSessionRequest(**arguments) response = await self.session_manager.create_session_async(request) return [ TextContent( type="text", text=json.dumps({ "sessionId": response.sessionId, }), ) ] except FileNotFoundError as e: return [ TextContent( type="text", text=json.dumps({ "error": { "type": "FileNotFoundError", "message": str(e), } }), ) ] except ValueError as e: return [ TextContent( type="text", text=json.dumps({ "error": { "type": "ValueError", "message": str(e), } }), ) ] except Exception as e: logger.exception("Error creating session") return [ TextContent( type="text", text=json.dumps({ "error": { "type": type(e).__name__, "message": str(e), } }), ) ]
- src/mcp_debug_tool/schemas.py:22-57 (schema)Pydantic model StartSessionRequest for input validation of sessions_create tool, with field validators for args and env.class StartSessionRequest(BaseModel): """Request to start a new debug session.""" entry: str = Field(..., description="Project-relative path to script") pythonPath: str = Field(..., description="Absolute path to Python interpreter (must have debugpy installed)") args: list[str] | None = Field(default=None, description="Command-line arguments") env: dict[str, str] | None = Field(default=None, description="Environment variables") useDap: bool | None = Field(default=True, description="Use DAP (debugpy) instead of bdb - recommended for all use cases") @field_validator('args') @classmethod def validate_args(cls, v: list[str] | None) -> list[str] | None: """Validate args list constraints.""" if v is not None: from .utils import MAX_ARG_LENGTH, MAX_ARGS_COUNT if len(v) > MAX_ARGS_COUNT: raise ValueError(f"Too many args (max {MAX_ARGS_COUNT})") for arg in v: if len(arg) > MAX_ARG_LENGTH: raise ValueError(f"Arg too long (max {MAX_ARG_LENGTH} chars)") return v @field_validator('env') @classmethod def validate_env(cls, v: dict[str, str] | None) -> dict[str, str] | None: """Validate env map constraints.""" if v is not None: from .utils import MAX_ENV_ENTRIES, MAX_ENV_KEY_LENGTH, MAX_ENV_VALUE_LENGTH if len(v) > MAX_ENV_ENTRIES: raise ValueError(f"Too many env vars (max {MAX_ENV_ENTRIES})") for key, val in v.items(): if len(key) > MAX_ENV_KEY_LENGTH: raise ValueError(f"Env key too long (max {MAX_ENV_KEY_LENGTH} chars)") if len(val) > MAX_ENV_VALUE_LENGTH: raise ValueError(f"Env value too long (max {MAX_ENV_VALUE_LENGTH} chars)") return v
- src/mcp_debug_tool/sessions.py:100-155 (handler)Core implementation in SessionManager.create_session: validates paths, creates DebugSession instance, generates UUID sessionId, stores in sessions dict.def create_session(self, request: StartSessionRequest) -> StartSessionResponse: """ Create a new debug session. Args: request: Session creation request Returns: Response with new session ID Raises: ValueError: If entry path is invalid FileNotFoundError: If entry script doesn't exist """ # Validate and resolve entry path entry_path = resolve_workspace_path(self.workspace_root, request.entry) if not entry_path.exists(): raise FileNotFoundError(f"Entry script not found: {request.entry}") if not entry_path.is_file(): raise ValueError(f"Entry path is not a file: {request.entry}") if entry_path.suffix != ".py": raise ValueError(f"Entry must be a Python file (.py): {request.entry}") # Determine workspace root for this session # If entry is absolute path, find the workspace root from the entry path session_workspace = self._find_workspace_root(entry_path) # Validate Python path (required) python_path = Path(request.pythonPath) if not python_path.exists(): raise FileNotFoundError(f"Python interpreter not found: {request.pythonPath}") if not python_path.is_file(): raise ValueError(f"Python path is not a file: {request.pythonPath}") # Generate session ID session_id = str(uuid.uuid4()) # Create session with DAP enabled by default use_dap = request.useDap if request.useDap is not None else True session = DebugSession( session_id=session_id, entry=entry_path, python_path=request.pythonPath, workspace_root=session_workspace, args=request.args or [], env=request.env or {}, use_dap=use_dap, ) self.sessions[session_id] = session return StartSessionResponse(sessionId=session_id)
- src/mcp_debug_tool/sessions.py:32-92 (helper)DebugSession class: holds session state, status, timings, breakpoints; used by SessionManager for sessions_create.class DebugSession: """Represents an active debug session.""" def __init__( self, session_id: str, entry: Path, python_path: str, workspace_root: Path, args: list[str] | None = None, env: dict[str, str] | None = None, use_dap: bool = True, ): self.id = session_id self.entry = entry self.workspace_root = workspace_root self.args = args or [] self.env = env or {} self.python_path = python_path self.use_dap = use_dap self.status = SessionStatus.IDLE self.created_at = datetime.now() self.updated_at = datetime.now() self.last_breakpoint: BreakpointTarget | None = None self.timings = SessionTimings() # bdb mode (legacy) self.process: subprocess.Popen | None = None self.reader_task = None # Background task for reading subprocess output # DAP mode (default) self.dap_wrapper = None # Will be set if use_dap=True def update_status(self, status: SessionStatus) -> None: """Update session status and timestamp.""" self.status = status self.updated_at = datetime.now() def update_breakpoint(self, file: str, line: int) -> None: """Update last breakpoint information.""" if self.last_breakpoint and self.last_breakpoint.file == file and self.last_breakpoint.line == line: self.last_breakpoint.hitCount += 1 else: self.last_breakpoint = BreakpointTarget(file=file, line=line, hitCount=1) self.updated_at = datetime.now() def update_timings(self, last_run_ms: float) -> None: """Update timing information.""" self.timings.lastRunMs = last_run_ms self.timings.totalCpuTimeMs += last_run_ms self.updated_at = datetime.now() def to_state_response(self) -> SessionStateResponse: """Convert to state response model.""" return SessionStateResponse( status=self.status, lastBreakpoint=self.last_breakpoint, timings=self.timings, )