pub trait CrossProtocolCodec:
Send
+ Sync
+ Debug {
// Required methods
fn downstream_protocol(&self) -> ProtocolSide;
fn encode_request(
&self,
downstream_side: ProtocolSide,
ir_method: &str,
raw_envelope: &Map<String, Value>,
report: &mut RequestCodecReport,
) -> Result<Map<String, Value>, CrossProtocolError>;
fn decode_reply(
&self,
downstream_side: ProtocolSide,
ir_method: &str,
reply: &Map<String, Value>,
report: &mut RequestCodecReport,
) -> Result<Map<String, Value>, CrossProtocolError>;
}Expand description
A codec that translates request and reply envelopes between the downstream leg’s protocol and the upstream’s protocol.
The downstream leg’s protocol is the one the client spoke; the upstream
is the one the bridge is calling out to. The two are usually different
in the cross-protocol case (an MCP client on one side, an A2A agent on
the other), and a BridgePeer for the upstream is a real connection
to that agent.
§Why the trait takes Leg not ProtocolVersion
The downstream leg’s ProtocolVersion says which MCP revision the
client negotiated. The cross-protocol decision is bigger than that —
it is “is this MCP at all, or is it A2A?” — and Leg already carries
the protocol shape. A bridge that only sees one leg’s protocol can
answer “MCP” or “A2A” and skip the per-revision question entirely,
which is what the per-revision ToolResultCodec is for on the way
back.
§Why the codec takes the raw downstream envelope, not just the IR
The IR is protocol-agnostic at the method-name level (it carries the
canonical name the bridge has assigned), but the parameters are
opaque: a tools/call arguments value is just an entry in
IrParams, indistinguishable from a SendMessage message field.
The codec needs the raw wire shape to know which entry is which, so
it re-reads raw_envelope rather than trying to re-derive the shape
from the IR. The bridge already has both — the IR for routing, the
raw envelope for translation.
Required Methods§
Sourcefn downstream_protocol(&self) -> ProtocolSide
fn downstream_protocol(&self) -> ProtocolSide
The protocol this codec expects the downstream leg to speak.
Sourcefn encode_request(
&self,
downstream_side: ProtocolSide,
ir_method: &str,
raw_envelope: &Map<String, Value>,
report: &mut RequestCodecReport,
) -> Result<Map<String, Value>, CrossProtocolError>
fn encode_request( &self, downstream_side: ProtocolSide, ir_method: &str, raw_envelope: &Map<String, Value>, report: &mut RequestCodecReport, ) -> Result<Map<String, Value>, CrossProtocolError>
Translates a downstream request envelope into the upstream’s wire form.
downstream_side is the protocol the downstream leg speaks
(A2A or MCP). ir_method is the canonical method name the
bridge has assigned (e.g. SendMessage for an A2A call,
tools/call for an MCP call). raw_envelope is the
downstream’s original wire shape, so the codec can read the
parameters in their native form.
§Errors
CrossProtocolError::MethodNotBridged if the method is one
this codec has no rule for.
Sourcefn decode_reply(
&self,
downstream_side: ProtocolSide,
ir_method: &str,
reply: &Map<String, Value>,
report: &mut RequestCodecReport,
) -> Result<Map<String, Value>, CrossProtocolError>
fn decode_reply( &self, downstream_side: ProtocolSide, ir_method: &str, reply: &Map<String, Value>, report: &mut RequestCodecReport, ) -> Result<Map<String, Value>, CrossProtocolError>
Translates an upstream reply envelope back into the downstream’s wire form.
downstream_side is the protocol the downstream leg speaks.
ir_method is the canonical method name the request carried; the
codec uses it to know which reply shape to expect (an A2A Task
reply for a SendMessage request, a Content list for a
tools/call request).
§Errors
The same set of errors as encode_request.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".