Skip to main content
Glama
i3wm-mcp

i3wm-mcp

by kuhyx

i3wm-mcp

A Model Context Protocol server for the i3 window manager (and, via the shared IPC, Sway). It lets an MCP client — Claude Code, Claude Desktop, the MCP Inspector — query and drive your i3/Sway session through a small set of well-described tools.

The tool definitions are deliberately tuned for a high Glama tool-definition-quality score: a consolidated, non-overlapping tool set, every parameter described, typed output schemas, and honest readOnlyHint/destructiveHint annotations.

Derived from caninja/i3wm-mcp (MIT). See ATTRIBUTION.md. This rewrite migrates the transport from the i3-msg CLI to the async i3ipc library, consolidates 43 tools into 13, and adds tests, CI, and output schemas.

Tools

Tool

Kind

What it does

get_tree

read

List windows from the layout tree, with filters.

get_focused

read

Details of the currently focused window.

list_workspaces

read

All active workspaces.

list_outputs

read

All display outputs (monitors).

get_config

read

Version + config + binding modes snapshot.

focus_window

mutate

Focus by direction / criteria / layer / parent-child.

move_window

mutate

Move a container to a direction / workspace / output / scratchpad / center.

manage_workspace

mutate

Switch / move-to / rename / navigate workspaces.

set_layout

mutate

Container layout, split orientation, border style.

toggle_window_state

mutate

Toggle floating / fullscreen / sticky.

exec_application

destructive

Launch a program via i3 exec (arbitrary code).

run_command

destructive

Raw i3/Sway command escape hatch (marks, gaps, bar, reload/restart).

kill_window

destructive

Close the focused or a matched window.

Rarely-used verbs (marks, i3-gaps, i3bar, scratchpad show/hide, reload, restart, and deliberately exit) are reached through run_command rather than dedicated tools, keeping the set small and distinct.

Related MCP server: FVWM3 Window Manager

Requirements

  • A running i3 (≥4.x) or Sway session.

  • Python ≥ 3.10.

The server locates the i3/Sway IPC socket from the environment, so it must be launched from within your graphical session (it needs DISPLAY, or SWAYSOCK/I3SOCK, in its environment). Clients that spawn it from inside the session — Claude Code, the MCP Inspector — inherit this automatically; a headless or systemd launch would need those variables passed explicitly.

Install

git clone https://github.com/kuhyx/i3wm-mcp
cd i3wm-mcp
python -m venv .venv
./.venv/bin/python -m pip install -e ".[dev]"

Run

./.venv/bin/python -m i3wm_mcp        # stdio transport

Register with Claude Code

claude mcp add i3wm -- /absolute/path/to/i3wm-mcp/.venv/bin/python -m i3wm_mcp

Inspect the tool definitions

npx @modelcontextprotocol/inspector ./.venv/bin/python -m i3wm_mcp

Develop

./.venv/bin/python -m pytest        # tests + 100% coverage gate
./.venv/bin/ruff check . && ./.venv/bin/ruff format --check .
./.venv/bin/mypy src
./.venv/bin/python scripts/rubric_check.py   # local TDQS proxy check

Safety

Read tools have no side effects. Mutation tools are reversible. The three destructive tools (exec_application, run_command, kill_window) can run arbitrary commands, close applications, or — via run_command — restart or exit the session; treat them accordingly and never feed them untrusted input.

License

MIT — see LICENSE.

Available Tools

12 tools
exec_applicationLaunch Application (i3 exec)A
Destructive

Launch an external program via i3's exec. DESTRUCTIVE / open-world: runs an arbitrary command line on the user's machine with their privileges — never pass untrusted input. Set no_startup_id=true for programs without startup-notification support (avoids a lingering busy cursor). For built-in i3 verbs use the dedicated tools instead — focus_window, move_window, set_layout — not this.

Inputs: command (required), no_startup_id. Returns: Roll-up returned by every mutating tool. ``success`` is the AND of every comman…

focus_windowFocus i3 WindowA
Idempotent

Move keyboard focus, selected by exactly one of: a direction; a specific window (class/title/instance/mark/con_id criteria); the parent/child container; the floating/tiling layer; or an output. Reversible. Supplying none or several selectors is rejected. To move the focused window instead of focusing, use move_window.

Inputs: mark, layer, title, con_id, +4 more. Returns: Roll-up returned by every mutating tool. ``success`` is the AND of every comman…

get_configInspect i3 ConfigurationA
Read-onlyIdempotent

Inspect i3/Sway configuration state in one call: version, whether the compositor is Sway, the loaded config path and (optionally) its full text, plus configured and active binding modes. Read-only. Set include_config_text=false to skip the potentially large config body. This is the only config-introspection tool; live layout comes from get_tree.

Inputs: include_config_text. Returns: A single-call snapshot of i3's version and configuration state.

get_treeQuery i3 Layout TreeA
Read-onlyIdempotent

List application windows from the i3/Sway layout tree, optionally filtered by class, title, instance, role, workspace, or floating/urgent state. Read-only. Returns matched leaf windows with their ids, marks and location; use a returned id as con_id in focus_window/move_window/kill_window. For only the active window use get_focused; for a flat workspace summary use list_workspaces; for monitors use list_outputs. Capped at 200 windows (truncated flags the cap).

