|
6 | 6 | _Notes on upcoming releases will be added here_ |
7 | 7 | <!-- END PLACEHOLDER - ADD NEW CHANGELOG ENTRIES BELOW THIS LINE --> |
8 | 8 |
|
| 9 | +_FastMCP alignment: new tools, prompts, and middleware (#15)_ |
| 10 | + |
9 | 11 | ### Breaking changes |
10 | 12 |
|
11 | | -- `search_panes` now returns a structured `SearchPanesResult` wrapper |
12 | | - instead of a bare `list[PaneContentMatch]`. The previous top-level |
13 | | - list is available as `result.matches`; new fields surface pagination |
14 | | - state (`truncated`, `truncated_panes`, `total_panes_matched`, |
15 | | - `offset`, `limit`) so agents can detect when the result set was |
16 | | - capped and re-request subsequent pages with a higher `offset`. |
17 | | - Migration for clients iterating the old shape: replace |
18 | | - `for m in search_panes(...)` with |
19 | | - `for m in search_panes(...).matches`. |
20 | | -- `fastmcp>=3.2.4` minimum (was `>=3.1.0`). Required for |
21 | | - `ReadonlyRetryMiddleware` to retry through the production tool |
22 | | - decorator path; under earlier fastmcp versions the middleware was |
23 | | - a no-op. |
| 13 | +- {tooliconl}`search-panes` now returns `SearchPanesResult` instead of |
| 14 | + `list[PaneContentMatch]`. Matches moved to `.matches`; new |
| 15 | + `truncated`, `truncated_panes`, `total_panes_matched`, `offset`, |
| 16 | + `limit` fields enable pagination. Migrate |
| 17 | + `for m in search_panes(...)` → `for m in search_panes(...).matches`. |
| 18 | +- Minimum `fastmcp>=3.2.4` (was `>=3.1.0`). Required for |
| 19 | + `ReadonlyRetryMiddleware` and per-parameter input-schema |
| 20 | + descriptions. |
24 | 21 |
|
25 | 22 | ### What's new |
26 | 23 |
|
27 | | -- `show_buffer` now bounds its response with `max_lines` (default 500, |
28 | | - matches `capture_pane`) and reports truncation via |
29 | | - `BufferContent.content_truncated` and |
30 | | - `BufferContent.content_truncated_lines`. A pathological |
31 | | - `load_buffer` staging can no longer dump unbounded content into the |
32 | | - model context on a single `show_buffer` call. Pass `max_lines=None` |
33 | | - for a full-buffer read. |
34 | | -- New tools: `list_servers`, `snapshot_pane`, `wait_for_text`, |
35 | | - `wait_for_content_change`, `wait_for_channel` / `signal_channel`, |
36 | | - buffer lifecycle (`load_buffer`, `paste_buffer`, `show_buffer`, |
37 | | - `delete_buffer`), hook introspection (`show_hook`, `show_hooks`), |
38 | | - plus pane / session / window helpers (`pipe_pane`, |
39 | | - `display_message`, copy-mode entry/exit, `paste_text`, |
40 | | - `select_pane`, `swap_pane`, `select_window`, `move_window`). |
41 | | -- Middleware stack: `TimingMiddleware`, `ErrorHandlingMiddleware`, |
42 | | - `AuditMiddleware` (digest-redacted argument summaries with |
43 | | - sensitive-payload protection), `SafetyMiddleware` (tier-gated |
| 24 | +**New tools** |
| 25 | + |
| 26 | +- Discovery: {tooliconl}`list-servers`. |
| 27 | +- Waits: {tooliconl}`wait-for-text`, |
| 28 | + {tooliconl}`wait-for-content-change`, {tooliconl}`wait-for-channel`, |
| 29 | + {tooliconl}`signal-channel`. All bounded, emit |
| 30 | + `ctx.report_progress` / `ctx.warning`, and propagate |
| 31 | + {exc}`asyncio.CancelledError` cleanly. |
| 32 | +- Buffers: {tooliconl}`load-buffer`, {tooliconl}`paste-buffer`, |
| 33 | + {tooliconl}`show-buffer`, {tooliconl}`delete-buffer`. |
| 34 | + Agent-namespaced as `libtmux_mcp_<uuid>_<name>` to prevent |
| 35 | + collisions; leaked buffers GC'd on graceful shutdown. |
| 36 | +- Hooks (read-only): {tooliconl}`show-hook`, {tooliconl}`show-hooks`. |
| 37 | +- Panes / windows: {tooliconl}`snapshot-pane`, {tooliconl}`pipe-pane`, |
| 38 | + {tooliconl}`display-message`, {tooliconl}`paste-text`, |
| 39 | + {tooliconl}`select-pane`, {tooliconl}`swap-pane`, |
| 40 | + {tooliconl}`select-window`, {tooliconl}`move-window`, |
| 41 | + {tooliconl}`enter-copy-mode`, {tooliconl}`exit-copy-mode`. |
| 42 | + |
| 43 | +**Prompt recipes** |
| 44 | + |
| 45 | +- Four prompts: `run_and_wait`, `diagnose_failing_pane`, |
| 46 | + `build_dev_workspace`, `interrupt_gracefully`. Set |
| 47 | + `LIBTMUX_MCP_PROMPTS_AS_TOOLS=1` to expose them as tools for |
| 48 | + tools-only MCP clients. |
| 49 | + |
| 50 | +**Middleware stack** |
| 51 | + |
| 52 | +- `TimingMiddleware`, `ErrorHandlingMiddleware`, `AuditMiddleware` |
| 53 | + (digest-redacted argument summaries), `SafetyMiddleware` (tier-gated |
44 | 54 | tool visibility), `ReadonlyRetryMiddleware` (transparent retry of |
45 | | - readonly tools on transient `LibTmuxException` — mutating tools |
46 | | - never retry), `TailPreservingResponseLimitingMiddleware` (caps |
47 | | - oversized output while keeping the tail). |
48 | | -- Four recipe prompts: `run_and_wait`, `diagnose_failing_pane`, |
49 | | - `build_dev_workspace`, `interrupt_gracefully`. Optional |
50 | | - `PromptsAsTools` transform (env-gated via |
51 | | - `LIBTMUX_MCP_PROMPTS_AS_TOOLS=1`) lets tools-only MCP clients |
52 | | - reach them. |
53 | | -- `wait_for_text` / `wait_for_content_change` emit |
54 | | - `ctx.report_progress` and `ctx.warning` notifications, and |
55 | | - propagate `asyncio.CancelledError` cleanly so MCP clients can |
56 | | - abort long waits. |
57 | | -- Best-effort lifespan-shutdown GC for leaked `libtmux_mcp_*` paste |
58 | | - buffers — agents that miss `delete_buffer` no longer pollute the |
59 | | - tmux server's buffer namespace across MCP restarts. |
60 | | -- Tool input schemas now carry per-parameter `description` fields |
61 | | - auto-extracted from existing NumPy-style docstrings (free with |
62 | | - the fastmcp 3.2.4 bump). |
| 55 | + readonly tools on transient {exc}`libtmux.exc.LibTmuxException`; |
| 56 | + mutating tools never retry), |
| 57 | + `TailPreservingResponseLimitingMiddleware` (trims oversized output |
| 58 | + from the head so the active prompt survives). |
| 59 | + |
| 60 | +**Bounded outputs** |
| 61 | + |
| 62 | +- {tooliconl}`capture-pane`, {tooliconl}`snapshot-pane`, |
| 63 | + {tooliconl}`show-buffer` accept `max_lines` (default 500) with |
| 64 | + tail-preserving truncation and typed `content_truncated` / |
| 65 | + `content_truncated_lines` signals. Pass `max_lines=None` to opt |
| 66 | + out. |
| 67 | + |
| 68 | +**Other** |
| 69 | + |
| 70 | +- Tool input schemas carry per-parameter `description` fields |
| 71 | + auto-extracted from NumPy-style docstrings. |
| 72 | +- Lifespan startup probe fails fast with {exc}`RuntimeError` if |
| 73 | + `tmux` is missing on `PATH`. |
| 74 | +- `SessionInfo.active_pane_id` surfaces the pane id returned by |
| 75 | + {tooliconl}`create-session`. |
63 | 76 |
|
64 | 77 | ### Fixes |
65 | 78 |
|
66 | | -- `build_dev_workspace` prompt recipe now uses the real tool parameter |
67 | | - names (`session_name=`, `pane_id=`, `direction=`) instead of |
68 | | - non-existent aliases. A new prompt-alignment test prevents future |
69 | | - drift between prompt text and tool signatures. The Linux-specific |
70 | | - `/var/log/syslog` example is replaced with an OS-neutral |
71 | | - `watch -n 1 date` default; callers can override via the new |
72 | | - `log_command` parameter. |
73 | | -- `build_dev_workspace` no longer instructs agents to wait for shell |
74 | | - prompts after launching screen-grabbing programs (`vim`, `watch`, |
75 | | - `tail -f`). Eliminates a class of false-positive timeouts on |
76 | | - agents following the recipe literally. |
77 | | -- macOS `TMUX_TMPDIR` self-kill guard: `_effective_socket_path` |
78 | | - queries tmux directly via `display-message #{socket_path}` before |
79 | | - falling back to env-based reconstruction; `_caller_is_on_server` |
80 | | - adds a basename-match fallback to close the residual launchd- |
| 79 | +- {tooliconl}`search-panes` neutralizes tmux format-string injection |
| 80 | + in the regex fast path. |
| 81 | +- macOS `TMUX_TMPDIR` self-kill guard: resolves the server socket via |
| 82 | + `tmux display-message #{socket_path}` before env-based |
| 83 | + reconstruction; basename-match fallback closes the launchd |
81 | 84 | divergence gap. |
82 | | -- `search_panes` neutralizes tmux format-string injection in the |
83 | | - regex fast path. |
84 | | -- `ReadonlyRetryMiddleware` retry warnings route through |
85 | | - `libtmux_mcp.retry` (was fastmcp's stock `fastmcp.retry`) so they |
86 | | - appear on the project's audit-stream namespace. |
| 85 | +- `build_dev_workspace` prompt uses the real tool parameter names |
| 86 | + (`session_name=`, `pane_id=`, `direction=`) and no longer waits for |
| 87 | + shell prompts after launching screen-grabbing programs (`vim`, |
| 88 | + `watch`, `tail -f`). New `log_command` parameter replaces the |
| 89 | + Linux-only `/var/log/syslog` default. |
| 90 | +- `ReadonlyRetryMiddleware` retry warnings log under |
| 91 | + `libtmux_mcp.retry`. |
87 | 92 |
|
88 | 93 | ### Documentation |
89 | 94 |
|
90 | | -- New per-tool docs pages: `buffers.md`, `hooks.md`, `waits.md`, |
91 | | - `tools/index.md`. Updated `panes.md` documents the |
92 | | - `SearchPanesResult` shape and migration from the previous flat |
93 | | - list. `docs/topics/safety.md` documents the macOS `TMUX_TMPDIR` |
94 | | - self-kill caveat, the audit log, `pipe_pane`, and |
95 | | - `set_environment`. |
| 95 | +- New per-tool pages: `buffers.md`, `hooks.md`, `waits.md`, |
| 96 | + `tools/index.md`. `panes.md` documents the `SearchPanesResult` |
| 97 | + migration. `safety.md` covers the macOS `TMUX_TMPDIR` caveat, the |
| 98 | + audit log, `pipe_pane`, and `set_environment`. |
96 | 99 |
|
97 | 100 | ## libtmux-mcp 0.1.0a1 (2026-04-13) |
98 | 101 |
|
|
0 commit comments