Skip to main content

ServerConfig

Struct ServerConfig 

Source
pub struct ServerConfig { /* private fields */ }
Expand description

The settings one Streamable HTTP server is built from.

Implementations§

Source§

impl ServerConfig

Source

pub fn new() -> Result<Self, EndpointError>

A configuration with every default: the specification’s endpoint, the domain’s default frame ceiling, a replay window of RECOMMENDED_CAPACITY, inline JSON answers, and the strict security headers.

§Errors

EndpointError, because the default endpoint is parsed rather than trusted — a const that could be wrong is a bug the caller finds out about at construction instead of at mount time.

Source

pub const fn max_concurrency(&self) -> NonZeroU32

How many requests may be in flight at once.

A ceiling rather than a queue: past this the connection is shed with 503, because a request that waits for a slot has already spent the caller’s timeout doing nothing. OWASP API Security Top 10:2023, API4:2023 (Unrestricted Resource Consumption).

Source

pub const fn with_max_concurrency(self, limit: NonZeroU32) -> Self

Sets the in-flight ceiling. A limit of zero is rejected by NonZeroU32, because a server that accepts nothing is a server that is up and useless.

Source

pub const fn request_timeout(&self) -> Duration

How long one request may take end to end.

Distinct from stream_timeout, which bounds the idle gap between events on an already-open stream. This one bounds the whole request, so a handler that never answers is dropped rather than holding a connection open forever.

Source

pub const fn with_request_timeout(self, timeout: Duration) -> Self

Sets the per-request deadline.

Source

pub const fn rate_limit(&self) -> &RateLimit

The per-subject request allowance.

Source

pub const fn with_rate_limit(self, limit: RateLimit) -> Self

Sets the per-subject allowance.

Source

pub const fn endpoint(&self) -> &Endpoint

The MCP endpoint path.

Source

pub const fn max_body(&self) -> MaxFrameSize

The largest POST body accepted, in bytes.

Enforced before the body is read into memory where the framework allows it, and again on the assembled buffer, because the two limits protect different things: the first the process, the second the framing layer.

Source

pub const fn replay_capacity(&self) -> NonZeroUsize

How many events a session retains for replay.

Source

pub const fn streaming(&self) -> Streaming

Whether a POST is answered inline or over SSE.

Source

pub const fn with_streaming(self, streaming: Streaming) -> Self

Sets the streaming policy.

Source

pub const fn stream_timeout(&self) -> Duration

How long a server-initiated stream stays open.

Source

pub const fn with_stream_timeout(self, timeout: Duration) -> Self

Sets the stream timeout. A zero timeout closes the stream as soon as its replay window is drained, which is a legitimate way to run a “deliver the backlog, then hang up” endpoint.

Source

pub const fn keep_alive(&self) -> Duration

How long a stream waits before emitting a keep-alive comment.

Source

pub const fn with_keep_alive(self, keep_alive: Duration) -> Self

Sets the keep-alive interval.

Source

pub const fn security(&self) -> &SecurityHeaders

The three security headers.

Source

pub fn with_security(self, security: SecurityHeaders) -> Self

Replaces the security headers.

Source

pub const fn required_scopes(&self) -> ScopeSet

The scopes a stateful request must hold.

Empty by default, and empty is not the same as unauthenticated. An empty requirement is a statement that this endpoint has nothing to protect; a caller that disagrees names the scope it needs and every request that arrives without it is refused. The alternative — a default that demands a scope — would make the transport refuse every request from every deployment that has not yet wired T16’s OAuth, which is a worse failure than serving a read-only endpoint to the public.

What the empty default does guarantee is fail-secure structure rather than fail-secure policy: an anonymous caller is AuthContext::anonymous, which holds no scopes, so the moment a scope is named the anonymous caller is refused. There is no path by which an unauthenticated request reaches a scope-bearing route.

Source

pub const fn with_required_scopes(self, scopes: ScopeSet) -> Self

Names the scopes a stateful request must hold.

Source

pub fn resource_metadata(&self) -> Option<&ResourceMetadata>

The RFC 9728 metadata this server publishes, if it publishes one.

None by default, because a server that names no authorization servers has nothing to publish and an empty document is not the same as no document.

Setting this does both halves of RFC 9728 at once: the router serves the document at ResourceUri::metadata_path, and a 401 carries the WWW-Authenticate challenge naming that same URL. One value, so the two cannot name different places.

Source

pub fn with_resource_metadata(self, metadata: ResourceMetadata) -> Self

Publishes metadata, enabling both the WWW-Authenticate challenge and the well-known route that serves it.

McpRouter::into_router mounts the document at the path its resource identifier implies. A consumer does not merge anything.

§Examples
use protocol_droid::adapters::primary::transport::http::ServerConfig;
use protocol_droid::domain::mcp::{ResourceMetadata, ResourceUri};

let metadata = ResourceMetadata::new(ResourceUri::new("https://example.com/mcp")?)
    .with_authorization_server("https://login.example.com");

// The route is mounted at /.well-known/oauth-protected-resource/mcp.
let config = ServerConfig::new()?.with_resource_metadata(metadata);
assert!(config.challenge().is_some());
Source

pub fn challenge(&self) -> Option<String>

The WWW-Authenticate challenge for a 401, if this server publishes metadata.

RFC 9728 §5.1: a 401 on a protected resource carries a WWW-Authenticate naming where the client can discover the authorization server, and that challenge is the only pointer a client gets. Without it a client holding an expired token has no URL to fetch authorization-server metadata from, which is the situation the challenge exists to solve.

Returns None rather than a bare Bearer when nothing is published: a challenge naming no resource metadata tells the client the scheme and nothing else, and a deployment that has not configured a document is better served by an unadorned 401 that it can recognise as misconfigured.

Trait Implementations§

Source§

impl Clone for ServerConfig

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ServerConfig

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Eq for ServerConfig

Source§

impl PartialEq for ServerConfig

Source§

fn eq(&self, other: &Self) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for ServerConfig

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DynClone for T
where T: Clone,

Source§

fn __clone_box(&self, _: Private) -> *mut ()

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> FromRef<T> for T
where T: Clone,

Source§

fn from_ref(input: &T) -> T

Converts to this type from a reference to the input type.
Source§

impl<A, B, T> HttpServerConnExec<A, B> for T
where B: Body,

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more