pub trait ServerInterceptor:
Send
+ Sync
+ 'static {
// Required methods
fn before<'a>(
&'a self,
ctx: &'a CallContext,
) -> Pin<Box<dyn Future<Output = Result<(), A2aError>> + Send + 'a>>;
fn after<'a>(
&'a self,
ctx: &'a CallContext,
) -> Pin<Box<dyn Future<Output = Result<(), A2aError>> + Send + 'a>>;
// Provided methods
fn on_complete<'a>(
&'a self,
ctx: &'a CallContext,
outcome: CallOutcome<'a>,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> { ... }
fn authenticates(&self) -> bool { ... }
}Expand description
A server-side interceptor for request processing.
Interceptors run before and after the core handler logic. They can be used for logging, authentication, rate-limiting, or other cross-cutting concerns.
§Object safety
This trait is designed to be used behind Arc<dyn ServerInterceptor>.
Required Methods§
Sourcefn before<'a>(
&'a self,
ctx: &'a CallContext,
) -> Pin<Box<dyn Future<Output = Result<(), A2aError>> + Send + 'a>>
fn before<'a>( &'a self, ctx: &'a CallContext, ) -> Pin<Box<dyn Future<Output = Result<(), A2aError>> + Send + 'a>>
Sourcefn after<'a>(
&'a self,
ctx: &'a CallContext,
) -> Pin<Box<dyn Future<Output = Result<(), A2aError>> + Send + 'a>>
fn after<'a>( &'a self, ctx: &'a CallContext, ) -> Pin<Box<dyn Future<Output = Result<(), A2aError>> + Send + 'a>>
Called after the request handler has succeeded, before its response is returned.
It is not called when the handler returned an error, and an error
it returns replaces the handler’s response. Until 2026-09-24 this said
the opposite on both counts, which no method did. For
SendMessage and SendStreamingMessage it runs once the task’s
events are being persisted — after a blocking send has collected
them, or once a stream’s processor is attached — so an error here
fails the call without orphaning the task the agent is running.
Use it for logging, metrics, or cleanup.
§Errors
Returns an A2aError if post-processing fails.
Provided Methods§
Sourcefn on_complete<'a>(
&'a self,
ctx: &'a CallContext,
outcome: CallOutcome<'a>,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>>
fn on_complete<'a>( &'a self, ctx: &'a CallContext, outcome: CallOutcome<'a>, ) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>>
Called once when a call ends, however it ends — with the response, with
an error, or by being dropped unanswered — on every interceptor whose
before was called for it.
This is the hook for work that must happen whatever the outcome:
releasing what before acquired, closing an audit record, counting
failures by caller. after cannot do that, because it
runs only on success and its error replaces the response.
The contract, in full:
- Pairing. It is called on an interceptor exactly when that
interceptor’s
beforewas called for the call, including when thatbeforereturned the error that refused it. An interceptor after the one that refused is not called, since itsbeforenever ran. - Order. Reverse insertion order, as for
after. - When. On a call that answers, after every
afterhook and before the response is returned, so a record it writes exists before the caller sees the answer. On a dropped call it runs in a task spawned when the call is dropped, withCallOutcome::Cancelled; if no Tokio runtime is running at that point it is not called. - Once. It is started at most once per interceptor per call. If
the call is dropped while one interceptor’s
on_completeis running, that one is not restarted, and the ones not yet started are then called withCallOutcome::Cancelled. - No effect on the response. It returns nothing, so it cannot change or fail the call.
For SendStreamingMessage and SubscribeToTask the call ends when
the stream is established and its first frame can be sent, not when
the stream closes — the same point at which after runs.
Calls that reach the handler through
ServerInterceptorChain::run_before and
run_after directly, rather than
through RequestHandler, do not call it.
The default does nothing.
Sourcefn authenticates(&self) -> bool
fn authenticates(&self) -> bool
Returns true if this interceptor authenticates requests — i.e. its
before hook rejects callers that do not present
valid credentials.
The extended agent card endpoint MUST require authentication (spec
§13.3); the handler uses this marker to verify that at least one
authenticating interceptor guards the chain before serving the card.
The default is false (logging/metrics-style interceptors do not
authenticate); auth interceptors — including custom ones — should
override this to true.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".