# kwin-mcp [Health: Active]

**Category:** 🖥️ OS Automation  
**Repository:** https://github.com/isac322/kwin-mcp  
**GitHub Stars:** 71  
**Views:** 1  
**Installs:** 0  
**Upvotes:** 0  
**Directory Page:** https://allmcps.com/mcp/kwin-mcp-2

## Description
MCP server for Linux desktop GUI automation on KDE Plasma 6 Wayland — 29 tools for virtual and live sessions

## Tools
Capabilities this server exposes over MCP:

- **session_start** — Start an isolated virtual KWin Wayland session (one at a time) with its own `dbus-run-session` bus, `kwin_wayland --virtual` compositor, AT-SPI2 bus and EIS input. `screen_width`/`screen_height` must be positive integers. `enable_clipboard=true` serves the clipboard tools (off by default because `w…
- **session_connect** — Attach to an already running KWin session: the real desktop or a KWin inside a container. Empty values default to `$DBUS_SESSION_BUS_ADDRESS` and `$WAYLAND_DISPLAY` (a socket name is resolved under `$XDG_RUNTIME_DIR`). Clipboard is always enabled. Actions affect real applications, and `window_close…
- **session_stop** — End the current session. Virtual: terminate the whole session process group (`SIGTERM`, then `SIGKILL` for members that remain), KWin, launched apps and the bus. Live: detach, kill only apps launched through kwin-mcp, restore the accessibility switch. Releases all held input and reports it. Idempot…
- **session_info** — Report the current session (or `null`): its kind, Wayland socket, bus address, screen size, enabled backends (input, clipboard, accessibility), retention and artifacts directory, every app launched through kwin-mcp, and the held input. Works without a session.
- **app_launch** — Launch a program in the session, split with `shlex` (no shell), in its own process group, with stdin closed. `env` adds environment variables for this process. stdout and stderr go to a log file read with `app_log`. An empty command or unbalanced quotes is an error. A failed launch keeps the sessio…
- **app_log** — Return the tail of the captured stdout/stderr of an app launched with `app_launch` (`session_info` lists the PIDs). `last_n_lines=0` returns the whole log.
- **screen_capture** — Capture the whole workspace, or a `region` rectangle of it, as a PNG via KWin ScreenShot2 (Spectacle fallback). Returns a `Frame`: the file path, the `kwin://screenshots/{name}` URI, the image size, `size_kb`, the image-to-logical `mapping` and `coverage`, plus the `Coordinate space` text line. `ma…
- **element_query** — Return the AT-SPI2 elements matching `locator`, in pre-order, with role, name, description, states, rectangle (or the reason it is unavailable), actions, text content (capped at 200 characters), slider/scrollbar value, `app`, `window_id`, `child_count` and a `ref` to use as a target. `locator.match…
- **element_act** — Invoke a named AT-SPI action (case-insensitive, e.g. `Press`, `Toggle`, `Activate`) on exactly one element without pointer coordinates: `element={ref}` from `element_query`, or `element={strict: Locator}` for a strict search with the same `match` modes (depth 64, fails closed on any unreadable node…
- **window_list** — List KWin windows, dialogs, popups and shell surfaces included, with `id`, `app_id`, `caption`, `kind`, `active`, `frame` and `client` rectangles, `moveable`/`resizeable`/`closeable`, and `desktops`. `filter` is the same `WindowSelector` the mutators use, applied as an AND-ed filter: `{active: true…
- **desktop_list** — List KWin virtual desktops in pager order (`id`, `name`) with the current one marked.
- **window_focus** — Raise and activate exactly one window through KWin scripting (`workspace.activeWindow`). The result reports the window's observed state afterwards, or that it vanished.
- **window_place** — Set the outer `frame` (any subset of `x`, `y`, `width`, `height`; omitted fields keep their value; signed 32-bit coordinates; width/height positive and at most the workspace size) and/or the virtual `desktop` (an id from `desktop_list`) of exactly one window, then read it back. KWin applies changes…
- **window_close** — Ask exactly one window to close, like its titlebar button; the app may refuse or keep it open behind a "save changes?" prompt, so confirm with `window_list`. On a live session the user must confirm first. An unconfirmed close, a window that cannot be closed, and an `{id}` that matches no window are…
- **pointer_click** — Move the pointer to `target` and click `count` times (1 single, 2 double, 3 triple) with `left`, `right` or `middle`. `modifiers` (e.g. `"ctrl+shift"`) are held during the click only; an unknown key name is an error raised before any input. `hold_ms` long-presses the last click (minimum press 25 ms…
- **pointer_move** — Move the pointer onto `target` and leave it there (hover, tooltips). Refused while a mouse button is held; use `pointer_hold(phase="move")` to move a held button.
- **pointer_scroll** — Move to `target` and scroll. `delta` positive = down/right, negative = up/left. `unit="smooth_step"` scrolls 15 px per unit smoothly; `unit="detent"` sends wheel clicks. `steps` splits `delta` into increments 10 ms apart.
- **pointer_drag** — Press a button at `from`, move with smooth interpolation through optional `waypoints` (`{x, y, dwell_ms}`, pausing `dwell_ms` at each), and release at `to` after pausing `dwell_ms` (for drop targets that need hover). The button and modifiers are always released, even on error.
- **pointer_hold** — Press, move or release one mouse button across calls, for custom drags: `press` (no event if already held), `move` (the button must be held), `release` (always sent). Every phase moves to `target` first. A held button stays held until released, `session_stop` or server exit, and every result report…
- **keyboard_press** — Press and release one key or chord at the keyboard focus, e.g. `Return`, `ctrl+c`, `alt+F4`, `shift+ctrl+z`. Unknown key names are an error.
- **keyboard_type** — Insert text at the keyboard focus. `method="keys"` sends per-key US-QWERTY events (letters, digits, ASCII punctuation, space, tab, newline) and rejects any other character before typing anything, with an error that says to retry with `method="unicode"`. `method="unicode"` types any text through `wt…
- **keyboard_hold** — Press or release one key or chord across calls (modifiers first on press, reverse order on release), e.g. hold `ctrl` while clicking several items. `press` of an already held key sends no event; `release` is always sent. Held keys stay held until released, `session_stop` or server exit, and every r…
- **touch_tap** — Tap `target` with one touch contact (does not move the pointer). `hold_ms` is the contact duration (minimum 10 ms; above 500 ms is a long-press).
- **touch_swipe** — Swipe with `fingers` parallel contacts from one target to another over `duration_ms` (10 ms per step). Contacts are spread vertically 20 px apart around the path. KWin consumes swipes with 3 or more fingers as global gestures (see [Limitations](#limitations)).
- **touch_pinch** — Two contacts move symmetrically around `center`: `end_distance < start_distance` pinches in, `end_distance > start_distance` zooms out.
- **clipboard_read** — Return the session clipboard text (`wl-paste`) as `{text}`. Virtual sessions need `enable_clipboard=true` and `wl-clipboard`. A missing `wl-paste` or an empty or unreadable clipboard is an error.
- **clipboard_write** — Own the session clipboard with `text` (any size, including NUL characters) through `wl-copy`, waiting up to 5 s for ownership. Replaces the current selection. Same requirements as `clipboard_read`. The result echoes text of up to 200 characters; longer text is reported as its length.
- **dbus_call** — Call any method on the session bus, in-process through dbus-python. The method's declared signature is introspected (Qt overloads supported). Each argument is a dbus-send string (`"int32:42"`, `"dict:string:variant:k,string:v"`) or a typed JSON object (`{"type": "int32", "value": 42}`, with `elemen…
- **wayland_list** — List the Wayland protocol globals the compositor advertises (`wayland-info`): the raw lines containing `filter` (case-sensitive) and the parsed `globals` (`interface`, `version`, `name`). Useful for verifying protocol access such as `org_kde_plasma_window_management`.

## Claude Desktop Quick Installation
Install path detected from listing signals. Uses `uvx` (confidence: high):

```json
"mcpServers": {
  "kwin-mcp": {
    "command": "uvx",
    "args": ["kwin-mcp"]
  }
}
```

## Documentation

## What kwin-mcp does

The kwin-mcp MCP server provides Linux desktop GUI automation for KDE Plasma 6 running on Wayland. It exposes 29 MCP tools for starting and managing sessions, launching applications, reading the AT-SPI2 accessibility tree, capturing screens, controlling windows, injecting mouse and keyboard input, handling touch, using the clipboard, and communicating over D-Bus.

Two operating modes are available. An isolated virtual session runs its own `dbus-run-session` and virtual KWin compositor, keeping application windows and injected input away from the user's desktop. A live session connects to an existing KWin environment, including a real KDE desktop or a KWin instance inside a container. The project describes this as suitable for collaborative workflows where an agent observes and operates an existing desktop.

The server is in the OS Automation category and supports applications that run on KDE Plasma 6 Wayland, including Qt, GTK, and Electron applications.

## How it works

In an isolated session, kwin-mcp starts the compositor and applications inside the session, then uses KWin's private EIS D-Bus interface and the standard `libei` protocol for input. This avoids XDG RemoteDesktop portal confirmation prompts. The isolation covers the desktop display and input path; it is not described as a filesystem or network sandbox.

Agents can inspect structured accessibility data instead of depending only on screenshots. AT-SPI2 exposes widget roles, names, coordinates, states, and available actions. Returned element references can be passed to pointer or touch operations, while element actions can invoke supported widget actions without coordinates. Screenshots remain available for visual verification.

Each tool provides an MCP output schema and structured content alongside readable text. This lets clients receive values such as window identifiers, element rectangles, and captured-frame paths without parsing unstructured output.

## Setup and configuration

kwin-mcp requires KDE Plasma 6 on Wayland and Python 3.12 or newer. Installation is available through `uv tool install kwin-mcp` or `pip install kwin-mcp`. The documented installation process may build PyGObject, Pycairo, and dbus-python, so isolated environments need a C compiler and development headers. On Debian 13, the README lists `build-essential`, `pkg-config`, `python3-dev`, `libcairo2-dev`, `libgirepository-2.0-dev`, and `libdbus-1-dev` as required packages.

For Claude Code, register the kwin-mcp MCP server in a project `.mcp.json` and run it with `uvx kwin-mcp`, or use the installed `kwin-mcp` command. The repository also documents a Claude Code plugin and an OpenCode plugin. Claude Desktop configuration is supported through its MCP configuration file. Live operation can be selected with the session connection tool or made the default with the `--default-live-session` flag.

## Tools and capabilities

The 29 tools cover:

- Virtual and live session creation, connection, and management
- Application launching and interaction
- Screen capture and observation
- AT-SPI2 accessibility-tree inspection
- Window management
- Mouse, keyboard, and multi-touch input
- Clipboard operations
- D-Bus access

The kwin-mcp MCP server is suited to end-to-end GUI tests, headless CI jobs, AI-guided desktop workflows, kiosk interfaces, and embedded Linux systems using KDE Plasma or a bare KWin Wayland compositor. Virtual sessions are intended for isolated testing; live connections are intended for existing desktops or containerized KWin environments.

_Full upstream README: https://allmcps.com/mcp/kwin-mcp-2/readme_

