|
| 1 | +# Debugging Web Applications with dap_launch |
| 2 | + |
| 3 | +This document explains the **correct and only** way to debug web applications (Flask, Django, FastAPI, etc.) using this MCP debugging server. |
| 4 | + |
| 5 | +## TL;DR |
| 6 | + |
| 7 | +**Use `dap_launch` for ALL debugging, including web apps.** The `dap_attach` approach does not work with debugpy. |
| 8 | + |
| 9 | +## How to Debug Web Apps |
| 10 | + |
| 11 | +### 1. Create a Launcher Script |
| 12 | + |
| 13 | +Create a script like `run_flask.py` that imports your web app as a module: |
| 14 | + |
| 15 | +```python |
| 16 | +from examples.web_flask import app |
| 17 | + |
| 18 | +if __name__ == "__main__": |
| 19 | + app.main() |
| 20 | +``` |
| 21 | + |
| 22 | +This avoids relative import issues when the debugger launches your app. |
| 23 | + |
| 24 | +### 2. Launch with dap_launch |
| 25 | + |
| 26 | +Use the MCP `dap_launch` tool to start your web app under debugger control: |
| 27 | + |
| 28 | +```json |
| 29 | +{ |
| 30 | + "name": "dap_launch", |
| 31 | + "input": { |
| 32 | + "program": "run_flask.py", |
| 33 | + "cwd": ".", |
| 34 | + "breakpoints_by_source": { |
| 35 | + "examples/web_flask/inventory.py": [18] |
| 36 | + }, |
| 37 | + "wait_for_breakpoint": false |
| 38 | + } |
| 39 | +} |
| 40 | +``` |
| 41 | + |
| 42 | +**Key points:** |
| 43 | + |
| 44 | +- Use `breakpoints_by_source` to set breakpoints in your business logic files |
| 45 | +- Set `wait_for_breakpoint=false` since you'll trigger breakpoints via HTTP requests |
| 46 | +- The debugger starts and controls the Flask/Django/FastAPI process |
| 47 | + |
| 48 | +### 3. Trigger Breakpoints via HTTP |
| 49 | + |
| 50 | +Make HTTP requests to your app to trigger breakpoints: |
| 51 | + |
| 52 | +```bash |
| 53 | +curl http://127.0.0.1:5001/total |
| 54 | +``` |
| 55 | + |
| 56 | +### 4. Wait for Stopped Event |
| 57 | + |
| 58 | +```json |
| 59 | +{ |
| 60 | + "name": "dap_wait_for_event", |
| 61 | + "input": { |
| 62 | + "name": "stopped", |
| 63 | + "timeout": 10 |
| 64 | + } |
| 65 | +} |
| 66 | +``` |
| 67 | + |
| 68 | +### 5. Inspect and Debug |
| 69 | + |
| 70 | +```json |
| 71 | +{"name": "dap_locals"} |
| 72 | +{"name": "dap_step_over"} |
| 73 | +{"name": "dap_continue"} |
| 74 | +``` |
| 75 | + |
| 76 | +### 6. Clean Up |
| 77 | + |
| 78 | +```json |
| 79 | +{"name": "dap_shutdown"} |
| 80 | +``` |
| 81 | + |
| 82 | +## Why Not dap_attach? |
| 83 | + |
| 84 | +The `dap_attach` approach was thoroughly investigated but **does not work with debugpy**. |
| 85 | + |
| 86 | +### What We Found |
| 87 | + |
| 88 | +When you run: |
| 89 | + |
| 90 | +```bash |
| 91 | +python -m debugpy --listen 5678 -m your.app |
| 92 | +``` |
| 93 | + |
| 94 | +And then try to connect to it directly: |
| 95 | + |
| 96 | +1. ✅ `initialize` request works and gets a response |
| 97 | +2. ❌ `attach` request sent but **debugpy never responds** |
| 98 | +3. ❌ Connection times out |
| 99 | + |
| 100 | +### Why It Fails |
| 101 | + |
| 102 | +- **debugpy is not a full DAP server** when started with `--listen` |
| 103 | +- It's designed for IDE integration (VS Code), not pure DAP attach scenarios |
| 104 | +- The adapter (`debugpy.adapter`) doesn't support `--connect-to` flag |
| 105 | +- Direct TCP connection to debugpy doesn't follow standard DAP protocol for attach |
| 106 | + |
| 107 | +### What We Tried |
| 108 | + |
| 109 | +1. **DirectDAPClient**: Created a TCP client to connect directly to debugpy |
| 110 | + - Result: debugpy doesn't respond to attach requests |
| 111 | + |
| 112 | +2. **StdioDAPClient with --connect-to**: Modified to launch adapter with connection flag |
| 113 | + - Result: `debugpy.adapter` doesn't support `--connect-to` flag |
| 114 | + |
| 115 | +3. **Multiple debugpy command variations**: Tested different flags and modes |
| 116 | + - Result: All failed with the same issue - no response to attach requests |
| 117 | + |
| 118 | +### Conclusion |
| 119 | + |
| 120 | +**debugpy fundamentally does not support the DAP attach workflow for already-running processes.** This is not a bug in our implementation - it's how debugpy works. |
| 121 | + |
| 122 | +## The Solution: dap_launch for Everything |
| 123 | + |
| 124 | +`dap_launch` works perfectly for all scenarios: |
| 125 | + |
| 126 | +- ✅ **Regular scripts**: Debugger starts and stops with the script |
| 127 | +- ✅ **Web servers**: Debugger starts Flask/Django/FastAPI and keeps it alive |
| 128 | +- ✅ **Long-running processes**: Debugger controls the entire lifecycle |
| 129 | +- ✅ **Breakpoints on HTTP requests**: Set breakpoints, trigger via curl/browser |
| 130 | +- ✅ **Module imports**: Use `breakpoints_by_source` for any file |
| 131 | + |
| 132 | +## Example: Complete Flask Debugging Session |
| 133 | + |
| 134 | +```json |
| 135 | +// 1. Launch Flask under debugger |
| 136 | +{ |
| 137 | + "name": "dap_launch", |
| 138 | + "input": { |
| 139 | + "program": "run_flask.py", |
| 140 | + "cwd": ".", |
| 141 | + "breakpoints_by_source": { |
| 142 | + "examples/web_flask/inventory.py": [18] |
| 143 | + }, |
| 144 | + "wait_for_breakpoint": false |
| 145 | + } |
| 146 | +} |
| 147 | + |
| 148 | +// 2. Trigger breakpoint (in bash) |
| 149 | +// curl http://127.0.0.1:5001/total |
| 150 | + |
| 151 | +// 3. Wait for stopped event |
| 152 | +{ |
| 153 | + "name": "dap_wait_for_event", |
| 154 | + "input": { |
| 155 | + "name": "stopped", |
| 156 | + "timeout": 10 |
| 157 | + } |
| 158 | +} |
| 159 | + |
| 160 | +// 4. Inspect variables |
| 161 | +{ |
| 162 | + "name": "dap_locals" |
| 163 | +} |
| 164 | + |
| 165 | +// 5. Continue execution |
| 166 | +{ |
| 167 | + "name": "dap_continue" |
| 168 | +} |
| 169 | + |
| 170 | +// 6. Shutdown |
| 171 | +{ |
| 172 | + "name": "dap_shutdown" |
| 173 | +} |
| 174 | +``` |
| 175 | + |
| 176 | +## References |
| 177 | + |
| 178 | +- [agent_instructions.md](agent_instructions.md) - Complete MCP tool documentation |
| 179 | +- [docs/mcp_usage.md](docs/mcp_usage.md) - Detailed usage guide |
| 180 | +- [examples/web_flask/README.md](examples/web_flask/README.md) - Flask example walkthrough |
0 commit comments