# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

mcp-debugger is a Model Context Protocol (MCP) server that provides step-through debugging capabilities for AI agents. It acts as a bridge between MCP clients (like Claude) and debug adapters, enabling structured debugging operations through JSON-based tool calls.

The project uses a **monorepo architecture** with dynamic adapter loading, allowing language-specific debug adapters to be developed and deployed independently.

## Monorepo Structure

```
mcp-debugger/
├── packages/
│   ├── shared/             # Shared interfaces, types, and utilities
│   ├── adapter-python/     # Python debug adapter using debugpy
│   ├── adapter-javascript/ # JavaScript/Node.js adapter using js-debug
│   ├── adapter-rust/       # Rust debug adapter using CodeLLDB
│   ├── adapter-go/         # Go debug adapter using Delve
│   ├── adapter-java/       # Java debug adapter using JDI bridge
│   ├── adapter-dotnet/     # .NET/C# debug adapter using netcoredbg
│   ├── adapter-mock/       # Mock adapter for testing
│   └── mcp-debugger/       # Self-contained CLI bundle (npx distribution)
├── src/
│   ├── adapters/          # Adapter loading and registry system
│   ├── container/         # Dependency injection container
│   ├── proxy/             # DAP proxy system
│   └── session/           # Session management
└── tests/                 # Comprehensive test suite
```

### Package Details

- **@debugmcp/shared**: Core interfaces and types used across all packages
- **@debugmcp/adapter-python**: Python debugging support via debugpy
- **@debugmcp/adapter-javascript**: JavaScript/Node.js debugging support via js-debug
- **@debugmcp/adapter-rust**: Rust debugging support via CodeLLDB
- **@debugmcp/adapter-go**: Go debugging support via Delve
- **@debugmcp/adapter-java**: Java debugging support via JDI bridge
- **@debugmcp/adapter-dotnet**: .NET/C# debugging support via netcoredbg
- **@debugmcp/adapter-mock**: Mock adapter for testing and development
- **@debugmcp/mcp-debugger**: Self-contained CLI bundle for npm distribution (npx-ready)

## Key Commands

### Building and Development

**IMPORTANT: This project uses pnpm, not npm.** The `workspace:*` protocol in dependencies requires pnpm. Run scripts via `npm run <script>` (which delegates to pnpm) or use pnpm directly.

```bash
# Install dependencies (including workspace packages)
pnpm install

# Build all packages and main project
npm run build

# Build specific packages
npm run build:shared
npm run build:adapters       # Build mock + python adapters
npm run build:adapters:all   # Build all adapters including JavaScript
npm run build:packages       # Build all packages in correct order via build-packages.cjs

# Clean build
npm run build:clean

# Development mode with watch
npm run dev

# Start the server (after building)
npm start
# or
node dist/index.js

# Run with specific transport modes
node dist/index.js                          # STDIO mode (default)
node dist/index.js http -p 3001             # Streamable HTTP mode (recommended for remote)
node dist/index.js sse -p 3001              # SSE mode (DEPRECATED — use http instead)
```

### Testing

```bash
# Run all tests
npm test

# Run specific test suites
npm run test:unit         # Unit tests only
npm run test:integration  # Integration tests only
npm run test:e2e         # End-to-end tests only

# Run tests with coverage
npm run test:coverage
npm run test:coverage:summary  # Show coverage summary

# Run tests in watch mode
npm run test:watch

# Run a specific test file
npx vitest run tests/unit/session/session-manager.test.ts

# Run smoke tests for quick validation
npm run test:e2e:smoke
```

### Code Quality

```bash
# Lint code
npm run lint

# Fix linting issues automatically
npm run lint:fix

# Check for personal paths (pre-commit hook)
npm run check:personal-paths
npm run check:all-personal-paths  # Check all files
```

### Docker

```bash
# Build Docker image
npm run docker-build
# or
docker build -t mcp-debugger:local .

# Test container locally
npm run test:e2e:container

# Run container
docker run -v $(pwd):/workspace mcp-debugger:local
```

### GitHub Actions Testing (Act)

```bash
# Test GitHub Actions locally using Act
npm run act:check    # Verify Act is installed
npm run act:lint     # Run lint job
npm run act:test     # Run test job (Ubuntu)
npm run act:test:all # Run all test jobs
npm run act:full     # Run full CI workflow
```

## Path Handling Policy 🚨 CRITICAL

**The project uses a TRUE HANDS-OFF approach to path handling:**

