Skip to content

mcp/mcp_router: add initial multiplexing and aggregation supports#42456

Merged
yanavlasov merged 26 commits intoenvoyproxy:mainfrom
botengyao:mcp_router_aggregation
Dec 12, 2025
Merged

mcp/mcp_router: add initial multiplexing and aggregation supports#42456
yanavlasov merged 26 commits intoenvoyproxy:mainfrom
botengyao:mcp_router_aggregation

Conversation

@botengyao
Copy link
Copy Markdown
Member

@botengyao botengyao commented Dec 8, 2025

MCP Request/Response Handling

Operation Direction Handling
initialize Fanout Aggregate session IDs into composite
tools/list Fanout Aggregate tools, prefix names
tools/call Targeted Strip prefix, route to specific backend
ping Fanout Return 200 with empty JSON response
notification/initialized Fanout Return 202

Key Decisions

  • Handle the streamable HTTP for MCP POST request.
  • This PR only handles the application/json content, event/stream response should also be supported but not this PR.
  • Body rewrite for tools/call: Use string search to replace prefixed tool name.
    -- The mcp decoder could provide a cursor to be more efficient and more robust
  • Content-Length handling: Set explicit length after body modification
  • Response aggregation: Full JSON parsing required for tools/list (multiple tool names to prefix)
  • mcp-session-id is the combined one from multiple backends, and there should be a limit.
  • Capability is gateway default now and should be controlled by the gateway.
  • Should combine with the mcp_filter. And the request flow is mcp_fitler -> other_filters (attributes aware) -> mcp_router -> backends.
82yHuofKFAMcHi2

#39174

static_resources:
  listeners:
    - name: mcp_listener
      address:
        socket_address:
          address: 0.0.0.0
          port_value: 10001
      filter_chains:
        - filters:
            - name: envoy.filters.network.http_connection_manager
              typed_config:
                "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
                stat_prefix: ingress_http
                route_config:
                  name: local_route
                  virtual_hosts:
                    - name: mcp_gateway
                      domains: ["gateway.com"]
                      routes:
                        - match:
                            path: "/mcp"
                          route:
                            cluster: mcp_service
                http_filters:
                  - name: envoy.filters.http.mcp
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.filters.http.mcp.v3.Mcp
                      traffic_mode: REJECT_NO_MCP
                      clear_route_cache: true
                  - name: envoy.filters.http.mcp_router
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.filters.http.mcp_router.v3.McpRouter
                      servers:
                        - name: echo_one
                          mcp_cluster:
                            cluster: mcp_service
                            path: "/mcp"
                        - name: echo_two
                          mcp_cluster:
                            cluster: mcp_service_2
                            path: "/mcp"
  clusters:
    - name: mcp_service
      type: STATIC
      lb_policy: ROUND_ROBIN
      load_assignment:
        cluster_name: mcp_service
        endpoints:
        - lb_endpoints:
          - endpoint:
              address:
                socket_address:
                  address: 127.0.0.1
                  port_value: 9000

    - name: mcp_service_2
      type: STATIC
      lb_policy: ROUND_ROBIN
      load_assignment:
        cluster_name: mcp_service
        endpoints:
        - lb_endpoints:
          - endpoint:
              address:
                socket_address:
                  address: 127.0.0.1
                  port_value: 9001

Commit Message:
Additional Description:
Risk Level:
Testing:
Docs Changes:
Release Notes:
Platform Specific Features:

@repokitteh-read-only
Copy link
Copy Markdown

As a reminder, PRs marked as draft will not be automatically assigned reviewers,
or be handled by maintainer-oncall triage.

Please mark your PR as ready when you want it to be reviewed!

🐱

Caused by: #42456 was opened by botengyao.

see: more, trace.

@repokitteh-read-only
Copy link
Copy Markdown

CC @envoyproxy/api-shepherds: Your approval is needed for changes made to (api/envoy/|docs/root/api-docs/).
envoyproxy/api-shepherds assignee is @mattklein123
CC @envoyproxy/api-watchers: FYI only for changes made to (api/envoy/|docs/root/api-docs/).

🐱

Caused by: #42456 was opened by botengyao.

see: more, trace.

Signed-off-by: Boteng Yao <boteng@google.com>
@botengyao botengyao force-pushed the mcp_router_aggregation branch from 61abcf6 to e2b03ea Compare December 8, 2025 07:19
Signed-off-by: Boteng Yao <boteng@google.com>
Signed-off-by: Boteng Yao <boteng@google.com>
@botengyao botengyao changed the title [DRAFT] mcp/mcp_router: add initial multiplexing and aggregation supports [WIP] mcp/mcp_router: add initial multiplexing and aggregation supports Dec 9, 2025
Signed-off-by: Boteng Yao <boteng@google.com>
Copy link
Copy Markdown
Contributor

@yanavlasov yanavlasov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/wait-any

