Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
_Notes on upcoming releases will be added here_
<!-- END PLACEHOLDER - ADD NEW CHANGELOG ENTRIES BELOW THIS LINE -->

### Development

**Minimum `pytest>=9.1.0`**

The dev and test dependency groups now require pytest 9.1.0 or newer. (#83)

## libtmux-mcp 0.1.0a14 (2026-06-14)

libtmux-mcp 0.1.0a14 adds tier-aware tool batching. {tooliconl}`call-readonly-tools-batch`, {tooliconl}`call-mutating-tools-batch`, and {tooliconl}`call-destructive-tools-batch` run an ordered list of existing MCP tools in a single call and return a per-operation result for each, preserving every nested tool's own structured output. Each wrapper caps the safety tier of the calls it will make — regardless of the server's `LIBTMUX_SAFETY` tier — and `on_error` selects stop-at-first-failure or continue-and-report handling. Aggregate results stay within the server's response limit.
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ dev = [
# Testing
"typing-extensions; python_version < '3.11'",
"gp-libs",
"pytest",
"pytest>=9.1.0", # >=9.1.0 attaches caplog to non-propagating loggers; see test_middleware
"pytest-rerunfailures",
"pytest-mock",
"pytest-watcher",
Expand All @@ -91,7 +91,7 @@ docs = [
testing = [
"typing-extensions; python_version < '3.11'",
"gp-libs",
"pytest",
"pytest>=9.1.0", # >=9.1.0 attaches caplog to non-propagating loggers; see test_middleware
"pytest-rerunfailures",
"pytest-mock",
"pytest-watcher",
Expand Down
12 changes: 4 additions & 8 deletions tests/test_middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -448,16 +448,13 @@ def test_send_keys_batch_schema_validation_redacts_inputs(
secret: str,
expected_fragments: tuple[str, ...],
caplog: pytest.LogCaptureFixture,
monkeypatch: pytest.MonkeyPatch,
) -> None:
"""Malformed batch schema errors do not echo raw key payloads."""
from fastmcp import Client

from libtmux_mcp.server import build_mcp_server

assert test_id
for logger_name in ("fastmcp", "fastmcp.server.server", "fastmcp.errors"):
monkeypatch.setattr(logging.getLogger(logger_name), "propagate", True)

async def _call() -> t.Any:
async with Client(build_mcp_server()) as client:
Expand Down Expand Up @@ -1109,7 +1106,6 @@ def test_tool_error_result_logs_at_error_log_level(
expected_level: int,
message_fragment: str,
caplog: pytest.LogCaptureFixture,
monkeypatch: pytest.MonkeyPatch,
) -> None:
"""``_log_error`` honors ``log_level``: WARNING expected, ERROR not.

Expand All @@ -1127,10 +1123,10 @@ def test_tool_error_result_logs_at_error_log_level(
"""
from fastmcp import Client

# fastmcp's logger doesn't propagate to root (rich handler);
# re-enable propagation so caplog sees the records.
monkeypatch.setattr(logging.getLogger("fastmcp"), "propagate", True)

# fastmcp's logger is non-propagating (rich handler); pytest >=9.1.0
# attaches caplog directly to it. ``fastmcp.errors`` records reach
# caplog by propagating up to ``fastmcp`` — re-enabling propagation
# to root would then double-capture each emit (``fastmcp`` + root).
probe = _error_probe_server()

async def _call() -> None:
Expand Down
7 changes: 0 additions & 7 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -914,18 +914,13 @@ def test_map_exception_operator_faults_stay_at_error(raised: Exception) -> None:

def test_expected_tool_error_logs_warning_through_server(
caplog: pytest.LogCaptureFixture,
monkeypatch: pytest.MonkeyPatch,
) -> None:
"""Fastmcp's server-layer error log honors ``ExpectedToolError.log_level``.

Uses a minimal FastMCP instance (no middleware stack) so the
assertion isolates fastmcp's own ``Error calling tool`` record —
the project middleware's log behavior is covered in
``test_middleware.py``.

fastmcp sets ``propagate = False`` on its logger (it installs a
rich handler instead), which hides records from caplog's
root-logger handler — re-enable propagation for the test.
"""
import asyncio
import logging
Expand All @@ -934,8 +929,6 @@ def test_expected_tool_error_logs_warning_through_server(

from libtmux_mcp._utils import ExpectedToolError

monkeypatch.setattr(logging.getLogger("fastmcp"), "propagate", True)

probe = FastMCP(name="probe")

@probe.tool
Expand Down
4 changes: 2 additions & 2 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading