查看: 263|回复: 3

MCP 实测:UIA 桌面自动化接入与安全配置

[复制链接]
发表于 1 小时前 | 显示全部楼层 |阅读模式
背景:把 Windows 桌面当成“操作系统级 DOM”

Windows-MCP 是 CursorTouch 组织开源(MIT 协议)的一个 MCP server,作者 Jeomon George,用 Python 实现。它的定位不是再造一套自动化框架,而是一层适配器:把 Windows 桌面的操作能力以 MCP 工具的形式暴露出去,挂载到 Claude Desktop、Cursor、Claude Code 等客户端后,模型就能读界面、点按钮、敲键盘、跑 PowerShell。

它最值得关注的技术主张写在 README 里:不依赖传统计算机视觉,也不使用针对特定任务微调的模型,可以配合任意 LLM 工作。落到实现层面,就是主要读 Windows UI Automation(UIA)的无障碍树,而不是靠截图猜像素。

作者在 XDA 实测文章的评论区解释过这个选择:如果网页可以靠 DOM 稳定自动化,操作系统层面为什么不能做类似的事?Windows-MCP 本质上就是把 Windows 无障碍 API 当作“操作系统级 DOM”来探索。这个类比抓住了关键——DOM 好自动化,是因为元素有稳定的标识,不需要靠像素去猜;UIA 树在 Windows 上承担的就是同一个角色。

它暴露了什么能力

在客户端里挂载成功之后,通过 tools/list 实际能拉到大约 20 个工具,可以按用途分成几类:

感知类:Snapshot 抓取完整桌面状态,包含 UI 树、可交互元素和坐标;Screenshot 只截画面,跳过 UI 树,适合快速看当前屏幕;DisplayInventory 返回显示器布局、分辨率、DPI 与缩放。

输入类:Click、Type、Scroll、Move、Shortcut、Wait,以及 WaitFor(等待某个元素或文本出现)。

批量输入类:MultiSelect、MultiEdit,用于批量勾选和批量填表。

系统类:App 负责应用启停、切窗口、改尺寸;PowerShell 执行命令;Process 管进程;Registry 操作注册表;Notification 发系统通知。

数据类:FileSystem 读写文件、Clipboard 操作剪贴板、Scrape 抓取网页。

客户端覆盖面比较全,Claude Desktop、Perplexity Desktop、Gemini CLI、Qwen Code、Codex CLI、Claude Code、Autohand Code 都有配置说明,其中 Claude Desktop 那边已经进入官方的 Desktop Extensions 目录。

从代码规模看,整个项目约 24860 行 Python,体量最大的目录是 src/windows_mcp/uia/,其中 controls.py 一个文件就有 6381 行。这里是把它知名的开源库 UIAutomation(yinkaisheng 那套)内联了进来。换句话说,项目的“操作系统底子”大部分站在现成实现之上,自己主要写的是把 UIA 信息翻译成模型可读结构的那一层。

三条感知通道与它们的取舍

它的感知能力不是单点方案,而是按场景分了三档:

第一档是 UIA 树,也就是 Snapshot 默认的 use_ui_tree=True。信息最全,能拿到元素名、类型、自动化 ID、坐标和可执行动作,但复杂界面下会明显变慢。

第二档是纯截图 Screenshot。速度快,但只能依赖视觉判断,拿不到元素 ID,可靠性取决于模型视觉能力和坐标计算是否准确。

第三档是浏览器 DOM,用 Snapshot(use_dom=True),对 Chrome、Edge、Firefox 生效,可以直接拿网页 DOM 并过滤掉浏览器外壳。这里有个细节值得记一笔:Firefox 不通过 UIA 暴露 RootWebArea,项目改用 IAccessible2 兜底。宁可换第二个无障碍 API 也不退回截图,基本说明了整个项目的路线性格。

模型看到的 Snapshot 大概长这样。下面这段是本机开着记事本时抓取的,只摘了记事本这一棵子树:
  1. ├── window "Untitled - Notepad 2e x64 [ZH]"
  2. │ ├── (939,92) 按钮 "New" [action: click]
  3. │ ├── (963,92) 按钮 "Open" [action: click]
  4. │ ├── (987,92) 按钮 "Browse" [action: click]
  5. │ ├── (1011,92) 按钮 "Save" [action: click]
  6. │ ├── (1235,92) 按钮 "Word Wrap" [action: click]
  7. │ ├── (1410,955) 滚动条 "水平滚动条" [action: click]
  8. │ ├── (1747,35) 按钮 "最小化" [action: click]
  9. │ ├── (1866,35) 按钮 "关闭" [action: click]
  10. │ └── 菜单栏 "应用程序"
  11. │ ├── (946,66) 菜单项 "File" [action: click]
  12. │ ├── (991,66) 菜单项 "Edit" [action: click]
  13. │ └── (1040,66) 菜单项 "View" [action: click]
