Skip to content

Commit 199404a

Browse files
committed
mcp(api[pane_tools]): drop respawn-pane resolver fallbacks
Trim respawn_pane's signature to the parameters it actually honors. The session_name / session_id / window_id fields existed only to mirror sibling pane tools' shared resolver shape, but the in-tool guard raised ToolError on any combination missing pane_id — so they were dead surface area broadcasting targeting flexibility to LLMs that did not exist. Validation now lives at the FastMCP schema boundary (pane_id: str, no default) instead of an in-tool ToolError raise. The two tests that exercised the runtime guard are deleted; one became a Python TypeError on the trimmed signature, the other passed a parameter that no longer exists. The remaining respawn_pane tests are unchanged — they all called with explicit pane_id from the start. Settled before respawn-pane reaches origin/main so no compat alias ships.
1 parent 6488a9a commit 199404a

3 files changed

Lines changed: 20 additions & 64 deletions

File tree

CHANGES

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,16 @@ _Notes on upcoming releases will be added here_
107107
branch. Settled before the tool reached ``origin/main`` so no
108108
compatibility alias is shipped — alignment is the load-bearing
109109
reason, not a fix to a previously released name.
110+
- {tooliconl}`respawn-pane` signature drops the optional
111+
``session_name`` / ``session_id`` / ``window_id`` resolver fallbacks
112+
that sibling pane tools accept. The runtime guard would have raised
113+
on any combination missing ``pane_id`` anyway (the tool requires
114+
explicit ``pane_id`` to prevent silent-kill-via-resolver), so the
115+
parameters were dead surface area broadcasting targeting flexibility
116+
to LLMs that did not exist. Validation now lives at the FastMCP
117+
schema boundary via ``pane_id: str`` rather than an in-tool
118+
``ToolError`` raise. Settled before the tool reached ``origin/main``
119+
so no compat alias ships.
110120

111121
### Refactor
112122

src/libtmux_mcp/tools/pane_tools/lifecycle.py

Lines changed: 10 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,7 @@ def kill_pane(
6060

6161
@handle_tool_errors
6262
def respawn_pane(
63-
pane_id: str | None = None,
64-
session_name: str | None = None,
65-
session_id: str | None = None,
66-
window_id: str | None = None,
63+
pane_id: str,
6764
kill: bool = True,
6865
shell: str | None = None,
6966
start_directory: str | None = None,
@@ -84,11 +81,13 @@ def respawn_pane(
8481
variables for the relaunched command (one ``-e KEY=VALUE`` flag
8582
per entry).
8683
87-
``pane_id`` is required — no fallback to ``_resolve_pane``'s
88-
"first pane in session/window" behaviour. Default ``kill=True``
89-
will terminate the resolved pane's process, so accidental targeting
90-
can silently kill an unrelated server. Resolve via ``list_panes``
91-
first.
84+
``pane_id`` is required — sibling pane tools accept a hierarchical
85+
fallback (``session_name`` / ``window_id`` / ``pane_index``) that
86+
resolves to "first pane in session/window", but combined with
87+
default ``kill=True`` that fallback could silently kill an
88+
unrelated process. The signature deliberately omits the resolver
89+
fields so the FastMCP schema rejects them at the framework
90+
boundary. Resolve via ``list_panes`` first.
9291
9392
Tip: call ``get_pane_info`` first if you need to capture
9493
``pane_current_command`` before respawn — the new process loses its
@@ -99,15 +98,7 @@ def respawn_pane(
9998
Parameters
10099
----------
101100
pane_id : str
102-
Pane ID (e.g. '%1'). Required — no fallback resolution.
103-
session_name : str, optional
104-
Accepted for backwards-compatibility with the ``_resolve_pane``
105-
signature shared across pane tools, but the explicit ``pane_id``
106-
guard above raises before this is consulted.
107-
session_id : str, optional
108-
See ``session_name``.
109-
window_id : str, optional
110-
See ``session_name``.
101+
Pane ID (e.g. '%1'). Required.
111102
kill : bool
112103
When True (default), pass ``-k`` to tmux so the current
113104
process is killed before respawning. When False, respawn
@@ -140,21 +131,8 @@ def respawn_pane(
140131
Serialized pane metadata after respawn. The pane_id is
141132
preserved; pane_pid reflects the new process.
142133
"""
143-
if pane_id is None:
144-
msg = (
145-
"respawn_pane requires an explicit pane_id (e.g. '%1') because "
146-
"default kill=True will terminate the resolved pane's process. "
147-
"Resolve the target via list_panes first."
148-
)
149-
raise ToolError(msg)
150134
server = _get_server(socket_name=socket_name)
151-
pane = _resolve_pane(
152-
server,
153-
pane_id=pane_id,
154-
session_name=session_name,
155-
session_id=session_id,
156-
window_id=window_id,
157-
)
135+
pane = _resolve_pane(server, pane_id=pane_id)
158136
caller = _get_caller_identity()
159137
if (
160138
caller is not None

tests/test_pane_tools.py

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -312,38 +312,6 @@ def test_respawn_pane_self_kill_guard(
312312
new_pane.kill()
313313

314314

315-
def test_respawn_pane_rejects_implicit_target(mcp_server: Server) -> None:
316-
"""respawn_pane refuses when no targeting parameter is supplied.
317-
318-
Without ``pane_id`` (or any other discriminator) ``_resolve_pane``
319-
falls back to the first pane of the first window of the first
320-
session — combined with default ``kill=True`` that could silently
321-
kill an unrelated server. The runtime guard requires explicit
322-
``pane_id``.
323-
"""
324-
with pytest.raises(ToolError, match="explicit pane_id"):
325-
respawn_pane(socket_name=mcp_server.socket_name)
326-
327-
328-
def test_respawn_pane_rejects_session_only_target(
329-
mcp_server: Server, mcp_session: Session
330-
) -> None:
331-
"""respawn_pane refuses ``session_name`` without ``pane_id``.
332-
333-
``session_name`` alone resolves to the first pane of the first
334-
window, which is not what the caller intends when recovering a
335-
wedged shell elsewhere in the session. The guard requires
336-
``pane_id`` regardless of which other targeting parameters are
337-
present.
338-
"""
339-
assert mcp_session.session_name is not None
340-
with pytest.raises(ToolError, match="explicit pane_id"):
341-
respawn_pane(
342-
session_name=mcp_session.session_name,
343-
socket_name=mcp_server.socket_name,
344-
)
345-
346-
347315
def test_respawn_pane_kill_false_on_dead_pane_succeeds(
348316
mcp_server: Server, mcp_session: Session
349317
) -> None:

0 commit comments

Comments
 (0)