Architecture¶
For contributors who need to understand the codebase internals.
Source layout¶
src/libtmux_mcp/
__init__.py # Entry point: main()
__main__.py # python -m libtmux_mcp support
server.py # FastMCP instance and configuration
_utils.py # Server caching, resolvers, serializers, error handling
models.py # Pydantic output models
middleware.py # Toolset, audit, and error-result middleware
tools/
batch_tools.py # call_read_tools_batch
server_tools.py # list_servers, list_sessions, create_session, kill_server, get_server_info
session_tools.py # list_windows, create_window, rename_session, kill_session
window_tools.py # list_panes, split_window, rename_window, kill_window, select_layout, resize_window
pane_tools.py # run_command, send_keys, send_keys_batch, capture_pane, capture_since, snapshot_pane, search_panes, wait_for_text
buffer_tools.py # load_buffer, paste_buffer, show_buffer, delete_buffer
hook_tools.py # show_hooks, show_hook
option_tools.py # show_option, set_option
env_tools.py # show_environment, set_environment
resources/
hierarchy.py # tmux:// URI resources
Request flow¶
Middleware wraps tool calls outermost-first (full ordering rationale in
the server.py stack comment):
MCP Client (Claude, Cursor, etc.)
→ stdio transport
→ FastMCP server (server.py)
→ TimingMiddleware (wall-time observer)
→ TailPreservingResponseLimitingMiddleware (response size backstop)
→ ToolErrorResultMiddleware (exceptions → is_error results)
→ AuditMiddleware (one log record per call)
→ ToolsetMiddleware (membership, fail-closed)
→ Tool function (tools/*.py)
→ libtmux Python objects
→ tmux binary (via subprocess)
The libtmux layer is the tmux object hierarchy:
Server, Session,
Window, and Pane.
Key design decisions¶
Tool registration¶
Each tool module defines a register(mcp) function that registers tools with metadata:
title— human-readable nameannotations— all four MCP hints (readOnlyHint,destructiveHint,idempotentHint,openWorldHint), never partialtags— the tool’s toolset, which drives filtering
Server caching¶
libtmux_mcp._utils maintains a thread-safe cache keyed by
(socket_name, socket_path, tmux_bin). Dead servers are evicted on
access via libtmux.Server.is_alive() checks.
Object resolution¶
Tools use resolver functions (_resolve_session(),
_resolve_window(), and
_resolve_pane()) that accept multiple
targeting parameters and resolve to the correct
libtmux object. Resolution follows a
priority chain: direct ID → name lookup → error.
Toolset middleware¶
ToolsetMiddleware implements
FastMCP’s middleware interface. It operates
as a secondary classification gate behind FastMCP’s native tag and name
visibility. Tools hidden by FastMCP return its unknown-tool error before
dispatch reaches this middleware.
Error handling¶
Three boundaries split the work:
Tool classification — the
handle_tool_errors()decorator wraps tool functions, mapping libtmux exceptions toExpectedToolError(agent-correctable: unknown ids, invalid arguments, transient tmux errors; logged at WARNING) or FastMCP tool errors (operator faults and unexpected bugs; logged at ERROR). The raise chains the original exception viafrom efor logs and debuggers.Schema classification — FastMCP validates tool arguments before tool code runs, so Pydantic validation failures never reach the decorator.
ToolErrorResultMiddlewareclassifies those schema-validation errors as expected, agent-correctable WARNINGs before converting them.Conversion —
ToolErrorResultMiddlewarecatches the exception once it has cleared the audit/toolset pair and returns an errorToolResultcarrying the message exactly as raised, plus a_metapayload (error_type,expected, and an optional agent-facingsuggestionfor recovery hints such as discovery tools or rejected-argument fixes).
Errors must stay exceptions through the audit/toolset pair so audit can detect failures before conversion in the outermost error layer. The response limiter sits outside conversion and may truncate large success or error results on the return path; its truncation path preserves is_error and _meta so oversized expected failures stay tool errors. Level policy lives in Logging.
References¶
libtmux — Core tmux Python library
FastMCP — MCP server framework
MCP Specification — Model Context Protocol