Expose a public message_handler seam for MCP ClientSession (consume server notifications e.g. tools/list_changed)
- Lingua principale
- Python
- Stelle
- 21.5k
- Fork
- 4k
- Merge medio
- 1g 14h
- PR unite (30g)
- 37
Descrizione
### Is your feature request related to a problem?
There is no supported way to have `McpToolset` / `MCPSessionManager` react to **server-initiated MCP notifications** — in particular `notifications/tools/list_changed`.
The underlying `mcp` SDK `ClientSession` accepts a `message_handler` constructor parameter, and invokes it for every incoming message (`_handle_incoming` → `await self._message_handler(req)`). But in ADK the `ClientSession` is constructed internally inside `SessionContext._run` (`google/adk/tools/mcp_tool/session_context.py`) with only `sampling_callback` / `sampling_capabilities` forwarded — no `message_handler`. So the SDK falls back to `_default_message_handler`, which silently discards all server notifications, including `ToolListChangedNotification`.
Neither `MCPSessionManager.__init__`, `SessionContext.__init__`, nor `McpToolset.__init__` exposes a `message_handler`, so there is no public hook.
Observed on `google-adk==2.3.0` (with `mcp==1.27.2`).
### Describe the solution you'd like
Forward an optional `message_handler: MessageHandlerFnT | None` through the same path as `sampling_callback`:
- `McpToolset(..., message_handler=...)` →
- `MCPSessionManager(..., message_handler=...)` →
- `SessionContext(..., message_handler=...)` →
- passed into the `ClientSession(...)` constructor.
This would let toolsets consume `tools/list_changed` (e.g. to invalidate a cached tool list) and other server notifications through a supported API.
### Describe alternatives you've considered
Today the only working hook is to assign the **private** attribute after `create_session()`:
```python
session = await super().create_session(headers=headers)
target = getattr(session, "_session", session)
if hasattr(target, "_message_handler"):
target._message_handler = my_handler
```
This works (the SDK reads `_message_handler` dynamically per message, so post-construction assignment takes effect on the running receive loop), but it depends on a private attribute that any ADK/SDK change could rename or remove. A public parameter would remove the need for this workaround.
### Additional context
Use case: a gateway that implements the MCP `tools/list_changed` capability emits the notification on the standalone GET SSE stream; the client wants to invalidate its cached `tools/list` result on receipt. The GET stream itself opens fine once the server returns an `mcp-session-id`; the only missing piece on the ADK side is delivery of the notification to a caller-supplied handler.
Guida per i contributori
Apri la guida per i contributori
Valutazione
Questa issue non è ancora stata valutata.