kwin-mcp
KDE Plasma 6 Wayland上Linux桌面GUI自动化的模型上下文协议服务器
](https://pypi.org/project/kwin-mcp/) ](https://pypi.org/project/kwin-mcp/)   
A. 模型上下文协议(MCP) 服务器,使AI代理(Claude Code、Cursor和其他MCP客户端)能够在完全隔离的虚拟KWin会话中启动、交互和观察任何Wayland应用程序,而不会影响用户的桌面。它还支持 实时桌面自动化 通过连接到现有的KWin会话(真实桌面或容器)进行协作工作流。kwin MCP拥有30个MCP工具,涵盖鼠标、键盘、触摸、剪贴板、可访问性树检查、屏幕截图捕获和窗口管理,提供了Linux上端到端GUI测试和桌面自动化所需的一切。
目录
为什么选择kwin mcp?
- 孤立会话 --每个会话都有自己的运行
dbus-run-session+kwin_wayland --virtual沙箱。您的主机桌面永远不会受到影响。 - 实时会话支持 --连接到真实的KDE Plasma桌面或容器内的KWin实例(例如。
systemd-nspawn)用于协作“共享我的屏幕”工作流。 - 交互不需要截图 --AT-SPI2可访问性树为AI代理提供了结构化的小部件数据(角色、名称、坐标、状态、可用操作),因此它可以与UI元素交互,而不仅仅依赖于视觉。
- 零授权提示 --直接使用KWin的私有EIS(仿真输入服务器)D-Bus接口,绕过XDG RemoteDesktop门户。没有用户确认对话框。
- 适用于任何Wayland应用程序 --在KDE Plasma 6 Wayland上运行的任何东西都可以工作:Qt、GTK、Electron等等。输入通过标准注入
libei协议。 - 全输入覆盖 --鼠标、键盘、多点触控和剪贴板——所有这些都是通过隔离会话注入的,以实现完全的桌面自动化。
用例
自动化GUI测试
在无头隔离会话中运行KDE/Qt/GTK应用程序的端到端GUI测试。kwin mcp在自己的虚拟kwin合成器中启动每个应用程序,通过鼠标、键盘和触摸输入进行交互,然后通过屏幕截图和可访问性树验证结果——所有这些都没有物理显示。
AI驱动的桌面自动化
让像Claude Code这样的AI代理自主操作桌面应用程序。代理读取可访问性树以理解UI,通过30个MCP工具执行操作,并通过屏幕截图观察结果——为任何Wayland应用程序创建一个完整的反馈循环。
实时桌面协作
连接到您的真实桌面会话,让Claude观察您所看到的内容并与之交互。使用 session_connect 或通过 --default-live-session 将实时模式设置为默认模式。还支持连接到在容器内运行的KWin(例如。 systemd-nspawn)用于隔离的代理桌面。
CI/CD中的无头GUI测试
将Linux桌面GUI测试集成到CI/CD管道中。kwin mcp的虚拟会话不需要X11或物理显示服务器,使其适用于Linux上的GitHub Actions或GitLab CI运行器等无头环境。
信息亭和嵌入式设备自动化
自动化运行KDE Plasma或KWin Wayland合成器的信息亭界面和嵌入式Linux桌面。使用 session_start 用于亭UI的隔离虚拟测试,或 session_connect 直接连接到实时信息亭或嵌入式设备会话,以实现实时自动化和诊断。
快速开始
需要Wayland上的KDE Plasma 6。看 系统要求 了解详情。
1.安装
# Using uv (recommended)
uv tool install kwin-mcp
# Or using pip
pip install kwin-mcp2.配置克劳德代码
添加到您的项目 .mcp.json:
{
"mcpServers": {
"kwin-mcp": {
"command": "uvx",
"args": ["kwin-mcp"]
}
}
}3.使用它
让Claude Code启动任何GUI应用程序并与之交互:
Start a KWin session, launch kcalc, and press the buttons to calculate 2 + 3.Claude Code将自动启动一个独立的会话,启动应用程序,读取可访问性树以查找按钮,单击它们,并截图以验证结果。
配置
建议:作为插件安装
将kwin-mcp连接到编辑器中的最快方法是安装一个捆绑的插件。每个插件自动注册MCP服务器 和 船舶 kwin-desktop-automation 技能,它教代理何时调用哪个工具(会话模式选择、观察→ act → 验证循环、US-QWERTY与Unicode打字、AT-SPI2表面局部坐标和其他平台陷阱)。
克劳德代码 --从市场安装插件:
/plugin marketplace add isac322/kwin-mcp
/plugin install kwin-mcp@kwin-mcpOpenCode --将npm插件添加到您的 opencode.json:
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["@isac322/kwin-mcp-opencode"]
}有关完整的集成指南(手动回退、自定义技能、故障排除),请参阅 docs/ai-agent-integration.md.
克劳德代码
添加到您的项目 .mcp.json:
{
"mcpServers": {
"kwin-mcp": {
"command": "uvx",
"args": ["kwin-mcp"]
}
}
}或者,如果全局安装:
{
"mcpServers": {
"kwin-mcp": {
"command": "kwin-mcp"
}
}
}克劳德桌面版
添加到您的 claude_desktop_config.json:
{
"mcpServers": {
"kwin-mcp": {
"command": "uvx",
"args": ["kwin-mcp"]
}
}
}直接运行
# As an installed script
kwin-mcp
# As a Python module
python -m kwin_mcp
# Interactive CLI (REPL for rapid testing)
kwin-mcp-cli
# Live session mode (default to real desktop instead of virtual)
kwin-mcp --default-live-session
kwin-mcp-cli --default-live-session可用工具
会话管理(3个工具)
| 工具 | 参数 | 说明 |
|---|---|---|
session_start | app_command? str, screen_width? int (1920), screen_height? int (1080), enable_clipboard? bool 错误的 keep_screenshots? bool 错误的 isolate_home? bool 错误的 keep_home? bool 错误的 env? dict | 启动一个孤立的KWin Wayland会话,可以选择启动一个应用程序。集 enable_clipboard=true 要启用剪贴板工具(需要 wl-clipboard).集 keep_screenshots=true 保存截图文件 session_stop.Set isolate_home=true 创建一个具有隔离XDG目录(配置、数据、缓存、状态)的临时主页,防止应用程序读取/写入主机用户设置。集 keep_home=true 在以下情况下保留隔离的主目录 session_stop.通过传递额外的环境变量 env. |
session_connect | dbus_address? str, wayland_display? str, keep_screenshots? bool (false) | 连接到现有的KWin会话(真实桌面或容器)。默认为 $DBUS_SESSION_BUS_ADDRESS 和 $WAYLAND_DISPLAY剪贴板始终处于启用状态。 session_stop 只会断开连接,而不会杀死KWin或预先存在的应用程序。 |
session_stop | _(无)_ | 暂停会议并进行清理。对于虚拟会话:终止KWin和所有应用程序。对于实时会话:在不杀死KWin或预先存在的应用程序的情况下断开连接。 |
观察(3个工具)
| 工具 | 参数 | 说明 |
|---|---|---|
screenshot | include_cursor? bool (false) | 捕获虚拟显示的屏幕截图(另存为PNG,返回文件路径) |
accessibility_tree | app_name? str, max_depth? int (15), role? str | 获取包含角色、名称、状态和坐标的AT-SPI2小部件树。使用 role 过滤到特定的元素类型(例如。 "button", "check box").不匹配的元素被隐藏,但它们的子元素仍被遍历。 |
find_ui_elements | query str, app_name? str, states? list[str] | 按名称、角色或描述搜索UI元素(不区分大小写)。可选地按AT-SPI2状态进行过滤(例如。 ["focused"], ["active", "visible"]). query 仅按状态过滤时可以为空。 |
鼠标输入(6个工具)
| 工具 | 参数 | 说明 |
|---|---|---|
mouse_click | x int, y int, button? str (“左”), double? bool, triple? bool, modifiers? list[str], hold_ms? int (0), screenshot_after_ms? list[int] | 在坐标处单击。支持左/右/中、单击/双击/三次、修改键(例如。 ["ctrl", "shift"]),长按通过 hold_ms. |
mouse_move | x int, y int, screenshot_after_ms? list[int] | 将光标(悬停)移动到坐标上,而不单击 |
mouse_scroll | x int, y int, delta int, horizontal? bool, discrete? bool, steps? int (1) | 在坐标处滚动。 delta 正=向下/向右,负=向上/向左。使用 discrete=true 对于车轮滴答声, steps 分成平滑的增量。 |
mouse_drag | from_x int, from_y int, to_x int, to_y int, button? str (“左”), modifiers? list[str], waypoints? list[[x,y,dwell_ms]], screenshot_after_ms? list[int] | 使用平滑插值从一个点拖动到另一个点。支持自定义 waypoints 对于复杂的拖动路径。 |
mouse_button_down | x int, y int, button? str (“左”) | 在坐标处按下鼠标按钮而不松开。与...一起使用 mouse_button_up 用于手动拖动控制。 |
mouse_button_up | x int, y int, button? str (“左”) | 在坐标处松开之前按下的鼠标按钮 |
键盘输入(5个工具)
| 工具 | 参数 | 说明 |
|---|---|---|
keyboard_type | text str, screenshot_after_ms? list[int] | 逐个字符键入文本字符串(美国QWERTY布局) |
keyboard_type_unicode | text str, screenshot_after_ms? list[int] | 通过以下方式键入任意Unicode文本(韩语、CJK等) wtype 或剪贴板回退(wl-copy +Ctrl+V)。需要 wtype 或 wl-clipboard 安装。 |
keyboard_key | key str, screenshot_after_ms? list[int] | 按下按键或按键组合(例如。, Return, ctrl+c, alt+F4, shift+Tab) |
keyboard_key_down | key str | 按住一个键而不松开。可用于在多个操作中按住修饰符(例如,在单击项目时按住Ctrl键)。 |
keyboard_key_up | key str | 释放之前持有的钥匙 |
触摸输入(4个工具)
| 工具 | 参数 | 说明 |
|---|---|---|
touch_tap | x int, y int, hold_ms? int (0), screenshot_after_ms? list[int] | 点击坐标。使用 hold_ms 长按手势。 |
touch_swipe | from_x int, from_y int, to_x int, to_y int, duration_ms? int (300), screenshot_after_ms? list[int] | 以可配置的持续时间从一个点滑动到另一个点 |
touch_pinch | center_x int, center_y int, start_distance int, end_distance int, duration_ms? int (500), screenshot_after_ms? list[int] | 用两根手指捏手势。 end_distance start_distance =掐掉。 |
touch_multi_swipe | from_x int, from_y int, to_x int, to_y int, fingers? int (3), duration_ms? int (300), screenshot_after_ms? list[int] | 多指滑动手势(2-5个手指)用于工作区切换等系统手势 |
剪贴板(2个工具)
| 工具 | 参数 | 说明 |
|---|---|---|
clipboard_get | _(无)_ | 读取当前剪贴板文本内容。需要 enable_clipboard=true 在 session_start 和 wl-clipboard 安装。 |
clipboard_set | text str | 设置剪贴板文本内容。要求与 clipboard_get. |
窗口管理(3个工具)
| 工具 | 参数 | 说明 |
|---|---|---|
launch_app | command str, env? dict | 在正在运行的会话中启动应用程序。返回PID和日志路径。 |
list_windows | _(无)_ | 通过AT-SPI2列出所有可访问的应用程序窗口,包括每个窗口的标题和活动/聚焦状态标记 |
focus_window | app_name str | 按应用程序名称聚焦窗口(不区分大小写匹配) |
UI轮询(1个工具)
| 工具 | 参数 | 说明 |
|---|---|---|
wait_for_element | query str, app_name? str, timeout_ms? int (5000), poll_interval_ms? int (200), expected_states? list[str] | 轮询可访问性树,直到出现与查询和/或状态匹配的元素或超时到期。使用 expected_states 等待状态变化(例如。 ["active"], ["checked"]). query 仅在等待状态更改时可以为空。 |
高级(3个工具)
| 工具 | 参数 | 说明 |
|---|---|---|
dbus_call | service str, path str, interface str, method str, args? list[str] | 调用隔离会话中的任何D-Bus方法。可用于控制KWin脚本、特定于应用程序的D-Bus API和系统服务。 |
read_app_log | pid int, last_n_lines? int (50) | 按PID读取已启动应用程序的stdout/stderr输出。集 last_n_lines=0 对于所有输出。 |
wayland_info | filter_protocol? str | 列出会话中可用的Wayland协议。可用于验证协议访问(例如。, plasma_window_management). |
帧捕获: 许多操作工具都接受可选screenshot_after_ms参数(例如。,[0, 50, 100, 200, 500])它在操作完成后以指定的延迟(以毫秒为单位)捕获屏幕截图。这对于观察悬停效果、单击动画和菜单转换等瞬态UI状态非常有用,而无需额外的MCP往返。帧捕获使用快速的KWin ScreenShot2 D-Bus接口(每帧约30-70ms)。
运作原理
Claude Code / AI Agent
|
| MCP (stdio)
v
kwin-mcp server (30 tools) kwin-mcp-cli (interactive REPL)
| |
+--- both delegate to AutomationEngine (core.py) ---+
|
|-- session_start (virtual) ---> dbus-run-session
| |-- at-spi-bus-launcher
| +-- kwin_wayland --virtual
| +-- [your app]
|
|-- session_connect (live) ----> existing KWin (real desktop / container)
|
|-- screenshot ---------------> KWin ScreenShot2 D-Bus (spectacle fallback)
|
|-- accessibility_tree -------> AT-SPI2 (via PyGObject)
|-- find_ui_elements ---------> AT-SPI2 (via PyGObject)
|-- wait_for_element ----------> AT-SPI2 (polling)
|
|-- mouse_* ------------------> KWin EIS D-Bus --> libei
|-- keyboard_* ---------------> KWin EIS D-Bus --> libei
|-- touch_* ------------------> KWin EIS D-Bus --> libei
| +-- screenshot_after_ms -> KWin ScreenShot2 D-Bus (fast frame capture)
|
|-- keyboard_type_unicode ----> wtype / wl-copy + Ctrl+V
|-- clipboard_* --------------> wl-copy / wl-paste (wl-clipboard)
|
|-- launch_app / list_windows / focus_window
| |-- subprocess spawn
| +-- AT-SPI2 (via PyGObject)
|
|-- dbus_call -----------------> dbus-send (generic D-Bus)
|-- read_app_log --------------> log file read
+-- wayland_info --------------> wayland-info三重隔离(+可选家庭隔离)
kwin mcp提供了与主机桌面的三层隔离:
- D-Bus隔离 --
dbus-run-session创建私有会话总线。隔离会话的服务(KWin、AT-SPI2、门户)对主机不可见。 - 显示器隔离 --
kwin_wayland --virtual使用虚拟帧缓冲区创建自己的Wayland合成器。主机显示器上没有显示窗口。 - 输入隔离 --输入事件仅通过KWin的EIS接口注入到隔离的合成器中。主机桌面未收到kwin mcp的任何输入。
- 主目录隔离 (可选)--何时
isolate_home=true已设置session_start,使用隔离的XDG目录创建临时HOME目录(XDG_CONFIG_HOME,XDG_DATA_HOME,XDG_CACHE_HOME,XDG_STATE_HOME).会话中的应用程序无法读取或修改主机用户设置(例如。~/.config/kdeglobals),提高测试的可重复性和安全性。XDG_RUNTIME_DIR故意不隔离,因为Wayland套接字位于那里。
输入注入
鼠标、键盘和触摸事件通过KWin的私有 org.kde.KWin.EIS.RemoteDesktop D-Bus接口。这将返回a libei 文件描述符,允许低级输入模拟,而不需要XDG RemoteDesktop门户(将显示用户授权对话框)。该连接使用:
- 绝对指针定位 用于基于精确坐标的交互
- evdev密钥 具有完整的美国QWERTY键盘输入映射
- 平滑拖动插值 (10+中间步骤),实现逼真的拖动操作
- EIS触摸模拟 用于多点触控手势(点击、滑动、捏合、多指滑动)
电脑屏幕截图工具
这 screenshot 工具通过KWin捕获 org.kde.KWin.ScreenShot2 D-Bus接口(每帧约30-70ms),带 spectacle CLI作为后备方案。对于具有以下功能的行动工具 screenshot_after_ms 参数,相同的D-Bus接口用于快速突发捕获。从管道中读取原始ARGB像素数据,并使用Pillow将其转换为PNG。
可访问性树
通过PyGObject查询隔离会话中的AT-SPI2可访问性总线(gi.repository.Atspi).这提供了一个结构化的树,其中包含所有UI小部件及其角色(按钮、文本字段、菜单项等)、名称、状态(聚焦、启用、可见等)、屏幕坐标和可用操作(单击、切换等)。
系统要求
| 要求 | 详细信息 |
|---|---|
| 操作系统 | Linux与KDE Plasma 6(Wayland会话) |
| python | 3.12或更高版本 |
| KWin | kwin_wayland 和 --virtual 标志支持(KDE Plasma 6.x) |
| 李贝 | 通常与KWin 6.x捆绑在一起(EIS输入仿真) |
| 奇观 | KDE屏幕截图工具(CLI模式) |
| AT-SPI2 | at-spi2-core 用于可访问性树支持 |
| PyG对象 | GObject自省Python绑定 |
| D-Bus | dbus-python 绑定 |
可选依赖关系:
| 套餐 | 必需 |
|---|---|
wl-clipboard (wl-copy, wl-paste) | clipboard_get, clipboard_set,以及 keyboard_type_unicode 剪贴板回退 |
wtype | keyboard_type_unicode (优于剪贴板回退) |
wayland-utils (wayland-info) | wayland_info 工具 |
安装系统依赖项
Arch Linux / Manjaro
sudo pacman -S kwin spectacle at-spi2-core python-gobject dbus-python-common
# Optional: for clipboard and Unicode input
sudo pacman -S wl-clipboard wtype wayland-utilsFedora (KDE Spin)
sudo dnf install kwin-wayland spectacle at-spi2-core python3-gobject dbus-python
# Optional: for clipboard and Unicode input
sudo dnf install wl-clipboard wtype wayland-utilsopenSUSE (KDE)
sudo zypper install kwin6 spectacle at-spi2-core python3-gobject python3-dbus-python
# Optional: for clipboard and Unicode input
sudo zypper install wl-clipboard wtype wayland-utilsKubuntu / KDE Neon
sudo apt install kwin-wayland spectacle at-spi2-core python3-gi gir1.2-atspi-2.0 python3-dbus
# Optional: for clipboard and Unicode input
sudo apt install wl-clipboard wtype wayland-utils安装
使用紫外线(推荐)
uv tool install kwin-mcp使用pip
pip install kwin-mcp来源
git clone https://github.com/isac322/kwin-mcp.git
cd kwin-mcp
uv sync
uv run kwin-mcp局限性
- 仅限美国QWERTY键盘布局 --
keyboard_type仅支持美国QWERTY键盘。对于非ASCII文本(韩语、CJK等),请使用keyboard_type_unicode,这需要wtype或wl-clipboard安装。 - 需要KDE Plasma 6+ --不支持较旧的KDE版本或其他Wayland合成器(GNOME、Sway)。
- AT-SPI2的可用性各不相同 --某些应用程序可能无法通过AT-SPI2完全公开其小部件树。
- 触摸输入是EIS模拟的 --触摸事件是通过KWin的EIS界面模拟的,而不是来自真实的触摸屏设备。大多数应用程序都能正确处理模拟触摸,但有些应用程序的行为可能与物理触摸不同。
- 剪贴板需要选择加入 --剪贴板工具(
clipboard_get,clipboard_set)默认情况下被禁用,因为wl-copy可以在单独的会话中挂起。启用enable_clipboard=true在session_start,并确保wl-clipboard已安装。 - QMenu(本地上下文菜单)可能不会出现在AT-SPI2中 --Qt的AT-SPI2桥不完全支持Wayland上的弹出菜单。上下文菜单在中可能不可见
accessibility_tree或find_ui_elements.解决方法:使用screenshot以视觉方式定位菜单项并按坐标单击。 - 屏幕边缘触发器不适用于EIS输入 --自动隐藏面板和图层外壳触发条依赖于Wayland表面输入路由,这可能不会对EIS注入的指针事件做出响应。解决方法:使用
dbus_call使用KWin脚本或键盘快捷键。 - AT-SPI2坐标是表面局部坐标,而不是屏幕全局坐标 --Wayland客户不知道他们的全球屏幕位置(按设计)。返回的坐标
find_ui_elements和accessibility_tree是相对于窗口的左上角,而不是虚拟屏幕。对于单窗口场景,这通常是可以的;对于多窗口布局,请结合screenshot用于绝对定位。
贡献
欢迎投稿!看 贡献.md 用于开发设置、代码风格指南和pull请求过程。
git clone https://github.com/isac322/kwin-mcp.git
cd kwin-mcp
uv sync
uv run ruff check src/
uv run ruff format --check src/
uv run ty check src/