1. **Accept all paths as-is** - No interpretation of Windows vs Linux paths
2. **Path resolution and existence checking** - For immediate LLM UX feedback (`SimpleFileChecker`)
3. **Container mode: Simple prefix** - Only `/workspace/` prepend for existence checks
4. **Pass resolved effective paths** - `src/server.ts` validates paths via `SimpleFileChecker` and passes the resolved `effectivePath` to SessionManager
5. **No cross-platform logic** - Avoids unsolvable edge cases and complexity

**Key Files:**
- `src/utils/simple-file-checker.ts` - Path resolution (via `resolvePathForRuntime`), relative-path rejection in host mode, and file existence checking
- `src/server.ts` - Uses SimpleFileChecker for validation, passes the resolved `effectivePath` to SessionManager

**Rationale:** Cross-platform path handling is theoretically impossible due to ambiguous edge cases. The debug adapter and OS know best how to handle paths for their environment.

## Architecture Overview

The codebase follows a **layered architecture with dependency injection** and **dynamic adapter loading**:

### Core Components

1. **MCP Server Layer** (`src/server.ts`, `src/index.ts`)
   - Entry point for MCP protocol communication
   - Handles tool registration and routing
   - Supports STDIO and Streamable HTTP transport modes (legacy SSE deprecated)
   - Dynamically discovers available language adapters

2. **Adapter System** (NEW)
   - **AdapterRegistry** (`src/adapters/adapter-registry.ts`): Manages adapter lifecycle
   - **AdapterLoader** (`src/adapters/adapter-loader.ts`): Dynamically loads adapters on-demand
   - **Language Adapters** (`packages/adapter-*`): Language-specific implementations
   - Supports both pre-registered and dynamically loaded adapters

3. **SessionManager** (`src/session/`)
   - Central orchestrator for debug sessions, implemented as a 4-class inheritance hierarchy:
     - `SessionManagerCore` (`session-manager-core.ts`): Lifecycle, state management, event handling, dependency wiring
     - `SessionManagerData` (`session-manager-data.ts`): Data retrieval (variables, stack traces, scopes) and adapter policy selection via `selectPolicy()`
     - `SessionManagerOperations` (`session-manager-operations.ts`): Debug operations (start, step, continue, breakpoints, attach/detach)
     - `SessionManager` (`session-manager.ts`): Final composition class that extends SessionManagerOperations. Implements `handleAutoContinue(sessionId)` which auto-continues past entry breakpoints when `stopOnEntry=false`
   - Coordinates ProxyManager instances (one per session)
   - Handles breakpoint management and queuing

4. **ProxyManager** (`src/proxy/proxy-manager.ts`)
   - Manages communication with debug proxy process
   - Spawns proxy worker in separate process
   - Implements typed event system for DAP events
   - Handles request/response correlation with timeouts

5. **DAP Proxy System** (`src/proxy/dap-proxy-*.ts`, `src/proxy/minimal-dap.ts`)
   - **ProxyRunner** (`dap-proxy-core.ts`): Pure business logic, message processing
   - **DapProxyWorker** (`dap-proxy-worker.ts`): Core worker handling debugging operations
   - **Adapter Policies**: Language-specific behavior via policy pattern (`DefaultAdapterPolicy`, `PythonAdapterPolicy`, `JsDebugAdapterPolicy`, `RustAdapterPolicy`, `GoAdapterPolicy`, `JavaAdapterPolicy`, `DotnetAdapterPolicy`, `MockAdapterPolicy`). Note: Java is fully wired to `JavaAdapterPolicy` in `DapProxyWorker.selectAdapterPolicy()` (not falling through to `DefaultAdapterPolicy`).
   - **ChildSessionManager** (`src/proxy/child-session-manager.ts`): Manages DAP child sessions within a single proxy process. Currently used by the js-debug adapter (`childSessionStrategy: 'launchWithPendingTarget'`), which spawns a child debug session for the actual debuggee while the parent session manages the launch orchestration.
   - Implements full Debug Adapter Protocol (DAP) communication

### Key Patterns

- **Dependency Injection**: All major components use constructor injection via interfaces
- **Factory Pattern**: `ProxyManagerFactory`, `SessionStoreFactory`, `AdapterFactory` for testability
- **Dynamic Loading**: Language adapters loaded on-demand via ES modules
- **Event-Driven**: Extensive EventEmitter usage for async communication
- **Process Isolation**: Each debug session runs in separate process for stability
- **Error Boundaries**: Centralized error handling with user-friendly messages

### Data Flow

```
MCP Client → MCP Server → SessionManager → ProxyManager → ProxyWorker → Language Adapter → Debug Runtime
                ↓
         AdapterRegistry → AdapterLoader → Dynamic Import of @debugmcp/adapter-*
```

### Dynamic Adapter Loading

