为什么你的 Windows 桌面 MCP 调用会静默失败:攻破 10 秒空闲门禁与避坑实录
你刚装好 windows-mcp,将其加到 Agent 的配置中,然后让它发送一条 Windows 系统通知,或者点击某个打开的应用窗口按钮。
工具调用在不到 200 毫秒内就返回了,大模型语气轻松地向你汇报:“通知已成功发送。”
然而屏幕上什么都没有发生。
当你把 MCP 协议传输的底层原始 JSON 结果打印出来时,既没有看到标准的 Python 异常,也没有看到 Win32 系统错误,而是看到这样一段内容:
{
"code": "CONTROL_PREEMPTED",
"status": {
"state": "user",
"generation": 3,
"wait_seconds": 9.8639,
"executed_steps": 0
}
}
或者在不同的时序下,后台进程直接抛出一串异常堆栈:
RuntimeError: AI control indicator is stopping
AI control indicator failed; releasing physical input
这就是导致大部分桌面 MCP 调用静默失败的隐蔽真凶。
根因剖析:桌面控制门禁(Desktop Control Policy)
windows-mcp 内部设计了一套桌面所有权控制机制(位于 src/windows_mcp/desktop/control_overlay.py 与 tools/control_policy.py)。
开发者为了避免 AI 在物理桌面上与正在操作鼠标键盘的真人“抢夺输入焦点”,实现了一个空闲检测看门狗:
- 在执行任何具有副作用的输入工具(
Click、Type、Move、Shortcut、Notification等)前,看门狗会通过 Win32 APIGetLastInputInfo读取最后一次物理输入的时间戳。 - 如果人类在过去 10 秒内(
WINDOWS_MCP_CONTROL_IDLE_TIMEOUT)移动过鼠标或敲击过键盘,服务端判定此时“人类正在使用电脑”。 - 此时它既不排队也不等待,而是立刻主动放弃执行,直接返回
CONTROL_PREEMPTED(控制权被抢占),工具实际执行步骤数为 0。
但现实使用场景是:你在终端敲完回车下达指令,或者在聊天框点下发送——这意味着你刚刚操作过键盘鼠标。你的系统空闲时间必然小于 1 秒,因此 Agent 随后的第一次工具调用几乎 100% 触发抢占拦截,导致操作直接被吞。
为什么 --no-control 参数不管用
翻看该项目的 README 或文档,你可能会看到关于 --control / --no-control 的说明。
很多人第一反应是给命令加上 --no-control:
uvx windows-mcp serve --no-control
但服务会在启动瞬间直接崩溃报错:
Usage: windows-mcp serve [OPTIONS]
Error: No such option '--no-control'.
这是因为该项目基于 Click 库构建 CLI,--no-control 只绑在顶层或其他模式上,serve 子命令的参数解析器中根本没有注册这个 CLI 标志。
真正有效的解法:WINDOWS_MCP_CONTROL=false
通过审查代码可以发现,配置加载模块(src/windows_mcp/config.py)会优先读取系统环境变量。
要彻底绕过这道 10 秒空闲限制,允许 Agent 在下达指令后立即获得执行权限,只需注入环境变量:
WINDOWS_MCP_CONTROL=false
将其填入 Agent 的配置文件 env 字段:
{
"command": "uvx",
"args": ["windows-mcp", "serve", "--exclude-tools", "PowerShell,Registry"],
"env": {
"WINDOWS_MCP_CONTROL": "false"
}
}
此时控制层覆盖(Overlay)、空闲看门狗以及拦截抢占逻辑将被完全旁路关闭。
验证与验收
为了验证问题已彻底根除,在鼠标持续移动的状态下通过原生 Python MCP 客户端发起 Toast 通知测试:
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())
终端实时输出:
Notification sent: "Windows-MCP Ready" - Immediate execution verified.
无需苦等 10 秒倒数,再无 CONTROL_PREEMPTED,所有桌面动作即时执行。关于什么时候该用系统 API、什么时候该让 Agent 操控物理键鼠,可以进一步参考:什么时候该让 AI 操控物理鼠标(以及什么时候绝对不要用)。
需要实现复杂的桌面端或企业级自动化?
如果你正在跨越遗留软件缺乏 API 的鸿沟,需要构建结合 MCP、无头浏览器与可靠键鼠模拟的桌面自动化链路:
- WhatsApp:+60 12-797 2969
- Email:[email protected]
- 网站:hoelee.com