Why Your Windows Desktop MCP Calls Silently Fail: Taming the 10-Second Idle Gate
You install windows-mcp, register it in your agent config, and ask your model to trigger a native Windows notification or click a button in an open desktop application.
The tool call finishes in under 200 milliseconds. The agent happily reports: “I have sent the notification.”
Nothing appeared on screen.
When you inspect the raw JSON response returned by the MCP protocol, you don’t find a standard Python exception or Win32 error. Instead, you see this:
{
"code": "CONTROL_PREEMPTED",
"status": {
"state": "user",
"generation": 3,
"wait_seconds": 9.8639,
"executed_steps": 0
}
}
Or, in slightly different timing conditions, your stdio process dumps a stack trace:
RuntimeError: AI control indicator is stopping
AI control indicator failed; releasing physical input
Here is the root cause of this failure mode and the exact configuration setting that fixes it.
The Culprit: The Desktop Control Gate
windows-mcp is designed around a concept called the Desktop Control Policy (implemented in src/windows_mcp/desktop/control_overlay.py and tools/control_policy.py).
The developers wanted to prevent an AI agent from fighting the human user for physical mouse and keyboard ownership. To achieve this, the server installs an idle detection watchdog:
- Before executing any state-changing input tool (
Click,Type,Move,Shortcut,Notification, etc.), it checks Windows user input timers (GetLastInputInfo). - If the user moved the physical mouse or pressed a keyboard key within the last 10 seconds (
WINDOWS_MCP_CONTROL_IDLE_TIMEOUT), the server considers the human to be actively using the machine. - Instead of waiting for you to stop typing, it aborts immediately, returning
CONTROL_PREEMPTEDand leaving the action unexecuted.
If you are chatting with your agent in a desktop window or typing commands in a terminal, you just touched the keyboard. Your idle timer is zero. Therefore, almost every single immediate tool call the agent issues will be preempted by default.
Why --no-control Fails
If you inspect the repository’s README or CLI documentation, you might see references to --control / --no-control.
Naturally, you might try adding --no-control to your server startup command:
uvx windows-mcp serve --no-control
The server instantly crashes on startup with:
Usage: windows-mcp serve [OPTIONS]
Error: No such option '--no-control'.
The CLI parser for the serve subcommand only exposes transport, network, and tool exclusion flags (--transport, --host, --port, --exclude-tools). It does not bind the control flag to the CLI argument group for serve.
The Real Fix: WINDOWS_MCP_CONTROL=false
The configuration loader (src/windows_mcp/config.py) reads desktop control settings directly from environment variables.
To completely bypass the 10-second idle lockout and allow the agent to execute actions immediately upon request, set:
WINDOWS_MCP_CONTROL=false
When injected into your MCP client’s environment block:
{
"command": "uvx",
"args": ["windows-mcp", "serve", "--exclude-tools", "PowerShell,Registry"],
"env": {
"WINDOWS_MCP_CONTROL": "false"
}
}
The control overlay, idle watchdog, and preemptive preemption logic are completely disabled.
Verification
To confirm the fix, send a toast notification through the raw MCP client while actively moving your mouse:
import asyncio
from mcp.client.stdio import stdio_client, StdioServerParameters
from mcp.client.session import ClientSession
async def main():
params = StdioServerParameters(
command="uvx",
args=["windows-mcp", "serve", "--exclude-tools", "PowerShell,Registry"],
env={"WINDOWS_MCP_CONTROL": "false", "ANONYMIZED_TELEMETRY": "false"}
)
async with stdio_client(params) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
res = await session.call_tool("Notification", arguments={
"title": "Windows-MCP Ready",
"message": "Immediate execution verified.",
"app_id": "Hermes Agent"
})
for c in res.content:
print(c.text)
asyncio.run(main())
Output:
Notification sent: "Windows-MCP Ready" - Immediate execution verified.
No 10-second wait, no CONTROL_PREEMPTED, and no silent drops. For more architectural nuance on when to rely on desktop UI drivers versus underlying APIs, see: When to Give Your Agent Physical Clicks (and When to Never, Ever Do It).
Need Resilient Desktop UI or Systems Automation?
If you are bridging legacy desktop applications lacking APIs and need robust, audit-proven agent workflows combining MCP and UI automation:
- WhatsApp: +60 12-797 2969
- Email: [email protected]
- Website: hoelee.com