Skip to content

Commit e4d23b5

Browse files
committed
mcp(fix[window_tools,session_tools]): Validate direction parameters
why: split_window silently ignored invalid directions (fell to default), create_window raised KeyError surfaced as "Unexpected error". what: - split_window: check _DIRECTION_MAP.get() result, raise ToolError if None - create_window: use .get() with explicit ToolError on invalid direction - Add tests for invalid direction in both tools
1 parent 29f3ad8 commit e4d23b5

File tree

4 files changed

+46
-1
lines changed

4 files changed

+46
-1
lines changed

src/libtmux/mcp/tools/session_tools.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,14 @@ def create_window(
9393
"before": WindowDirection.Before,
9494
"after": WindowDirection.After,
9595
}
96-
kwargs["direction"] = direction_map[direction.lower()]
96+
resolved = direction_map.get(direction.lower())
97+
if resolved is None:
98+
from fastmcp.exceptions import ToolError
99+
100+
valid = ", ".join(sorted(direction_map))
101+
msg = f"Invalid direction: {direction!r}. Valid: {valid}"
102+
raise ToolError(msg)
103+
kwargs["direction"] = resolved
97104
window = session.new_window(**kwargs)
98105
return json.dumps(_serialize_window(window))
99106

src/libtmux/mcp/tools/window_tools.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,12 @@ def split_window(
121121
pane_dir: PaneDirection | None = None
122122
if direction is not None:
123123
pane_dir = _DIRECTION_MAP.get(direction.lower())
124+
if pane_dir is None:
125+
from fastmcp.exceptions import ToolError
126+
127+
valid = ", ".join(sorted(_DIRECTION_MAP))
128+
msg = f"Invalid direction: {direction!r}. Valid: {valid}"
129+
raise ToolError(msg)
124130

125131
new_pane = window.split(
126132
direction=pane_dir,

tests/mcp/test_session_tools.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
import json
66
import typing as t
77

8+
import pytest
9+
from fastmcp.exceptions import ToolError
10+
811
from libtmux.mcp.tools.session_tools import (
912
create_window,
1013
kill_session,
@@ -50,6 +53,19 @@ def test_create_window(mcp_server: Server, mcp_session: Session) -> None:
5053
assert data["window_name"] == "mcp_test_win"
5154

5255

56+
def test_create_window_invalid_direction(
57+
mcp_server: Server, mcp_session: Session
58+
) -> None:
59+
"""create_window raises ToolError on invalid direction."""
60+
with pytest.raises(ToolError, match="Invalid direction"):
61+
create_window(
62+
session_name=mcp_session.session_name,
63+
window_name="bad_dir",
64+
direction="sideways",
65+
socket_name=mcp_server.socket_name,
66+
)
67+
68+
5369
def test_rename_session(mcp_server: Server, mcp_session: Session) -> None:
5470
"""rename_session renames an existing session."""
5571
original_name = mcp_session.session_name

tests/mcp/test_window_tools.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
import json
66
import typing as t
77

8+
import pytest
9+
from fastmcp.exceptions import ToolError
10+
811
from libtmux.mcp.tools.window_tools import (
912
kill_window,
1013
list_panes,
@@ -57,6 +60,19 @@ def test_split_window_with_direction(mcp_server: Server, mcp_session: Session) -
5760
assert "pane_id" in data
5861

5962

63+
def test_split_window_invalid_direction(
64+
mcp_server: Server, mcp_session: Session
65+
) -> None:
66+
"""split_window raises ToolError on invalid direction."""
67+
window = mcp_session.active_window
68+
with pytest.raises(ToolError, match="Invalid direction"):
69+
split_window(
70+
window_id=window.window_id,
71+
direction="diagonal",
72+
socket_name=mcp_server.socket_name,
73+
)
74+
75+
6076
def test_rename_window(mcp_server: Server, mcp_session: Session) -> None:
6177
"""rename_window renames a window."""
6278
window = mcp_session.active_window

0 commit comments

Comments
 (0)