mcp-windows-debug
A Windows-only MCP server that gives AI models eyes and hands on a Windows machine, enabling file reading, screenshots, mouse/keyboard injection, and an auto-debug loop with a safety-focused watchdog for protected abort regions.
README
mcp-windows-debug
A TypeScript/Node.js MCP server that plugs into OpenCode over stdio and gives the model eyes and hands on a Windows machine: it reads project files, captures screenshots, moves the mouse and types keys, and runs an auto-debug loop against a target application.
Safety is the point of the whole design. A separate native C++ watchdog process installs global low-level keyboard and mouse hooks so a human can always click a protected abort button, even while the model is injecting input. The Node MCP server and the watchdog are two independent processes, so a stalled Node event loop cannot freeze your input or silently drop the safety layer. Every action flows through three gates: a governor, a freshness check, and a window-scoping guard. Details are in the Security model section below.
This is a Windows-only v1. macOS and Linux backends plug in later behind the same provider interfaces; they are not implemented yet.
Quick start
git clone https://github.com/wgm66/mcp-windows-debug.git
cd mcp-windows-debug
npm install && npm run build
cd src\watchdog && build.bat # build the C++ watchdog (MSVC required)
node dist\index.js --validate-config # verify your OpenCode config
Installation
Prerequisites:
- Node.js 20 or newer, plus npm
- Windows 10 or 11
- Administrator access, needed only to run the watchdog (see below)
Install dependencies and build the TypeScript:
npm install
npm run build
npm run build runs tsc and produces dist/index.js, which is the entry
point OpenCode launches.
Next, build the watchdog. It is a C++ Win32 console app compiled with MSVC, no CMake, MSBuild, or MinGW involved:
cd src\watchdog
build.bat
build.bat requires the VS2019 Build Tools (MSVC 14.29) and the Windows SDK.
The toolchain paths are hardcoded in the script, so it expects them at their
default install locations. The output is src\watchdog\watchdog.exe, which the
Node server locates relative to the project root at runtime.
The watchdog must run elevated. Global low-level hooks refuse to install from a non-elevated process. Two ways to satisfy this:
- Start OpenCode from an elevated terminal, so the spawned watchdog inherits elevation.
- Pre-start the watchdog as admin yourself before starting a debug session.
The server cannot request UAC elevation on its own in this build. A debug
session that cannot reach an elevated watchdog fails with
ELEVATION_REQUIRED, and a non-elevated watchdog run prints
ERROR_ACCESS_DENIED and exits with code 1 rather than silently doing nothing.
OpenCode configuration
Add a windows-debug entry under the mcp key in your OpenCode config
(opencode.json). Note the key is mcp, not mcpServers:
{
"mcp": {
"windows-debug": {
"type": "local",
"command": ["node", "<abs-path>/dist/index.js"],
"environment": {}
}
}
}
Replace <abs-path> with the absolute path to this project, using forward
slashes so the JSON needs no escaping. For example, if the project lives at
G:\工程开发\AI全场景图形化调试, the command becomes:
"command": ["node", "G:/工程开发/AI全场景图形化调试/dist/index.js"]
The command is an array of argv tokens. The environment map is empty by
default; the per-session watchdog token is generated by the server itself and
passed to the watchdog over the process environment, so you do not need to set
anything here.
Usage
A debug session has a fixed shape: register protected abort buttons, start the session, let the model work through the auto-debug loop, then end the session.
Register abort buttons. A session cannot start with zero protected regions.
Pass one or more screen rectangles to start_debug_session as regions
({ x, y, w, h, id }, physical pixels). Injected input aimed inside any
registered region is blocked by the watchdog. Human input always passes, so the
region is a guaranteed physical abort area the model cannot reach. Regions are
append-only for the session lifetime; there is deliberately no way to remove or
move one after start.
Start the session. start_debug_session spawns or attaches the watchdog,
registers every region, and starts the heartbeat. The orchestrator begins
monitoring the current foreground window as the debug target. Pass
sandbox: 'desktop' to run injection on a private Win32 desktop
(PostMessage-based, user's real mouse/keyboard untouched) instead of
SendInput (which moves the real cursor). sandbox: 'rdp' is reserved but
not implemented in v1.
The auto-debug loop. While the session is active, the orchestrator polls the
target window for changes: title, rectangle, foreground status, and optionally a
screenshot-signature diff. When a trigger fires, it captures a fresh screenshot
and exposes it as the debug://context resource. The client (OpenCode) polls
debug://context, decides what to do, and calls execute_action with that
decision. The orchestrator never decides actions on its own; it only executes
client decisions, and only after the governor, freshness, and safety gates all
pass.
End the session. end_debug_session sends SHUTDOWN, kills the watchdog if
it does not respond within one second, releases any held modifier keys, and
returns to IDLE. If the MCP process dies without a clean shutdown, the watchdog's
dead-man switch removes the hooks on its own (see the Security model section).
Tools
Ten tools are registered.
| Tool | Purpose |
|---|---|
read_file |
Read a text file from an absolute path; binary files return base64. |
list_directory |
List the immediate entries of a directory. |
capture_window |
Capture a window by exact title as a PNG; empty title means the frontmost window. |
mouse_click |
Click at logical screen coordinates with a given button. |
mouse_move |
Move the cursor to logical screen coordinates. |
key_press |
Press a key, optionally holding modifiers. |
type_text |
Type a text string as keyboard input. |
start_debug_session |
Spawn or attach the watchdog and register protected abort regions. Accepts optional sandbox: 'desktop' for isolated PostMessage injection. |
end_debug_session |
End the active session and shut down the watchdog. |
execute_action |
Execute a client-decided action inside the active session. |
inspect_element |
Enumerate visible UI elements (name, role, rect, enabled) via UIAutomation tree walker. |
The four input tools (mouse_click, mouse_move, key_press, type_text)
all route through the safety layer's injectGuarded gate. Calling them with no
active session returns NO_ACTIVE_SESSION. Calling them while the cursor or
keyboard focus is outside the target window returns
WINDOW_SCOPE_VIOLATION.
Resources
Three resources are registered.
| URI | Content |
|---|---|
screenshot://full |
PNG capture of the primary monitor. |
screenshot://monitor/{index} |
PNG capture of a specific monitor by 0-based index. |
debug://context |
JSON snapshot of the auto-debug loop: status, target, trigger, screenshot, governor state. |
Governor limits
The orchestrator enforces a fixed throttle on interventions:
- 5 second cooldown between actions
- 6 interventions per minute
- auto-pause after 3 consecutive failures
- hard 30-minute session cap, after which the session auto-ends
Rejections for cooldown, rate limit, or pause are throttling, not failures. Only a stale-state refusal or an injection error counts toward the 3-failure pause.
Security model
What this design guarantees, and what it does not.
Dual-process isolation. The Node MCP server and the native watchdog are separate processes. A stuck Node event loop cannot block the hooks or drop the safety layer, because the watchdog runs its own message loop.
Dead-man switch. The watchdog listens on a named pipe and treats any byte as
a heartbeat. If no heartbeat arrives for more than 2 seconds, it calls
UnhookWindowsHookEx on both hooks and exits cleanly. Combined with the removal
grace period, hooks come down within 3 seconds of MCP death, so a crashed or
killed server never leaves input blocked. This is the fail-safe contract; it is
not a sub-second guarantee.
Window scoping. Every injection is refused unless a session is active and the cursor and keyboard focus are inside the session target window.
Secure-desktop handling. If the OS switches to the secure desktop (UAC prompt or lock screen), the orchestrator pauses and refuses injection with zero input attempted.
Append-only audit. Every file read, injected action, screenshot request, and intervention decision is logged to an append-only audit log. Keystroke content and file content are never written to it.
What it does NOT guarantee. Read this part carefully, because these are the honest residual risks.
- Injected-input filtering is not absolute blocking. The watchdog blocks
input carrying the
LLKHF_INJECTED/LLMHF_INJECTEDflags when the destination falls inside a protected region. That stops machine-injected input, which is whatSendInputproduces. It does not stop every possible input source. Another process could theoretically synthesize non-flagged input by other means, and that input would pass the filter. This tool does not claim absolute physical blocking. Treat the abort button as a strong, best-effort safety net, not a mathematical guarantee. - It is a remote-control primitive in the worst case. The full tool surface is file read plus screenshot capture plus keyboard and mouse injection. If an attacker or a misbehaving model controls it, that is the capability they get. Use it on a machine and against windows you are willing to have that surface pointed at.
- Antivirus and EDR can flag it. Global low-level hooks and
SendInputinjection are exactly the techniques remote-access tools and keyloggers use. Expect false positives from AV/EDR products, including the watchdog being quarantined or killed mid-session. The dead-man switch makes that safe (hooks come down), but it will interrupt sessions. See Troubleshooting. - Elevation widens the surface. The watchdog needs admin to install global hooks, so a session runs with an elevated process in the picture. Do not run it on a machine where that exposure is unacceptable.
No keystroke or button content is ever read or logged by the watchdog; only the injected flag and the cursor destination are inspected. Transport is the local named pipe only. There is no TCP, no network listener, no remote control.
Troubleshooting
Antivirus or EDR flags the watchdog. Add an exclusion for
src\watchdog\watchdog.exe (or the project directory) in your AV/EDR console.
The durable fix is code signing: a signed binary is far less likely to be
quarantined. If the watchdog gets killed mid-session, the session transitions to
IDLE and all input tools are refused until a new start_debug_session.
Windows detaches the hook (LowLevelHooksTimeout). Low-level hook
procedures have a hard execution budget, controlled by
HKCU\Control Panel\Desktop\LowLevelHooksTimeout (default 300 ms). If the hook
proc runs too long, Windows silently removes it. The watchdog keeps its hook
proc well under 100 ms, so this should not trigger in normal use. If you see
hooks dropping on a heavily loaded machine, the problem is system load or
interference from another low-level hook, not this tool.
Clicks land at the wrong place on a multi-monitor or mixed-DPI setup. Coordinates are mapped between logical and physical pixels using per-monitor DPI. On mixed-DPI multi-monitor setups there is a known limitation: the logical to physical conversion passes logical coordinates to a call that expects physical pixels. It is harmless at 96 DPI but can drift on scaled monitors. If a click misses, capture a screenshot first, read the target coordinates from it, and prefer working on the primary monitor.
A UAC prompt appears, or injection silently fails. The watchdog runs
elevated, so spawning it can surface a UAC prompt. If you cancel it, the session
fails with ELEVATION_REQUIRED. The server cannot re-request elevation on its
own in this build, so pre-start the watchdog as admin before starting the
session, or launch OpenCode from an elevated terminal.
ERROR_ACCESS_DENIED when running the watchdog manually. This is the
expected behavior for a non-elevated shell. The watchdog refuses to run without
admin and prints ERROR_ACCESS_DENIED with exit code 1, so there is no silent
no-op. Run it from an elevated PowerShell instead.
Session recording
Sessions can be recorded as JSON transcripts for later replay. The recorder
hooks into the audit log and captures every tool call (name, args, result,
timestamp) without keystroke content (data minimization). Transcripts are
saved to .omo/recordings/session-<id>.json.
# A session transcript can be replayed programmatically:
node -e "const { SessionRecorder } = require('./dist/recording'); SessionRecorder.replay('.omo/recordings/session-xxx.json', async (call) => { console.log(call.toolName, call.args); })"
UIAutomation (accessibility API)
The inspect_element tool enumerates visible UI elements via the
UIAutomation tree walker (competitor parity with terminator-mcp-agent and
Windows MCP Inspector). In v1, this is a stub that returns elements from the
injected deps seam; full COM interop requires a native N-API addon (future
work). The UIAutomationProvider class implements InputProvider but throws
UIAutomationError for injection methods in v1 — use SendInput or
PostMessage paths for actual injection.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。