DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

nalikip /

nalikip/dsh-unified-desktop

Verified

两个 Windows 桌面自动化 MCP,44 个工具里 15 个是重复或危险的——合成一个 29 工具的统一面,内建危险调用拦截。

★ 0 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@a21f11bd

dsh-unified-desktop

CI License: MIT Node Platform

两个 Windows 桌面自动化 MCP,44 个工具,其中 15 个是重复或危险的。

这个插件把它们合成一个:29 个工具,一个命名空间,内建危险调用拦截。

不是简单的代理转发。它知道 click 该用哪个后端(wincu 走 UIA Invoke,不抢焦点), ocr 只有一边有,read_webpage 的 DOM 模式只有另一边有, 而 PowerShell / Registry / FileSystem / Process 两边都不该暴露。

合并的是 dsh-computer-use-win(UI Automation + OCR + 元素级语义操作) 与 Windows-MCP(浏览器 DOM + 区域截图 + 应用启动)。 每个取舍的理由见 能力归属矩阵。


它解决的问题

单独装这两个插件,模型会看到 44 个工具、两份互相打架的说明:

问题 具体表现
能力重复 click / Click、type_text / Type、scroll / Scroll… 共 10 组,模型不知道该选哪个
上下文吃紧 两套 schema 合计 61,599 tokens(实测),光工具定义就吃掉大半上下文
危险工具裸露 windows-mcp 默认暴露 PowerShell(任意命令)、Registry(改注册表)、FileSystem、Process(kill)
无统一入口 两个 MCP server 各自启动,工具命名空间分裂成两个

合并后的变化

分开装 本插件
MCP server 数 2 1
工具数 44 29
重复能力 10 组 已去重
危险工具 全部裸露 内建守卫拦截
工具命名空间 分裂成两个 统一 mcp__desk__*

工具数与去重结果由 lib/catalog.mjs 的 CATALOG / EXCLUDED 定义, node test/catalog-test.mjs 会校验一致性(43 项断言)。

关于上下文占用的说明:44 个工具的实测基线是 61,599 tokens, 数据在 docs/tool-footprint.json(2026-10-22 从两个后端实时拉 tools/list 后统计)。 合并后只保留 29 个工具的 schema,但具体数值随上游 schema 体积变化,本项目未持续测量—— 本插件只做去重与重命名,不裁剪单个工具的 schema。 想在自己的环境里量,可以跑 node test/aggregate-e2e.mjs,它会打印当前工具面的字符数与估算 token。

和通用 MCP 网关有什么不同

GitHub 上已有成熟的多 MCP 聚合方案(1MCP 525★、 IBM mcp-context-forge 4.7k★、 MCP-Gateway 155★)。它们是横向的:接任意 N 个 server,靠配置里的 filter 规则裁剪工具面。

本项目是纵向的:只为两个特定后端服务,靠一张能力归属表做语义级去重—— 它知道 Snapshot 该拆成「树模式用 wincu、DOM 模式并入 read_webpage」, 而通用网关只能按名字过滤,不知道这两个工具其实是同一件事的不同实现。

如果你要接的是别的 MCP server,用上面那些通用网关更合适。 如果你就在 Windows 上用这两个后端,这张归属表是为你写的。

44 个后端工具去重为 29 个

这张图由 node scripts/gen-dedup-svg.mjs 从 lib/catalog.mjs 生成, 数字与代码永远一致,不会随文档改动而失同步。

架构

DSH ──stdio──> [aggregate.mjs] ──stdio──> wincu server.mjs
                              └─stdio──> windows-mcp.exe

聚合层负责三件事:

  1. 合并工具面 —— 从两个后端拉 tools/list,按目录去重合并
  2. 路由调用 —— tools/call 按目录映射到对应后端
  3. 内建守卫 —— 危险参数在转发前拦截

能力分工

一句话概括:交互类全给 wincu,系统与浏览器类全给 windows-mcp。

选 wincu 的(它更强):

能力 为什么用 wincu
snapshot / read_tree / find UIA 树 + RuntimeId 精确元素定位
ocr 只有 wincu 有,Windows.Media.Ocr 字级坐标
click / double_click 优先走 UIA Invoke 模式,不抢焦点
invoke / set_value 只有 wincu 有,UIA 语义操作
type_text 剪贴板路径支持中文,且恢复原剪贴板
窗口管理 activate / close / move

选 windows-mcp 的(wincu 没有):

能力 用途
read_webpage 浏览器 DOM 模式,读当前标签页,绕开反爬
screenshot 区域截图 region + 多屏 display
launch_app 按开始菜单名启动应用
notify Windows toast 通知
clipboard 读写剪贴板
display_info / control_status 显示器信息、桌面控制权

不暴露的工具