Comment thread api/envoy/extensions/filters/http/mcp_router/v3/mcp_router.proto
Comment thread source/extensions/filters/http/mcp_router/mcp_router.h
Copy link
Copy Markdown
Member Author

@botengyao botengyao left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review!

Comment thread api/envoy/extensions/filters/http/mcp_router/v3/mcp_router.proto
Comment thread source/extensions/filters/http/mcp_router/mcp_router.h
Signed-off-by: Boteng Yao <boteng@google.com>
Signed-off-by: Boteng Yao <boteng@google.com>
Signed-off-by: Boteng Yao <boteng@google.com>
Signed-off-by: Boteng Yao <boteng@google.com>
Signed-off-by: Boteng Yao <boteng@google.com>
Signed-off-by: Boteng Yao <boteng@google.com>
Signed-off-by: Boteng Yao <boteng@google.com>
Signed-off-by: Boteng Yao <boteng@google.com>
Signed-off-by: Boteng Yao <boteng@google.com>
@botengyao botengyao marked this pull request as ready for review December 11, 2025 15:32
Signed-off-by: Boteng Yao <boteng@google.com>
@botengyao botengyao changed the title [WIP] mcp/mcp_router: add initial multiplexing and aggregation supports mcp/mcp_router: add initial multiplexing and aggregation supports Dec 11, 2025
Signed-off-by: Boteng Yao <boteng@google.com>
Signed-off-by: Boteng Yao <boteng@google.com>
Signed-off-by: Boteng Yao <boteng@google.com>
Copy link
Copy Markdown
Contributor

@yanavlasov yanavlasov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/wait

Comment thread source/extensions/filters/http/mcp_router/mcp_router.h Outdated
Comment thread source/extensions/filters/http/mcp_router/mcp_router.h Outdated
Comment thread source/extensions/filters/http/mcp_router/mcp_router.h Outdated
Comment thread source/extensions/filters/http/mcp_router/mcp_router.cc Outdated
Signed-off-by: Boteng Yao <boteng@google.com>
Signed-off-by: Boteng Yao <boteng@google.com>
Signed-off-by: Boteng Yao <boteng@google.com>
Signed-off-by: Boteng Yao <boteng@google.com>
Signed-off-by: Boteng Yao <boteng@google.com>
Copy link
Copy Markdown
Contributor

@yanavlasov yanavlasov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Let's just split config into a separate file and will then submit.

/wait

Comment thread source/extensions/filters/http/mcp_router/mcp_router.h Outdated
Signed-off-by: Boteng Yao <boteng@google.com>
@yanavlasov yanavlasov merged commit b079581 into envoyproxy:main Dec 12, 2025
24 of 25 checks passed
@yanavlasov
Copy link
Copy Markdown
Contributor

Bypassing API review as we are changing it very repidly and it will be likely to be quite different in its stable form. Will review API separately once we have stabilized it.

MayorFaj pushed a commit to MayorFaj/envoy that referenced this pull request Dec 15, 2025
…voyproxy#42456)

#### MCP Request/Response Handling

| Operation | Direction | Handling |
|-----------|-----------|----------|
| `initialize` | Fanout | Aggregate session IDs into composite |
| `tools/list` | Fanout | Aggregate tools, prefix names |
| `tools/call` | Targeted | Strip prefix, route to specific backend |
| `ping` | Fanout | Return 200 with empty JSON response |
| `notification/initialized` | Fanout | Return 202 |

#### Key Decisions

- Handle the streamable HTTP for MCP POST request. 
- This PR only handles the `application/json` content, `event/stream`
response should also be supported but not this PR.
- **Body rewrite for `tools/call`**: Use string search to replace
prefixed tool name.
-- The mcp decoder could provide a cursor to be more efficient and more
robust
- **Content-Length handling**: Set explicit length after body
modification
- **Response aggregation**: Full JSON parsing required for `tools/list`
(multiple tool names to prefix)
- `mcp-session-id` is the combined one from multiple backends, and there
should be a limit.
- Capability is gateway default now and should be controlled by the
gateway.
- Should combine with the mcp_filter. And the request flow is mcp_fitler
-> other_filters (attributes aware) -> mcp_router -> backends.


<img width="3462" height="1252" alt="82yHuofKFAMcHi2"
src="https://github.com/user-attachments/assets/25dfd31b-7f8c-4b3a-8306-650801adf283"
/>

envoyproxy#39174 

