关于 Deskwright
Deskwright 是面向 AI Agent 的 MCP 服务,可让其操作 GNOME Wayland 上的真实应用。它结合原生控件访问与视觉交互,也能运行独立虚拟桌面,避免占用用户屏幕。
主要功能
- 01启动并控制 GNOME 应用
- 02检查控件并执行受保护操作
- 03使用鼠标、键盘和剪贴板
- 04通过 OCR 读取屏幕文字并录屏
- 05在虚拟桌面运行具名会话
适用场景
- 01自动化 Linux 原生应用任务
- 02工作时让 Agent 使用独立桌面
- 03验证界面操作并等待状态变化
- 04在干净桌面会话中录制或测试工作流
MCP 相关
该 MCP 服务向 MCP 客户端提供桌面控制工具,涵盖应用、控件、窗口、输入、截图和会话操作。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
uvx deskwrightDESKWRIGHT_SESSIONWhich desktop to drive: 'primary' (the screen you are looking at), 'headless' for an invisible virtual-monitor session, or 'headless:<name>' to pick one of several.DESKWRIGHT_INPUT_BACKENDForce the input path: 'mutter' for GNOME's org.gnome.Mutter.RemoteDesktop (no consent dialog), 'portal' for org.freedesktop.portal.RemoteDesktop (one consent, then persisted). Auto-selected when unset.本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
33收录的工具列表 · 更新于 2 周前
此工具无需参数。
详细介绍
Deskwright
面向 GNOME Wayland 上 AI Agent 的计算机操控能力。
让你的编码 Agent 使用 Linux 桌面。或者给它一个自己的桌面,这样它就 不会再抢你的鼠标。
Claude Code 可以编辑文件并运行命令,但它无法打开 GIMP、 点击设置对话框中的按钮,或读取原生应用显示的内容。 在 macOS 和 Windows 上,它可以通过计算机操控功能做到这些。在 Linux 上, 这项功能仍列在 Anthropic 的待办列表中。
本项目为 GNOME 填补了这一空白。它由一个 MCP 服务和一个小型 Shell 扩展组成, 可让 Agent 操控实际桌面:启动应用、读取控件、点击、输入、拖动、管理窗口、 OCR 和录屏。任何 MCP 客户端都能操控它,包括 Claude Code、Codex、Cursor 以及你自己的脚本。
大家通常最喜欢的功能是:DESKWRIGHT_SESSION=headless 可以在虚拟显示器上运行
所有操作,这个显示器不会出现在你的任何屏幕上。Agent 可以使用真正的 GNOME
桌面,同时不会抢占你的焦点。
Linux 混合模式 Beta:0.2.0b1
此 Beta 版本新增了受保护的原生控件、精确的多控件查询、自适应视觉回退,以及更短的已验证执行批次。它支持 GNOME Wayland;尚未实现 Windows 支持。请参阅交互指南 和测量结果与限制。
全新安装:
pipx install --system-site-packages 'deskwright==0.2.0b1'
deskwright-setup
对于现有的 pipx 安装,pipx upgrade --pip-args='--pre' deskwright
会保留现有的 system-site-packages 设置。运行 deskwright-setup 复制
更新后的扩展;如果安装程序报告扩展已更改,请注销并重新登录。
重启 MCP 连接以加载更新后的 Python 工具。
仅重启连接无法重新加载 GNOME Shell 扩展。
为什么要做这个项目
Wayland 会有意阻止应用查看或操作其他窗口。这条规则很好,也正因如此,
xdotool、wmctrl 和 grim 在 GNOME 上要么毫无作用,要么以一种看似是你自己的错误的方式失败。我找到的每个 Linux 计算机操控项目,要么都附带运行
X11 的 Docker 容器,要么悄悄假定系统使用 X11,结果无法正常工作。
于是我开始寻找 GNOME 实际允许做什么,结果发现能做的事情相当多, 只是不在大家会去找的地方。Mutter 通过 D-Bus 响应请求。AT-SPI 是为屏幕阅读器打造的无障碍层,它会公开每个运行中的应用内的所有真实控件,包括控件名称、角色和执行的操作。而 Shell 扩展则运行在 gnome-shell 自身内部,其他组件也都在那里。
第二点的重要性比听起来更大。触发控件自身的无障碍操作,并不是一种更好的点击方式,而是完全不同的操作:不会点错,窗口移动后依然有效,而且完全不需要指针。Agent 以这种方式工作时,不必再猜测坐标,也不用每次操作后都截屏来确认结果。
安装
你需要在 Wayland 上运行 GNOME Shell。运行 echo $XDG_CURRENT_DESKTOP $XDG_SESSION_TYPE 检查,输出应包含 GNOME 和 wayland。
懒人方式:交给你的 Agent
打开 Claude Code、Codex 或你使用的其他工具,然后说:
在这台机器上设置 https://github.com/tristanmuzzu/deskwright, 按照 AGENTS.md 操作。
AGENTS.md 是为 Agent 编写的操作手册。其中列出了每条命令、如何检查命令是否执行成功、Debian、Fedora 和 Arch 对应的正确软件包名称,以及少数可能出错的情况及其修复方法。你的 Agent 会请你输入一次 sudo 密码,并告诉你注销一次。你只需要做这些。
手动操作:两条命令,然后注销
pipx install --system-site-packages deskwright
deskwright-setup
deskwright-setup 会逐步说明每项操作。它会启用辅助功能标志、安装捆绑的 Shell 扩展,并根据你的发行版给出对应的安装命令,告知你缺少哪些系统软件包,让你不必猜测软件包名称。它绝不会自行运行 sudo。
然后注销并重新登录。 一次即可。这个步骤无法省略:在 Wayland 上,gnome-shell 只会在会话启动时加载扩展。
最后一步,将你的客户端指向它:
claude mcp add deskwright --scope user -- deskwright
就这样。让你的 Agent 打开一个应用,它就会打开。
为什么要用 --system-site-packages,不用会有什么问题
PyGObject 不会向 PyPI 发布 wheel。它在各发行版中都是系统软件包(python3-gi、python3-gobject、python-gobject),所以隔离的 venv 无法导入它。若不启用这个标志,服务会正常启动,但第一次点击时就会因 input_backend_failed 而退出。
uvx 没有等效标志,这也是这里使用 pipx 的唯一原因。如果你不想用 pipx,也可以直接运行 python3 -m venv --system-site-packages,然后运行 pip install deskwright,效果完全相同。
改用 Claude Code 插件
该仓库也是一个插件市场。它会注册 MCP 服务和一项技能,教 Agent 优先使用哪个工具。
claude plugin marketplace add tristanmuzzu/deskwright
claude plugin install deskwright@deskwright
该插件会从自身的检出目录运行服务,因此无需通过 pip 安装。你仍需要安装系统软件包和扩展,所以请在 Claude Code 为你克隆的检出目录中运行一次设置命令:
~/.claude/plugins/marketplaces/deskwright/bin/deskwright-setup
然后像上面一样注销并重新登录。
从克隆的仓库开始,进行开发
git clone https://github.com/tristanmuzzu/deskwright
cd deskwright
bin/deskwright-setup
./mcp_server.py --self-test
./mcp_server.py 与 deskwright 命令使用相同的入口点,因为较早的注册项已经指向这个路径。
CONTRIBUTING.md 介绍了目录结构,以及哪些测试套件需要真实会话。
检查是否正常工作
DESKWRIGHT_SESSION=headless deskwright --self-test
你需要看到 18/18 passed。测试会在虚拟显示器上运行,而不是在你的屏幕上,因此你可以放心地一边工作一边运行。首次运行大约需要 20 秒,因为它必须启动第二个 gnome-shell。
移除 DESKWRIGHT_SESSION=headless,即可改为测试你的真实桌面。运行时请留意屏幕:自测会注入真实输入,因为它要检查用于拒绝危险按键组合的防护措施。
遇到问题时,让你的 Agent 调用 desktop_health。它会用一行话回答当前桌面是否可用,然后说明目前哪些机制有效,以及每种机制实际会执行什么操作。
可执行的操作
41 个工具。每个工具返回的信息都足够,无需再次调用即可了解发生了什么。下面的顺序就是 Agent 应该优先使用它们的顺序。在适当情况下使用原生控件和精确查询;进行视觉操作或处理无障碍信息不完整的情况时,使用截图和常规输入。
| 工具 | 用途 |
|---|---|
ui_apps、ui_tree、ui_find | 查找内容。默认情况下,ui_find 会向下搜索 30 层,因为 GTK4 的嵌套深度远超预期。 |
ui_press | 通过索引路径调用控件的兼容性 API。需要 expect_name 或 expect_role;调用后请检查状态。优先使用 ui_action,以利用原生标识和模态框保护。 |
ui_observe、ui_snapshot、ui_query、ui_inspect、ui_action、ui_wait | 有范围限制的原生引用、受保护的操作和精确的完成检查。请参阅语义交互。 |
ui_set_text | 通过索引路径写入内容并进行精确回读的兼容性 API。优先使用 ui_action,以利用原生引用、当前值比较和模态框保护。 |
ui_read_text | 读取控件内容。用它来验证操作是否成功。 |
launch_app | 通过桌面 ID 启动应用,并在一次调用中等待其窗口出现。 |
screen_map | 查看所有内容的位置(以像素为单位):窗口按堆叠顺序从前到后排列;还会列出当前聚焦应用的每个可按控件,以及点击位置。每个控件都带有 ref: N,可直接传给 ui_press 或 pointer_click。无需复制坐标,使用时会重新验证标识。 |
pointer_click、pointer_move、pointer_drag、pointer_scroll | 在绝对屏幕坐标上执行真实指针输入。传入 expect_window 后,如果点击会落在其他位置,操作就会被拒绝,并指出阻挡窗口的名称,以便你在同一次调用中改换目标。 |
pointer_path | 按住一个按钮,沿一系列屏幕点绘制连续曲线,并限制持续时间且检查是否被中断。需要指定目标窗口。 |
window_at、pointer_position | 在点击前,查看某个点上的点击会命中什么;以及指针当前的位置,或如实说明目前只知道最近一次设置的位置。 |
find_text | 查找可见字符串的屏幕坐标。使用 OCR 查找一个窗口约需 0.3 秒,不会在对话记录中包含图像。对于 Chrome、Electron 和 Qt,这是合适的选择,因为这些程序几乎不会向 ui_find 暴露信息。 |
wait_for | 等待窗口、控件、文本、焦点变化或剪贴板,而不是猜测等待若干秒。 |
region_changed | 等待像素发生变化。适用于 wait_for 无法表达的情况,例如回复到达或加载指示器停止。 |
assert_state | 根据证据判断通过或失败,让长时间运行的流程自行决定是否已完成。 |
do_steps | 在一次调用中执行已知的一系列步骤。运行前会验证,并对每个步骤进行重试;结束时或出错步骤处会提供一张图片。 |
list_windows、activate_window、window_layout、window_manage | 管理窗口列表、焦点和布局。window_layout 无法关闭窗口;通用工具 window_manage 仍保留关闭功能。 |
screenshot、zoom | 获取图片,或截取单个窗口、区域或控件的全分辨率裁剪图。zoom 不会缩放,因此小字仍清晰可读。 |
screencast、frames | 用于查看动态内容,因为静态图无法展示动态。frames 还会报告逐帧差异序列,可据此判断滚动是平滑还是卡顿。 |
type_text、press_keys、hold_key | 通过合成器的按键符号执行键盘输入,并在输入前确认焦点。 |
clipboard_read、clipboard_write | 粘贴胜过敲击两千次按键;回读内容可以确认是否已成功粘贴。 |
journal | 记录 Agent 执行的所有操作:参数、结果、操作是否生效以及截图哈希。可用于审查无人值守的运行过程,或在上下文重置后确认当前状态。 |
desktop_health | 先用一行说明桌面是否可用,再提供详细信息。 |
工作时使用的第二个桌面
需要查看屏幕的 Agent,能发挥的作用只有一半。deskwright-headless 会在虚拟显示器上启动一个独立的 GNOME 会话,并为它配备独立的会话总线、独立的 gnome-shell --headless 和独立的运行时目录。绑定到该会话的服务可用同样的 41 个工具操控这个桌面,而你仍可使用实体桌面。
deskwright-headless start # about 200 MB of gnome-shell, idempotent
deskwright-headless status # liveness, memory, bus address
deskwright-headless stop # don't leave it idling on an 8 GB machine
将它注册为第二个 MCP 服务后,你就可以把耗时较长的任务交给它:
claude mcp add deskwright-headless --scope user --env DESKWRIGHT_SESSION=headless -- deskwright
会话有各自的名称,因此两个 Agent 可以各自拥有一个桌面,不必看着彼此的窗口移动:
deskwright-headless start --name work
deskwright-headless list # every session, memory used, memory free
DESKWRIGHT_SESSION=headless:work deskwright
为会话指定独立的主目录后,它启动的 GNOME 就是全新使用过的状态:没有桌面图标、没有会话恢复、没有最近打开的文件。录制演示或进行干净环境测试时,你就需要这样做,因为默认行为是共用主目录,编辑器会打开你上次的文档。
deskwright-headless start --name demo --home /tmp/demo-home
这里设有防护措施,因为每个会话都是一个实际的合成器,内存占用约为 205 MB:每个名称都有启动锁,避免两个 Agent 同时启动同一个会话;设有会话数量上限(DESKWRIGHT_HEADLESS_MAX,默认值为 4);并设有最低可用内存限制,若启动会导致机器使用交换空间,就会拒绝启动。可能导致这种情况的 Agent 无法预见这一点,所以由服务负责把关。
遇到问题时
扩展显示为 INACTIVE,或窗口工具无法使用。 你还没有注销。gnome-shell 必须重启会话才能加载扩展,没有其他解决办法。在此之前,你仍可使用 AT-SPI、指针、键盘和剪贴板,但无法使用窗口管理、扩展截图、指针位置或停止开关。
应用在 ui_tree 中没有显示任何控件。 在启用 toolkit-accessibility 时,该应用已经在运行。应用会在启动时读取此设置,因此请重启应用。
Chrome、Electron 或 Qt 应用看起来是空的。 从 AT-SPI 的角度来看,它们确实如此。请改用 find_text,它会对屏幕进行 OCR 并返回坐标。对于 Chrome,使用 --force-renderer-accessibility 启动它,就能获取真实的树结构,但会略微影响性能。
所有操作都因 input_backend_failed 失败。 pipx 未使用 --system-site-packages。请使用该标记重新安装:
pipx install --force --system-site-packages deskwright
每次调用 ui_* 都提示“Namespace Atspi not available”。 你安装了 python3-gi,但没有安装 AT-SPI typelib;它是一个独立的软件包:Debian 和 Ubuntu 上的 gir1.2-atspi-2.0,Fedora 和 Arch 上的 at-spi2-core。deskwright-setup --check 会检测到此问题并指出缺少的包。
工具返回 halted。 有人按下了 Super+Ctrl+Escape,也就是停止开关。再按一次即可解除停止状态。
屏幕锁定后,一半工具停止工作。 这是预期行为。GNOME 会卸载未声明 unlock-dialog 的扩展,因此在解锁之前,截图和窗口几何信息都不可用。AT-SPI 仍可正常工作,因此 ui_find、ui_press 和 ui_read_text 仍然可用。
本项目不会做什么
以下内容是项目有意排除的功能,而不只是默认关闭:
- 不破解 CAPTCHA。 CAPTCHA 的用途是区分人和软件,而本项目就是软件。
- 不提供输入凭据的功能。 本项目没有任何功能用于收集、存储或自动填充机密信息。操作日志不会记录输入的内容,只记录输入量。
- 不规避检测。 不添加模仿人类操作的时间抖动,不伪造指纹,也不对抗反机器人措施。
- 没有云服务、遥测或账户。 本项目是在会话总线上运行的本地进程,不会有任何数据离开本机。
在这条界线的另一边,设计上则刻意保持宽松。我们信任 Agent,工具的职责是增强它的能力,而不是限制它。所有安全预算都用于三件事:始终可由人触发的停止开关、防范无法撤销操作的防护措施,以及如实记录发生过的事情。SECURITY.md 会直言启用本项目实际上会开放哪些能力,建议你在让它访问真实屏幕之前先阅读。
实际工作原理
Wayland 会禁止 Wayland 客户端进行所有这些操作。它对 D-Bus 没有任何限制,而突破口就在这里。共有四种机制,大致按承担的工作量从多到少排列:
- AT-SPI,用于所有语义操作。真实的控件、真实的操作,无需指针。
- gnome-shell 扩展,通过 D-Bus 实现 gnome-shell 独有的功能:窗口枚举和控制、屏幕截图、指针位置,以及用于紧急停止开关的按键绑定捕获。
org.gnome.Mutter.RemoteDesktop,用于指针和键盘。使用绝对坐标和按键符号,而非按键位置,因此键盘布局不会改变输入内容。xdg-desktop-portal,以标准化方式实现相同功能。这是连接非 GNOME 合成器的途径。
值得注意的是,第 2 种是其中唯一尚未开放的机制。Mutter 的 ScreenCast 和 RemoteDesktop 接口会响应会话总线上的任何客户端,且不会显示同意对话框。这就是为什么这里的录制无需权限弹窗,以及为什么 portal 是它们的调用方,而不是挡在它们前面的门禁。SECURITY.md 中列出了准确的命令,如果你想自己核实,而不是听我一面之词,可以查看。
docs/field-notes.md 是详细版本:一路上遇到的每道障碍、合成器拒绝了什么,以及塑造工具界面的测量结果。如果遇到行为异常,或准备修改代码,请阅读此文件。
要求
deskwright-setup --check 会给出准确答案。它会检测所有内容、给出适用于你所用发行版的软件包名称,并在缺少硬性要求时以非零状态码退出。简要说明如下:
| 平台 | 状态 |
|---|---|
| GNOME Shell 50 on Wayland | 已验证。 基于 50.1(Ubuntu 26.04)开发,每次变更都会针对它运行实时测试套件。 |
| GNOME Shell 48 到 49 | 应该可用。 D-Bus 和 AT-SPI 接口相同,但未经测试。欢迎反馈,请附上 desktop_health 输出。 |
| KDE Plasma、Sway、Hyprland | 仅输入。 portal 后端可驱动指针和键盘,但窗口管理和屏幕截图需要针对每种合成器进行适配,目前尚未完成。desktop_health 会提示它不可用,这个提示是准确的。 |
| X11 | 非目标平台。xdotool 在该平台上已经能很好地完成这些工作。 |
使用 Claude Code,不要使用 Cowork。 在 Linux 上,桌面应用会在 QEMU/KVM 虚拟机中运行 Cowork 任务,因此它启动的 MCP 服务也运行在该虚拟机中,无法访问你的会话总线、gnome-shell 或屏幕。在那里,这里的一切都会失效。请通过 Claude Code CLI、Code 标签页,或任何运行在主机本身上的其他 MCP 客户端使用它。
使用 Claude Code,不要使用 Cowork。 在 Linux 上,桌面应用会在 QEMU/KVM 虚拟机中运行 Cowork 任务,因此它启动的 MCP 服务也运行在该虚拟机中,无法访问你的会话总线、gnome-shell 或屏幕。在那里,这里的一切都会失效。请通过 Claude Code CLI、Code 标签页,或任何运行在主机本身上的其他 MCP 客户端使用它。
软件包使用 Debian 名称(deskwright-setup 会显示你的软件包名称):python3-gi、gir1.2-atspi-2.0、python3-pil、libglib2.0-bin、wl-clipboard、tesseract-ocr。ydotool 是可选项,仅在输入回退时使用。无头会话还需要 gnome-shell 和 dbus-daemon 可执行文件,任何常规桌面环境都已包含它们。
贡献、安全与许可证
CONTRIBUTING.md 介绍了项目布局、测试套件及各自的运行要求。SECURITY.md 以直白的方式阐述了威胁模型。ROADMAP.md 按顺序说明了后续计划及其原因。
Apache-2.0。如果你成功在非 GNOME 合成器上运行它,或在早于 50 的 GNOME 版本上运行它,请提交 issue 并说明情况。这是任何人能提供的最有用的信息。
mcp-name: io.github.tristanmuzzu/deskwright
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。