风险类(内建守卫,且 DSH 原生工具已覆盖):

工具 排除原因
PowerShell 任意命令执行;DSH 原生 pwsh 已覆盖且受策略管辖
Registry 直接改注册表,风险过高
FileSystem DSH 原生 read/write/edit/glob/grep 已覆盖
Process kill 风险高

重复类(已由 wincu 的更强实现替代):

Click、Type、Move、Scroll、Shortcut、Wait、WaitFor、Snapshot、MultiSelect、MultiEdit

完整清单见 lib/catalog.mjs 的 EXCLUDED。

每一项「为什么留这个、为什么砍那个」的完整推导,见 docs/capability-matrix.md。

工具清单(29 个)

观察 snapshot screenshot read_tree element_info find ocr list_windows read_webpage display_info control_status health

鼠标键盘 click double_click type_text keypress scroll move_mouse drag set_value invoke focus

窗口 activate_window close_window move_window launch_app

等待 wait wait_for

系统 notify clipboard

安装

前置:

# 1. wincu(提供 UIA + OCR)
dsh plugin --profile web add dsh-computer-use-win

# 2. windows-mcp(提供 DOM + 应用启动)
uv tool install windows-mcp --python 3.14

安装本插件:

dsh plugin --profile web add <本目录路径>

打后端补丁(重要):

node scripts/patch-backend.mjs

不打补丁的话,windows-mcp 会要求你连续空闲 10 秒才允许操作, 否则 screenshot / read_webpage / launch_app 等全部返回 USER_CONTROL。 详见 docs/backend-patch.md。

⚠️ 这个补丁会直接修改你本机的 windows-mcp 安装

scripts/patch-backend.mjs 不是插件,它改写 uv tool 安装目录下的 windows_mcp/desktop/control.py 与 control_hooks.py 源文件。执行前请知悉:

  • 先备份或确认可回滚。撤销用 node scripts/patch-backend.mjs --revert; 彻底还原也可以 uv tool install --force windows-mcp --python 3.14 重装。
  • 上游不认可这个修改。它是本地规避 #498 的权宜之计。 该缺陷已在 PR #508 修复并合并进上游 main, 但尚未进入 PyPI 发布版(最新仍是 0.8.8)。上游发新版本后应移除本补丁。
  • 升级 windows-mcp 会让补丁失效,需要重新执行。
  • 补丁状态检查:node scripts/patch-backend.mjs --check

重要:本插件已聚合 wincu 的能力,需禁用独立挂载的 wincu避免工具重复。 在 profile 的 cordis.patch.yml 加:

- id: mcp-dsh-computer-use-win
  disabled: true

重启 DSH,工具以 mcp__desk__* 出现。

设置项

项 默认 说明
enabledTools 全部 29 个 暴露哪些工具
guardEnabled true 策略守卫开关
auditLog true 写审计日志
idleThresholdSeconds 0.5 windows-mcp 桌面控制门的空闲阈值(秒)
wcuServerPath 自动探测 wincu server.mjs 路径
wmExePath 自动探测 windows-mcp.exe 路径
toolCallTimeoutMs 180000 工具超时

一个关键实现细节

wincu 必须用 .generations/live/ 下的真实路径启动,不能用 profiles/web/node_modules 的软链接。

因为它的入口判断是:

import.meta.url === pathToFileURL(process.argv[1]).href

软链接会让 import.meta.url 解析成真实路径,而 argv[1] 是链接路径,两者不等, server 会静默退出(exit 0,无任何输出)。

本插件的 resolveWcuServer() 会自动优先选 .generations 路径。

测试

npm test                        # 全部 6 个套件

单独跑:

node test/catalog-test.mjs        # 目录一致性、去重、危险工具排除(43 断言)
node test/config-test.mjs         # 配置校验与路径解析(21 断言)
node test/backend-patch-test.mjs  # 后端补丁状态与行为(14 断言,无后端时跳过)
node test/aggregate-e2e.mjs       # 工具面合并、双后端路由(13 断言)
node test/concurrency-test.mjs    # 并发不串号(6 断言)
node test/electron-verify.mjs     # DSH 真实 Electron 运行时(7 断言)

catalog-test、config-test、backend-patch-test 不需要运行中的后端,任何环境都能跑 (CI 默认跑这三个)。其余三个需要本机已安装 wincu 与 windows-mcp。

诊断

遇到 wm 工具被拒(USER_CONTROL)时:

node scripts/diagnose-gate.mjs

输出补丁状态、5 秒内的钩子触发统计、以及 MCP 层实测结果。 完整排查过程见 docs/diagnosis-user-control.md。

排错