The system supports dynamic adapter loading through:

1. **AdapterLoader**: Attempts to load adapters by package name (`@debugmcp/adapter-{language}`)
2. **Fallback Paths**: Checks multiple locations (node_modules, packages directory)
3. **Registry Integration**: Auto-registers dynamically loaded adapters
4. **Container Mode**: Pre-loads known adapters in Docker environments

### State Management

Sessions use **`SessionState`** as the primary state model, stored directly on each `ManagedSession` and checked throughout the codebase:
- **SessionState**: `CREATED` → `INITIALIZING` → `READY` → `RUNNING` ⇄ `PAUSED` → `STOPPED` | `ERROR`

A dual-state overlay (`SessionLifecycleState` + `ExecutionState`) is derived from `SessionState` via `mapLegacyState()` in `_updateSessionState()`:
- **SessionLifecycleState**: `CREATED` → `ACTIVE` → `TERMINATED` (coarse lifecycle)
- **ExecutionState**: `INITIALIZING` → `RUNNING` ⇄ `PAUSED` → `TERMINATED` | `ERROR` (fine-grained execution)

`SessionState` is the actively used model; the dual-state fields are kept in sync as a secondary representation.

## Important Files and Directories

### Core System
- `src/server.ts` - Main MCP server implementation
- `src/session/` - Session management (4-class hierarchy: `session-manager-core.ts` → `session-manager-data.ts` → `session-manager-operations.ts` → `session-manager.ts`)
- `src/proxy/proxy-manager.ts` - Proxy process management
- `src/proxy/dap-proxy-worker.ts` - Debug adapter protocol implementation

### Adapter System
- `src/adapters/adapter-registry.ts` - Adapter lifecycle management
- `src/adapters/adapter-loader.ts` - Dynamic adapter loading (7 known adapters)
- `packages/shared/` - Shared interfaces and types
- `packages/adapter-python/` - Python debug adapter (debugpy)
- `packages/adapter-javascript/` - JavaScript/Node.js debug adapter (js-debug)
- `packages/adapter-rust/` - Rust debug adapter (CodeLLDB)
- `packages/adapter-go/` - Go debug adapter (Delve)
- `packages/adapter-java/` - Java debug adapter (JDI bridge)
- `packages/adapter-dotnet/` - .NET/C# debug adapter (netcoredbg)
- `packages/adapter-mock/` - Mock adapter for testing

### Distribution
- `packages/mcp-debugger/` - Self-contained CLI bundle for npm/npx distribution

### Supporting Infrastructure
- `src/container/dependencies.ts` - Dependency injection container
- `src/utils/error-messages.ts` - Centralized error messages
- `tests/` - Comprehensive test suite (unit, integration, e2e)
- `examples/` - Example scripts for debugging
- `docs/architecture/` - Detailed architecture documentation

## Development Guidelines

1. **TypeScript Strict Mode**: All code must pass TypeScript strict mode checks
2. **Monorepo Management**: Use pnpm workspaces for package management (`pnpm install`, not `npm install`)
3. **Build Order**: Packages must build in order: shared → adapters → main server. This is managed by `scripts/build-packages.cjs`
4. **Test Coverage**: Maintain >90% test coverage
5. **Error Handling**: Use centralized error messages from `error-messages.ts`
6. **Logging**: Use Winston logger with appropriate log levels
7. **Async Operations**: All DAP operations are async with timeouts
8. **Process Cleanup**: Always ensure proper cleanup of spawned processes
9. **Adapter Development**: New language adapters should implement `IAdapterFactory` from `@debugmcp/shared`

## Testing Approach

The project uses Vitest with three test levels:
- **Unit Tests**: Test components in isolation with mocks
- **Integration Tests**: Test component interactions
- **E2E Tests**: Test full debugging workflows with real debug adapters

## Common Debugging Scenarios

When debugging issues:
1. Enable debug logging: `DEBUG=debug-mcp:* node dist/index.js`
2. Check proxy process output in logs
3. Verify language-specific requirements (e.g., `python -m debugpy --version`)
4. Use `dryRunSpawn: true` in `start_debugging` tool arguments to test configuration without starting a real debug session

## Adding New Language Adapters

To add support for a new language:

1. **Create Package**: Add new package under `packages/adapter-{language}/`
2. **Implement Interfaces**: Implement `IAdapterFactory` and `IDebugAdapter` from `@debugmcp/shared`
3. **Export Factory**: Export a factory class named `{Language}AdapterFactory`
4. **Register in root `package.json`**: Add `"@debugmcp/adapter-{language}": "workspace:*"` to `optionalDependencies`
5. **Add Vitest alias**: Add `{ find: '@debugmcp/adapter-{language}', replacement: path.resolve(__dirname, './packages/adapter-{language}/src/index.ts') }` to `resolve.alias` in `vitest.config.ts`
6. **Update adapter count**: Update hardcoded adapter counts in tests (`adapter-loader.test.ts`, `models.test.ts`)
7. **Add Tests**: Include unit and integration tests in the package
8. **Run `pnpm install`**: To link the new workspace package

