kde-desktop-mcp
Provides tools for inspecting and automating KDE Plasma desktops, including creating private virtual sessions, launching applications, observing and manipulating windows, displays, pointer/focus state, taking screenshots, sending guarded keyboard and pointer input, inspecting MPRIS media players, and controlling live PipeWire audio settings.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@kde-desktop-mcp create a private desktop and open Kate in it"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
KDE Desktop Automation
A Python toolkit, CLI, and MCP server for inspecting and automating KDE Plasma. It defaults to a separate, private KWin session; access to the live desktop must be selected explicitly.
Codeberg (primary) · GitHub mirror
Prototype: support depends on the installed KDE/Wayland components and system utilities. Input is best-effort and does not prove an application acted on it. A private session isolates its compositor and home directory, but is not a security sandbox and runs as your Unix user.
What it can do
Create private virtual desktops and launch applications inside them.
Observe windows, displays, pointer/focus context, and optional screenshots.
Find, inspect, activate, minimize/restore, and place windows; send guarded keyboard/text input and coordinate clicks/drags.
Inspect and control MPRIS media players.
Inspect and change live PipeWire audio settings (live desktop only).
Expose the same target-aware operations through an stdio MCP server.
Capabilities vary by target and installed tools. There is no accessibility tree, OCR-based control discovery, or app-specific action API yet. See the usage guide for exact commands and limitations.
Related MCP server: quickshell-mcp
Requirements
Linux with KDE Plasma on Wayland; private sessions use KWin's virtual-output backend. Exact support depends on the installed Plasma/KWin version.
Python 3.12 or newer and uv to install from a checkout.
Optional system utilities provide additional features. Run
kde-desktop doctorto see which are available; per-targetcapabilitiesreports what can be used.
Quick start
git clone https://codeberg.org/marvin1099/kde-desktop-automation.git
cd kde-desktop-automation
uv sync
uv run kde-desktop doctor
uv run kde-desktop session create --name agent --width 1280 --height 800 --jsonCopy the session_id from the result and use it for commands in that private
desktop:
SESSION_ID='agent-...'
uv run kde-desktop --session "$SESSION_ID" observe --json
uv run kde-desktop session launch "$SESSION_ID" -- kate --new /tmp/agent-note.txt
uv run kde-desktop --session "$SESSION_ID" screenshot --output /tmp/agent.png --json
uv run kde-desktop session stop "$SESSION_ID"To deliberately target the real desktop, pass --session user-desktop on each
command. Private sessions cannot see host windows or media players. Do not run
untrusted applications in them: they are not an OS-level sandbox.
MCP server
After uv sync, configure your MCP client to launch kde-desktop-mcp from this
checkout:
{
"mcpServers": {
"kde-desktop": {
"command": "uv",
"args": [
"run",
"--directory",
"/absolute/path/to/kde-desktop-automation",
"kde-desktop-mcp"
]
}
}
}Every MCP desktop call requires an explicit session value: a managed session
ID or user-desktop when intentionally using the live desktop.
Safety essentials
A missing or stopped private session never falls back to the live desktop.
Window-targeted input requires that window to already be active; it is guarded by focus, not atomically routed to the window.
Global clicks and drags use logical desktop coordinates, move the pointer, and may change focus. A successful input receipt is not proof of an app effect; inspect again and verify the result independently.
Window placement is a KWin frame-geometry request. KWin may constrain it; the tool reads back and reports the effective geometry.
Audio controls are live-desktop-only. Private sessions do not provide an isolated audio server.
Guides
Development
uv sync --all-groups
uv run pytest -q
uv run ruff check .
uv run ruff format --check .
uv run mypy src
uv buildThe private-KWin tests are opt-in. The Dolphin-to-Kate drag test additionally
requires Dolphin, Kate, kdotool, and wl-paste:
KDE_DESKTOP_RUN_KWIN_INTEGRATION=1 \
KDE_DESKTOP_RUN_KWIN_DND_INTEGRATION=1 \
uv run pytest tests/test_kwin_integration.py::test_private_dolphin_drag_and_drop_opens_file_in_kate -qLicense
Licensed under the GNU Affero General Public License v3.0 only.
Available Tools
32 toolskde_audio_listARead-only
List live PipeWire outputs, inputs, defaults, volume/mute, and active output streams. Requires session='user-desktop'.
Inputs: session (required).
kde_audio_route_streamADestructive
Move one live output stream to a sink after checking its exact stream ID and application name; requires session='user-desktop'.
Inputs: session (required), sink_name (required), stream_id (required), application_name (required), +1 more.
kde_audio_set_defaultCDestructive
Set and verify the live default output sink or input source.
Inputs: session (required), direction (required), device_name (required).
kde_audio_set_muteCDestructive
Explicitly mute or unmute one live sink/source and verify the result.
Inputs: muted (required), session (required), direction (required), device_name (required).
kde_audio_set_volumeBDestructive
Set and verify a live sink/source volume from 0 through 100 percent.
Inputs: session (required), direction (required), device_name (required), volume_percent (required).
kde_capabilitiesBRead-only
Report supported operations and known limitations for a selected target.
Inputs: session (required).
kde_desktop_observeBRead-only
Return a fresh desktop snapshot with windows, logical display geometry, pointer/focus context, and screenshot metadata/image content when Spectacle is available.
Inputs: session (required).
kde_display_listARead-only
List logical display geometry in the selected target session.
Inputs: session (required).
kde_input_clickBDestructive
Click an already-active target window at normalized window coordinates [0, 1].
Inputs: x (required), y (required), session (required), window_id (required), +1 more.
kde_input_click_atADestructive
Click a global logical-desktop pixel coordinate, not a window-relative point. The point must lie on a listed display; this may move the pointer or change focus.
Inputs: x (required), y (required), session (required), button.
kde_input_dragBDestructive
Drag between global logical-desktop pixel coordinates. Every interpolated point must lie on a listed display; steps are limited to 1–64. Duration and start/end pauses are bounded to make real UI drag-and-drop gestures deliverable without changing their global-coordinate semantics. This can move the pointer or change the active window and is not bound to a particular window.
Inputs: end_x (required), end_y (required), session (required), start_x (required), +6 more.
kde_input_keyBDestructive
Send a key chord to an already-active target window; no implicit activation.
Inputs: chord (required), session (required), window_id (required).
kde_input_typeADestructive
Type literal text into an already-active target window; no implicit activation.
Inputs: text (required), session (required), window_id (required).
kde_media_controlADestructive
Submit play, pause, play-pause, stop, next, previous, or a relative seek to one explicitly selected MPRIS player. For seek, seconds is required, must be non-zero, and is an offset (negative rewinds). Use kde_media_seek_to when you need an absolute playback position.
Inputs: action (required), player (required), session (required), seconds.
kde_media_inspectARead-only
Read playback status, title/artist/album, current position, and duration from one explicitly selected MPRIS player.
Inputs: player (required), session (required).
kde_media_listBRead-only
List MPRIS players registered on the selected session's D-Bus.
Inputs: session (required).
kde_media_seek_toADestructive
Seek one exact listed MPRIS player to an absolute position from 0 through 86400 seconds. The request is not verified; inspect the player afterward.
Inputs: player (required), session (required), position_seconds (required).
kde_pointer_positionARead-only
Read the selected session's current pointer position without moving it.
Inputs: session (required).
kde_screenshotBRead-only
Capture the selected desktop and return the PNG as an MCP image result.
Inputs: session (required), output, overwrite.
kde_session_createB
Create an isolated private KWin session; never creates or attaches to the live desktop.
Inputs: name, width, height, make_default.
kde_session_launchA
Launch an executable with argv inside a managed private KWin session; no shell is used.
Inputs: argv (required), session_id (required).
kde_session_listARead-only
List managed private KWin sessions and identify the private default.
Inputs: no named parameters.
kde_session_showBRead-only
Inspect a managed private KWin session by ID.
Inputs: session_id (required).
kde_session_stopADestructive
Stop a managed private session and its tracked applications. Does not affect the live desktop. On shared servers, use only through the coordinator authorized to manage that session.
Inputs: session_id (required).
kde_session_useAIdempotent
Set the persisted private default for CLI clients that omit --session. This does not change MCP desktop calls, which require an explicit session.
Inputs: session_id (required).
kde_window_activateB
Activate a selected window. user-desktop activation changes real user focus.
Inputs: session (required), window_id (required).
kde_window_findARead-only
Find exactly one window by app ID and/or title substring; ambiguity returns candidates.
Inputs: session (required), title, app_id.
kde_window_inspectARead-only
Inspect one window using a UUID from the same selected session.
Inputs: session (required), window_id (required).
kde_window_listARead-only
List windows in a private session or explicitly selected user-desktop.
Inputs: session (required).
kde_window_set_geometryADestructiveIdempotent
Set an explicit KWin frame rectangle in logical desktop pixels and verify its effective geometry. This is window placement, not a simulated mouse drag.
Inputs: x (required), y (required), width (required), height (required), +2 more.
kde_window_set_minimizedADestructiveIdempotent
Set a window's minimized state explicitly and verify it. Setting false restores it; live changes may change user focus.
Inputs: session (required), minimized (required), window_id (required).
kde_window_waitBRead-only
Wait up to 60 seconds for a unique matching window, optionally until KWin reports fullscreen or its geometry fills a logical display.
Inputs: session (required), title, app_id, timeout, +2 more.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 32 tools
Most tools are clearly partitioned by domain and action (session_*, window_*, input_*, audio_*, media_*), and descriptions actively disambiguate near-pairs like click vs click_at (window-relative vs global) and media_control vs media_seek_to (relative vs absolute). Minor residual overlap remains: kde_screenshot vs kde_desktop_observe (which also returns screenshot content), and kde_window_find/wait/list/inspect all target the same resource from different angles.
Every tool follows the same kde_<domain>_<verb>_<noun> snake_case pattern (kde_session_create, kde_audio_set_volume, kde_media_seek_to, kde_window_set_geometry). The domain prefix groups tools predictably and no mixed conventions appear.
32 tools is heavy for a single server, though the count is spread across seven genuinely distinct subsystems (sessions, windows, input, audio, media, display, screenshot) rather than being padding. It sits at the edge where an agent must scan a large surface to pick a tool, but each tool still maps to a real operation.
Coverage is broad and lifecycle-ish for sessions, audio, media, and window placement/state, but there are notable desktop-automation gaps: no window close/kill tool and no mouse scroll/wheel input, both of which are core to GUI automation and would force workarounds. Session management also lacks an explicit delete (only stop/launch).
Maintenance
Related MCP Connectors
Securely control computers you explicitly pair through files, terminals, processes, screenshots, desktop UI/input, clipboard, browser automation, diagnostics, and document tools.
Drive real devices from your AI Coding tool. Embed a client SDK (Unity, Godot, Flutter, iOS/macOS, Android, React Native, Web) in your app, then capture screenshots, traverse the UI tree, inject taps and key events, and run automated test tasks on the physical device over a secure relay.
Eyes and hands on real Windows PCs — observe, click, type via Glasswarp API.
Operate Linux, macOS and Windows from your LLM. Every action runs through an auditable allowlist.
Related MCP Servers
- AlicenseNot gradedqualityAmaintenanceEnables AI agents to automate Linux desktop GUI by launching and interacting with Wayland applications in isolated virtual KWin sessions, or connecting to live desktops for collaborative automation.159 PyPI78MIT
- AlicenseNot gradedqualityCmaintenanceEnables driving a Quickshell QML app inside a headless compositor, with tools to screenshot windows, inspect their object trees, and read or write QML state.MIT
- AlicenseNot gradedqualityBmaintenanceEnables AI agents to automate and observe Linux desktop GUIs on KDE Plasma 6 Wayland through isolated virtual sessions or live desktop connections, providing 30 tools for input, clipboard, accessibility tree inspection, screenshots, and window management.2MIT
- AlicenseNot gradedqualityBmaintenanceEnables AI agents to inspect, automate, and test desktop GUI applications on Wayland through window/desktop streaming, semantic AT-SPI accessibility tree inspection, and boundary-clamped mouse, keyboard, drag, and scroll input injection. It also manages application process lifecycle, captures window frames, and registers Python GUI scripts as native Linux desktop launchers.25 PyPI1MIT