agentic-community / agentic-community/mcp-gateway-registry
Support MCP server-initiated notifications end-to-end through the gateway proxy
- 主要语言
- Python
- 星标
- 912
- 派生
- 234
- 平均合并
- 1 天 11 小时
- 30 天内合并 PR
- 62
描述
## Summary
Support MCP server-initiated notifications (e.g. `notifications/tools/list_changed`, `notifications/resources/updated`, progress and logging notifications) end-to-end through the gateway proxy.
Today these are **not supported**, and the reason is structural rather than a missing handler: since the tools/list filtering hop was introduced (#1026), every MCP POST is routed through the auth-server `/mcp-proxy` endpoint, which **fully buffers** the upstream response before returning it to the client. Server-to-client notifications that depend on an open, incrementally-flushed stream therefore cannot reach the client while the stream is live.
## Current behavior (why it is not implicitly supported)
1. **Client -> server notifications** (e.g. `notifications/initialized`) flow through, but only because the method is explicitly allow-listed in the scope check (`registry/services/scope_service.py`). Other `notifications/*` methods are not allow-listed and would be denied by authorization.
2. **Server -> client notifications** are blocked by response buffering on the inner proxy hop:
- `auth_server/server.py` opens `client.stream(...)` and then immediately calls `_read_bounded(...)`, which accumulates all chunks into a list and only returns once the upstream stream closes.
- The result is returned as a single non-streaming `Response`. Even though the content-type (`text/event-stream`) is preserved, the body is delivered all at once after the stream ends, not incrementally.
- nginx `proxy_buffering off` on the SSE transport block does not help, because the buffering is on the auth-server -> upstream hop downstream of nginx.
- If an upstream holds the stream open to push notifications, the proxy blocks until `MCP_PROXY_TIMEOUT` and then returns everything at once (or times out).
## Proposed work
1. **Stream-preserving proxy path**: for methods other than `tools/list` (which needs the full body for filtering), relay the upstream response to the client as a `StreamingResponse` that forwards `aiter_bytes()` chunk-by-chunk, preserving SSE framing and flush timing. Keep the bounded-buffer + filter path only for `tools/list`.
2. **Scope allow-list**: broaden the `notifications/*` allow-list so notification methods are not denied by authorization.
3. **Long-lived SSE / streamable-HTTP channel**: handle the server-push GET channel for streamable-http transport (the current proxy is POST-oriented per #1026), so server-initiated notifications have a delivery path.
4. **Tests**: add coverage asserting notifications are delivered incrementally (not buffered until stream close) and that `tools/list` filtering still works.
## Acceptance criteria
- A server-initiated `notifications/tools/list_changed` (and `resources/updated`) reaches a connected MCP client through the gateway while the stream is live.
- `tools/list` response filtering (#1026) continues to work unchanged.
- The DoS body-size cap is preserved for the buffered (filtered) path.
- Deploy modes (docker-compose, Helm, ECS) all covered.
## References
- Buffering proxy hop: `auth_server/server.py` (`_read_bounded`, `mcp_proxy`), introduced with tools/list filtering in #1026.
- Scope allow-list: `registry/services/scope_service.py` (`notifications/initialized`).
- nginx SSE transport block: `registry/core/nginx_service.py`.
贡献指南
调研方向
Start with `auth_server/server.py`, especially `mcp_proxy` and `_read_bounded`, since that hop does the full-response buffering and defines the main behavior change. Then inspect `registry/services/scope_service.py` around `notifications/initialized` and `registry/core/nginx_service.py` for SSE/proxy settings. Run existing MCP proxy/integration tests covering this path, then add tests for incremental delivery of `notifications/tools/list_changed` and `notifications/resources/updated` while verifying `tools/list` still uses bounded filtered responses and passes existing deploy setups.
由索引模型根据 Issue 内容生成。
评估
- 技术栈
- nginx, python
- 领域
- backend-api-design
- Issue 类型
- 功能
- 难度
- 4/5
- 预计耗时
- 3-5 天
- 活跃度
- 冷清
- 描述清晰度
- 基本清楚
- 新手友好度
- 50/100