Example structure:
```
packages/adapter-{language}/
├── src/
│   ├── index.ts         # Export {Language}AdapterFactory
│   ├── {language}-debug-adapter.ts  # Implement IDebugAdapter
│   └── {language}-adapter-factory.ts  # Implement IAdapterFactory
├── tests/
├── package.json         # Must include "type": "module" and workspace:* dep on @debugmcp/shared
├── tsconfig.json
└── vitest.config.ts     # Optional if tests run from root
```

## Language-Specific Requirements

### Python
- Python 3.7+ must be installed
- debugpy must be installed: `pip install debugpy`
- The system will auto-detect Python path or use `PYTHON_PATH` env var

### JavaScript/Node.js
- Node.js 18+ must be installed
- Uses bundled js-debug adapter (VSCode's debugger)
- Supports JavaScript and TypeScript debugging
- Auto-detects TypeScript configuration

### Rust
- Rust toolchain must be installed (rustc, cargo)
- Uses vendored CodeLLDB debug adapter (auto-downloaded during `pnpm install`)
- Supports both MSVC and GNU toolchains on Windows

### Java
- JDK 21+ must be installed (`java` and `javac` on PATH, or `JAVA_HOME` set)
- Uses JDI bridge (`JdiDapServer.java`) — a single Java file compiled on first use via `javac`
- **Must compile target code with `javac -g`** for variable inspection (includes `LocalVariableTable`)
- Launch mode: The adapter derives `mainClass` from the `program` field in the launch config and transparently forwards `classpath`, `sourcePath`, `cwd`, `env`, and `args` — JDI bridge spawns the JVM and connects via JDI
- Attach mode: Connect to JVM with JDWP agent (`-agentlib:jdwp=...`). JDI bridge handles deferred breakpoints natively via `ClassPrepareRequest`
- Zero external dependencies — JDI (`com.sun.jdi.*`) ships with every JDK
- See `docs/java/README.md` for architecture details

### Go
- Go 1.18+ must be installed
- Delve debugger must be installed: `go install github.com/go-delve/delve/cmd/dlv@latest`
- Uses Delve's native DAP protocol support

### .NET/C#
- .NET 6+ SDK must be installed
- netcoredbg must be installed: download from [Samsung releases](https://github.com/Samsung/netcoredbg/releases) or build from source
- Set `NETCOREDBG_PATH` environment variable to the netcoredbg executable, or add its directory to PATH
- PDB symbols must be in Portable format (compile with `/debug:portable` or the adapter's auto Pdb2Pdb conversion)
- Uses TCP-to-stdio bridge on all platforms (works around a netcoredbg --server mode bug originally discovered on Windows)
- See `docs/dotnet/README.md` for architecture details and debugging guide

### Mock (Testing)
- No external requirements
- Used for testing the debug infrastructure

## MCP Integration with Claude Code CLI

### Installation for Claude Code

Choose the installation method that best fits your use case:

#### Option 1: NPX (No Installation Required)
```bash
# Best for: Trying out mcp-debugger
/home/ubuntu/.claude/local/claude mcp add-json mcp-debugger \
  '{"type":"stdio","command":"npx","args":["@debugmcp/mcp-debugger","stdio"]}'
```

#### Option 2: Global NPM Install
```bash
# Best for: Regular use across projects
npm install -g @debugmcp/mcp-debugger
/home/ubuntu/.claude/local/claude mcp add-json mcp-debugger \
  '{"type":"stdio","command":"mcp-debugger","args":["stdio"]}'
```

#### Option 3: Docker
```bash
# Best for: Isolation and consistency
/home/ubuntu/.claude/local/claude mcp add-json mcp-debugger \
  '{"type":"stdio","command":"docker","args":["run","-i","--rm","-v","${PWD}:/workspace","debugmcp/mcp-debugger:latest","stdio"]}'
```

#### Option 4: Build from Source
```bash
# Best for: One-off use from a local clone
pnpm install && npm run build
/home/ubuntu/.claude/local/claude mcp add-json mcp-debugger \
  '{"type":"stdio","command":"node","args":["/home/ubuntu/mcp-debugger/dist/index.js","stdio"]}'
```

**Note**: The `stdio` argument is critical - it tells the server to suppress all console output which would otherwise corrupt the JSON-RPC protocol communication.

#### Option 5: Dev Proxy (Current Setup — Recommended for Development)
```bash
# Best for: Active development of mcp-debugger itself
pnpm install && npm run build
claude mcp add-json mcp-debugger \
  '{"type":"stdio","command":"node","args":["tools/dev-proxy/dev-proxy.mjs"]}'
```

The dev proxy (`tools/dev-proxy/dev-proxy.mjs`) is a lightweight MCP proxy that sits between Claude Code and mcp-debugger. It maintains a stable stdio connection to Claude Code while managing the backend as a restartable Streamable HTTP child process (default; legacy SSE and stdio modes are also supported via `DEV_PROXY_BACKEND_TRANSPORT`). This means you can rebuild and restart mcp-debugger **without restarting Claude Code** (which would lose conversation context).

**When to use**: Whenever you are actively developing mcp-debugger — making code changes, adding adapters, or installing new toolchains (Go, etc.) that need to be picked up by the running server.

**How it works**: After code changes, call the `dev_rebuild_and_restart` tool. The proxy kills the backend, runs `npm run build`, spawns a fresh process, and reconnects — all transparently. If the backend crashes, dev tools remain available to bring it back.

**Configuration** (env vars, all optional):
- `DEV_PROXY_PORT` — Backend HTTP port (default: 3001; used by `http` and `sse` modes)
- `DEV_PROXY_BUILD_CMD` — Build command (default: `npm run build`)
- `DEV_PROXY_ROOT` — Project root (default: auto-detected)
- `DEV_PROXY_BACKEND_TRANSPORT` — `http` (default), `sse` (legacy/deprecated), or `stdio`

#### Verify Installation

After adding the MCP server:

1. **Check connection status**:
   ```bash
   /home/ubuntu/.claude/local/claude mcp list
   # Should show: mcp-debugger ... - ✓ Connected
   ```

2. **Restart Claude Code** for the changes to take effect

### Configuration Details
- **Location**: Configuration saved to `/home/ubuntu/.claude.json` under the project's `mcpServers` section
- **Server Type**: STDIO (local server)
- **Command**: `node /home/ubuntu/mcp-debugger/dist/index.js stdio` (stdio argument is required!)
- **Status Check**: After restart, type `/mcp` in Claude Code to see connected servers

### Available Tools After Integration
Once connected, the following 21 MCP tools become available:
- `create_debug_session` - Start a new debug session
- `list_debug_sessions` - List active debug sessions
- `list_supported_languages` - Show available language adapters
- `set_breakpoint` - Set breakpoints in code
- `start_debugging` - Begin debugging a script
- `attach_to_process` - Attach debugger to a running process
- `detach_from_process` - Detach debugger from a process
- `close_debug_session` - Clean up sessions
- `step_over`, `step_into`, `step_out` - Step through code
- `continue_execution` - Continue running
- `pause_execution` - Pause a running program
- `list_threads` - List all threads in a debug session
- `get_variables` - Inspect variables in scope
- `get_local_variables` - Get local variables in current frame
- `get_stack_trace` - Inspect call stack
- `get_scopes` - Get variable scopes for a stack frame
- `evaluate_expression` - Evaluate expressions in debug context
- `get_source_context` - Get source code around current position
- `redefine_classes` - Hot-swap changed Java classes into a running JVM (Java only)

**Dev proxy only** (these 3 tools are injected by the dev proxy process itself, not by the main mcp-debugger server):
- `dev_restart_debugger` - Restart the backend (pass `rebuild: true` to build first)
- `dev_rebuild_and_restart` - Run `npm run build` then restart the backend
- `dev_server_status` - Check backend state, PID, uptime, tool count

### Troubleshooting MCP Connection
- **If server shows "Failed to connect"**:
  - Ensure the `stdio` argument is included in the configuration
  - The server silences console output at startup to protect stdio/IPC transports, but misconfigured builds or third-party code may still produce output
  - Use the `add-json` command shown above to properly configure with the stdio argument
  - Note: The `stdio` command is the default subcommand (`isDefault: true` in CLI setup), so explicitly passing `stdio` is optional but recommended for clarity
- **Test the server manually**:
  ```bash
  echo '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{"roots":{},"sampling":{}},"clientInfo":{"name":"test","version":"1.0.0"}},"id":1}' | node dist/index.js stdio
  # Should return clean JSON without any log messages
  ```
- **Verify Python and debugpy are installed**: `python3 -m debugpy --version`
- **Check logs if needed**: Set `DEBUG=debug-mcp:*` environment variable (only for troubleshooting, not for normal operation)