Skip to main content

McpContext

Struct McpContext 

Source
pub struct McpContext {
    pub client_name: Option<String>,
    pub client_version: Option<String>,
    pub session_id: Option<String>,
    pub auth_claims: Option<String>,
    pub progress_token: Option<String>,
    /* private fields */
}
Expand description

Per-request context passed to tool handlers registered via McpServer::tool_with_context — caller identity and session info that a plain Fn(&str) -> ... tool handler has no way to see.

Constructed in McpServer::execute from the current request’s headers plus whatever clientInfo was recorded for this session at initialize time (see McpServer::handle_request_with_context).

Fields§

§client_name: Option<String>

clientInfo.name sent in this session’s initialize call, if the client sent one and this request carries a recognized Mcp-Session-Id.

§client_version: Option<String>

clientInfo.version sent in this session’s initialize call, under the same conditions as client_name.

§session_id: Option<String>

The Mcp-Session-Id header on this request, if present — the value the server minted and returned in the initialize response header for this session (see the module docs’ Sessions section).

§auth_claims: Option<String>

The verified caller’s claims as a JSON string: the serialized [crate::sso::OidcClaims] when [McpServer::require_oauth] (sso feature) is configured and this request’s bearer token verified, or {"sub":"<identity>"} for a token from McpServer::require_bearer_tokens. None if OAuth isn’t configured, or for a hand-built context (e.g. handle_request in tests) that bypassed McpServer::execute’s auth check entirely.

§progress_token: Option<String>

The raw JSON value of params._meta.progressToken from the triggering tools/call request, if the client sent one — a spec string | number, so this is stored pre-rendered (already correctly quoted if it’s a string) rather than decoded, and spliced back verbatim by Self::report_progress. None for anything other than a tools/call whose caller asked for progress updates.

Implementations§

Source§

impl McpContext

Source

pub fn report_progress( &self, progress: f64, total: Option<f64>, message: Option<&str>, )

Push a notifications/progress event over the SSE channel for this request’s progressToken, if the client asked for progress updates (params._meta.progressToken on the triggering tools/call) and this context was built through a live McpServer (via execute(), not a bare McpContext { .. } — see the sse_clients field doc).

Silently does nothing in either case — a handler doesn’t need to branch on whether progress reporting is actually wired up before calling this; it’s always safe to call.

total and message are both optional, matching the spec’s notifications/progress shape: {"progressToken":...,"progress":..., "total":...,"message":"..."} (with total/message omitted when not given here).

use rust_web_server::mcp::{McpContent, McpServer};

let server = McpServer::new("my-server", "1.0")
    .tool_with_context("long_job", "Do something slow", "{}", |ctx, _args| {
        ctx.report_progress(0.0, Some(100.0), Some("starting"));
        // ... do work ...
        ctx.report_progress(100.0, Some(100.0), Some("done"));
        Ok(McpContent::text("done"))
    });
Source

pub fn is_cancelled(&self) -> bool

true if the client sent notifications/cancelled referencing this tools/call’s request id.

Rust cannot forcibly interrupt a running synchronous closure — same limitation crate::timeout::with_timeout documents — so this is cooperative cancellation: nothing happens automatically. A handler that does its own iterative work (processing a batch of items, say) can check this between steps and return early; a handler that never checks it runs to completion regardless, exactly as before this existed.

Always false if the client never sent a cancellation, if this wasn’t dispatched as a tools/call (the only method cancellation applies to), or if ctx was built without a live server behind it.

use rust_web_server::mcp::{McpContent, McpServer};

let server = McpServer::new("my-server", "1.0")
    .tool_with_context("process_batch", "Process many items", "{}", |ctx, _args| {
        for i in 0..1_000_000 {
            if ctx.is_cancelled() {
                return Err("cancelled by client".to_string());
            }
            // ... process item i ...
        }
        Ok(McpContent::text("done"))
    });
Source

pub fn sample( &self, request: SamplingRequest, timeout: Duration, ) -> Result<SamplingResponse, String>

Deprecated by MCP 2026-07-28 (SEP-2577): Sampling keeps working with clients that use it, for at least twelve months, but new servers shouldn’t rely on it.

Ask the connected client to run LLM inference (“sampling”) and block until it replies or timeout elapses — the server-initiated half of sampling/createMessage. This reverses the usual request direction: the server sends a JSON-RPC request to the client over the GET /mcp SSE stream, and the client answers with its own POST /mcp carrying a JSON-RPC response (no method) that McpServer::handle_request_with_context recognizes and routes back here instead of treating it as an invalid request.

Blocking (not async fn) is deliberate: tool handlers in this crate are plain synchronous closures — there is no async tool handler support yet (MCP_TODO.md’s TODO-17) for this to .await inside of. The calling thread parks on the response channel for up to timeout; on a thread-pool server this ties up one worker for that long, same tradeoff crate::timeout::with_timeout already accepts for bounding a slow handler’s caller.

Fails fast, before sending anything, if: the client’s initialize call never declared capabilities.sampling (it wouldn’t know what to do with the request); this request has no session id (nothing to address the request to); or ctx has no live server behind it. Otherwise fails with a timeout error if the client never responds — including if it simply has no GET /mcp SSE connection open for this session, since there’s no separate “not connected” signal.

use rust_web_server::mcp::{McpServer, PromptMessage, SamplingRequest};
use std::time::Duration;

let server = McpServer::new("my-server", "1.0")
    .tool_with_context("ask_llm", "Ask the connected client's model a question", "{}", |ctx, _args| {
        let response = ctx.sample(
            SamplingRequest {
                messages: vec![PromptMessage::user("What is 2+2?")],
                max_tokens: 100,
                system_prompt: None,
            },
            Duration::from_secs(30),
        )?;
        Ok(response.content)
    });
Source

pub fn list_roots(&self, timeout: Duration) -> Result<Vec<McpRoot>, String>

Deprecated by MCP 2026-07-28 (SEP-2577): Roots keeps working with clients that use it, for at least twelve months, but new servers shouldn’t rely on it.

Ask the connected client which filesystem roots (workspace directories, mounted volumes, …) it has access to — useful for a file-system-aware tool that should only operate within the client’s declared workspace rather than the whole filesystem.

Like Self::sample, this reverses the usual request direction (a server-initiated roots/list request over SSE, answered by the client’s own POST /mcp) and blocks the calling thread for up to timeout — see sample’s docs for why blocking is deliberate here.

The result is cached per session: the first call after initialize (or after the client sends notifications/roots/list_changed, which invalidates the cache) does a live round trip; later calls in the same session return the cached list without sending anything. A tool handler can call this on every invocation without worrying about spamming the client with redundant roots/list requests.

Fails fast, before sending anything, under the same conditions as Self::sample (translated to roots): the client never declared capabilities.roots, this request has no session id, or ctx has no live server behind it.

use rust_web_server::mcp::McpServer;
use std::time::Duration;

let server = McpServer::new("my-server", "1.0")
    .tool_with_context("list_workspace_files", "List files in the client's workspace", "{}", |ctx, _args| {
        let roots = ctx.list_roots(Duration::from_secs(10))?;
        let names: Vec<String> = roots.iter().map(|r| r.uri.clone()).collect();
        Ok(rust_web_server::mcp::McpContent::text(names.join(", ")))
    });

Trait Implementations§

Source§

impl Clone for McpContext

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 McpContext

Source§

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

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

impl Default for McpContext

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

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<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> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

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