复制代码

模型不需要猜“那个长得像保存的图标在哪”,它知道有个按钮叫 Save,坐标是 (1011, 92),可以点击。官方演示的闭环也是这样跑的:看状态 → 启动应用 → 等待加载 → 再确认状态 → 输入文字,每一步都是一次独立的工具调用。

边界:UIA 读不到的地方怎么办

结构化的代价是定位绑死在可访问性接口上。自绘画布、游戏、DirectX 界面以及部分 Electron 窗口,UIA 树基本是空的,靠元素名点击这条路就走不通,README 自己也承认不适合用来玩游戏。

但要说得准确一点:UIA 读不到并不等于完全瞎了。Screenshot 这条通道可以把画面交给支持视觉输入的模型;README 把视觉明确定位成可选能力(Use Any LLM, Vision Optional),Snapshot 也支持 use_vision=True 把截图一起带上。真正的含义是——没有可用 UIA 信息时,模型可以退回到截图加坐标,但可靠性不再由项目兜底,取决于客户端与模型自身的视觉能力,以及坐标算得准不准。

性能瓶颈作者解释得很直接:性能依然严重依赖界面里可交互元素的数量,因为一切都由无障碍树驱动,庞大复杂的 UI 层级会拖慢速度,所以项目投入了大量通用、非硬编码的启发式规则来裁剪和压缩这些树。代码里能对应上,src/windows_mcp/tree/ 下有 budget.py(树预算)和 cache_utils.py(缓存)负责这件事。

另外两个工程细节也值得知道:截图后端是一条三级降级链 dxcam → mss → pillow,我本机上直接落到了最慢的 pillow;截图后会画一圈橙红色边框作为视觉反馈,可以通过环境变量 WINDOWS_MCP_DISABLE_FLASH=1 关闭。

真机跑一遍:握手与首次工具调用

我用 uvx 在本机拉起服务,以 stdio 方式启动,直接按 MCP 协议的 JSON-RPC 手动调用。初始化握手返回的关键信息:
  1. {
  2. "protocolVersion": "2025-06-18",
  3. "serverInfo": { "name": "windows-mcp", "version": "4.0.10" },
  4. "instructions": "Windows MCP server provides tools to interact directly with the Windows desktop..."
  5. }
复制代码

第一次真实调用是让它报本机 PowerShell 版本:
  1. tools/call PowerShell {"command": "$PSVersionTable.PSVersion.ToString()"}
  2. → Response: 5.1.26100.9549
  3. → Status Code: 0
复制代码

调用成功。这里有个容易被忽略的差别:它走的是 Windows PowerShell 5.1,而不是 PowerShell 7。如果你要写的脚本依赖 PS7 的语法或模块,这一点会直接影响结果。

随后走了一遍完整 GUI 闭环:App 启动记事本 → Wait 等待 → Click 定位 → Type 输入 → Screenshot 截图。文字确实是通过 Type 工具写进去的,全程没有碰键盘。

需要提醒的是,握手返回的 serverInfo 版本号与文档里建议锁定的版本号并不一致,前者是 4.0.10,而配置示例里给的是 0.8.6、演示源码里是 0.8.5。这类版本号错位在快速迭代的开源项目里常见,但用之前最好自己确认一遍实际装到的是哪个版本。

上手建议与安全边界

如果你打算试,几条实操心得很值得提前知道:

第一,先放虚拟机或 Windows Sandbox。这不是个人谨慎,而是厂商安全文档里明写的要求。一个能读屏、能敲键盘、能执行 PowerShell 的进程,本质上就是一双手。

第二,关掉用不到的高危工具。启动参数 --exclude-tools "PowerShell,Registry,FileSystem" 能砍掉一大片攻击面,默认全开的设定并不适合随手尝试。注意这只是工具级开关,管不到命令级——只要 PowerShell 工具还开着,它内部能跑什么就没有限制。

第三,锁定版本。不要让 uvx 自己挑,明确写 windows-mcp==0.8.6,并在安装前确认本地 Python 版本满足要求,否则可能在不知情的情况下用了旧版。

第四,远程访问必须配鉴权。--auth-key + --ip-allowlist + TLS 三件套要一起上,不要把 --host 0.0.0.0 裸着暴露。这个项目就因为没有鉴权吃过一个 HIGH 级漏洞:CVE-2026-48989,0.7.5 之前的 HTTP 模式控制面不带任何认证,可以被任意来源访问。

第五,关遥测。项目使用 PostHog 收集匿名使用数据,ANONYMIZED_TELEMETRY 默认开启(README 环境变量表写 true,实测的 0.8.5 源码里也是 os.getenv("ANONYMIZED_TELEMETRY", "true"))。项目声明不采集个人信息、工具参数和输出,如果在意,在客户端配置里加一行即可,注意值要写成字符串:
  1. "env": { "ANONYMIZED_TELEMETRY": "false" }
