Skip to content

mcp(fix[wait]): Stop using the deprecated MCP Logging capability - #110

Open
tony wants to merge 2 commits into
mainfrom
mcp-logging-deprecation
Open

mcp(fix[wait]): Stop using the deprecated MCP Logging capability#110
tony wants to merge 2 commits into
mainfrom
mcp-logging-deprecation

Conversation

@tony

@tony tony commented Jul 25, 2026

Copy link
Copy Markdown
Member

Closes #109.

MCP deprecated the protocol-level Logging capability in SEP-2577, effective with the 2026-07-28 revision, naming stderr as the migration path for stdio servers. wait_for_text was the only place this server exercised it: three ctx.warning calls reaching the wire as notifications/message. They are now ordinary libtmux_mcp.* log records.

Scoped to exactly that. The logging capability is advertised by FastMCP's own handshake, not by anything in this repo — the three call sites are the only part that is ours to remove.

Checked against the full registry

All six entries in the deprecated features registry, against src/ and tests/:

Feature Used here?
Logging Yeswait.py:434, :730, :838 via _maybe_log
Roots No
Sampling No
includeContext: "thisServer"/"allServers" No — the one include_context=False hit is pydantic's ValidationError.errors()
HTTP+SSE transport No — stdio-only (fastmcp.json:9, server.py:468)
Dynamic Client Registration No — no auth surface at all

FastMCP will not flag this for you

Worth recording, because it rules out waiting for a warning. In fastmcp 4.0.0a2 the two SEP-2577 features are handled differently:

  • ctx.sample() emits a warn-once FastMCPDeprecationWarning (fastmcp_slim/fastmcp/server/context.py:113, fired at :1092 and :1209).
  • The logging path warns nothing at runtime. send_log_message carries only a static # ty: ignore[deprecated] (context.py:1659) with the comment "Deprecated upstream in SDK v2 but deliberately kept per compat directive; removed with the multi-round-trip follow-up."

So an SDK upgrade would keep these three calls working silently until MRTR removes them. This was findable only by reading the registry.

Behavior

ctx.report_progress is untouched — progress is not deprecated, and the 2026-07-28 draft explicitly keeps it flowing on the response stream of the request it relates to.

No result field was added. Two of the three warnings are already in the tool result — an invalid regex raises a tool error carrying the identical text, and a timeout is outcome == "timeout". The third, the history-limit trim-risk band, is a diagnostic; WaitForTextResult documents field count as load-bearing (outputSchema is re-sent every request), so a field no agent branches on would be a permanent tax.

_compile_patterns becomes synchronous, since removing the await left it with nothing to await.

Verification

ruff check, ruff format --check, mypy (65 files), pytest --reruns 0 (801 passed), just build-docs clean.

The four migrated tests were checked with a negative control rather than trusted for passing: removing the timeout logger.warning from the source turns test_wait_for_text_warns_on_timeout red with messages = []. Note for future readers — caplog.at_level(..., logger=...) does not scope capture (records reach caplog.records by propagation to root), so aiming the fixture at a bogus logger name does not fail these tests. The logger= argument is kept for level-setting and to match the suite's convention.

@codecov-commenter

codecov-commenter commented Jul 25, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 86.10%. Comparing base (5c35acf) to head (f78baac).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #110      +/-   ##
==========================================
+ Coverage   86.08%   86.10%   +0.02%     
==========================================
  Files          46       46              
  Lines        3593     3584       -9     
  Branches      516      515       -1     
==========================================
- Hits         3093     3086       -7     
+ Misses        355      354       -1     
+ Partials      145      144       -1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@tony
tony force-pushed the mcp-logging-deprecation branch from a2d5718 to 5dbc028 Compare July 25, 2026 22:25
@tony tony changed the title mcp(fix[wait]): Warn on stderr, not deprecated MCP log notifications mcp(fix[wait]): Stop using the deprecated MCP Logging capability Jul 25, 2026
@tony

tony commented Jul 25, 2026

Copy link
Copy Markdown
Member Author

Code review

