Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Let AI agents debug your code inside VS Code - set breakpoints, step through exe

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![VS Code](https://img.shields.io/badge/VS%20Code-1.104.0+-blue.svg)](https://code.visualstudio.com/)
[![Version](https://img.shields.io/badge/version-1.1.4-green.svg)](https://github.com/microsoft/DebugMCP)
[![Version](https://img.shields.io/badge/version-1.2.0-green.svg)](https://github.com/microsoft/DebugMCP)
[![VS Marketplace](https://img.shields.io/badge/VS%20Marketplace-Install-blue.svg)](https://marketplace.visualstudio.com/items?itemName=ozzafar.debugmcpextension)

> ⭐ **If you find DebugMCP useful, please [star the repo on GitHub](https://github.com/microsoft/DebugMCP)!** It helps others discover the project and motivates continued development.
Expand Down Expand Up @@ -274,14 +274,23 @@ Configure DebugMCP behavior in VSCode settings:
```json
{
"debugmcp.serverPort": 3001,
"debugmcp.timeoutInSeconds": 180
"debugmcp.timeoutInSeconds": 180,
"debugmcp.bindHost": ["127.0.0.1", "::1"]
}
```

| Setting | Default | Description |
|---------|---------|-------------|
| `debugmcp.serverPort` | `3001` | Port number for the MCP server |
| `debugmcp.timeoutInSeconds` | `180` | Timeout for debugging operations |
| `debugmcp.bindHost` | `["127.0.0.1", "::1"]` | Network interface(s) the HTTP server binds to. Accepts a string or array of strings. See [Security model](#security-model) before changing. |

### Security model

DebugMCP exposes powerful debugger primitives (`evaluate_expression`, `start_debugging`, …) over an unauthenticated local HTTP endpoint. To keep that surface safe, the server enforces two controls:

1. **Loopback-only bind.** The HTTP server binds to the IPv4 and IPv6 loopback addresses (`127.0.0.1` and `::1`) by default, so other hosts on your network cannot reach `http://<your-ip>:3001/mcp`. Binding both families ensures clients that resolve `localhost` to either family connect successfully. The `debugmcp.bindHost` setting (string or array of strings) lets you opt into a different interface (for example, when forwarding the port into a remote container), but doing so exposes the unauthenticated debugger to anything that can route to that address — do not point it at `0.0.0.0` or a LAN address on an untrusted network.
2. **Host / Origin header validation.** Every request must carry a `Host` header naming a loopback address (`localhost`, `127.0.0.1`, or `[::1]`); any port suffix in the `Host` must also match the server's listening port. Requests with any other `Host` — including those that arrive via DNS rebinding from a malicious webpage — are rejected with HTTP 403. The same loopback check is applied to the `Origin` header when present.


## FAQ
Expand Down
23 changes: 23 additions & 0 deletions docs/agent-resources/troubleshooting/python.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,29 @@
}
```

## Debugging a Specific Test (pytest / unittest):

DebugMCP dispatches single-test debugging through VS Code's Test Explorer, which requires the Python extension to have **discovered** the test. If discovery hasn't run, `start_debugging` with a `testName` will appear to do nothing (the file opens, the cursor jumps to the test, but no debug session starts).

Discovery requires the test framework to be enabled in workspace settings. Add **one** of the following to `.vscode/settings.json`:

```jsonc
// For pytest:
{
"python.testing.pytestEnabled": true
}

// For unittest:
{
"python.testing.unittestEnabled": true,
"python.testing.unittestArgs": ["-v", "-s", ".", "-p", "test_*.py"]
}
```

Alternatively, run **"Python: Configure Tests"** from the VS Code command palette once — it will write the appropriate settings for you.

Verify discovery worked by opening the Testing view (beaker icon in the sidebar): your tests should appear in the tree. If the tree is empty, the framework isn't configured correctly.

## Debugging Tips:
- Use `print()` statements for quick debugging
- Leverage Python's `pdb` module for command-line debugging
Expand Down
72 changes: 30 additions & 42 deletions docs/architecture/debugConfigurationManager.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,75 +2,63 @@

## Purpose

Manages debug launch configurations by reading from `launch.json` for explicitly named configs, creating defaults when needed, and supporting test-specific debugging across multiple languages and test frameworks.
Produces the argument passed to `vscode.debug.startDebugging()` — either a launch.json configuration name or a minimal `DebugConfiguration` stub.

## Motivation

Different languages and test frameworks require different debug configurations. Rather than forcing AI agents to understand these details, `DebugConfigurationManager` auto-detects the appropriate configuration based on file extension and test framework conventions.
Earlier versions of this class manually parsed `launch.json`, scored configurations, and assembled fully populated per-language config objects. That duplicated work VS Code and the language debug extensions already do better:

- **VS Code** resolves launch.json configurations by name when you pass a string to `startDebugging`.
- **Language extensions** (Python, JS/TS, Java, .NET, Go, …) each register a `DebugConfigurationProvider` whose `resolveDebugConfiguration` hook fills in `cwd`, `console`, `env`, `stopOnEntry`, and other sensible defaults for a minimal stub.

Delegating to those mechanisms keeps this class small and ensures defaults stay aligned with whatever the installed language extensions consider current.

## Responsibility

- Read and parse `.vscode/launch.json` configurations
- Auto-select the most relevant launch configuration for the target file/test
- Respect an explicitly provided `configurationName` when supplied by the agent
- Create default configurations when none exist
- Detect programming language from file extensions
- Generate test-specific configurations for various frameworks
- Validate workspace setup for debugging
- Return a launch.json configuration name when the caller provides one — VS Code looks it up itself.
- Otherwise, return a minimal launch stub (`type`, `request`, `name`, `program`) for the file's language and let the language extension resolve the rest.
- For `.NET` (`coreclr`), locate the project's built DLL since `program` cannot be a `.cs` source file.
- Detect the debugger `type` from a file extension.

**Test debugging is not handled here.** It is routed through `DebuggingExecutor.debugTestAtCursor`, which uses VS Code's built-in `testing.debugAtCursor` command to dispatch to whichever `TestController` owns the test under the cursor. That path supports any language whose extension registers a Test Explorer integration and correctly handles parent/child process attach (e.g. `dotnet test`'s testhost).

## Key Concepts

### Configuration Sources
### Return type

1. **User's launch.json**: Preferred if available
2. **Default Configuration**: Auto-generated based on file extension
3. **Test Configuration**: Special handling for unit test files
`getDebugConfig()` returns `string | vscode.DebugConfiguration`. Both forms are accepted by `vscode.debug.startDebugging(folder, nameOrConfiguration)`.

### Language Detection
### Language detection

Maps file extensions to debug types:
Maps file extensions to debugger `type` values:
- `.py` → `python`
- `.js/.ts/.jsx/.tsx` → `node` (pwa-node)
- `.js/.ts/.jsx/.tsx` → `pwa-node`
- `.java` → `java`
- `.cs` → `coreclr`
- `.cs/.csproj` → `coreclr`
- `.cpp/.cc/.c` → `cppdbg`
- `.go` → `go`
- `.rs` → `lldb`
- `.php` → `php`
- `.rb` → `ruby`

### Test Framework Support
### Test framework support

| Language | Frameworks |
|----------|------------|
| Python | unittest |
| Node.js | Jest, Mocha (auto-detected) |
| Java | JUnit |
| .NET | xUnit, NUnit, MSTest |
Test launches are dispatched via `DebuggingExecutor.debugTestAtCursor`, not via this class. Any language with a registered `TestController` is supported (Python unittest/pytest, Jest, Mocha, JUnit, C# Dev Kit, Go, Rust, ...).

### Configuration Selection Flow
### Selection flow

When starting debugging, the manager:
1. Loads available launch.json configurations
2. Scores configurations based on language/type/request/test relevance
3. Selects the best match automatically
4. Falls back to an auto-detected default configuration when needed
1. If `configurationName` is provided and is not the sentinel `Default Configuration`, return that name verbatim.
2. Otherwise, if the file is C# (`coreclr`), walk up to find the `.csproj`, locate its built DLL under `bin/{Debug,Release}/<tfm>/`, and return a coreclr config pointing at that assembly.
3. Otherwise, return `{ type, request: 'launch', name: 'DebugMCP Launch', program: fileFullPath }`.

## Key Code Locations
## Key code locations

- Class definition: `src/utils/debugConfigurationManager.ts`
- Interface: `IDebugConfigurationManager`
- Default configs: `createDefaultDebugConfig()`
- Test configs: `createTestDebugConfig()`
- .NET assembly lookup: `findNearestCsproj()`, `findBuiltAssembly()`, `createDotNetLaunchConfig()`
- Language detection: `detectLanguageFromFilePath()`
- Configuration selection: `selectBestLaunchConfiguration()`

## JSON Parsing

Handles common launch.json quirks:
- Strips comments (`//` and `/* */`)
- Removes trailing commas before `}` or `]`
- Test launches: see `DebuggingExecutor.debugTestAtCursor` in `src/debuggingExecutor.ts`

## Python Test Name Formatting
## Python test name formatting

For Python tests, the manager auto-detects the class name from the test file to build the full test path (`module.ClassName.test_method`). This allows AI agents to specify just the test method name.
Python test name handling now lives in the Python extension's `TestController`; we no longer format `module.ClassName.test_method` ourselves.
19 changes: 10 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 9 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "debugmcpextension",
"displayName": "DebugMCP",
"description": "Let AI agents debug your code inside VS Code — breakpoints, step-through execution, variable inspection, and expression evaluation. Automatically exposes itself as an MCP (Model Context Protocol) server for seamless integration with AI assistants.",
"version": "1.1.4",
"version": "1.2.0",
"publisher": "ozzafar",
"author": {
"name": "Oz Zafar",
Expand All @@ -15,6 +15,7 @@
},
"keywords": [
"debug",
"debugmcp",
"mcp",
"debugging",
"ai",
Expand Down Expand Up @@ -69,13 +70,19 @@
"properties": {
"debugmcp.timeoutInSeconds": {
"type": "number",
"default": 180,
"default": 300,
"description": "Timeout in seconds"
},
"debugmcp.serverPort": {
"type": "number",
"default": 3001,
"description": "Port number for the DebugMCP server"
},
"debugmcp.bindHost": {
"type": ["string", "array"],
"items": { "type": "string" },
"default": ["127.0.0.1", "::1"],
"markdownDescription": "Network interface(s) the DebugMCP HTTP server binds to. **Defaults to `[\"127.0.0.1\", \"::1\"]` (IPv4 + IPv6 loopback only).** Accepts a single string or an array of strings. ⚠️ **Security warning:** changing this to `0.0.0.0` or a LAN address exposes the unauthenticated MCP debugger — including arbitrary code execution via `evaluate_expression` and `start_debugging` — to every host on the network. Only change this if you fully understand the risk."
}
}
}
Expand All @@ -92,7 +99,6 @@
"@modelcontextprotocol/sdk": "^1.26.0",
"@types/express": "^5.0.3",
"express": "^5.2.1",
"jsonc-parser": "^3.3.1",
"zod": "^3.25.76"
},
"devDependencies": {
Expand Down
Loading
Loading