<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE rfc>
<rfc xmlns:xi="http://www.w3.org/2001/XInclude" category="std" docName="draft-gaikwad-agent-proxy-modes-00" ipr="trust200902" obsoletes="" updates="" submissionType="IETF" xml:lang="en" version="3" consensus="true">
<front>
<title abbrev="Agent-Tool Proxy Modes">Proxy Modes for Agent-Tool Protocols</title>
<seriesInfo name="Internet-Draft" value="draft-gaikwad-agent-proxy-modes-00" status="standard"/>
<author initials="M." surname="Gaikwad" fullname="Madhava Gaikwad">
<organization>Independent</organization>
<address><email>gaikwad.madhav@gmail.com</email>
<uri>https://github.com/mcpx-project</uri></address>
</author>
<date year="2026" month="August" day="13"/>
<area>ART</area>
<workgroup>Independent Submission</workgroup>
<keyword>proxy</keyword>
<keyword>gateway</keyword>
<keyword>agent</keyword>
<keyword>intermediary</keyword>
<keyword>MCP</keyword>
<abstract>
<t>Agent-tool protocols such as the Model Context Protocol (MCP) enable AI applications to discover and invoke external tools, resources, and prompts through a standardized JSON-RPC interface. As deployments scale, intermediaries (proxies, gateways, sidecars) are inserted between clients and servers to provide transport adaptation, capability aggregation, security enforcement, and operational governance.</t>
<t>No specification currently defines the behavioral requirements for such intermediaries. This document establishes a taxonomy of proxy modes, a layered architecture for pluggable proxy functionality, and normative requirements for each mode. It is designed to be protocol-agnostic in its architecture while referencing MCP as the primary instantiation.</t>
</abstract>
</front>
<middle>
<section anchor="introduction"><name>Introduction</name>
<section anchor="problem-statement"><name>Problem Statement</name>
<t>Agent-tool protocols define how AI clients discover and invoke capabilities exposed by servers. The Model Context Protocol <xref target="MCP"/> is the protocol for which the largest number of independent intermediary implementations is known to the author, and is used throughout as the worked instantiation.</t>
<t>Production deployments routinely insert intermediaries between clients and servers. The author surveyed twelve MCP intermediary implementations in Q1 2026, listed in Appendix E. Each had arrived independently at its own semantics for namespace collision resolution, session management, authentication propagation, capability aggregation, and failure handling. No two of the twelve could be substituted for one another without changing client or server configuration, which is the property this document exists to supply.</t>
<t>The survey is a convenience sample of implementations that were public and documented at that date. It is not exhaustive, and the count should be read as a lower bound on the population rather than a measurement of it.</t>
<t>The requirements in this document are written in terms of an abstract agent-tool protocol. MCP is used throughout as the worked instantiation because it is the protocol for which implementation experience exists (<xref target="app-c"/>); the taxonomy and layer model are intended to apply to any JSON-RPC agent-tool protocol with capability discovery.</t>
<t>This fragmentation mirrors the early history of HTTP proxying, which was resolved through a series of RFCs (RFC 2616, RFC 7230, RFC 9110) that defined proxy behavior normatively. Agent-tool protocols require equivalent treatment.</t>
</section>
<section anchor="scope"><name>Scope</name>
<t>This document defines:</t>
<ul>
<li>A taxonomy of proxy modes applicable to agent-tool protocols</li>
<li>A layered architecture enabling pluggable proxy functionality</li>
<li>Normative behavioral requirements per mode and per layer</li>
<li>Security considerations specific to intermediaries in agent-tool protocol deployments</li>
</ul>
<t>This document does not define:</t>
<ul>
<li>The agent-tool protocol itself (see <xref target="MCP"/>)</li>
<li>Transport-layer specifications, which are defined by each agent-tool protocol</li>
<li>Specific authentication protocols (see <xref target="RFC9207"/>)</li>
</ul>
</section>
<section anchor="relationship-to-other-specifications"><name>Relationship to Other Specifications</name>
<t>This document references and builds upon:</t>
<ul>
<li>Model Context Protocol <xref target="MCP"/> for protocol-specific semantics</li>
<li><xref target="RFC9110"/> for HTTP proxy terminology</li>
<li><xref target="RFC8693"/> for token propagation patterns</li>
<li><xref target="RFC9207"/> for authorization server identification</li>
<li><xref target="RFC7239"/> for proxy hop tracing precedent</li>
<li>W3C Trace Context <xref target="TRACE-CONTEXT"/> for distributed tracing</li>
</ul>
</section>
<section anchor="relationship-to-agent-tool-protocol-governance"><name>Relationship to Agent-Tool Protocol Governance</name>
<t>Agent-tool protocols such as MCP are specified and governed outside the IETF. This document does not modify any such protocol and imposes no requirements on protocol specifications, their maintainers, or their conformance processes. Its normative requirements apply solely to intermediaries, and only to those that claim conformance to this document.</t>
<t>Where a protocol community adopts these requirements, it does so through its own process and its own document, which is self-contained and normatively independent of this one. A companion specification for MCP exists on that basis (<xref target="app-b"/>).</t>
</section>
</section>
<section anchor="terminology"><name>Terminology</name>
<t>The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 <xref target="RFC2119"/> <xref target="RFC8174"/> when, and only when, they appear in all capitals, as shown here.</t>
<section anchor="definitions"><name>Definitions</name>
<t><strong>Agent-Tool Protocol:</strong> A JSON-RPC-based protocol enabling AI applications (clients) to discover and invoke capabilities (tools, resources, prompts) exposed by servers. MCP is the primary example.</t>
<t><strong>Client:</strong> An application that initiates connections and sends requests for tool discovery, invocation, and resource access.</t>
<t><strong>Server:</strong> A process that exposes tools, resources, and prompts to clients via the agent-tool protocol.</t>
<t><strong>Intermediary:</strong> Any component inserted into the communication path between a client and one or more servers. Synonyms include "proxy," "gateway," and "sidecar."</t>
<t><strong>Backend:</strong> A server as seen from the perspective of an intermediary. An intermediary may connect to one or more backends.</t>
<t><strong>Capability Surface:</strong> The set of tools, resources, and prompts that an entity (server or intermediary) advertises to its clients.</t>
<t><strong>Namespace:</strong> A scoping mechanism that prevents name collisions when an intermediary aggregates capabilities from multiple backends.</t>
<t><strong>Mode:</strong> A classification of intermediary behavior based on protocol awareness, deployment position, and client visibility.</t>
<t><strong>Layer:</strong> A functional stratum within an intermediary's processing pipeline, with defined input/output interfaces.</t>
<t><strong>Transport:</strong> The wire protocol used for message delivery (e.g., stdio, SSE, Streamable HTTP, WebSocket).</t>
<t><strong>Binding:</strong> The mapping of this document's abstract requirements onto a specific agent-tool protocol. A binding is a separate document, produced by that protocol's own process.</t>
</section>
<section anchor="binding-defined-parameters"><name>Binding-Defined Parameters</name>
<t>This document specifies intermediary behavior in terms of an abstract agent-tool protocol. Seven parameters are left to the binding. A binding MUST define each; this document uses the terms below wherever the value would otherwise appear.</t>
<artwork type="ascii-art"><![CDATA[
+---+------------------------+------------------------------+
| # | Parameter              | What the binding fixes       |
+===+========================+==============================+
| 1 | METADATA-FIELD         | Where per-message extension  |
|   |                        | metadata is carried          |
+---+------------------------+------------------------------+
| 2 | HOP-KEY                | Key under which the hop      |
|   |                        | sequence is stored           |
+---+------------------------+------------------------------+
| 3 | NAME-DELIMITER         | Separator for namespaced     |
|   |                        | capability names             |
+---+------------------------+------------------------------+
| 4 | NAME-CHARSET           | Characters legal in a        |
|   |                        | capability name              |
+---+------------------------+------------------------------+
| 5 | LIST-METHODS           | Methods that enumerate the   |
|   |                        | capability surface           |
+---+------------------------+------------------------------+
| 6 | INVOKE-METHODS         | Methods that target exactly  |
|   |                        | one backend                  |
+---+------------------------+------------------------------+
| 7 | CHANGE-SIGNAL          | Notification that the        |
|   |                        | capability surface changed   |
+---+------------------------+------------------------------+
]]></artwork>
<t>A binding MUST additionally state whether the protocol carries an initialization handshake, which selects between the dispositions of <xref target="single-handshake-vs-dual-handshake"/>.</t>
<t><xref target="app-d"/> gives these values for two protocols.</t>
</section>
</section>
<section anchor="proxy-mode-taxonomy"><name>Proxy Mode Taxonomy</name>
<t>This document defines seven proxy modes. Modes are not mutually exclusive; a single intermediary MAY implement multiple modes simultaneously.</t>
<section anchor="mode-classification-axes"><name>Mode Classification Axes</name>
<t>Modes are classified along three axes:</t>
<ol>
<li><strong>Protocol awareness:</strong> Whether the intermediary understands agent-tool protocol semantics (message types, tool names, capability negotiation) or operates on raw transport data.</li>
</ol>
<ol>
<li><strong>Deployment position:</strong> Whether the intermediary is deployed by the client operator (client-side), the server operator (server-side), or the network operator (network-side).</li>
</ol>
<ol>
<li><strong>Client visibility:</strong> Whether the client is configured to address the intermediary explicitly or is unaware of its presence.</li>
</ol>
</section>
<section anchor="mode-summary"><name>Mode Summary</name>
<artwork type="ascii-art"><![CDATA[
+===============+============+=============+=============+
| Mode          | Protocol   | Deployment  | Client      |
|               | Awareness  | Position    | Visibility  |
+===============+============+=============+=============+
| Relay         | None       | Client-side | Explicit    |
+---------------+------------+-------------+-------------+
| Forward       | Full       | Client-side | Explicit    |
+---------------+------------+-------------+-------------+
| Reverse       | Full       | Server-side | Transparent |
+---------------+------------+-------------+-------------+
| Transparent   | Level 1:   | Network-    | Transparent |
|               | Transport  | side        |             |
|               | Level 2:   |             |             |
|               | Full       |             |             |
+---------------+------------+-------------+-------------+
| Sidecar       | Full       | Server-side | Transparent |
+---------------+------------+-------------+-------------+
| Federation    | Full       | Any         | Explicit    |
+---------------+------------+-------------+-------------+
| Conversion    | Full       | Server-side | Transparent |
+---------------+------------+-------------+-------------+
]]></artwork>
</section>
<section anchor="mode-topologies"><name>Mode Topologies</name>
<t>The three axes above resolve into four distinct placements. <tt>==&gt;</tt> marks a link the client explicitly addresses; <tt>--&gt;</tt> marks a link the client does not know it is traversing.</t>
<artwork type="ascii-art"><![CDATA[
Relay, Forward          client ==> I ---> backend(s)
  client-addressed, one hop, client knows the hop exists

Reverse, Conversion     client ==> I ---> backend(s)
  client addresses I believing I is the backend

Transparent             client ---> [ I ] ---> backend
  client addresses the backend; the network diverts the
  connection through I

Sidecar                 client ---> I ---> backend
                                    +--- co-located ---+
  I is bound to one backend at the same host or pod

Federation              client ==> I ---> I' ---> backend
  I' is itself an intermediary; hops chain
]]></artwork>
<t>Relay and Forward differ in protocol awareness, not topology. Reverse and Conversion differ in whether the backend speaks the agent-tool protocol at all.</t>
</section>
</section>
<section anchor="layered-proxy-architecture"><name>Layered Proxy Architecture</name>
<t>An intermediary's processing pipeline is organized into seven layers. Each layer defines an interface contract. Implementations MUST implement Layer 1 (Transport). All other layers are OPTIONAL and independently pluggable. OPTIONAL means optional to implement; an intermediary that implements a layer MUST satisfy that layer's normative requirements. <xref target="layer-independence-and-conformance-tiers"/> names the conformance classes that group these layers.</t>
<section anchor="layer-stack"><name>Layer Stack</name>
<artwork type="ascii-art"><![CDATA[
+----------------------------------------------------------+
| Layer 7: Capability     negotiation, composition,        |
|                         progressive disclosure           |
+----------------------------------------------------------+
| Layer 6: Session/State  multiplex, isolate, stateless    |
|                         passthrough, version mediation   |
+----------------------------------------------------------+
| Layer 5: Policy         auth, RBAC, filtering, DLP,      |
|                         rate limiting (interceptors)     |
+----------------------------------------------------------+
| Layer 4: Resilience     circuit breakers, retries,       |
|                         timeouts, partial failure        |
+----------------------------------------------------------+
| Layer 3: Routing        namespace resolution,            |
|                         capability mapping, fan-out      |
+----------------------------------------------------------+
| Layer 2: Discovery      backend registration, health     |
|                         checks, hot reload, topology     |
+----------------------------------------------------------+
| Layer 1: Transport      wire protocol adaptation,        |
|                         serialization/deserialization    |
+----------------------------------------------------------+

Cross-cutting: Observability (tracing, metrics, audit)
Cross-cutting: Configuration (portable schema)
]]></artwork>
</section>
<section anchor="layer-independence-and-conformance-tiers"><name>Layer Independence and Conformance Tiers</name>
<t>Each layer MUST define its interface independently of other layers. Swapping the implementation of one layer MUST NOT require changes to adjacent layers. This ensures:</t>
<ul>
<li>A minimal transport-adapting intermediary implements Layer 1 only.</li>
<li>A routing intermediary adds Layers 2 and 3.</li>
<li>A full intermediary implements all seven layers.</li>
<li>All conform to the same specification at different levels.</li>
</ul>
<t>These groupings are the named conformance tiers:</t>
<table>
<thead><tr>
<th>Tier</th>
<th>Layers</th>
</tr></thead>
<tbody>
<tr>
<td>Tier 1</td>
<td>Layer 1</td>
</tr>
<tr>
<td>Tier 2</td>
<td>Layers 1-3</td>
</tr>
<tr>
<td>Tier 3</td>
<td>Layers 1-7</td>
</tr>
</tbody></table>
<t>An intermediary MUST declare the highest tier it satisfies. An intermediary above Tier 1 MUST also declare its mode set (<xref target="proxy-mode-taxonomy"/>).</t>
<t>A tier names layer coverage only. The mode taxonomy of <xref target="proxy-mode-taxonomy"/> is a separate axis, declared independently, and the awareness levels of <xref target="awareness-levels"/> apply only within Transparent mode. The three are not interchangeable, so an intermediary declares a tier, a mode set, and, for Transparent mode, an awareness level. The tiers are named by number rather than reusing mode names, so that a declaration cannot be read as a mode.</t>
</section>
<section anchor="layer-invocation-order"><name>Layer Invocation Order</name>
<t>A client-to-server message traverses the stack upward, 1 through</t>
<ol>
<li>A server-to-client message, including a reverse request such as</li>
</ol>
<t>sampling or elicitation, traverses it downward, 7 through 1. The stack is therefore symmetric, and a layer sees both directions.</t>
<artwork type="ascii-art"><![CDATA[
         client-to-server            server-to-client

              L7  Capability  <--+
              ^                   |
              L6  Session         |
              ^                   v
              L5  Policy      <-------> policy applies
              ^                   |     in both directions
              L4  Resilience      |
              ^                   |
              L3  Routing         |
              ^                   v
              L2  Discovery       |
              ^                   |
        +---> L1  Transport  -----+---> to backend
        |
     from client
]]></artwork>
<t>A layer that is not implemented is skipped in both directions.</t>
</section>
</section>
<section anchor="mode-definitions"><name>Mode Definitions</name>
<section anchor="relay-mode"><name>Relay Mode</name>
<t>A Relay intermediary performs transport adaptation without understanding agent-tool protocol semantics. It operates on raw byte streams or deserialized JSON-RPC envelopes without inspecting their content.</t>
<t>Requirements:</t>
<ul>
<li>MUST forward all messages bidirectionally without modification.</li>
<li>MUST NOT perform capability negotiation with either endpoint.</li>
<li>MUST NOT perform a separate initialization handshake with the backend; client initialization messages are forwarded as-is.</li>
<li>SHOULD bridge between different transport types (e.g., stdio to Streamable HTTP).</li>
<li>MAY buffer messages during transport reconnection.</li>
</ul>
<t>Applicable layers: Layer 1 only.</t>
<t>Illustrated by: sparfenyuk/mcp-proxy, Supergateway (Appendix E).</t>
</section>
<section anchor="forward-proxy-mode"><name>Forward Proxy Mode</name>
<t>A Forward proxy is explicitly configured by the client and operates with full protocol awareness. The client sends all agent-tool protocol messages to the proxy, which routes them to the appropriate backend(s).</t>
<t>Requirements:</t>
<ul>
<li>MUST perform its own initialization handshake with each backend.</li>
<li>MUST present a unified capability surface to the client.</li>
<li>MUST resolve namespace collisions when aggregating multiple backends (see <xref target="namespace-management"/>).</li>
<li>MUST forward bidirectional messages (server-to-client requests such as sampling, elicitation, progress, and logging).</li>
<li>SHOULD implement Layers 1-3. MAY implement Layers 4-7.</li>
<li>SHOULD maintain session isolation between concurrent clients by default.</li>
<li>MAY cache capability lists (tools/list, resources/list, prompts/list) subject to the capability layer requirements in <xref target="layer-7-capability"/>, and MUST invalidate a cached list when the originating backend signals that its capability surface has changed or when that backend is marked unhealthy.</li>
</ul>
<t>Applicable layers: Layers 1-3 (minimum), all layers (maximum).</t>
<t>Illustrated by: FastMCP proxy, MCProxy, plugged.in, MCPJungle (Appendix E).</t>
</section>
<section anchor="reverse-proxy-mode"><name>Reverse Proxy Mode</name>
<t>A Reverse proxy is deployed by the server operator and is transparent to clients. The client believes it is communicating directly with a server.</t>
<t>Requirements:</t>
<ul>
<li>MUST present itself as a standard agent-tool protocol server to clients.</li>
<li>MUST perform independent initialization handshakes with backend servers.</li>
<li>MUST support session affinity or session replication when operating in stateful protocol modes.</li>
<li>SHOULD implement backend health checking (Layer 2).</li>
<li>SHOULD support dynamic backend addition and removal without client disconnection.</li>
<li>MAY perform load balancing across multiple instances of the same backend server.</li>
</ul>
<t>Applicable layers: Layers 1-3 (minimum), all layers (maximum).</t>
<t>Illustrated by: Microsoft mcp-gateway, agentgateway (Appendix E).</t>
</section>
<section anchor="transparent-mode"><name>Transparent Mode</name>
<t>A Transparent intermediary intercepts agent-tool protocol traffic at the network layer without client or server configuration. Traffic is redirected to the intermediary via routing rules (e.g., iptables TPROXY/REDIRECT, WCCP, DNS- based interception, policy-based routing).</t>
<t>This mode applies ONLY to HTTP-based transports. Non-HTTP transports (e.g., stdio) have no network path to intercept.</t>
<section anchor="awareness-levels"><name>Awareness Levels</name>
<t>Transparent intermediaries operate at one of two awareness levels. An implementation MUST declare which level it supports.</t>
<t><strong>Level 1 (Transport-aware):</strong> The intermediary inspects HTTP-layer metadata (headers, URI path) without parsing JSON-RPC request or response bodies.</t>
<t><strong>Level 2 (Protocol-aware):</strong> The intermediary parses JSON-RPC message bodies and may modify, filter, or compose messages with full protocol understanding.</t>
<t>This distinction exists because body inspection is computationally expensive and introduces latency. Level 1 provides useful policy enforcement (rate limiting, access control by method type) at near-zero overhead. Level 2 enables full intermediary functionality at higher cost.</t>
</section>
<section anchor="general-requirements"><name>General Requirements</name>
<t>Interception is a deployment concern, distinct from the transparent-mode protocol behavior defined here. The requirements of this section apply regardless of how interception is achieved, and the mechanism MAY be supplied by the surrounding network infrastructure rather than by the intermediary itself.</t>
<ul>
<li>MUST NOT require client-side configuration changes.</li>
<li>MUST resolve each intercepted connection to exactly one backend, using either the preserved original destination or an explicit mapping supplied by the deployment.</li>
<li>Where the intermediary performs its own interception, it MUST support at least one interception mechanism (IP redirect, DNS interception, or policy-based routing), and MUST preserve the original destination address. Implementations using IP-level redirect MUST use <tt>SO_ORIGINAL_DST</tt> or the platform equivalent to recover it.</li>
</ul>
<t>Original-destination recovery is platform-specific and is not a protocol requirement. An intermediary that accepts an integration-provided backend selection conforms to this section without implementing any interception mechanism of its own, but MUST document which mechanism it expects and how the original destination reaches it. Without that statement the deployment assumption is unverifiable and the conformance claim cannot be checked.</t>
</section>
<section anchor="level-1-requirements"><name>Level 1 Requirements</name>
<ul>
<li>MUST forward all messages (including initialization handshakes) without modification. The client and backend negotiate directly (single-handshake passthrough).</li>
<li>MUST NOT perform an independent initialization handshake with the backend.</li>
<li>MUST NOT modify request or response bodies.</li>
<li>MUST NOT implement namespace management (tools are not aggregated and names are not rewritten).</li>
<li>MAY inspect transport-layer headers for policy decisions (rate limiting, logging, access control). Header-based routing at this level depends on the binding defining headers that carry method and target; MCP does so in <xref target="MCP-SEP-2243"/>.</li>
<li>MAY log intercepted traffic to an external telemetry pipeline without injecting data into the message stream.</li>
<li>MUST forward all bidirectional messages (server-to-client requests) unmodified.</li>
<li>MUST NOT implement circuit breakers. Transport errors from the backend MUST be forwarded to the client as-is.</li>
</ul>
<t>Applicable layers: Layer 1 (Transport), Layer 5 (Policy  - header-based filtering only).</t>
</section>
<section anchor="level-2-requirements"><name>Level 2 Requirements</name>
<ul>
<li>MUST parse JSON-RPC message bodies to make routing, filtering, and policy decisions.</li>
<li>MAY perform an independent initialization handshake with the backend (dual-handshake). If so, all requirements for Forward mode capability negotiation apply.</li>
<li>MAY modify messages (inject metadata, filter capability lists, enforce content policies).</li>
<li>MUST implement namespace management (<xref target="namespace-management"/>) when routing to multiple backends.</li>
<li>MAY implement circuit breakers, subject to the constraint that for single-backend deployments the intermediary MUST NOT fabricate JSON-RPC responses (the client believes it is talking directly to the backend).</li>
<li>MAY filter or block bidirectional messages (sampling, elicitation) per policy configuration.</li>
</ul>
<t>Applicable layers: Layers 1-5 (typical), optionally Layers 6-7.</t>
</section>
<section anchor="tls-considerations"><name>TLS Considerations</name>
<t>TLS termination MAY be performed by the surrounding infrastructure (for example a TLS-terminating load balancer in front of the intermediary), in which case the intermediary operates on an already-decrypted stream and the requirements below apply to whichever component terminates TLS.</t>
<t>Three dispositions are distinguished:</t>
<t><strong>Passthrough.</strong> The encrypted stream is forwarded without being decrypted. No certificate is presented and no CA trust change is required. Body inspection is impossible, so this disposition is available only to Level 1 intermediaries, and only those whose policy decisions derive from connection-level metadata rather than HTTP headers.</t>
<t><strong>Termination and re-origination.</strong> The intermediary terminates the client's TLS connection and opens a separate TLS connection to the backend. It MUST present a certificate matching the original destination hostname, requiring either dynamic certificate generation or wildcard certificates, and the client MUST trust the issuing CA (typically distributed via enterprise CA management). This disposition is required for any inspection of HTTP headers or message bodies, and therefore for any Level 2 function and for header-based Level 1 filtering.</t>
<t><strong>Plaintext.</strong> For unencrypted transports, TLS considerations do not apply. The intermediary SHOULD log a warning when operating on plaintext traffic outside a development environment.</t>
<t>An intermediary MUST declare which disposition it implements. The intermediary MUST NOT downgrade TLS (intercepting an encrypted connection and forwarding plaintext) unless explicitly configured within a trusted network boundary.</t>
</section>
<section anchor="authentication-constraints"><name>Authentication Constraints</name>
<t>Transparent intermediaries face unique authentication constraints. The client is unaware of the intermediary's existence, so the intermediary MUST NOT initiate authentication flows (e.g., OAuth redirects) with the client. Client identity is limited to:</t>
<ul>
<li>Inspecting existing credentials on intercepted requests.</li>
<li>Network-level identity (source IP, mTLS, VLAN).</li>
<li>Enterprise identity infrastructure (service mesh, SSO tokens injected by network fabric).</li>
</ul>
<t>The RECOMMENDED token propagation pattern for Transparent mode is Passthrough (<xref target="token-propagation-patterns"/>, pattern 2) because the backend expects to authenticate the client directly. This is an exception to the general recommendation of Credential Injection for other modes.</t>
<t>Illustrated by: see <xref target="app-c"/>.</t>
</section>
</section>
<section anchor="sidecar-mode"><name>Sidecar Mode</name>
<t>A Sidecar intermediary is deployed alongside a single backend server (typically in the same container pod or host) and intercepts all traffic to/from that server.</t>
<t>Requirements:</t>
<ul>
<li>MUST be transparent to both clients and the co-located server.</li>
<li>MUST forward all protocol messages, applying configured interceptors at defined extension points (pre-request, post-request, pre-response, post-response).</li>
<li>SHOULD support pluggable interceptors for validation, mutation, and observation (see Layer 5).</li>
<li>MUST NOT aggregate capabilities from multiple backends (this distinguishes it from Forward and Reverse modes).</li>
</ul>
<t>Applicable layers: Layers 1, 4, 5 (typical).</t>
<t>Illustrated by: no shipping implementation was identified in the survey; the interceptor model of <xref target="MCP-SEP-1763"/> is the nearest proposal.</t>
</section>
<section anchor="federation-mode"><name>Federation Mode</name>
<t>A Federation intermediary aggregates other intermediaries (not direct backend servers) into a hierarchical topology. This enables multi-level organizational structures.</t>
<t>Requirements:</t>
<ul>
<li>MUST support chained namespace resolution across multiple levels of intermediary.</li>
<li>MUST propagate authentication context across intermediary hops.</li>
<li>MUST include hop-tracing metadata (see <xref target="hop-tracing"/>) to enable end-to-end request tracing.</li>
<li>SHOULD support heterogeneous protocol versions across federated intermediaries.</li>
<li>SHOULD define a federation discovery mechanism enabling intermediaries to find and negotiate with each other.</li>
</ul>
<t>Applicable layers: All layers.</t>
<t>Illustrated by: no complete implementation was identified in the survey. MetaMCP provided partial support, one endpoint per namespace (Appendix E).</t>
</section>
<section anchor="conversion-mode"><name>Conversion Mode</name>
<t>A Conversion intermediary translates a non-agent-tool protocol (e.g., REST/OpenAPI, gRPC) into agent-tool protocol semantics, presenting the converted capabilities as native tools.</t>
<t>Requirements:</t>
<ul>
<li>MUST generate valid tool schemas from the source protocol's schema definitions (e.g., OpenAPI operation -&gt; MCP tool).</li>
<li>MUST preserve the source protocol's authentication requirements and propagate them appropriately.</li>
<li>SHOULD generate tool descriptions suitable for LLM consumption from source protocol documentation.</li>
<li>MAY cache converted schemas with appropriate invalidation.</li>
</ul>
<t>Applicable layers: Layers 1-3, plus a protocol translation sublayer between Layers 1 and 2.</t>
<t>Illustrated by: Kong ai-mcp-proxy, agentgateway, Unla (Appendix E).</t>
</section>
</section>
<section anchor="layer-interface-specifications"><name>Layer Interface Specifications</name>
<section anchor="layer-1-transport"><name>Layer 1: Transport</name>
<t><strong>Interface:</strong></t>
<artwork type="ascii-art"><![CDATA[
Input:  Raw bytes or transport-specific frames from the
        upstream (client-facing) connection.
Output: Raw bytes or transport-specific frames to the
        downstream (backend-facing) connection.
]]></artwork>
<t><strong>Pluggable components:</strong></t>
<ul>
<li>Transport adapter (stdio &lt;-&gt; SSE &lt;-&gt; Streamable HTTP &lt;-&gt; WebSocket)</li>
<li>TLS termination/origination</li>
<li>Compression/decompression</li>
</ul>
<t><strong>Requirements:</strong></t>
<ul>
<li>MUST support at least one client-facing and one backend-facing transport type.</li>
<li>SHOULD support multiple transport types simultaneously.</li>
<li>MUST preserve message boundaries across transport translations.</li>
</ul>
</section>
<section anchor="layer-2-discovery"><name>Layer 2: Discovery</name>
<t><strong>Interface:</strong></t>
<artwork type="ascii-art"><![CDATA[
Input:  Backend configuration (static, service discovery, or
        self-registration).
Output: A registry of available backends with their health
        status, capabilities, and connection parameters.
]]></artwork>
<t><strong>Pluggable components:</strong></t>
<ul>
<li>Backend registry (static file, service discovery, API-driven self-registration)</li>
<li>Health checker (passive failure detection, active probing via JSON-RPC <tt>ping</tt>, MCP-native capability polling)</li>
<li>Topology manager (add/remove backends at runtime, hot reload)</li>
</ul>
<t><strong>Requirements:</strong></t>
<ul>
<li>MUST support at least static backend configuration.</li>
<li>SHOULD support dynamic backend addition and removal without client disconnection.</li>
<li>SHOULD implement health checking with configurable intervals.</li>
<li>MUST emit backend status change events to Layer 4 (Resilience).</li>
</ul>
</section>
<section anchor="layer-3-routing"><name>Layer 3: Routing</name>
<t><strong>Interface:</strong></t>
<artwork type="ascii-art"><![CDATA[
Input:  A deserialized JSON-RPC message (method name, params).
Output: One or more (backend, transformed_message) pairs.
]]></artwork>
<t><strong>Pluggable components:</strong></t>
<ul>
<li>Namespace resolver (prefix-based, priority-based, manual mapping, passthrough)</li>
<li>Fan-out strategy (for list methods: parallel query all backends; for call methods: single-target lookup)</li>
<li>Response aggregator (for fan-out: merge, deduplicate, order)</li>
</ul>
<t><strong>Requirements:</strong></t>
<ul>
<li>MUST fan out each LIST-METHOD to all healthy backends and aggregate the responses.</li>
<li>MUST route each INVOKE-METHOD to exactly one backend, resolved per <xref target="reverse-resolution"/>.</li>
<li>MUST reject a request whose target cannot be resolved.</li>
</ul>
</section>
<section anchor="layer-4-resilience"><name>Layer 4: Resilience</name>
<t><strong>Interface:</strong></t>
<artwork type="ascii-art"><![CDATA[
Input:  A routed request (from Layer 3) and backend health
        status (from Layer 2).
Output: A request to forward, a cached/buffered response,
        or an error to return to the client.
]]></artwork>
<t><strong>Pluggable components:</strong></t>
<ul>
<li>Circuit breaker (state machine per <xref target="circuit-breaker-states"/>, with configurable failure thresholds and reset timeouts)</li>
<li>Retry policy (exponential backoff, jitter, max attempts)</li>
<li>Timeout policy (per-request, per-backend)</li>
<li>Message buffer (<xref target="message-buffering"/>)</li>
<li>Partial failure strategy (<xref target="partial-failure-semantics"/>)</li>
</ul>
<t><strong>Requirements:</strong></t>
<ul>
<li>SHOULD implement circuit breakers with per-backend state.</li>
<li>SHOULD implement request timeouts.</li>
<li>MUST NOT retry an INVOKE-METHOD that may have side effects unless the target is annotated idempotent.</li>
<li>MAY retry LIST-METHODs and other read-only methods.</li>
<li>MUST propagate breaker state to Layer 7, per <xref target="circuit-breaker-states"/>.</li>
</ul>
</section>
<section anchor="layer-5-policy"><name>Layer 5: Policy</name>
<t>Layer 5 is an interceptor chain: each policy sees the message, and may pass, mutate, or reject it. MCP SEP-1763 <xref target="MCP-SEP-1763"/> describes the same shape for that protocol.</t>
<t><strong>Interface:</strong></t>
<artwork type="ascii-art"><![CDATA[
Input:  A request or response message, authentication context,
        and policy configuration.
Output: The message (unmodified, mutated, or rejected) plus
        an audit record.
]]></artwork>
<t><strong>Pluggable components:</strong></t>
<ul>
<li>Authentication handler (OAuth 2.1, API key, mTLS, JWT validation)</li>
<li>Authorization engine (RBAC, ABAC, CEL expressions, OPA policies)</li>
<li>Token propagation strategy (passthrough, exchange <xref target="RFC8693"/>, credential injection, per-upstream credentials)</li>
<li>Content filter (DLP scanning, PII redaction, tool argument validation)</li>
<li>Rate limiter (per-client, per-tool, per-backend)</li>
</ul>
<t><strong>Extension points for interceptors (per SEP-1763 pattern):</strong></t>
<ul>
<li><tt>pre-route</tt>: Before routing decision, on raw client request.</li>
<li><tt>post-route</tt>: After routing decision, before backend forward.</li>
<li><tt>pre-response</tt>: After backend response, before client delivery.</li>
<li><tt>post-response</tt>: After client delivery, for audit/logging.</li>
</ul>
<t><strong>Requirements:</strong></t>
<ul>
<li>MUST support at least one authentication mechanism.</li>
<li>SHOULD implement per-tool authorization when aggregating multiple backends.</li>
<li>MUST NOT forward client credentials to backends unless explicitly configured to do so (credential injection is the RECOMMENDED default).</li>
<li>MUST log policy decisions for audit purposes.</li>
</ul>
</section>
<section anchor="layer-6-session-and-state"><name>Layer 6: Session and State</name>
<t><strong>Interface:</strong></t>
<artwork type="ascii-art"><![CDATA[
Input:  Client session context and backend session contexts.
Output: Session mapping (client session -> one or more
        backend sessions) and version mediation decisions.
]]></artwork>
<t><strong>Pluggable components:</strong></t>
<ul>
<li>Session strategy: - <strong>Passthrough:</strong> Forward session identifiers without modification (Relay mode only). - <strong>Multiplex:</strong> Map one client session to N backend sessions, encoding the mapping in a composite session token. - <strong>Isolate:</strong> Create independent backend sessions per client request (default for Forward mode). - <strong>Stateless:</strong> Operate without sessions; per-request capabilities carried in message metadata.</li>
<li>Version mediator (negotiate protocol versions independently per backend, present a consistent version to the client)</li>
</ul>
<t><strong>Requirements:</strong></t>
<ul>
<li>MUST support stateless operation per the 2026-07-28 MCP specification when backends support it.</li>
<li>SHOULD support stateful operation for backwards compatibility with pre-2026-07-28 backends.</li>
<li>MUST NOT leak backend session identifiers to clients.</li>
<li>MUST isolate backend sessions from each other to prevent context mixing.</li>
</ul>
</section>
<section anchor="layer-7-capability"><name>Layer 7: Capability</name>
<t><strong>Interface:</strong></t>
<artwork type="ascii-art"><![CDATA[
Input:  Capability advertisements from all healthy backends,
        circuit breaker states, and policy filter results.
Output: A composed capability surface to advertise to clients.
]]></artwork>
<t><strong>Pluggable components:</strong></t>
<ul>
<li>Capability compositor: - <strong>Union:</strong> Advertise all capabilities from all backends. - <strong>Intersection:</strong> Advertise only capabilities supported by all backends. - <strong>Curated:</strong> Advertise an explicitly configured subset.</li>
<li>Tool count optimizer (progressive disclosure: expose a subset, provide a search tool for discovery of additional capabilities)</li>
<li>Bidirectional message forwarder (configure which server-to- client message types are forwarded: sampling, elicitation, progress, logging)</li>
</ul>
<t><strong>Requirements:</strong></t>
<ul>
<li>MUST advertise only capabilities the intermediary can route. This is the governing rule of the layer; the two that follow are its consequences.</li>
<li>MUST withdraw capabilities of an unhealthy backend within a configurable window.</li>
<li>SHOULD emit CHANGE-SIGNAL when the surface changes.</li>
<li>SHOULD support selective forwarding of server-to-client message types.</li>
</ul>
</section>
</section>
<section anchor="capability-negotiation-through-intermediaries"><name>Capability Negotiation Through Intermediaries</name>
<section anchor="single-handshake-vs-dual-handshake"><name>Single-Handshake vs Dual-Handshake</name>
<t>For protocol versions that carry an initialization handshake, an intermediary either forwards the client's handshake to the backend (single-handshake passthrough) or performs its own handshake with each backend and composes the results (dual-handshake).</t>
<t>The disposition is determined by mode:</t>
<table>
<thead><tr>
<th>Mode</th>
<th>Handshake</th>
</tr></thead>
<tbody>
<tr>
<td>Relay</td>
<td>MUST NOT dual-handshake</td>
</tr>
<tr>
<td>Transparent, Level 1</td>
<td>MUST NOT dual-handshake</td>
</tr>
<tr>
<td>Transparent, Level 2</td>
<td>MAY dual-handshake</td>
</tr>
<tr>
<td>All other modes</td>
<td>MUST dual-handshake</td>
</tr>
</tbody></table>
<t>In Relay mode and at Transparent Level 1, the client's initialization flows through to the backend unchanged. Injecting an additional handshake at these positions would be observable to a client that believes it is addressing the backend directly, which both dispositions are defined to prevent.</t>
<t>At Transparent Level 2 the choice is per connection. An intermediary that dual-handshakes MUST satisfy the composition requirements of <xref target="capability-composition"/>; an intermediary that does not MUST satisfy the Level 1 requirements of <xref target="level-1-requirements"/> for the duration of that connection. The intermediary MUST track which disposition is in effect per connection, because it determines whether namespace resolution (<xref target="namespace-management"/>) and capability composition apply.</t>
<t>For stateless protocol versions that carry no handshake, this section does not apply; see <xref target="stateless-capability-declaration"/>.</t>
<artwork type="ascii-art"><![CDATA[
Single-handshake passthrough      Dual-handshake

client      I      backend        client      I      backend
  |         |         |             |         |         |
  |--init-->|         |             |--init-->|         |
  |         |--init-->|             |         |--init-->| b1
  |         |<--ok----|             |         |<--ok----|
  |<--ok----|         |             |         |--init-->| b2
  |         |         |             |         |<--ok----|
  |--ready->|         |             |<--ok----|
  |         |--ready->|             |   (composed)
  |         |         |             |         |         |

I forwards; the capability       I terminates the handshake and
surface the client sees is       advertises a surface it composed
the backend's own                itself; names are namespaced
]]></artwork>
</section>
<section anchor="capability-composition"><name>Capability Composition</name>
<t>When composing capabilities from multiple backends, the intermediary MUST:</t>
<ol>
<li>Collect capability advertisements from all healthy backends.</li>
<li>Apply namespace prefixing (<xref target="namespace-management"/>) to avoid collisions.</li>
<li>Apply policy filters (Layer 5) to remove unauthorized capabilities.</li>
<li>Apply progressive disclosure limits (Layer 7) if configured.</li>
<li>Return the composed result to the client.</li>
</ol>
</section>
<section anchor="stateless-capability-declaration"><name>Stateless Capability Declaration</name>
<t>For stateless protocol modes (MCP 2026-07-28 and later), the intermediary MUST include its own identity and capabilities in the <tt>_meta</tt> field of each response, enabling clients to distinguish intermediary-provided metadata from backend-provided metadata.</t>
</section>
</section>
<section anchor="namespace-management"><name>Namespace Management</name>
<section anchor="collision-problem"><name>Collision Problem</name>
<t>When an intermediary aggregates backends that expose identically named tools, resources, or prompts, a collision occurs. The intermediary MUST resolve such collisions deterministically.</t>
</section>
<section anchor="resolution-strategies"><name>Resolution Strategies</name>
<t>Intermediaries MUST implement at least one of the following strategies and MUST declare which strategy is in effect:</t>
<ol>
<li><strong>Prefix:</strong> Prepend a backend identifier to each capability name using a delimiter. The delimiter MUST be <tt>__</tt> (double underscore) for tool names, as <tt>/</tt> and <tt>.</tt> are not accepted in LLM tool name parameters. MCP fixes this value in <xref target="MCP-SEP-993"/>. The backend identifier MUST NOT contain the delimiter sequence, since reverse resolution splits on the first occurrence and an identifier carrying the delimiter would resolve ambiguously.</li>
</ol>
<t>Example: Backend "github" tool "create_issue" becomes <tt>github__create_issue</tt>.</t>
<ol>
<li><strong>Priority:</strong> When collisions occur, retain the capability from the highest-priority backend and discard duplicates. The intermediary MUST log discarded capabilities.</li>
</ol>
<ol>
<li><strong>Manual:</strong> Require explicit per-capability name overrides in configuration. The intermediary MUST reject startup if unresolved collisions exist.</li>
</ol>
<ol>
<li><strong>Passthrough:</strong> Do not resolve collisions; forward the first match. This strategy is NOT RECOMMENDED for production deployments.</li>
</ol>
</section>
<section anchor="reverse-resolution"><name>Reverse Resolution</name>
<t>Prefixing on the way out and stripping on the way in are one mechanism seen from two directions. An intermediary MUST reverse the resolution on an INVOKE-METHOD, and MUST reject a name that does not resolve to exactly one backend.</t>
<artwork type="ascii-art"><![CDATA[
  LIST-METHOD (fan-out, prefix applied)

    backend "github"  create_issue  --+
    backend "jira"    create_issue  --+--> github__create_issue
                                           jira__create_issue

  INVOKE-METHOD (single target, prefix stripped)

    github__create_issue
       |
       +-- split on first NAME-DELIMITER
       |
       +-- "github" ---> routing table ---> backend
       |
       +-- "create_issue" -------------> sent as the original name

  Result returns unmodified. Results are not namespaced.
]]></artwork>
<t>The split takes the first occurrence of NAME-DELIMITER, which is why a backend identifier MUST NOT contain it (<xref target="resolution-strategies"/>).</t>
</section>
</section>
<section anchor="authentication-and-token-propagation"><name>Authentication and Token Propagation</name>
<section anchor="token-propagation-patterns"><name>Token Propagation Patterns</name>
<t>Intermediaries MUST implement at least one of the following token propagation patterns:</t>
<ol>
<li><strong>Credential Injection:</strong> The intermediary holds backend credentials and injects them into backend requests. The client never sees backend credentials. This is the RECOMMENDED default.</li>
</ol>
<ol>
<li><strong>Token Passthrough:</strong> The intermediary forwards the client's token to the backend unchanged. This pattern is NOT RECOMMENDED due to confused deputy risks (see Security Considerations).</li>
</ol>
<ol>
<li><strong>Token Exchange:</strong> The intermediary exchanges the client's token for a backend-specific token using RFC 8693 Token Exchange. This provides audit trails and scope restriction.</li>
</ol>
<ol>
<li><strong>Per-Upstream Credentials:</strong> The intermediary maintains its own credential set per backend, refreshing tokens independently. If authentication fails for a backend, the intermediary SHOULD skip that backend and log a warning rather than failing the entire request.</li>
</ol>
</section>
<section anchor="client-authentication"><name>Client Authentication</name>
<t>Intermediaries operating in Forward or Reverse mode SHOULD implement OAuth 2.1 with PKCE for client authentication, consistent with the MCP Authorization specification.</t>
</section>
</section>
<section anchor="session-semantics"><name>Session Semantics</name>
<section anchor="stateful-protocol-versions"><name>Stateful Protocol Versions</name>
<t>For stateful protocol versions (MCP pre-2026-07-28), the intermediary MUST maintain a mapping between client sessions and backend sessions. The intermediary MUST NOT expose backend session identifiers to clients.</t>
</section>
<section anchor="stateless-protocol-versions"><name>Stateless Protocol Versions</name>
<t>For stateless protocol versions (MCP 2026-07-28 and later), the intermediary operates without session state. Per-request metadata (<tt>_meta</tt>) carries client identity and capabilities. The intermediary MUST forward <tt>_meta</tt> fields to backends and MAY augment them with intermediary-specific metadata.</t>
</section>
<section anchor="mixed-version-deployments"><name>Mixed-Version Deployments</name>
<t>When an intermediary connects to backends running different protocol versions, it MUST:</t>
<ul>
<li>Negotiate the appropriate protocol version independently with each backend.</li>
<li>Present a consistent protocol version to the client (RECOMMENDED: the highest version supported by all backends, or the highest version supported by the intermediary itself).</li>
<li>Translate protocol-level differences transparently.</li>
</ul>
</section>
</section>
<section anchor="resilience-and-failure-handling"><name>Resilience and Failure Handling</name>
<section anchor="circuit-breaker-states"><name>Circuit Breaker States</name>
<t>Intermediaries implementing circuit breakers SHOULD follow the standard three-state model:</t>
<artwork type="ascii-art"><![CDATA[
                    failures exceed threshold
        +-------------------------------------------+
        |                                           v
   +----------+                               +----------+
   |  CLOSED  |                               |   OPEN   |
   | forward  |                               |  reject  |
   +----------+                               +----------+
        ^                                           |
        |                                           |
        | trial succeeds                            | reset
        |                                           | timeout
        |            +-------------+                |
        +------------|  HALF-OPEN  |<---------------+
                     |  one trial  |
                     +-------------+
                            |
                            +--- trial fails ---> OPEN
]]></artwork>
<t>A state change is not private to Layer 4. On entering OPEN the intermediary MUST withdraw that backend's capabilities from the advertised surface and emit CHANGE-SIGNAL; on returning to CLOSED it MUST restore them and emit CHANGE-SIGNAL again. An intermediary that breaks the circuit while continuing to advertise the backend's capabilities presents a surface it cannot serve, which <xref target="layer-7-capability"/> forbids.</t>
</section>
<section anchor="partial-failure-semantics"><name>Partial Failure Semantics</name>
<t>For fan-out operations (<tt>tools/list</tt>, <tt>resources/list</tt>):</t>
<ul>
<li>The intermediary SHOULD return partial results from healthy backends rather than failing the entire request.</li>
<li>The intermediary MUST indicate which backends were unavailable in the response metadata.</li>
</ul>
<t>For single-target operations (<tt>tools/call</tt>):</t>
<ul>
<li>The intermediary MUST return an error if the target backend is unavailable.</li>
<li>The intermediary MUST NOT silently redirect to a different backend unless explicitly configured for failover.</li>
</ul>
</section>
<section anchor="message-buffering"><name>Message Buffering</name>
<t>During backend restarts or reconnections, intermediaries MAY buffer incoming messages and replay them upon recovery. The intermediary MUST:</t>
<ul>
<li>Bound the buffer size to prevent resource exhaustion.</li>
<li>Discard buffered messages after a configurable timeout.</li>
<li>Emit <tt>notifications/tools/list_changed</tt> after replay if the backend's capability surface changed during the restart.</li>
</ul>
</section>
</section>
<section anchor="observability"><name>Observability</name>
<section anchor="distributed-tracing"><name>Distributed Tracing</name>
<t>Intermediaries MUST propagate W3C Trace Context <xref target="TRACE-CONTEXT"/> fields (<tt>traceparent</tt>, <tt>tracestate</tt>) through the extension metadata of JSON-RPC messages. An intermediary MUST NOT alter a propagated value in place; where a value must be transformed, the intermediary carries the transformed value separately and leaves the original verbatim.</t>
<t>If no trace context is present on an incoming request, the intermediary SHOULD generate a <tt>traceparent</tt>.</t>
<t>In MCP this propagation is carried in <tt>_meta</tt> per the conventions of MCP SEP-414 <xref target="MCP-SEP-414"/>.</t>
</section>
<section anchor="hop-tracing"><name>Hop Tracing</name>
<t>Intermediaries SHOULD record hop metadata in METADATA-FIELD under HOP-KEY, so that clients and operators can trace the path a request took. This serves the purpose for agent-tool protocols that the <tt>Forwarded</tt> header <xref target="RFC7239"/> serves for HTTP.</t>
<t>Each entry SHOULD carry the intermediary's name, its mode (<xref target="proxy-mode-taxonomy"/>), its version, and a timestamp. An intermediary MUST append; the order of the sequence is the path.</t>
<artwork type="ascii-art"><![CDATA[
   client        gateway         team-proxy       backend
     |              |                |               |
     |------------->|                |               |
     |              |--------------->|               |
     |              |                |-------------->|
                    |                |
   HOP-KEY = [ ]    [ gateway ]      [ gateway,      ]
                                     [ team-proxy    ]

   An intermediary that overwrote instead of appending would
   erase every hop upstream of itself.
]]></artwork>
<t><xref target="app-d"/> gives HOP-KEY for two protocols.</t>
</section>
<section anchor="metrics"><name>Metrics</name>
<t>Intermediaries SHOULD expose the following metrics per backend, per tool, and per client:</t>
<ul>
<li>Request count (total, success, failure)</li>
<li>Latency (p50, p95, p99)</li>
<li>Circuit breaker state transitions</li>
<li>Cache hit/miss ratio (for capability list caching)</li>
<li>Active connection count</li>
</ul>
</section>
</section>
<section anchor="security-considerations"><name>Security Considerations</name>
<section anchor="confused-deputy"><name>Confused Deputy</name>
<t>An intermediary that forwards client tokens to backends without audience validation may act as a confused deputy, granting the client access to resources it is not authorized for. Intermediaries MUST validate token audiences before forwarding. Credential Injection (<xref target="token-propagation-patterns"/>, pattern 1) avoids this class of attack entirely.</t>
</section>
<section anchor="tool-poisoning"><name>Tool Poisoning</name>
<t>A compromised backend may return malicious tool schemas designed to manipulate LLM behavior. Intermediaries SHOULD validate tool definitions against a schema allowlist before exposing them to clients.</t>
</section>
<section anchor="capability-surface-expansion"><name>Capability Surface Expansion</name>
<t>Aggregating multiple backends increases the attack surface proportionally. Intermediaries MUST apply least-privilege principles: only expose capabilities that are explicitly authorized for the requesting client.</t>
</section>
<section anchor="namespace-squatting"><name>Namespace Squatting</name>
<t>In prefix-based namespace resolution, a malicious backend could register tool names designed to shadow tools from other backends. Intermediaries MUST ensure that backend identifiers used as prefixes are assigned by the intermediary operator, not self-declared by backends.</t>
</section>
<section anchor="session-fixation"><name>Session Fixation</name>
<t>Intermediaries that maintain session mappings MUST generate their own session identifiers for client-facing sessions and MUST NOT reuse backend session identifiers.</t>
</section>
</section>
<section anchor="iana-considerations"><name>IANA Considerations</name>
<t>This document has no IANA actions.</t>
<t>[Note to RFC Editor: This section may be updated if the document defines any registries or media types.]</t>
</section>
</middle>
<back>
<references><name>Normative References</name>
<reference anchor="RFC2119">
<front>
<title>Key words for use in RFCs to Indicate Requirement Levels</title>
<author initials="S." surname="Bradner"/>
<date year="1997"/>
</front>
<seriesInfo name="RFC" value="2119"/>
<seriesInfo name="BCP" value="14"/>
</reference>
<reference anchor="RFC8174">
<front>
<title>Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words</title>
<author initials="B." surname="Leiba"/>
<date year="2017"/>
</front>
<seriesInfo name="RFC" value="8174"/>
<seriesInfo name="BCP" value="14"/>
</reference>
<reference anchor="RFC9110">
<front>
<title>HTTP Semantics</title>
<author initials="R." surname="Fielding"/>
<date year="2022"/>
</front>
<seriesInfo name="RFC" value="9110"/>
</reference>
<reference anchor="RFC8693">
<front>
<title>OAuth 2.0 Token Exchange</title>
<author initials="M." surname="Jones"/>
<date year="2020"/>
</front>
<seriesInfo name="RFC" value="8693"/>
</reference>
<reference anchor="RFC9207">
<front>
<title>OAuth 2.0 Authorization Server Issuer Identification</title>
<author initials="K." surname="Meyer zu Selhausen"/>
<author initials="D." surname="Fett"/>
<date year="2022"/>
</front>
<seriesInfo name="RFC" value="9207"/>
</reference>
</references>
<references><name>Informative References</name>
<reference anchor="MCP" target="https://modelcontextprotocol.io/specification/">
<front>
<title>Model Context Protocol Specification</title>
<author><organization>Anthropic</organization></author>
<date year="2026"/>
</front>
</reference>
<reference anchor="RFC7239">
<front>
<title>Forwarded HTTP Extension</title>
<author initials="A." surname="Petersson"/>
<author initials="M." surname="Nilsson"/>
<date year="2014"/>
</front>
<seriesInfo name="RFC" value="7239"/>
</reference>
<reference anchor="TRACE-CONTEXT" target="https://www.w3.org/TR/trace-context/">
<front>
<title>Trace Context</title>
<author><organization>W3C</organization></author>
<date year="2021"/>
</front>
</reference>
<reference anchor="MCP-SEP-993">
<front>
<title>Namespaces</title>
<author initials="P." surname="White"/>
<date year="2025"/>
</front>
</reference>
<reference anchor="MCP-SEP-1763">
<front>
<title>Interceptors for Model Context Protocol</title>
<author><organization>Sambhav</organization></author>
<date year="2025"/>
</front>
</reference>
<reference anchor="MCP-SEP-2243">
<front>
<title>HTTP Standardization</title>
<author initials="M." surname="Kistler"/>
<date year="2026"/>
</front>
</reference>
<reference anchor="MCP-SEP-414">
<front>
<title>W3C Trace Context propagation in _meta</title>
<author><organization/></author>
<date year="2025"/>
</front>
</reference>
<reference anchor="RFC7942">
<front>
<title>Improving Awareness of Running Code: The Implementation Status Section</title>
<author initials="Y." surname="Sheffer"/>
<author initials="A." surname="Farrel"/>
<date year="2016"/>
</front>
<seriesInfo name="RFC" value="7942"/>
<seriesInfo name="BCP" value="205"/>
</reference>
<reference anchor="YAMP" target="https://github.com/mcpx-project">
<front>
<title>yamp: a forward and transparent MCP proxy</title>
<author initials="M." surname="Gaikwad"/>
<date year="2026"/>
</front>
</reference>
</references>
<section anchor="app-a"><name>Mode Selection Guide</name>
<artwork type="ascii-art"><![CDATA[
+===============================+====================+
| Deployment Scenario           | Recommended Mode   |
+===============================+====================+
| Bridge stdio to HTTP for a    | Relay              |
| single backend                |                    |
+-------------------------------+--------------------+
| Aggregate 3-5 backends for    | Forward            |
| a development team            |                    |
+-------------------------------+--------------------+
| Production server behind a    | Reverse            |
| load balancer                 |                    |
+-------------------------------+--------------------+
| Audit/log all MCP traffic     | Transparent        |
| without touching clients or   | (Level 1)          |
| servers                       |                    |
+-------------------------------+--------------------+
| Network-level tool filtering  | Transparent        |
| and DLP for MCP traffic       | (Level 2)          |
+-------------------------------+--------------------+
| Enterprise-wide tool          | Forward +          |
| governance with multiple      | Federation         |
| teams                         |                    |
+-------------------------------+--------------------+
| Per-server security policy    | Sidecar            |
| without modifying server code |                    |
+-------------------------------+--------------------+
| Exposing REST APIs as         | Conversion         |
| agent-tool capabilities       |                    |
+-------------------------------+--------------------+
]]></artwork>
</section>
<section anchor="app-b"><name>Relationship to the MCP SEP</name>
<t>This Internet-Draft defines the protocol-agnostic architecture and taxonomy. A companion MCP SEP, "Proxy and Gateway Behavioral Specification for MCP", carries the MCP binding.</t>
<t>The two documents are normatively independent in one direction only. The SEP is self-contained: it restates every requirement it imposes and does not rely on this document for the force of any requirement, so an implementer can conform to it without reading this draft. This document, in turn, imposes nothing on MCP (<xref target="relationship-to-agent-tool-protocol-governance"/>). The relationship is that the SEP is one binding of the model described here, and this appendix is informative.</t>
<t>The SEP provides MCP-specific normative requirements, including:</t>
<ul>
<li>MCP-specific namespace delimiter conventions</li>
<li><tt>_meta</tt> field schemas for hop tracing</li>
<li>Capability composition rules for MCP primitives (tools, resources, prompts, sampling, elicitation)</li>
<li>Integration with MCP authorization specification</li>
<li>Conformance test requirements per SEP-2484</li>
</ul>
<t>---</t>
</section>
<section anchor="app-c"><name>Implementation Status</name>
<t>This section records the status of known implementations of the protocol defined by this specification, per <xref target="RFC7942"/>. Its purpose is to record the experience of implementers and to inform the working group's judgment of running code. It is not a catalog of features, and inclusion is neither an endorsement nor a statement of production readiness.</t>
<t>This section is to be removed before publication as an RFC.</t>
<section anchor="app-c-1"><name>yamp</name>
<ul>
<li><strong>Organization:</strong> independent</li>
<li><strong>Name and URL:</strong> yamp (Yet Another MCP Proxy) <xref target="YAMP"/></li>
<li><strong>Description:</strong> A forward and transparent proxy for the Model Context Protocol, implemented twice from this specification, once in Rust and once in Python. The two arms are pinned to identical behavior by a shared golden corpus rather than by inspection: a differential corpus fixes the output of every pure function, a golden-flow corpus fixes the exact client-facing message sequence of whole exchanges, and a clause-to-test traceability matrix maps normative statements to the tests that evidence them in both arms.</li>
<li><strong>Level of maturity:</strong> research and reference implementation, not a production deployment.</li>
<li><strong>Coverage:</strong> The modes of <xref target="mode-definitions"/> are covered as follows. Relay, Forward, and Transparent (Level 1 and Level 2) are implemented. Reverse is partial, providing backend pools with connect-time failover but neither request-level load balancing nor session replication. Federation is partial, in that proxies chain, with no federation discovery mechanism. Conversion is partial, covering REST to MCP with no gRPC and no full OpenAPI import. Sidecar is not implemented. Of the layers in <xref target="layer-interface-specifications"/>, transport, routing, resilience, and capability are implemented; discovery, policy, and session are partial.</li>
<li><strong>Conformance tier:</strong> Tier 3 (<xref target="layer-independence-and-conformance-tiers"/>), with the layer gaps noted above.</li>
<li><strong>Interception:</strong> the transparent modes take an integration-provided backend selection and do not perform their own interception, as permitted by <xref target="general-requirements"/>.</li>
<li><strong>Version compatibility:</strong> implements this draft, revision 00.</li>
<li><strong>Licensing:</strong> Apache License 2.0.</li>
<li><strong>Implementation experience:</strong> Implementing the specification twice surfaced two defects in the specification itself, both now corrected. A backend identifier must not contain the namespace delimiter, because reverse resolution splits on the first delimiter (<xref target="resolution-strategies"/>). Original-destination recovery for the transparent modes (<tt>SO_ORIGINAL_DST</tt>) proved to be a platform-specific hook rather than a protocol concern, and <xref target="general-requirements"/> was rewritten to separate interception as a deployment concern from the transparent-mode protocol behavior. A third question is recorded as unresolved rather than fixed. The conformance model of <xref target="layer-independence-and-conformance-tiers"/> is expressed per tier and per mode, but implementation coverage did not fall on those boundaries: Reverse mode was implemented with backend pools and connect-time failover but without session replication, and the model provides no way to declare that precisely. An intermediary must either overclaim Reverse or omit working functionality. Sub-mode capability declaration is a candidate for a future revision.</li>
<li><strong>Contact:</strong> Madhava Gaikwad, gaikwad.madhav@gmail.com</li>
</ul>
<t>---</t>
</section>
</section>
<section anchor="app-d"><name>Example Bindings</name>
<t>Informative. This appendix instantiates the seven parameters of <xref target="binding-defined-parameters"/> for two protocols, to show that the requirements of this document are separable from any one of them. Neither entry is a binding; a binding is produced by the protocol's own process. The MCP column reflects the companion SEP of <xref target="app-b"/>. The A2A column is the author's reading of a protocol this document has not been implemented against, and is offered to locate the seams, not as a specification.</t>
<artwork type="ascii-art"><![CDATA[
+------------------+---------------------+---------------------+
| Parameter        | MCP                 | A2A                 |
+==================+=====================+=====================+
| METADATA-FIELD   | _meta               | message metadata    |
+------------------+---------------------+---------------------+
| HOP-KEY          | io.modelcontext     | binding-defined     |
|                  | protocol/proxy-hops |                     |
+------------------+---------------------+---------------------+
| NAME-DELIMITER   | __                  | binding-defined;    |
|                  |                     | skill ids are URI-  |
|                  |                     | shaped, so a URI-   |
|                  |                     | safe separator fits |
+------------------+---------------------+---------------------+
| NAME-CHARSET     | [a-zA-Z0-9_-]       | wider; see below    |
+------------------+---------------------+---------------------+
| LIST-METHODS     | tools/list          | agent card fetch    |
|                  | resources/list      |                     |
|                  | prompts/list        |                     |
+------------------+---------------------+---------------------+
| INVOKE-METHODS   | tools/call          | task submission     |
|                  | resources/read      |                     |
|                  | prompts/get         |                     |
+------------------+---------------------+---------------------+
| CHANGE-SIGNAL    | notifications/      | agent card re-fetch |
|                  | tools/list_changed  | (poll, not push)    |
+------------------+---------------------+---------------------+
| Handshake?       | yes before          | no                  |
|                  | 2026-07-28; no      |                     |
|                  | after               |                     |
+------------------+---------------------+---------------------+
]]></artwork>
<t>Three seams are visible in the second column, and they are the useful output of the exercise.</t>
<t><strong>CHANGE-SIGNAL may not exist.</strong> A protocol whose capability surface is discovered by fetching a document, rather than announced by a notification, gives an intermediary no push signal. <xref target="layer-7-capability"/>'s SHOULD is then satisfiable only by re-publishing the document. <xref target="circuit-breaker-states"/>'s MUST, which requires emitting CHANGE-SIGNAL on breaker transitions, is not satisfiable at all. A binding for such a protocol MUST state what replaces it, and the likely answer is a bounded staleness window.</t>
<t><strong>Namespacing may be unnecessary.</strong> Where capability identifiers are already globally scoped, collisions cannot occur and <xref target="namespace-management"/> has nothing to resolve. NAME-DELIMITER is then unused. The requirement to implement a collision strategy should be read as conditional on the binding declaring that collisions are possible.</t>
<t><strong>The unit of invocation may not be a call.</strong> A protocol whose invocation is a long-running task with its own lifecycle does not map cleanly onto the single request/response assumed by Sections 6.3 and 11.2. Partial-failure semantics for fan-out are defined here in terms of responses that arrive or fail; a task that is accepted and later abandoned is neither.</t>
<t>A revision of this document should either resolve these three cases in the body or state that its scope is protocols with push change notification, scoped-per-backend names, and request/response invocation. The second is the honest reading of the current text.</t>
</section>
<section anchor="app-e"><name>Surveyed Implementations</name>
<t>Informative. These are the twelve implementations referred to in <xref target="problem-statement"/>, surveyed in Q1 2026 from public documentation and source. The mode column records which mode of <xref target="mode-definitions"/> each best illustrates, as assessed by the author from published behavior at that date. It is not a conformance statement, and none of these implementations claims conformance to this document.</t>
<artwork type="ascii-art"><![CDATA[
+----+----------------------+--------------------------------+
|    | Implementation       | Mode illustrated               |
+====+======================+================================+
|  1 | sparfenyuk/mcp-proxy | Relay                          |
+----+----------------------+--------------------------------+
|  2 | Supergateway         | Relay                          |
+----+----------------------+--------------------------------+
|  3 | FastMCP proxy        | Forward                        |
+----+----------------------+--------------------------------+
|  4 | MCProxy              | Forward                        |
+----+----------------------+--------------------------------+
|  5 | plugged.in           | Forward                        |
+----+----------------------+--------------------------------+
|  6 | MCPJungle            | Forward                        |
+----+----------------------+--------------------------------+
|  7 | Microsoft            | Reverse                        |
|    | mcp-gateway          |                                |
+----+----------------------+--------------------------------+
|  8 | agentgateway (AAIF)  | Reverse; also Conversion       |
+----+----------------------+--------------------------------+
|  9 | Kong ai-mcp-proxy    | Conversion                     |
+----+----------------------+--------------------------------+
| 10 | Unla                 | Conversion                     |
+----+----------------------+--------------------------------+
| 11 | MetaMCP              | Federation, partial            |
+----+----------------------+--------------------------------+
| 12 | Stacklok ToolHive    | surveyed; not attributed to    |
|    |                      | a single mode                  |
+----+----------------------+--------------------------------+
]]></artwork>
<t>Two observations follow from the table and support <xref target="problem-statement"/>.</t>
<t>No surveyed implementation covered more than two of the seven modes, and none declared which mode it implemented. The vocabulary for such a declaration did not exist.</t>
<t>Sidecar mode is absent. The author identified no implementation that binds an intermediary to a single co-located backend and mediates all of its traffic, which is why <xref target="sidecar-mode"/> cites a proposal rather than a shipping implementation.</t>
</section>
</back>
</rfc>
