Repository navigation
mcp(feat[teardown]): Ask before every kill tool - #154
Merged
Merged
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
why: A nested tool that returns an InputRequiredResult, the 2026-07-28 way to ask the user a question, came back from call_read_tools_batch as a row with success=true and empty content. The question never reached the user and the agent was told the call succeeded. No inspect tool asks today; the first one that does would hit it. what: - Raise ExpectedToolError in _ensure_tool_result for fastmcp's InputRequiredToolResult, so the row fails and names the tool to call directly; on_error="continue" keeps the other rows running - Test the batch refusal, and pin that the tail-preserving response limiter returns a question untouched Fixes #150
why: kill_session's confirmation (elicitation on both protocol eras
plus a restart-proof target identity) lived in session_tools.py, and
the other kill tools need the same flow.
what:
- Move the confirmation into _utils.py as _ask_before_teardown, which
returns the 2026-07-28 question, raises on a decline or a changed
target, and lets the kill proceed when the client cannot ask
- Generalize the identity to _tmux_identity(target, id_format):
#{pid}:#{start_time} plus the object's id format, or nothing for
the server itself
- kill_session calls the helper; its behaviour and tests are unchanged
why: Only kill_session asked the user before killing. kill_window,
kill_pane and kill_server end processes just as surely: every pane
in a window, the process in a pane, every session on a server.
what:
- Make kill_window, kill_pane and kill_server async and confirm through
_ask_before_teardown; each question names what would be lost: the
window's name, the pane's running command, the server's socket and
session count
- Identify the target as #{pid}:#{start_time} plus #{window_id} or
#{pane_id}, or bare for the server; display-message -p needs no
attached client, so kill_server carries one too
- Clients without elicitation kill without asking, as before; the wire
schema is unchanged, as the tool-surface snapshot confirms
- Test accept, decline and no capability for each tool on both eras,
and await the tools in the existing direct-call tests
- Note the confirmation on the kill-window, kill-pane and kill-server
doc pages
Fixes #152
why: The safe-behaviour sample prompt named only kill_session and kill_server, and now that every kill tool asks through elicitation, an agent following it makes the user confirm twice in clients that support elicitation. what: - Name all four kill tools in the sample prompt and keep the instruction for clients without elicitation - Add a note that the last sentence can be dropped where the client supports elicitation - Widen the unreleased CHANGES entry from kill_session to every kill tool Fixes #153
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #149, which adds the
kill_sessionconfirmation this extends. Merge #149 first.Fixes #150, fixes #152, fixes #153.
Summary
kill_window,kill_paneandkill_server.call_read_tools_batchrow whose tool asks for user input.Changes by area
Teardown confirmation
src/libtmux_mcp/_utils.py:_confirm_teardownholds the two-era elicitation flow, and_ask_before_teardownadds the decline error and the identity recheck._tmux_identityreads#{pid}:#{start_time}:<id>from any tmux object.src/libtmux_mcp/tools/window_tools.py,src/libtmux_mcp/tools/pane_tools/lifecycle.py,src/libtmux_mcp/tools/server_tools.py:kill_window,kill_paneandkill_serverbecome async and ask through the helper.src/libtmux_mcp/tools/session_tools.py:kill_sessionuses the same helper.Batch
src/libtmux_mcp/tools/batch_tools.py:_ensure_tool_resultraises a row error for fastmcp'sInputRequiredToolResultand tells the agent to call the tool directly.Docs
docs/tools/window/kill-window.md,docs/tools/pane/kill-pane.md,docs/tools/server/kill-server.md: a Confirmation note on each page.docs/topics/prompting.md: the sample prompt names all four kill tools. A note says the confirm-first sentence can be dropped in clients that ask through elicitation.CHANGES: the kill-confirmation entry covers all four tools.Design decisions
ctxand hides it from the schema, and the tool-surface snapshot is unchanged.kill_serverhas no object id to compare, so its identity is the server's#{pid}:#{start_time}. A server restarted on the same socket during the question gets a new pid and is left alone.call_read_tools_batchadmits onlyinspecttools, none of which ask today, so the guard is for the next one that does.ResponseLimitingMiddlewarereturns anInputRequiredToolResultuntouched, and our subclass rebuilds only results it trimmed.Test plan
kill_window,kill_paneandkill_serveraccept, decline, and client-cannot-ask cases on 2025-11-25 and 2026-07-28 (test_kill_tools_ask_before_killing)test_kill_session_confirmation)test_batch_refuses_a_tool_that_asks_for_input)test_response_limiter_passes_a_question_through)test_tool_surface_matches_snapshot)ruff format --check,ruff check, andmypy .just build-docswith no warnings