复制代码

第六,中文系统下注意 App 工具的匹配问题。按开始菜单名字启动应用可能失败,优先用 launch_executable 加完整路径。

小结

Windows-MCP 的技术路线选得对:用 UIA 当操作系统级 DOM,把结构化元素清单喂给任意 LLM,避开视觉方案对模型能力的高依赖;同时用截图通道作为兜底,用树预算和缓存来控制复杂界面的开销。但它目前的工程细节还偏毛糙,性能强依赖界面元素数量,安全默认值也需要使用者自己收紧。

它适合的目标是:目标明确、允许试错、失败代价低、界面由标准 Win32 控件构成的自动化任务。而需要精确点击和填表的场景,浏览器侧仍然建议走 CDP(Playwright 那一套)更稳。两者各管一段,并不互相替代。
回复

使用道具 举报

发表于 1 小时前 | 显示全部楼层

Re: MCP 实测:UIA 桌面自动化接入与安全配置

感谢分享,这篇把 Windows-MCP 的定位和取舍讲得很清楚。把 UIA 无障碍树类比成操作系统级 DOM 很贴切,也解释了为什么它不优先走截图视觉。三档感知通道里,我最认同 Firefox 那块宁可换 IAccessible2 也不退回截图的处理,说明项目对稳定标识的执念。记事本 Snapshot 的例子也很直观,模型能看到 Save 和坐标,不用猜图标。 边界部分说得很实在,自绘画布、游戏、DirectX、部分 Electron 读不到 UIA 时,视觉只是可选补充,可靠性不由项目兜底,这点对预期管理很重要。性能依赖可交互元素数量也能理解,复杂 UI 树大就会慢。 另外标题提到了安全配置,但正文更多在讲感知和接入。我比较关心 PowerShell、Registry、FileSystem 这些系统级工具挂到客户端后的权限边界,比如是否有默认禁用、白名单、敏感操作确认或审计日志。如果后面能展开这块,会很有帮助。
回复 支持 反对

使用道具 举报

发表于 1 小时前 | 显示全部楼层

Re: MCP 实测:UIA 桌面自动化接入与安全配置

感谢分享,信息量很足。把 UIA 无障碍树类比成“操作系统级 DOM”这个点一下就讲通了,为什么它不做视觉猜像素而是走结构化元素。三档感知通道的分层也很实用:UIA 树信息全但复杂界面会慢,截图快但依赖视觉,浏览器 DOM 对网页更稳,Firefox 用 IAccessible2 兜底这个细节也很有代表性。 我比较认同的是它对边界的说明:自绘画布、游戏、DirectX、部分 Electron 窗口读不到 UIA 时,Screenshot 和 use_vision 只能算退回方案,可靠性不再由项目兜底。这个预期管理很重要,不然容易误以为挂上 MCP 就什么界面都能点。 另外看到系统类里有 PowerShell、Registry、FileSystem,这些权限挺大。标题提到安全配置,但正文里还没展开,不知道后续会不会补充接入时如何做权限限制、操作确认或白名单?比如在 Claude Desktop、Cursor 这类客户端里,是不是主要靠客户端询问和用户自己控制?如果这块能展开,对实际落地会很有帮助。
回复 支持 反对

使用道具 举报

发表于 1 小时前 | 显示全部楼层

Re: MCP 实测:UIA 桌面自动化接入与安全配置

感谢分享,这个思路挺开眼界的。把 UIA 树当成操作系统级 DOM 来用,确实比纯视觉方案稳得多,尤其是有明确元素名和坐标的时候,模型不需要猜“那个像保存的图标在哪”,直接点 Save 就行,可靠性完全不是一个量级。Firefox 那边 UIA 读不到 RootWebArea 就换 IAccessible2 兜底,宁可切第二个无障碍 API 也不退回截图,这个路线性格确实很鲜明。 不过边界也很真实:自绘画布、游戏、部分 Electron 窗口 UIA 树基本是空的,退回截图后就得看模型视觉能力和坐标算得准不准了,项目本身不兜底。性能瓶颈也是,界面元素一多就慢,毕竟全由无障碍树驱动,复杂 UI 层级拖速度。这个取舍感觉挺合理的,没有银弹。 另外标题里提到了“安全配置”,但正文好像还没展开?像 PowerShell、Registry、FileSystem 这类高权限工具,实际挂到客户端后怎么限制权限、避免模型误操作或越权,其实是挺关键的一环。如果后面能聊聊安全方面的设计和实践,应该会很有帮助。整体看,这个适配器层定位很清晰,不重复造轮子,主要把 UIA 信息翻译成模型可读结构,这个方向挺对的。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-10-16 21:58 , Processed in 0.029763 second(s), 18 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部