diff --git a/assets/agw-docs/pages/agentgateway/mcp/apps.md b/assets/agw-docs/pages/agentgateway/mcp/apps.md new file mode 100644 index 000000000..df76a9141 --- /dev/null +++ b/assets/agw-docs/pages/agentgateway/mcp/apps.md @@ -0,0 +1,12 @@ +**MCP Apps** (the `io.modelcontextprotocol/ui` extension) let MCP tools return interactive user-interface (UI) resources that an MCP host can render, rather than plain text. A tool can return a UI resource identified by a `ui://` URI, and the host displays it to the user. Agentgateway supports MCP Apps automatically, including when you federate multiple MCP servers. + +## How agentgateway handles MCP Apps + +You do not need to configure anything to use MCP Apps through agentgateway. UI resources pass through the gateway like any other MCP resource, with two behaviors worth knowing about: + +- **Multiplexing**: When you federate multiple MCP servers into one endpoint, agentgateway rewrites the `ui://` resource URIs so that they still route to the correct upstream target while remaining valid `ui://` URIs that hosts can render. For more information, see the {{< conditional-text include-if="standalone" >}}[Virtual MCP]({{< link-hextra path="/mcp/connect/virtual" >}}){{< /conditional-text >}}{{< conditional-text include-if="kubernetes" >}}[Virtual MCP]({{< link-hextra path="/mcp/virtual" >}}){{< /conditional-text >}} guide. +- **Authorization**: Any authorization rules that you configure also apply to UI resources. If a rule denies access to a UI resource, agentgateway does not advertise it to the client. For more information, see {{< conditional-text include-if="standalone" >}}[MCP authorization]({{< link-hextra path="/mcp/mcp-authz" >}}){{< /conditional-text >}}{{< conditional-text include-if="kubernetes" >}}[Tool access]({{< link-hextra path="/mcp/tool-access" >}}){{< /conditional-text >}}. + +## MCP Apps and tool name prefixing + +MCP Apps can call tools from within the rendered UI. By default, agentgateway prefixes tool names with the target name when you federate multiple MCP servers, which can interfere with app-originated tool calls that use the tool's plain name. To expose unprefixed tool names, adjust the tool name prefixing behavior on the MCP backend. For more information, see the {{< conditional-text include-if="standalone" >}}[Virtual MCP]({{< link-hextra path="/mcp/connect/virtual#tool-name-prefixing" >}}){{< /conditional-text >}}{{< conditional-text include-if="kubernetes" >}}[Virtual MCP]({{< link-hextra path="/mcp/virtual" >}}){{< /conditional-text >}} guide. diff --git a/assets/agw-docs/pages/agentgateway/mcp/multiplex.md b/assets/agw-docs/pages/agentgateway/mcp/multiplex.md index c7c5dcd19..fbaf8fe88 100644 --- a/assets/agw-docs/pages/agentgateway/mcp/multiplex.md +++ b/assets/agw-docs/pages/agentgateway/mcp/multiplex.md @@ -155,20 +155,34 @@ EOF EOF ``` - {{< callout type="info" >}} - **Failure mode**: By default, agentgateway uses `FailClosed` behavior, which means that if any MCP target fails to initialize or becomes unavailable during a fanout, the entire session fails. To allow the gateway to skip failed targets and continue serving from the healthy ones, set the `failureMode` field to `FailOpen` on the {{< reuse "agw-docs/snippets/backend.md" >}}: - - ```yaml - - spec: - mcp: - failureMode: FailOpen - targets: - ... - ``` - - With `FailOpen`, if one MCP server is down, the gateway still serves tools from the remaining healthy servers. If all targets fail, the gateway returns an error. - {{< /callout >}} + > [!NOTE] + > **Failure mode**: By default, agentgateway uses `FailClosed` behavior, which means that if any MCP target fails to initialize or becomes unavailable during a fanout, the entire session fails. To allow the gateway to skip failed targets and continue serving from the healthy ones, set the `failureMode` field to `FailOpen` on the {{< reuse "agw-docs/snippets/backend.md" >}}: + > + > ```yaml + > + > spec: + > mcp: + > failureMode: FailOpen + > targets: + > ... + > ``` + > + > With `FailOpen`, if one MCP server is down, the gateway still serves tools from the remaining healthy servers. If all targets fail, the gateway returns an error. + + > [!NOTE] + > **Tool name prefixing**: When multiplexing, agentgateway namespaces tool and prompt names with the target name so that identical names from different servers do not collide. Resource URIs always retain target routing information and are unaffected. Control this behavior with the `prefixMode` field on the {{< reuse "agw-docs/snippets/backend.md" >}}: + > + > * `Conditional` (default): Prefix names only when the backend has more than one target. + > * `Always`: Always prefix names, even with a single target. + > * `Never`: Never prefix names. Calls are routed by looking up which target serves the name, so names must be unique across all targets. Use this mode when clients need plain tool names, such as for [MCP Apps]({{< link-hextra path="/mcp/apps" >}}). + > + > ```yaml + > spec: + > mcp: + > prefixMode: Never + > targets: + > ... + > ``` ## Step 2: Route with agentgateway {#agentgateway} diff --git a/assets/agw-docs/pages/agentgateway/mcp/spec-compatibility.md b/assets/agw-docs/pages/agentgateway/mcp/spec-compatibility.md new file mode 100644 index 000000000..540bd1404 --- /dev/null +++ b/assets/agw-docs/pages/agentgateway/mcp/spec-compatibility.md @@ -0,0 +1,37 @@ +Agentgateway supports MCP servers and clients across MCP specification versions and translates between them automatically. In most cases, you do not need to change your existing MCP servers or clients immediately to adopt the newer specification. + +## Supported specification versions + +Agentgateway supports MCP protocol versions as described in [Version support]({{< link-hextra path="/reference/versions/" >}}). Earlier versions are automatically negotiated as described later and typically work, but are not guaranteed. + +### 2026-07-28 support + +The `2026-07-28` revision changes how MCP works at its core. MCP becomes stateless and sessionless. Instead of a stateful `initialize` handshake and an `Mcp-Session-Id` for the lifetime of a session, a modern client discovers server capabilities with a `server/discover` request and carries the required context in each request's `_meta`. + +The sessionless protocol is the recommended direction for MCP going forward, and agentgateway supports it by default. Older, session-based clients and servers remain supported, so a mix of older and newer clients and servers can coexist behind the same gateway. + +## Automatic version negotiation + +Agentgateway sits between a downstream client and one or more upstream MCP servers, and negotiates the protocol version for you. + +- **Newer client to newer server**: The `server/discover` request is forwarded and answered directly. This is the optimal path, with no fallback requests. +- **Newer client to older server**: The older server rejects the modern request, and the client falls back to the older `initialize` flow. Agentgateway handles the fallback transparently. Make sure that your client can handle the older flow gracefully. +- **Older client to newer server**: The client uses the older `initialize` flow, which agentgateway continues to support. + +When you federate multiple MCP servers into one endpoint, agentgateway takes the **intersection** of the protocol versions that the targets support, so the client only negotiates a version that every target can serve. For more information, see the {{< conditional-text include-if="standalone" >}}[Virtual MCP]({{< link-hextra path="/mcp/connect/virtual" >}}){{< /conditional-text >}}{{< conditional-text include-if="kubernetes" >}}[Virtual MCP]({{< link-hextra path="/mcp/virtual" >}}){{< /conditional-text >}} guide. + +> [!NOTE] +> Because most environments run a mix of MCP versions for the foreseeable future, this compatibility handling is on by default and requires no configuration. You do not need to upgrade all of your MCP servers to the newer specification at once. + +## Response caching + +The `2026-07-28` revision adds caching controls to responses such as `server/discover` and `tools/list`. Because agentgateway can apply policies (such as authorization, external authentication, or external processing) that make a response specific to an individual request, it cannot safely tell clients that a proxied response is cacheable. To guarantee correct behavior, agentgateway disables caching on the responses that it proxies. + +## What you can still configure + +Version negotiation, sessionless protocol support, and [MCP Apps]({{< link-hextra path="/mcp/apps" >}}) all work automatically. + +The MCP behavior that you can tune includes: + +- {{< conditional-text include-if="standalone" >}}[Session handling]({{< link-hextra path="/mcp/connect/http#stateless-sessions" >}}) (`statefulMode`) for how agentgateway proxies session-based servers.{{< /conditional-text >}}{{< conditional-text include-if="kubernetes" >}}[Session routing]({{< link-hextra path="/mcp/session" >}}) (`sessionRouting`) for how agentgateway proxies session-based servers.{{< /conditional-text >}} +- Tool name prefixing when federating multiple MCP servers: {{< conditional-text include-if="standalone" >}}[Virtual MCP]({{< link-hextra path="/mcp/connect/virtual" >}}).{{< /conditional-text >}}{{< conditional-text include-if="kubernetes" >}}[Virtual MCP]({{< link-hextra path="/mcp/virtual" >}}).{{< /conditional-text >}} diff --git a/assets/agw-docs/pages/reference/versions.md b/assets/agw-docs/pages/reference/versions.md index afd5bb52b..566757ca5 100644 --- a/assets/agw-docs/pages/reference/versions.md +++ b/assets/agw-docs/pages/reference/versions.md @@ -12,7 +12,7 @@ Review the following information about supported release versions for the [agent `*` Gateway API versions: The agentgateway project is conformant to the Kubernetes Gateway API specification. For more details, see the [Gateway API docs](https://gateway-api.sigs.k8s.io/docs/implementations/list/#agentgateway) and agentgateway conformance report per version, such as Gateway API [v1.5.0](https://github.com/kubernetes-sigs/gateway-api/tree/main/conformance/reports/v1.5.0/agentgateway-agentgateway). -`†` Agentgateway supports the MCP spec at the listed version. Earlier versions might also work, but are not guaranteed. Make sure that your MCP clients are not running at a more recent version than your MCP servers. +`†` Agentgateway supports the MCP spec at the listed version. {{< version include-if="latest" >}}Earlier versions might also work, but are not guaranteed. Make sure that your MCP clients are not running at a more recent version than your MCP servers.{{< /version >}}{{< version include-if="main" >}}For more information, see [MCP spec compatibility]({{< link-hextra path="/mcp/spec-compatibility/" >}}).{{< /version >}} `‡` Istio versions: Istio must run on a compatible version of Kubernetes. For example, Istio 1.29 is tested, but not supported, on Kubernetes 1.30. For more information, see the [Istio docs](https://istio.io/latest/docs/releases/supported-releases/). diff --git a/content/docs/kubernetes/main/mcp/apps.md b/content/docs/kubernetes/main/mcp/apps.md new file mode 100644 index 000000000..103f06331 --- /dev/null +++ b/content/docs/kubernetes/main/mcp/apps.md @@ -0,0 +1,8 @@ +--- +title: MCP Apps +weight: 8 +description: Serve interactive MCP Apps (UI resources) through agentgateway, including across federated MCP servers. +test: skip +--- + +{{< reuse "agw-docs/pages/agentgateway/mcp/apps.md" >}} diff --git a/content/docs/kubernetes/main/mcp/spec-compatibility.md b/content/docs/kubernetes/main/mcp/spec-compatibility.md new file mode 100644 index 000000000..ef9fa6a08 --- /dev/null +++ b/content/docs/kubernetes/main/mcp/spec-compatibility.md @@ -0,0 +1,8 @@ +--- +title: MCP spec compatibility +weight: 7 +description: Learn how agentgateway supports and translates between MCP specification versions, including the stateless 2026-07-28 revision. +test: skip +--- + +{{< reuse "agw-docs/pages/agentgateway/mcp/spec-compatibility.md" >}} diff --git a/content/docs/standalone/main/mcp/apps.md b/content/docs/standalone/main/mcp/apps.md new file mode 100644 index 000000000..471be17ce --- /dev/null +++ b/content/docs/standalone/main/mcp/apps.md @@ -0,0 +1,8 @@ +--- +title: MCP Apps +weight: 14 +description: Serve interactive MCP Apps (UI resources) through agentgateway, including across federated MCP servers. +test: skip +--- + +{{< reuse "agw-docs/pages/agentgateway/mcp/apps.md" >}} diff --git a/content/docs/standalone/main/mcp/connect/http.md b/content/docs/standalone/main/mcp/connect/http.md index c43860437..daac5523c 100644 --- a/content/docs/standalone/main/mcp/connect/http.md +++ b/content/docs/standalone/main/mcp/connect/http.md @@ -2,6 +2,10 @@ title: Streamable HTTP weight: 15 description: Connect to MCP servers via streamable HTTP with automatic session management +test: + mcp-stateless: + - file: ${versionRoot}/mcp/connect/http.md + path: mcp-stateless --- Connect to an MCP server via streamable HTTP. @@ -36,6 +40,100 @@ sequenceDiagram 3. **State encoding**: The session state is encoded into the session ID using AES-256-GCM encryption 4. **Session resumption**: Subsequent requests with the same session ID are automatically routed to the same backend +## Stateless sessions {#stateless-sessions} + +By default, agentgateway proxies streamable HTTP in **stateful** mode, as described in the previous section. You can instead run in **stateless** mode with the `statefulMode` field, so that agentgateway does not create a session or return an `Mcp-Session-Id` header. Each request is treated independently, and the client must send the full context that the request needs. This mode suits stateless agents, or MCP servers where the client handles state directly. + +{{< callout type="info" >}} +The `statefulMode` field controls how agentgateway proxies session-based servers. It is separate from the newer, inherently sessionless `2026-07-28` MCP protocol, which agentgateway supports automatically through version negotiation. For more information, see [MCP spec compatibility]({{< link-hextra path="/mcp/spec-compatibility" >}}). +{{< /callout >}} + +To use stateless mode, set `statefulMode` to `stateless` on the MCP configuration. + +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + statefulMode: stateless + targets: + - name: mcp + mcp: + host: http://localhost:3005/mcp/ +``` + +When you send an `initialize` request through agentgateway in stateless mode, the response returns `HTTP 200` with no `Mcp-Session-Id` header. In the default stateful mode, the same request returns an `Mcp-Session-Id` header that pins the session to a backend. + +{{< doc-test paths="mcp-stateless" >}} +# WHAT THIS TEST VALIDATES: +# * statefulMode: stateless is accepted and the MCP endpoint serves an initialize request (HTTP 200) +# * In stateless mode, the initialize response does NOT include an Mcp-Session-Id header +# WHAT THIS TEST DOES NOT VALIDATE (and why): +# * The visible example uses a streamable HTTP upstream (host: http://localhost:3005/mcp/); +# the hidden test config uses a self-contained stdio target so no external MCP server is +# needed. statefulMode governs the downstream (client-facing) session, independent of the +# upstream transport, so the stateless behavior under test is the same. +# * The default stateful contrast (Mcp-Session-Id present) is covered by other pages that +# use the default configuration. +{{< /doc-test >}} + +{{< doc-test paths="mcp-stateless" >}} +# Install agentgateway binary +{{< reuse "agw-docs/snippets/install-agentgateway-binary.md" >}} +{{< /doc-test >}} + +{{< doc-test paths="mcp-stateless" >}} +cat <<'EOF' > config.yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + statefulMode: stateless + targets: + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +EOF +{{< /doc-test >}} + +{{< doc-test paths="mcp-stateless" >}} +agentgateway -f config.yaml & +AGW_PID=$! +trap 'kill $AGW_PID 2>/dev/null' EXIT +sleep 3 +{{< /doc-test >}} + +{{< doc-test paths="mcp-stateless" >}} +YAMLTest -f - <<'EOF' +- name: MCP endpoint accepts initialize request in stateless mode + http: + url: "http://localhost:3000" + path: /mcp + method: POST + headers: + content-type: application/json + accept: "application/json, text/event-stream" + body: | + {"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}},"id":1} + source: + type: local + expect: + statusCode: 200 +EOF +{{< /doc-test >}} + +{{< doc-test paths="mcp-stateless" >}} +# Assert that stateless mode does not return an Mcp-Session-Id header +if curl -sS -D - -o /dev/null -X POST http://localhost:3000/mcp/ \ + -H 'Content-Type: application/json' \ + -H 'Accept: application/json, text/event-stream' \ + -d '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}},"id":1}' \ + | grep -qi 'mcp-session-id'; then + echo "FAIL: stateless mode returned an Mcp-Session-Id header" + exit 1 +fi +echo "PASS: no Mcp-Session-Id header in stateless mode" +{{< /doc-test >}} + ## Before you begin {{< reuse "agw-docs/snippets/prereq-agentgateway.md" >}} diff --git a/content/docs/standalone/main/mcp/connect/virtual.md b/content/docs/standalone/main/mcp/connect/virtual.md index fea66d9bc..c52f27892 100644 --- a/content/docs/standalone/main/mcp/connect/virtual.md +++ b/content/docs/standalone/main/mcp/connect/virtual.md @@ -8,7 +8,7 @@ Federate tools of multiple MCP servers on the agentgateway by using MCP {{< glos ## About multiplexing {#about} -Multiplexing combines multiple MCP servers (targets) within a single backend into one unified MCP server. All targets are exposed together so that clients can access tools from all targets simultaneously. Tools are prefixed with the target name (e.g., `time_get_current_time`, `everything_echo`) +Multiplexing combines multiple MCP servers (targets) within a single backend into one unified MCP server. All targets are exposed together so that clients can access tools from all targets simultaneously. By default, when a backend has more than one target, tool names are prefixed with the target name (e.g., `time_get_current_time`, `everything_echo`) to avoid collisions. You can change this behavior with the `prefixMode` field, described in [Tool name prefixing](#tool-name-prefixing). {{% details title="Example multiplexing configuration" closed="false" %}} @@ -129,6 +129,34 @@ routes: {{< reuse-image-light src="img/ui-tool-time-current.png" >}} {{< reuse-image-dark srcDark="img/ui-tool-time-current-dark.png" >}} +## Tool name prefixing {#tool-name-prefixing} + +When you multiplex multiple targets, agentgateway namespaces tool and prompt names with the target name so that identical names from different servers do not collide. Resource URIs retain target routing information and are unaffected. Control this behavior with the `prefixMode` field on the MCP configuration. + +| `prefixMode` | Behavior | +|--------------|----------| +| `conditional` (default) | Prefix tool and prompt names only when the backend has more than one target. | +| `always` | Always prefix names, even when the backend has a single target. | +| `never` | Never prefix names. Calls are routed by looking up which target serves the name, so names must be unique across all targets. | + +Use `never` when clients need to call tools by their plain names, such as for [MCP Apps]({{< link-hextra path="/mcp/apps" >}}) that issue tool calls from a rendered UI. Because unprefixed names must be unique, agentgateway fails to start if two targets expose the same tool name in this mode. + +```yaml +# yaml-language-server: $schema=https://agentgateway.dev/schema/config +mcp: + port: 3000 + prefixMode: never + targets: + - name: time + stdio: + cmd: uvx + args: ["mcp-server-time"] + - name: everything + stdio: + cmd: npx + args: ["@modelcontextprotocol/server-everything"] +``` + ## Next steps - Apply different policies to different MCP targets with [MCP target policies]({{< link-hextra path="/mcp/mcp-target-policies/" >}}). diff --git a/content/docs/standalone/main/mcp/spec-compatibility.md b/content/docs/standalone/main/mcp/spec-compatibility.md new file mode 100644 index 000000000..a03a0f248 --- /dev/null +++ b/content/docs/standalone/main/mcp/spec-compatibility.md @@ -0,0 +1,8 @@ +--- +title: MCP spec compatibility +weight: 12 +description: Learn how agentgateway supports and translates between MCP specification versions, including the stateless 2026-07-28 revision. +test: skip +--- + +{{< reuse "agw-docs/pages/agentgateway/mcp/spec-compatibility.md" >}}