工具没出现(mcp__desk__* 不存在)

  1. 看日志 %APPDATA%\dsh-desktop\logs\harness.log,搜 [aggregate]
  2. 正常情况下应有:
    [aggregate] unified-desktop 0.1.0 ready (wcu=true wm=true guard=true)
    [wcu] windows-computer-use MCP server 0.5.0 ready
    [wm] Starting MCP server 'windows-mcp'
    
  3. 如果 wcu=false:检查 wincu 是否安装。路径必须是 profiles\.generations\live\dsh-computer-use-win+*\node_modules\dsh-computer-use-win\mcp\server.mjs
  4. 如果 wm=false:uv tool install windows-mcp --python 3.14

loader 一直显示 still waiting for 1 plugin entries

这是正常的。MCP 初始化约需 30-40 秒(两个后端依次启动),loader 只是计时提示, 插件就绪后不再刷新该行。

工具重复出现(mcp__wincu__* 和 mcp__desk__* 都有)

说明独立的 wincu 没有被禁用。在 profile 的 cordis.patch.yml 加:

- id: mcp-dsh-computer-use-win
  disabled: true

调用返回 USER_CONTROL

windows-mcp 的桌面控制门。两种情况:

  1. 没打后端补丁 → 执行 node scripts/patch-backend.mjs 后重启
  2. 打了补丁但你正在操作 → 停下鼠标键盘约 idleThresholdSeconds 秒再试

用 control_status 查看当前状态:state: "ready" 表示可操作,"user" 表示正在等你空闲。

如果一直卡在 user 且 wait_seconds 固定在某个值附近不动,说明有设备在高频上报 无位移的鼠标移动(常见于无线接收器)。补丁 2 已处理这种情况,确认它是否应用:

node scripts/patch-backend.mjs --check

DOM 模式读不到网页

read_webpage 的 use_dom=true 需要浏览器(Chrome/Edge/Firefox)有活动标签页, 且该页面已加载完成。

已知限制

  1. 不是沙箱。守卫是正则黑名单,挡得住直白危险命令,挡不住刻意构造的绕过。
  2. wincu 升级可能破坏路径。resolveWcuServer 按目录名前缀匹配,升级后版本号变化会自动重新探测。
  3. 两个后端独立启动。一个挂了另一个仍可用,但相应工具会缺失。
  4. DOM 模式依赖浏览器。read_webpage 的 use_dom 需要 Chrome/Edge/Firefox 活动标签页。
  5. 参数未做归一化。两个后端的参数名保持原样(如 wincu 用 elementId,wm 用 loc/label), 模型需要按各工具自己的 schema 传参。归一化在 Unreleased 计划中。
  6. 依赖本地后端补丁。windows-mcp 0.8.8 的桌面控制门在部分硬件上不可用, 本项目通过 scripts/patch-backend.mjs 修复。已向上游报告 (CursorTouch/Windows-MCP#498); 若上游合并,可移除本地补丁。详见 docs/upstream-tracking.md。

设计取舍

为什么用「聚合」而不是「改源码合并」

两个后端分别是 Node(wincu)和 Python(windows-mcp)。真合并意味着用同一种语言重写另一方的核心能力:

  • 把 wincu 的 OCR + UIA RuntimeId 机制移植到 Python —— 工作量大且易出错
  • 把 windows-mcp 的 DOM 提取移植到 Node —— 需要重写 CDP/IAccessible2 逻辑

聚合层用 MCP 协议做边界,两个后端各自演进,互不干扰。代价是多一个进程,收益是 升级任一方都不需要改聚合层(除非工具名变了,那会在 buildToolList 里报 missing backend tool)。

为什么排除 PowerShell / Registry / FileSystem / Process

不是能力不够,而是重复且危险:

  • DSH 原生已有 pwsh、read/write/edit/glob/grep,且受 DSH 沙箱与审批管辖
  • MCP server 是独立进程,DSH 的沙箱管不到它(dsh-fs-sandbox 的策略只作用于 DSH 自己的工具)
  • 保留它们等于开一条绕过沙箱的通道,收益为零

贡献

git clone <repo>
cd dsh-unified-desktop
npm test          # 需要本机已装 wincu 与 windows-mcp

添加新工具:

  1. 在 lib/catalog.mjs 的 CATALOG 加条目(name / backend / target / description)
  2. 跑 node test/catalog-test.mjs —— 它会校验命名规范、去重、能力覆盖
  3. 跑 node test/aggregate-e2e.mjs —— 确认后端真的提供了该工具

修改守卫规则:编辑 lib/guard.mjs 的 PS_RULES / REG_DENY_PREFIX,然后跑 npm test。

License

MIT。聚合层原创;能力来自两个上游项目(均为 MIT)。

上游的版权声明见 THIRD-PARTY-NOTICES.md。

—/ 5

No ratings yet

Verified DSH bundle

Commit a21f11bd3a6c

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout