agentic-community / agentic-community/mcp-gateway-registry

Support MCP server-initiated notifications end-to-end through the gateway proxy

未关闭
#1,460 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看
architecture enhancement feature-request
主要语言
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

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。