```
static_resources:
  listeners:
    - name: mcp_listener
      address:
        socket_address:
          address: 0.0.0.0
          port_value: 10001
      filter_chains:
        - filters:
            - name: envoy.filters.network.http_connection_manager
              typed_config:
                "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
                stat_prefix: ingress_http
                route_config:
                  name: local_route
                  virtual_hosts:
                    - name: mcp_gateway
                      domains: ["gateway.com"]
                      routes:
                        - match:
                            path: "/mcp"
                          route:
                            cluster: mcp_service
                http_filters:
                  - name: envoy.filters.http.mcp
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.filters.http.mcp.v3.Mcp
                      traffic_mode: REJECT_NO_MCP
                      clear_route_cache: true
                  - name: envoy.filters.http.mcp_router
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.filters.http.mcp_router.v3.McpRouter
                      servers:
                        - name: echo_one
                          mcp_cluster:
                            cluster: mcp_service
                            path: "/mcp"
                        - name: echo_two
                          mcp_cluster:
                            cluster: mcp_service_2
                            path: "/mcp"
  clusters:
    - name: mcp_service
      type: STATIC
      lb_policy: ROUND_ROBIN
      load_assignment:
        cluster_name: mcp_service
        endpoints:
        - lb_endpoints:
          - endpoint:
              address:
                socket_address:
                  address: 127.0.0.1
                  port_value: 9000

    - name: mcp_service_2
      type: STATIC
      lb_policy: ROUND_ROBIN
      load_assignment:
        cluster_name: mcp_service
        endpoints:
        - lb_endpoints:
          - endpoint:
              address:
                socket_address:
                  address: 127.0.0.1
                  port_value: 9001
```

Commit Message:
Additional Description:
Risk Level:
Testing:
Docs Changes:
Release Notes:
Platform Specific Features:

---------

Signed-off-by: Boteng Yao <boteng@google.com>
Signed-off-by: MayorFaj <mayorfaj@gmail.com>
grnmeira pushed a commit to grnmeira/envoy that referenced this pull request Mar 20, 2026
…voyproxy#42456)

#### MCP Request/Response Handling

| Operation | Direction | Handling |
|-----------|-----------|----------|
| `initialize` | Fanout | Aggregate session IDs into composite |
| `tools/list` | Fanout | Aggregate tools, prefix names |
| `tools/call` | Targeted | Strip prefix, route to specific backend |
| `ping` | Fanout | Return 200 with empty JSON response |
| `notification/initialized` | Fanout | Return 202 |

#### Key Decisions

- Handle the streamable HTTP for MCP POST request.
- This PR only handles the `application/json` content, `event/stream`
response should also be supported but not this PR.
- **Body rewrite for `tools/call`**: Use string search to replace
prefixed tool name.
-- The mcp decoder could provide a cursor to be more efficient and more
robust
- **Content-Length handling**: Set explicit length after body
modification
- **Response aggregation**: Full JSON parsing required for `tools/list`
(multiple tool names to prefix)
- `mcp-session-id` is the combined one from multiple backends, and there
should be a limit.
- Capability is gateway default now and should be controlled by the
gateway.
- Should combine with the mcp_filter. And the request flow is mcp_fitler
-> other_filters (attributes aware) -> mcp_router -> backends.

<img width="3462" height="1252" alt="82yHuofKFAMcHi2"
src="https://github.com/user-attachments/assets/25dfd31b-7f8c-4b3a-8306-650801adf283"
/>

envoyproxy#39174

```
static_resources:
  listeners:
    - name: mcp_listener
      address:
        socket_address:
          address: 0.0.0.0
          port_value: 10001
      filter_chains:
        - filters:
            - name: envoy.filters.network.http_connection_manager
              typed_config:
                "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
                stat_prefix: ingress_http
                route_config:
                  name: local_route
                  virtual_hosts:
                    - name: mcp_gateway
                      domains: ["gateway.com"]
                      routes:
                        - match:
                            path: "/mcp"
                          route:
                            cluster: mcp_service
                http_filters:
                  - name: envoy.filters.http.mcp
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.filters.http.mcp.v3.Mcp
                      traffic_mode: REJECT_NO_MCP
                      clear_route_cache: true
                  - name: envoy.filters.http.mcp_router
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.filters.http.mcp_router.v3.McpRouter
                      servers:
                        - name: echo_one
                          mcp_cluster:
                            cluster: mcp_service
                            path: "/mcp"
                        - name: echo_two
                          mcp_cluster:
                            cluster: mcp_service_2
                            path: "/mcp"
  clusters:
    - name: mcp_service
      type: STATIC
      lb_policy: ROUND_ROBIN
      load_assignment:
        cluster_name: mcp_service
        endpoints:
        - lb_endpoints:
          - endpoint:
              address:
                socket_address:
                  address: 127.0.0.1
                  port_value: 9000

    - name: mcp_service_2
      type: STATIC
      lb_policy: ROUND_ROBIN
      load_assignment:
        cluster_name: mcp_service
        endpoints:
        - lb_endpoints:
          - endpoint:
              address:
                socket_address:
                  address: 127.0.0.1
                  port_value: 9001
```

Commit Message:
Additional Description:
Risk Level:
Testing:
Docs Changes:
Release Notes:
Platform Specific Features:

---------

Signed-off-by: Boteng Yao <boteng@google.com>
Signed-off-by: Gustavo <grnmeira@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants