fast-agent watches server state through subscriptions/listen, and only there
Kind: nuance · Status: current · Last verified: 2026-08-25 · Clients: fast-agent · Revisions: 2026-07-28, 2025-11-25
_subscription_filter returns None unless client.discover_result is set, so the whole subscription loop is gated on the connection having negotiated 2026-07-28. On that path fast-agent reads the server's DiscoverResult.capabilities and asks for exactly what the server offers: tools_list_changed, prompts_list_changed, resources_list_changed, and the resource URIs it currently has materialized if the server advertises resources.subscribe.
It then compares what it asked for against the honored filter the server returns, and records the connection as open or partial accordingly. A server that silently accepts a filter it will not serve is visible in /mcp rather than mistaken for a quiet one.
The event handling is level-triggered. handle_subscription_event ignores which event arrived and re-runs the full attachment refresh. Changing the selected resource set mid-stream is handled by closing and reopening the stream — the loop calls that state rotating.
resources/subscribe is never called. The URI-level subscription is expressed entirely through the subscriptions/listen filter, so on a handshake-era connection fast-agent has no resource subscription at all.
What the fallback path keeps
On a 2025-11-25 connection the same information arrives as notifications, and fast-agent's message_handler sorts them into three buckets:
| Notification | Handled |
|---|---|
notifications/progress |
recorded on the transport timeline |
notifications/tools/list_changed |
refreshes that server's tools |
| everything else | forwarded to server_notification_callback |
server_notification_callback is initialized to None in the aggregator's constructor and assigned nowhere in src/. The only assignment in the repository is in tests/unit/fast_agent/mcp/test_client_callback_runtime.py. So on the handshake path notifications/prompts/list_changed, notifications/resources/list_changed, notifications/resources/updated and notifications/message are received, matched, and dropped.
The comment beside the attribute describes it as the hook for exactly those — "log messages, resource updates, etc." It is an extension point with no production consumer, not a disabled feature.
Logging
There is no logging/setLevel call anywhere in the repository, and no handler that renders a notifications/message. Server log output reaches the dropped bucket above on the legacy path and is not requested at all on the modern one.
Sources
- src/fast_agent/mcp/mcp_connection_manager.py, _subscription_filter and _run_subscription_loop, commit
1b58e686,src/fast_agent/mcp/mcp_connection_manager.py:525-596, 2026-08-25 - src/fast_agent/mcp/client_callback_runtime.py, _handle_message, commit
1b58e686,src/fast_agent/mcp/client_callback_runtime.py:252-284, 2026-08-25 - src/fast_agent/mcp/mcp_aggregator.py, server_notification_callback, commit
1b58e686,src/fast_agent/mcp/mcp_aggregator.py:503, 2026-08-25