A side-by-side look at the Hypruse and Kwin MCP MCP servers: transport, auth, tools, quality signals, and the config to install either one in Claude, Cursor, Windsurf or VS Code.
Verdict: choose Hypruse for os automation work as a local process; choose Kwin MCP for os automation as a local process. You can also run both side by side in one mcpServers block.
desktop, screenshot, zoom.session_start, session_connect, session_stop.Rows where the two servers differ are marked.
| Spec | K Kwin MCP | |
|---|---|---|
| Category | OS Automation | OS Automation |
| Quality signal | 57/100 · Good | 59/100 · Good |
| Install command | Confirmed | Confirmed |
| Transport | Local subprocess (stdio) | Local subprocess (stdio) |
| Auth | No auth required | No auth required |
| Pricing | Free | Free |
| Required env vars | None listed | None listed |
| Verified owner | Community listing | Community listing |
| GitHub stars | 36 | 71 |
| Directory activity | 1 views 0 installs 0 upvotes | 1 views 0 installs 0 upvotes |
| Tools | 15 | 29 |
| Full listing | View Hypruse | View Kwin MCP |
desktopOne-call semantic snapshot: monitors, workspaces, windows (address/class/title/geometry), active window, cursor, and layer surfaces (launchers, bars, notification popups) with a best-effort kind and geometry. A listed layer is one the compositor tracks, not one you can see: transparent and dormant…screenshotFocused monitor, one window by address (with grim 1.5+ on Hyprland 0.54+, even hidden or covered; metadata `visible` says whether the compositor draws it, `source` whether the pixels are the window's own or a screen crop, and a hidden capture may be stale), or `x,y,WxH` region; returns image + coor…zoomNative-resolution re-capture around an estimated point (optionally clamped to a window): the precision step before clicking small controls, same metadata contractuiRead a window's accessibility tree (AT-SPI, GTK/Qt apps that expose one) and return clickable elements by name with exact global coordinates, no screenshot; reports current values too (typed text, slider position, checkbox state); falls back to vision when an app exposes nothingmarksSet-of-Marks capture: the window screenshot with every accessible control drawn as a numbered mark, plus a JSON legend (role, name, current value, exact click point per number); needs ImageMagick for the drawing, degrades to the legend alone without itclick_uiClick a control by accessible NAME or by a `marks` number in one call: the coordinate comes from the tree. In the window you are in, the click goes through the real pointer (visible, same safety guarantees); in any other window, the control's accessibility action presses it in the background. An am…pointermove / click / drag / scroll (discrete wheel notches) in global coordinates. Your real cursor, so by default it is refused where the input would land on a window other than yourskeyboardType literal text (unicode-safe) or press app-level combos (`ctrl+shift+t`, `esc`, `F5`); an optional `window` address says where the keys go: the window you are in is focused and typed into, any other window gets them in the background. Compositor binds (`super+...`) go through `use_bind`, not herehyprSwitch workspace, focus/move/close windows, fullscreen, floating (pure IPC, milliseconds; `close_window` also waits up to 1s for the destroy event, so its result and `then=` observation reflect the close instead of racing it)launchStart an app, silently on the next of the agent's own workspaces unless you name one (or pass `background=false` for yours), block on its actual `openwindow` event, return its address; detects single-instance apps (browsers) whose window ignores exec rules and moves it to the requested workspacebindsThe user's own keybinds, decoded (`SUPER+Q`, action, description); the agent runs one with `use_binduse_bindExecute a keybind by combo (`SUPER+F`), running its bound action, so the agent drives the owner's own launchers and shortcuts. Not available for binds in a Lua `hyprland.lua`: those are anonymous closures Hyprland exposes no way to call, so `binds` shows them as action `lua` and `use_bind` says so…session_startStart 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_connectAttach 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_stopEnd 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_infoReport 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_launchLaunch 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_logReturn 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_captureCapture 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_queryReturn 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_actInvoke 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_listList 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_listList KWin virtual desktops in pager order (`id`, `name`) with the current one marked.window_focusRaise and activate exactly one window through KWin scripting (`workspace.activeWindow`). The result reports the window's observed state afterwards, or that it vanished.Paste either block (or both) into your client config, e.g. claude_desktop_config.json or ~/.cursor/mcp.json. We only show a config when the install command is confirmed.
{
"mcpServers": {
"hypruse": {
"command": "uvx",
"args": [
"hypruse"
]
}
}
}
{
"mcpServers": {
"kwin-mcp-2": {
"command": "uvx",
"args": [
"kwin-mcp"
]
}
}
}