Inputs: role, title, urgent, floating, +3 more. Returns: Windows matched from the layout tree, plus a match count.

kill_windowClose i3 WindowA
Destructive

Close a window — the focused one, or one matched by class/title/instance/mark/con_id. DESTRUCTIVE: the target application is asked to quit and may discard unsaved work; there is no undo, and matching several windows closes all of them. To move a window out of the way instead of closing it, use move_window (e.g. to the scratchpad).

Inputs: mark, title, con_id, instance, +1 more. Returns: Roll-up returned by every mutating tool. ``success`` is the AND of every comman…

list_outputsList i3 OutputsA
Read-onlyIdempotent

List display outputs (monitors): name, active/primary state, current workspace and geometry. Read-only. Use before moving windows or workspaces between monitors with move_window or manage_workspace; for the workspaces themselves use list_workspaces.

Inputs: no named parameters. Returns: All display outputs (monitors).

list_workspacesList i3 WorkspacesA
Read-onlyIdempotent

List all active workspaces with number, name, visibility, focus, urgency and owning output. Read-only. Use this for navigation decisions; for the windows on a workspace use get_tree with a workspace filter, and for monitors use list_outputs.

Inputs: no named parameters. Returns: All active workspaces.

manage_workspaceManage i3 WorkspaceA

Act on workspaces: switch to one, move_container_to one (optionally following), rename one, or navigate next/prev/back_and_forth. Reversible. action selects the operation and determines which of name/new_name/direction are required. To move a single window rather than switch, use move_window; to list workspaces use list_workspaces.

Inputs: action (required), name, follow, new_name, +1 more. Returns: Roll-up returned by every mutating tool. ``success`` is the AND of every comman…

move_windowMove i3 WindowA

Move the focused container (or one matched by class/title/instance/mark/con_id) to exactly one destination: a direction (with pixel amount), a workspace, an output, the scratchpad, or a screen position (center). Reversible; returns per-command success. To change focus rather than move, use focus_window; to move whole workspaces between monitors, use manage_workspace.

Inputs: mark, title, con_id, instance, +7 more. Returns: Roll-up returned by every mutating tool. ``success`` is the AND of every comman…

run_commandRun Raw i3 CommandA
Destructive

Run a raw i3/Sway command string — the escape hatch for operations without a dedicated tool: marks (mark/unmark), i3-gaps (gaps ...), i3bar (bar ...), scratchpad show/hide, and reload/restart. DESTRUCTIVE / open-world: the payload is unrestricted and CAN include kill, restart, reload, or exit (which logs the user out), so validate before sending. Prefer the typed tools (focus_window, move_window, set_layout, ...) whenever one fits.

Inputs: command (required). Returns: Roll-up returned by every mutating tool. ``success`` is the AND of every comman…

set_layoutSet i3 LayoutA

Set how the focused container arranges children: container layout (stacking/tabbed/split*), the split orientation for the next window, and/or the border style. Reversible. Provide at least one of layout/split/border; border_width applies only to the pixel border. For floating/fullscreen/sticky state use toggle_window_state.

Inputs: split, border, layout, border_width. Returns: Roll-up returned by every mutating tool. ``success`` is the AND of every comman…

toggle_window_stateToggle i3 Window StateA

Enable, disable, or toggle one boolean window state — floating, fullscreen, or sticky — on the focused window. Reversible. Omit enable to toggle, or set it true/false to force. fullscreen_scope picks per-output ('normal') vs across-all ('global'). For layout/border changes use set_layout.

Inputs: state (required), enable, fullscreen_scope. Returns: Roll-up returned by every mutating tool. ``success`` is the AND of every comman…

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A4.7/5.0

    Scored across 12 tools

    Disambiguation5/5

    Each tool has a distinct purpose: inspecting state (get_tree/list_workspaces/list_outputs/get_config), navigating/focusing (focus_window), moving (move_window/kill_window), workspace management (manage_workspace), layout changes (set_layout/toggle_window_state), and execution (exec_application/run_command). Overlap is minimal and well-documented.

    Naming Consistency5/5

    All tool names follow a consistent verb_noun pattern using snake_case, e.g., get_tree, list_workspaces, focus_window, toggle_window_state. No mixing of conventions.

    Tool Count5/5

    With 12 tools, the scope is well-balanced for an i3/Sway MCP server. It covers essential operations without being bloated or sparse.

    Completeness4/5

    The tool set covers most common i3 actions including tree queries, focus, move, workspace management, layout changes, and execution. Minor gaps exist for operations like marks and scratchpad control, but these are accessible via run_command.

    Maintenance

    ActivityMaintained
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • F
      license
      Not graded
      quality
      Not graded
      maintenance
      Enables interaction with the FVWM3 window manager for configuration generation, window management, and debugging. Provides access to config files, runtime state, and control tools for managing desktops, monitors, and tiling operations.
      -
    • A
      license
      A
      quality
      D
      maintenance
      Allows AI assistants to create, manage, and interact with tmux sessions, windows, and panes programmatically.
      19
      19 PyPI
      MIT
    • F
      license
      Not graded
      quality
      D
      maintenance
      Exposes Sway window manager commands as native tools for Claude Code, enabling window management, workspace navigation, and display configuration through natural language.
      -