hyprland-mcp
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| HYPRLAND_INSTANCE_SIGNATURE | No | The Hyprland instance signature, needed if running outside the Hyprland session. Defaults to auto-detected from environment. |
Capabilities
Features and capabilities supported by this server
| Capability | Details |
|---|---|
| tools | {
"listChanged": true
} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| list_windowsA | List all open windows (clients) with their address, class, title, workspace, position, size, and floating/fullscreen state. |
| get_active_windowB | Get the currently focused/active window. |
| focus_windowA | Focus a window by its unique address (from list_windows) or by class/title regex selector (e.g. 'class:^(firefox)$'). |
| close_windowA | Close a window by address or selector. Sends the same signal as clicking the close button (not force-kill). |
| kill_active_windowA | Force-kill the currently focused window (hl.dsp.window.kill(), the 0.55+ equivalent of the old killactive dispatcher). |
| move_window_to_workspaceB | Move a window to a different workspace. |
| move_active_windowC | Move the active window by a pixel delta, or to an absolute position. |
| resize_active_windowA | Resize the active window by a pixel delta, or to an exact size. |
| toggle_floatingA | Toggle floating mode for a window (or the active one if no target given). |
| toggle_fullscreenC | Toggle fullscreen for the active window. |
| pin_windowA | Pin the active window so it stays visible across all workspaces. Only works on FLOATING windows — Hyprland rejects pinning a tiled window with a 'Window does not qualify to be pinned' warning (not an error; the call succeeds but has no effect). Use toggle_floating first if this warns and the window should stay pinned. |
| list_workspacesA | List all workspaces across all monitors, including window counts and last-focused window. |
| get_active_workspaceA | Get the currently active workspace on the focused monitor. |
| switch_workspaceA | Switch the focused monitor to a given workspace. |
| move_workspace_to_monitorB | Move an entire workspace (and all its windows) to a different monitor. |
| rename_workspaceC | Rename a workspace by id. |
| toggle_special_workspaceA | Show or hide a named special workspace (Hyprland's version of a scratchpad) on the current monitor. To put a window INTO a special workspace in the first place, use move_window_to_workspace with workspace set to 'special:' — this tool only toggles its visibility. Confirmed: hl.dsp.workspace.toggle_special('name') (bare string arg, not a table). |
| list_monitorsA | List all connected monitors with resolution, position, scale, refresh rate, and active workspace. |
| focus_monitorA | Move focus to a given monitor. NOTE: unlike window/workspace dispatchers, the 0.55+ Lua path for monitor focus isn't documented anywhere confirmable at authoring time — this guesses hl.dsp.focus() (the same top-level dispatcher used for window focus) also accepts a |
| set_monitor_configA | Apply a monitor config via 'hyprctl keyword monitor', same syntax as hyprland.conf's monitor= line. Useful for resolution/position/scale/enable-disable changes. Unlike 'dispatch', 'keyword' is a config-value setter rather than the dispatch mechanism that changed in 0.55, so this should be unaffected — but if it errors on your version, the Lua equivalent is likely hl.config({ monitor = { ... } }), which isn't reachable through this tool's escape hatches (they're dispatch-only) and would need a small code change. |
| hyprland_dispatchA | Escape hatch: run any Hyprland dispatcher not covered by a dedicated tool. As of Hyprland 0.55, |
| hyprctl_rawA | Escape hatch: run any raw hyprctl subcommand that ISN'T 'dispatch' — e.g. 'reload', 'version', 'splash', 'layers', 'devices', 'systeminfo'. These take plain argv, not Lua expressions (only 'dispatch' changed syntax in 0.55). Pass '-j' yourself as the first arg if you want JSON output. |
| get_config_optionA | Read the current value of a Hyprland config option, e.g. 'general:gaps_in' or 'decoration:rounding'. |
| set_config_optionA | Set a Hyprland config option at runtime via 'hyprctl keyword'. This does NOT persist to hyprland.conf — it's a live, in-memory override until reload. Good for experimenting before writing the value into the actual config file. |
| reload_hyprland_configA | Reload hyprland.conf (equivalent to 'hyprctl reload'). |
| get_hyprland_versionA | Get the running Hyprland version, commit, and build flags. |
| list_keybindsA | List all configured keybindings, including modmask, key, dispatcher, and argument. |
| send_notificationA | Send a desktop notification via notify-send (requires a notification daemon like mako or dunst running). If notify-send is unavailable, falls back to Hyprland's built-in hl.notification.create — but a real-session test confirmed this fallback produces NO VISIBLE notification even though the underlying call succeeds without error (likely a Hyprland 0.55.4 rendering gap, not a bug in this call). Practically: if notify-send isn't installed, treat this tool as non-functional and tell the user to install a real notification daemon rather than assuming the fallback message means something appeared. |
| dismiss_notificationsB | Dismiss all currently visible Hyprland built-in on-screen notifications. UNVERIFIABLE as of this writing: send_notification's fallback was confirmed to produce no visible notification in the first place, so there was nothing on a real session to confirm this actually clears. The underlying call (hl.notification.get() + :dismiss() per handle) runs without erroring, but that's equally consistent with 'it worked' and 'it iterated over nothing'. Given send_notification's fallback is effectively non-functional right now, this tool likely has nothing to do in practice either. |
| take_screenshotA | Capture a screenshot with grim. Captures the whole layout (all monitors) by default, or a single output if 'monitor' is given. Requires grim to be installed. |
| take_region_screenshotA | Interactively capture a screen region: opens slurp so you can click-drag a selection on your actual screen right now, then captures it with grim. This blocks until a region is selected (Escape cancels). Requires grim and slurp. |
| screenshot_active_windowA | Screenshot just the currently focused window, cropped via grim -g using the window's box from hyprctl activewindow. |
| toggle_launcherA | Open Hyprland's first-party app launcher/picker (hyprlauncher), or close it if it's already open. hyprlauncher runs as a self-managing daemon: the first call starts the daemon and shows its window; every call after that just toggles the window, near-instantly, without restarting the daemon. Use this for 'open the launcher' / 'let me search for an app' style requests. |
| prewarm_launcher_daemonA | Start the hyprlauncher daemon in the background WITHOUT opening its window (hyprlauncher -d). Useful once at session start so the first real toggle_launcher call is instant rather than paying daemon-startup cost. Safe to call even if the daemon is already running. |
| tag_windowA | Add, remove, or toggle a static tag on a window. Tags are used for grouping windows and can be matched in window rules (e.g. hl.window_rule({ match = { tag = 'code' }, ... })). Confirmed syntax: hl.dsp.window.tag({ tag = '+code' }) adds, '-code' removes, 'code' (no prefix) toggles. |
| toggle_groupA | Make a group from the active window (like i3wm's 'tabbed' container), or ungroup it if it's already grouped. Confirmed: hl.dsp.group.toggle(). |
| group_cycleA | Cycle to the next or previous window within the active group. Confirmed: hl.dsp.group.next() and hl.dsp.group.prev(). |
| toggle_group_lockA | Lock/unlock the active group so new windows can't (or can) join it automatically. Confirmed path: hl.dsp.group.lock(); exact toggle-vs-explicit-state argument shape isn't documented anywhere I could confirm, so this calls it with no arguments (assumed toggle, matching the pattern of group.toggle()). If it doesn't behave as expected, try hyprland_dispatch with a raw_expression like "hl.dsp.group.lock({ action = 'toggle' })" instead. |
| deny_window_from_groupB | Prevent a window from being added to a group, or from becoming a group itself. NOTE: this is documented as existing ('the window.deny_from_group dispatcher') but its Lua path is a best-effort guess (hl.dsp.window.deny_from_group) by analogy with the other window.* dispatchers — not directly confirmed. Verify before relying on it. |
| move_cursorB | Move the cursor to absolute screen coordinates. Confirmed: hl.dsp.cursor.move({ x, y }). |
| move_cursor_to_cornerB | Move the cursor to one of a window's four corners. Confirmed: hl.dsp.cursor.move_to_corner({ corner, window? }). |
| set_sunset_temperatureA | Set hyprsunset's color temperature in Kelvin (lower = warmer/more orange, e.g. 2500-4000 for a strong blue-light filter; higher, e.g. 6500, is closer to neutral daylight). This override is temporary and will be replaced once hyprsunset's next scheduled profile activates. |
| disable_sunset_filterA | Disable hyprsunset's blue-light filter entirely, returning color temperature to normal (hyprctl hyprsunset identity). Temporary — reverts at the next scheduled profile. |
| set_sunset_gammaA | Set or adjust hyprsunset's gamma (perceived brightness). Absolute percent (e.g. '50' = 50%) or a relative delta with an explicit sign (e.g. '+10', '-10'). Max is 150% by default, raisable via max-gamma in hyprsunset.conf, hard-capped at 200%. Using gamma for brightness degrades color accuracy — prefer real monitor brightness control (DDC/backlight) if available. |
| reset_sunsetA | Reset hyprsunset override(s) back to whatever the current time-based profile specifies. NOTE: a Hyprland forum bug report (hyprsunset v0.3.3) found this specific command returns 'invalid command' while temperature/identity/gamma work fine — if you hit that, there's no clean workaround short of manually calling set_sunset_temperature/set_sunset_gamma/disable_sunset_filter with the values your profile should have at the current time. |
| get_sunset_profileA | Print hyprsunset's currently active time-based profile. NOTE: the same forum bug report affecting reset_sunset also reported this command as broken on hyprsunset v0.3.3 — if it errors, that's a known upstream issue, not a wiring problem here. |
| set_wallpaperA | Set the wallpaper for a monitor (or the fallback for all monitors that don't have one specifically assigned, if monitor is omitted). Loads the image on demand — no separate preload step needed on current hyprpaper versions. |
| list_active_wallpapersA | List the currently active wallpaper path for each monitor. |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/keanehatescoding/hyprland-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server