hypr-cua-mcp
Provides tools to control and inspect the Hyprland compositor: list windows and outputs, take screenshots, focus windows, launch applications, manage workspaces, toggle floating windows, send layout messages, and run raw dispatchers.
Provides tools to drive terminals in detached tmux sessions on an isolated hypr-cua socket, enabling background command execution and interaction without stealing window focus.
Provides computer-use capabilities on Wayland sessions: screenshots via grim, clipboard access via wl-clipboard, and absolute pointer/keyboard input via uinput, with coordinates mapped from screenshots to the compositor's global layout.
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., "@hypr-cua-mcpscreenshot my focused monitor and click the Firefox window"
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.
hypr-cua-mcp
A Hyprland/Wayland computer-use MCP server. It gives an MCP client (Claude Code, etc.) the ability to see your desktop, understand it via the Hyprland tree, and drive it with mouse + keyboard. It runs locally over stdio.
Why this exists: generic Linux computer-use servers are blind to the compositor —
they hand the model a giant multi-monitor screenshot and hope its pixel guesses
land. This server crops to one output (or one window) with grim, downscales to
the vision-API budget, and exposes hyprctl's tree so the model targets windows
by identity, not luck. Coordinates are always given in the screenshot the model
was just shown; the server maps them back to global layout pixels.
Built for Wayland/Hyprland: grim (capture) + a self-owned uinput device
(input) + hyprctl (tree/control) + wl-clipboard. It is the Wayland successor
to i3-computer-use-mcp (X11).
Tools
Window ids are Hyprland addresses (0x…) from list_windows — not integers.
See
Tool | What it does |
| Every Hyprland window: id (address), class, title, workspace, output, global rect, floating/focus/visibility |
| Active monitors: global geometry, scale, workspace |
| Screenshot one output (default: focused), downscaled to the API budget |
| Full-res crop of a single window (by address) — best for small text |
| Current global pointer location |
Act
Tool | What it does |
| Pointer actions; coords in a screenshot's pixel space (pass its |
| Keyboard input; with a |
| Exact text in/out of the |
Control Hyprland (needs a Lua config, see Requirements)
Tool | What it does |
| Focus a window by address (best-effort; see the follow_mouse caveat under Safety) |
| Launch an app via Hyprland's exec dispatcher |
| Switch to / move a window (by address) to a workspace |
| Toggle a window's floating state |
| Send a message to the active layout engine (e.g. |
| Raw Hyprland dispatcher escape hatch ( |
Work off-screen (no window, no focus stolen)
Tool | What it does |
| Drive terminals in detached tmux sessions on an isolated |
| Run a command as a background task and poll it ( |
| Drive tabs in a dedicated Chrome over the DevTools protocol, never your main profile (see Browser channel) |
Related MCP server: claude-workman
The coordinate model (the important bit)
The Hyprland tree uses global layout pixels spanning all monitors. Screenshots are cropped + downscaled, so every screenshot records a mapping frame (region origin + per-axis scale). Pointer tools accept coordinates in the screenshot's pixel space and translate them:
global_x = region.x + screenshot_x / scale_x
global_y = region.y + screenshot_y / scale_yPractically: take a screenshot (it returns a frame_id), then call
click(x, y, frame_id=…) with the pixel you see in that image. Pointer tools
reject a missing or stale frame_id rather than guessing against the wrong one.
The uinput pointer positions absolutely: global pixels map to the device's abs
axes via the layout extent read from hyprctl monitors (verified ~1px).
Requirements
Hyprland on Wayland. Developed and tested on Hyprland 0.56 across three monitors at scale 1.
A Lua config (
hyprland.lua, Hyprland 0.55+) for the window-control tools. These tools go throughhyprctl evaland Hyprland's Luahl.dispatchAPI:focus_window,launch,goto_workspace,move_window_to_workspace,set_floating,layout_message,run_dispatch, plustype_text/keywith acon_idandmove_mouse(follow=True). Everything else works with any config: screenshots, pointer and keyboard input, the window tree, the clipboard, and the tmux/task/browser channels.Read-write access to
/dev/uinputfor mouse and keyboard input (see below).Python 3.11+ and
uv.It runs inside your Hyprland session: it needs
WAYLAND_DISPLAY,XDG_RUNTIME_DIRandHYPRLAND_INSTANCE_SIGNATUREfrom the environment. MCP clients launched from your desktop pass these through.
Install the dependencies
The server shells out to a handful of CLI tools. screenshot needs grim, the
clipboard tools need wl-clipboard, and everything reads/drives Hyprland through
hyprctl; tmux and a Chromium/Chrome are only needed for the optional terminal
and browser channels.
Tool | Needed for | Arch | Debian/Ubuntu |
| tree + control (required) | bundled with | bundled with |
|
|
|
|
|
|
|
|
| runs the server + syncs Python deps |
| see astral.sh/uv |
|
|
|
|
Chromium / Chrome |
|
|
|
Arch, in one go (Hyprland assumed already installed):
sudo pacman -S grim wl-clipboard uv tmux chromiumInput uses a self-owned uinput device, so the process needs read-write on
/dev/uinput. It needs no root and no ydotoold. Run getfacl /dev/uinput. If it
lists your user with rw (typically through a uaccess udev rule), you're set. If
not, add a rule that grants access to the user logged in at the seat:
echo 'KERNEL=="uinput", SUBSYSTEM=="misc", TAG+="uaccess", OPTIONS+="static_node=uinput"' \
| sudo tee /etc/udev/rules.d/60-hypr-cua-uinput.rules
sudo udevadm control --reload && sudo udevadm triggerThe Python deps (mcp, pillow, evdev, websocket-client) are synced by uv
on first launch.
Miss one and the matching tool says so: calling screenshot without grim
returns "grim not found; install it …" straight to the model, so it can tell you
what to install instead of failing on a cryptic traceback.
Register with your MCP client
It's a local stdio server. The client starts it on demand, and you don't need a clone.
Claude Code:
claude mcp add hypr-cua -- uvx hypr-cua-mcpClients with an mcpServers JSON config (Cursor, Gemini CLI, Cline, …):
{
"mcpServers": {
"hypr-cua": {
"command": "uvx",
"args": ["hypr-cua-mcp"]
}
}
}Codex CLI (~/.codex/config.toml):
[mcp_servers.hypr-cua]
command = "uvx"
args = ["hypr-cua-mcp"]From a local checkout: the wrapper syncs deps on first launch and makes the browser channel attach-only (see Browser channel).
claude mcp add hypr-cua -- /path/to/hypr-computer-use-mcp/bin/hypr-cua-mcpReconnect your client (in Claude Code: /mcp → reconnect) to pick up the server.
Smoke-test the plumbing first (read-only, no clicks):
uvx hypr-cua-mcp --selftestBrowser channel
The cdp_* tools drive Chrome/Chromium tabs over the DevTools protocol, so
browser work needs no window focus. They never open your main profile. By default
they attach to a browser on port 9222. If nothing is listening there, they launch a
throwaway Chrome with a fresh temp profile.
For logins that persist, run a dedicated automation profile and make the server
attach-only with HYPR_CUA_CDP_AUTOLAUNCH=0. The checkout's bin/hypr-cua-mcp
wrapper sets that for you, and bin/hypr-cua-chrome starts the browser. With
uvx, the equivalent is:
chromium --user-data-dir="$HOME/.local/share/hypr-cua-chrome" \
--remote-debugging-port=9222 --remote-allow-origins=http://127.0.0.1:9222 \
--no-first-run --no-default-browser-checkLog in only to what you're happy to automate. Any local process that can reach the debug port can drive that profile.
Variable | Default | Effect |
|
| DevTools port to attach to (or launch on) |
|
|
|
| fresh temp dir | Profile directory for an auto-launched browser |
| first Chrome/Chromium on | Browser binary to auto-launch |
Set them in your client's server config. In Claude Code:
claude mcp add hypr-cua -e HYPR_CUA_CDP_AUTOLAUNCH=0 -- uvx hypr-cua-mcp. In JSON
configs, add an "env": {…} block next to command.
Safety
No auth — it's a local stdio server. Don't expose it over a socket.
There is no sandbox on Wayland: it drives your real desktop and can click anything you can — terminals with sudo, your password manager, Slack, email. Supervise live runs.
Emergency stop: kill the MCP server (its uinput device dies with it).
follow_mouse=1caveat: Hyprland keyboard focus tracks the pointer, sofocus_window(address)is best-effort — the reliable way to focus a window for typing is to click it via screenshot coordinates.type_text(con_id=…)raises rather than typing into an unverified window.Input is real uinput, so it resets the compositor idle timer naturally (no synthetic-input self-lock, unlike X11). See
docs/gotchas.md.
Known limitations
Typing is US-ASCII only:
type_textskips any other character. For anything else,write_clipboardand paste.Capture on monitors with scale ≠ 1 is untested, and the crop is likely off there.
The synthetic pointer doesn't hover-focus. Click to focus, or use
move_mouse(follow=True).cdp_click/cdp_typeinject JavaScript, so pages that insist on trusted input events won't react.
Details, plus the task runner's edge cases:
KNOWN-ISSUES.md.
Project status
Stable and maintained. hypr-cua-mcp does what it set out to do, so the commit log is quiet on purpose. Expect bug fixes, Hyprland-compatibility updates and dependency bumps, not a stream of new features. A quiet repo here means done, not abandoned. Issues and PRs still get answered.
Contributing
Bug reports and fixes are welcome; for anything bigger, open an issue first. See
CONTRIBUTING.md,
and AGENTS.md
for setup, tests, and the Hyprland conventions that bite.
Registry
On PyPI as hypr-cua-mcp and in the MCP
registry as com.smirnovlabs/hypr-cua-mcp (manifest:
server.json).
mcp-name: com.smirnovlabs/hypr-cua-mcp
License
MIT — see LICENSE.
This server cannot be deployed
Maintenance
Related MCP Connectors
Remote MCP server exposing your Node Command fleet (files, shell, processes, browser) to AI hosts.
MCP server for visual regression testing: triage a PR's UI diffs from your coding agent.
Official Browserless MCP server: browser automation, scraping, screenshots and PDFs for AI agents.
Eyes and hands on real Windows PCs — observe, click, type via Glasswarp API.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceMCP server for controlling Hyprland Wayland compositor: screen capture, mouse/keyboard injection, and automation via native Hyprland IPC and wlr protocols.MIT
- AlicenseNot gradedqualityCmaintenanceEnables MCP clients to control a Linux/X11 desktop like a human: see the screen, move the mouse, click UI elements via the accessibility tree, type text, and manage windows.MIT
- AlicenseNot gradedqualityBmaintenanceEnables MCP clients to inspect and control an Omarchy/Hyprland desktop by taking screenshots, focusing windows, moving/clicking the mouse, scrolling, typing text, and sending keyboard shortcuts.MIT
- AlicenseAqualityBmaintenanceEnables AI agents to control Hyprland desktops via MCP, including pointer/keyboard input, screenshots, launching apps, and natural-language window targeting using a local decision model.141MIT