Skip to main content

ServerInterceptor

Trait ServerInterceptor 

Source
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§

Source

fn before<'a>( &'a self, ctx: &'a CallContext, ) -> Pin<Box<dyn Future<Output = Result<(), A2aError>> + Send + 'a>>

Called before the request handler processes the method call.

Return Err(...) to abort the request with an error response.

§Errors

Returns an A2aError to reject the request.

Source

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§

Source

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 before was called for the call, including when that before returned the error that refused it. An interceptor after the one that refused is not called, since its before never ran.
  • Order. Reverse insertion order, as for after.
  • When. On a call that answers, after every after hook 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, with CallOutcome::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_complete is running, that one is not restarted, and the ones not yet started are then called with CallOutcome::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.

Source

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".

Implementors§