Summary
MCP has deprecated the protocol-level Logging capability. wait_for_text is the only tool in this server that uses it, via three _maybe_log calls that emit notifications/message. This server is stdio-only, so the specified migration path — log to stderr — is a direct swap onto the stdlib loggers the codebase already uses everywhere else.
Upstream status
MCP adopted a feature lifecycle and deprecation policy in SEP-2596, which defines Active/Deprecated/Removed states, a twelve-month minimum deprecation window, and a canonical deprecated features registry.
SEP-2577 (merged 2026-05-15) deprecates Roots, Sampling, and Logging, effective with the 2026-07-28 revision. The registry gives Logging's migration path as "Log to stderr for stdio transports; use OpenTelemetry for observability", and the rationale as "overlaps with stderr and OpenTelemetry". Earliest removal is the first revision released on or after 2027-07-28.
Separately, SEP-2575 removes logging/setLevel in the same revision and moves log level to a per-request _meta key, with a hard constraint: "servers MUST NOT emit notifications/message for requests that did not include this field". Under 2026-07-28 the current unconditional emissions are therefore not merely deprecated but non-conforming.
This is not urgent — the pinned SDK negotiates 2025-11-25 (mcp.types.LATEST_PROTOCOL_VERSION), where Logging is still Active — but the migration is small and there is no reason to carry it.
Affected code
All three call sites are in wait_for_text:
| Site |
What it reports |
Already reaches the agent? |
wait.py#L434 |
invalid regex |
Yes — identical text is raised as ExpectedToolError on the next line |
wait.py#L730 |
history-limit trim-risk band |
No |
wait.py#L838 |
no match before timeout |
Yes — WaitForTextResult.outcome == "timeout" plus elapsed |
The helper is _maybe_log at wait.py#L124-L143; its own docstring names the wire method at wait.py#L133.
Why stderr rather than a result field
The two tests covering this behavior state the intent: the warnings exist "so MCP client log panels record the cause independent of the tool result" (test_pane_tools.py#L3997-L3999) and for "human log readers" (test_pane_tools.py#L4040-L4044). That is an operator/observability role, which is precisely what the spec redirects to stderr — and under stdio, MCP clients surface server stderr in those same log panels.
Promoting them to WaitForTextResult fields instead would contradict that model's stated design constraint: "Field count is load-bearing. outputSchema is re-sent on every request of every session, so a field that no agent branches on is a permanent tax." (models.py#L243-L246). Two of the three warnings are already redundant with the tool result or the raised error, and the third is documented as a caveat in the tool docstring at wait.py#L555-L561, where the agent meets it at tool-selection time.
Proposed change
- Replace
_maybe_log with stderr logging through the existing module logger; drop the transport-closed suppression, which has no analogue for stdlib logging.
- Drop the now-unused
ctx parameter from _compile_patterns.
- Reword the
ctx.warning reference in the wait_for_text docstring at wait.py#L559.
- Rewrite the two tests to assert on captured log records rather than a recording context stub.
- Add a
MIGRATION note: MCP clients that displayed these three warnings in a log panel sourced from notifications/message will now receive them on stderr.
ctx.report_progress at wait.py#L114 is not affected. Progress notifications are not deprecated, and the 2026-07-28 draft explicitly keeps them flowing on the response stream of the request they relate to.
Out of scope
Checked and unaffected: no Roots, no Sampling, no includeContext, no HTTP+SSE transport, and no Dynamic Client Registration anywhere in src/ — the server is stdio-only at server.py#L468.
Two adjacent observations, deliberately not bundled here:
_meta keys minted at middleware.py#L313-L343 (error_type, expected, suggestion) are bare names. That is legal — the prefix is optional — but reverse-DNS namespacing is the spec's SHOULD, and bare names risk collision with future MCP-reserved keys.
- SEP-2596 obliges Tier 1 SDKs to emit a runtime
DeprecationWarning when a deprecated feature is exercised. pyproject.toml currently silences DeprecationWarning for libtmux.*, libtmux_mcp.*, and tests, which would mask exactly that signal once the SDK starts emitting it.
Summary
MCP has deprecated the protocol-level Logging capability.
wait_for_textis the only tool in this server that uses it, via three_maybe_logcalls that emitnotifications/message. This server is stdio-only, so the specified migration path — log tostderr— is a direct swap onto the stdlib loggers the codebase already uses everywhere else.Upstream status
MCP adopted a feature lifecycle and deprecation policy in SEP-2596, which defines Active/Deprecated/Removed states, a twelve-month minimum deprecation window, and a canonical deprecated features registry.
SEP-2577 (merged 2026-05-15) deprecates Roots, Sampling, and Logging, effective with the
2026-07-28revision. The registry gives Logging's migration path as "Log tostderrfor stdio transports; use OpenTelemetry for observability", and the rationale as "overlaps with stderr and OpenTelemetry". Earliest removal is the first revision released on or after 2027-07-28.Separately, SEP-2575 removes
logging/setLevelin the same revision and moves log level to a per-request_metakey, with a hard constraint: "servers MUST NOT emitnotifications/messagefor requests that did not include this field". Under2026-07-28the current unconditional emissions are therefore not merely deprecated but non-conforming.This is not urgent — the pinned SDK negotiates
2025-11-25(mcp.types.LATEST_PROTOCOL_VERSION), where Logging is still Active — but the migration is small and there is no reason to carry it.Affected code
All three call sites are in
wait_for_text:wait.py#L434ExpectedToolErroron the next linewait.py#L730wait.py#L838WaitForTextResult.outcome == "timeout"pluselapsedThe helper is
_maybe_logatwait.py#L124-L143; its own docstring names the wire method atwait.py#L133.Why stderr rather than a result field
The two tests covering this behavior state the intent: the warnings exist "so MCP client log panels record the cause independent of the tool result" (
test_pane_tools.py#L3997-L3999) and for "human log readers" (test_pane_tools.py#L4040-L4044). That is an operator/observability role, which is precisely what the spec redirects to stderr — and under stdio, MCP clients surface server stderr in those same log panels.Promoting them to
WaitForTextResultfields instead would contradict that model's stated design constraint: "Field count is load-bearing.outputSchemais re-sent on every request of every session, so a field that no agent branches on is a permanent tax." (models.py#L243-L246). Two of the three warnings are already redundant with the tool result or the raised error, and the third is documented as a caveat in the tool docstring atwait.py#L555-L561, where the agent meets it at tool-selection time.Proposed change
_maybe_logwith stderr logging through the existing module logger; drop the transport-closed suppression, which has no analogue for stdlib logging.ctxparameter from_compile_patterns.ctx.warningreference in thewait_for_textdocstring atwait.py#L559.MIGRATIONnote: MCP clients that displayed these three warnings in a log panel sourced fromnotifications/messagewill now receive them on stderr.ctx.report_progressatwait.py#L114is not affected. Progress notifications are not deprecated, and the2026-07-28draft explicitly keeps them flowing on the response stream of the request they relate to.Out of scope
Checked and unaffected: no Roots, no Sampling, no
includeContext, no HTTP+SSE transport, and no Dynamic Client Registration anywhere insrc/— the server is stdio-only atserver.py#L468.Two adjacent observations, deliberately not bundled here:
_metakeys minted atmiddleware.py#L313-L343(error_type,expected,suggestion) are bare names. That is legal — the prefix is optional — but reverse-DNS namespacing is the spec'sSHOULD, and bare names risk collision with future MCP-reserved keys.DeprecationWarningwhen a deprecated feature is exercised.pyproject.tomlcurrently silencesDeprecationWarningforlibtmux.*,libtmux_mcp.*, andtests, which would mask exactly that signal once the SDK starts emitting it.