Skip to content

Commit e5926bd

Browse files
committed
mcp(refactor[server_tools]): centralize socket_name exemption
The contract "every registered tool accepts socket_name except list_servers" was encoded in two places: the prose of ``_BASE_INSTRUCTIONS`` (server.py) and a hardcoded set in ``test_registered_tools_accept_socket_name`` (tests/test_server.py). A second exempt tool would have required two synchronized edits. Lift the exemption to a module-level constant ``SOCKET_NAME_EXEMPT: frozenset[str]`` next to ``list_servers`` in ``server_tools.py``. The test imports it; the docstring near the constant tells future contributors to update the ``_BASE_INSTRUCTIONS`` prose alongside any addition. No behaviour change.
1 parent c2dd6ef commit e5926bd

2 files changed

Lines changed: 14 additions & 4 deletions

File tree

src/libtmux_mcp/tools/server_tools.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,16 @@ def _probe_server_by_path(socket_path: pathlib.Path) -> ServerInfo | None:
259259
)
260260

261261

262+
#: Tools that intentionally do NOT accept ``socket_name`` because they
263+
#: discover or enumerate sockets themselves rather than connecting to a
264+
#: known one. Read by ``test_registered_tools_accept_socket_name`` to
265+
#: enforce the agent-facing contract advertised in
266+
#: :data:`libtmux_mcp.server._BASE_INSTRUCTIONS`. When you add a new
267+
#: discovery-style tool, append it here AND update the prose in
268+
#: ``_BASE_INSTRUCTIONS`` so the two stay in lockstep.
269+
SOCKET_NAME_EXEMPT: frozenset[str] = frozenset({"list_servers"})
270+
271+
262272
@handle_tool_errors
263273
def list_servers(
264274
extra_socket_paths: list[str] | None = None,

tests/test_server.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -207,16 +207,15 @@ def test_registered_tools_accept_socket_name() -> None:
207207
from fastmcp.tools.function_tool import FunctionTool
208208

209209
from libtmux_mcp.tools import register_tools
210-
211-
socket_name_exempt = {"list_servers"}
210+
from libtmux_mcp.tools.server_tools import SOCKET_NAME_EXEMPT
212211

213212
mcp = FastMCP(name="socket-name-contract")
214213
register_tools(mcp)
215214

216215
tools = asyncio.run(mcp.list_tools())
217216
assert tools, "register_tools should have registered at least one tool"
218217
for tool in tools:
219-
if tool.name in socket_name_exempt:
218+
if tool.name in SOCKET_NAME_EXEMPT:
220219
continue
221220
assert isinstance(tool, FunctionTool), (
222221
f"Tool {tool.name!r} is not a FunctionTool; the registry "
@@ -226,7 +225,8 @@ def test_registered_tools_accept_socket_name() -> None:
226225
sig = inspect.signature(tool.fn)
227226
assert "socket_name" in sig.parameters, (
228227
f"Tool {tool.name!r} omits socket_name; either add it, "
229-
f"add to socket_name_exempt, or update _BASE_INSTRUCTIONS"
228+
f"add to server_tools.SOCKET_NAME_EXEMPT, or update "
229+
f"_BASE_INSTRUCTIONS"
230230
)
231231

232232

0 commit comments

Comments
 (0)