Found 2 issues:

  1. The new breaking-changes paragraph has no (#110) PR ref (AGENTS.md says "PR refs (#NN) sit at the end of each deliverable's prose paragraph, not on every sentence.")

Every prior deliverable in the file carries its own ref, added before merge — (#100), (#98), (#91), (#89). This paragraph ends at "delivered only as an MCP warning notification". with none.

libtmux-mcp/CHANGES

Lines 20 to 26 in 5dbc028

A client that subscribed to MCP log notifications no longer receives these three
over the protocol. Nothing an agent can act on is lost: the invalid regex is
still raised as a tool error, and the timeout is still reported as
`WaitForTextResult.outcome`. This supersedes the 0.1.0a19 note that the
trim-risk signal is "delivered only as an MCP warning notification".

  1. WaitForTextResult.outcome is cited with plain backticks instead of the {attr} role (AGENTS.md says "Always link autodoc'd APIs. Any class, function, exception, attribute, or tool slug that has its own rendered page must be cited via the appropriate role ({class}, {func}, {exc}, {attr}, {tooliconl}) — never with plain backticks.")

Precedent in the same file: {attr}`~libtmux_mcp.models.SessionInfo.active_pane_id`. The same shape was flagged on #100 for RunCommandResult.effective_timeout.

libtmux-mcp/CHANGES

Lines 22 to 25 in 5dbc028

over the protocol. Nothing an agent can act on is lost: the invalid regex is
still raised as a tool error, and the timeout is still reported as
`WaitForTextResult.outcome`. This supersedes the 0.1.0a19 note that the
trim-risk signal is "delivered only as an MCP warning notification".

Checked and not flagged: no correctness bugs. Both _compile_patterns call sites drop await/ctx= cleanly, the two lazy logger.warning sites have matching placeholder/arg counts, _TRANSPORT_CLOSED_EXCEPTIONS is still used by the untouched _maybe_report_progress, and all four rewritten tests were traced to their origin commits and still guard the same regressions. The removal of _maybe_log's transport-closed suppression is sound — that guard existed because ctx.* does async I/O over the MCP transport, which logging.Handler.emit() does not.

Separately, docs/topics/logging.md claims FastMCP forwards stdlib log records to clients via the MCP logging capability. That is false against fastmcp 3.4.4 — only explicit Context.log-family calls reach the wire — and it predates this PR, so it belongs in its own change rather than here.

@tony
tony force-pushed the mcp-logging-deprecation branch from 5dbc028 to 9fae3b2 Compare July 25, 2026 23:14
tony added 2 commits July 26, 2026 06:16
why: MCP deprecated the protocol-level Logging capability in SEP-2577,
effective revision 2026-07-28, naming stderr as the migration path for
stdio servers. wait_for_text was the only place this server exercised
it -- three ctx.warning calls reaching the wire as
notifications/message. The `logging` capability itself is advertised by
FastMCP's handshake, not by us; these three call sites are the only
part that is ours to remove.

Note FastMCP will not flag this for us. In 4.0.0a2 ctx.sample() emits a
warn-once FastMCPDeprecationWarning, but the logging path carries only
a static `# ty: ignore[deprecated]` on send_log_message and warns
nothing at runtime, so an SDK upgrade would keep this working silently
until the multi-round-trip follow-up removes it.

what:
- Drop _maybe_log; warn through the module logger already at wait.py:36
- Make _compile_patterns synchronous now that it awaits nothing, and
  drop the ctx argument from both call sites
- Leave ctx.report_progress alone; progress is not deprecated and the
  2026-07-28 draft keeps it on the request's response stream
- Move four tests onto caplog and drop the two stub Context.warning
  methods the tool no longer calls
- Correct the one wait_for_text doc sentence naming the old mechanism
why: The channel change is visible to any client that subscribed to
MCP log notifications, and it supersedes an explicit promise in the
0.1.0a19 notes that the trim-risk signal is "delivered only as an MCP
warning notification".

what:
- Add a breaking-changes entry and a matching MIGRATION section
@tony
tony force-pushed the mcp-logging-deprecation branch from 9fae3b2 to f78baac Compare July 26, 2026 11:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Migrate wait_for_text off the deprecated MCP Logging capability (SEP-2577)

2 participants