mcp_kit/server/auth_context.rs
1//! Task-local auth identity context.
2//!
3//! Before dispatching a `tools/call`, `resources/read`, or `prompts/get`
4//! request, `core.rs` calls [`scope`] to set the current identity for that
5//! async task. Handler code retrieves it via [`current`] (or through the
6//! [`Auth`] extractor, which calls [`current`] internally).
7//!
8//! Using a task-local means:
9//! - `ToolHandlerFn` signatures stay **unchanged** — no breaking API change.
10//! - Concurrently running handlers in different tasks each see their own identity.
11//! - The overhead is a single `tokio::task_local!` lookup per extractor use.
12//!
13//! [`Auth`]: crate::server::extract::Auth
14
15use std::future::Future;
16
17use crate::auth::AuthenticatedIdentity;
18
19tokio::task_local! {
20 /// The identity of the authenticated caller for the current MCP request.
21 /// `None` means the request was unauthenticated (or auth is not configured).
22 static CURRENT_AUTH: Option<AuthenticatedIdentity>;
23}
24
25/// Run `fut` with `identity` set as the current auth context for this task.
26///
27/// Called by `core.rs` before dispatching each handler invocation.
28pub fn scope<F: Future>(
29 identity: Option<AuthenticatedIdentity>,
30 fut: F,
31) -> impl Future<Output = F::Output> {
32 CURRENT_AUTH.scope(identity, fut)
33}
34
35/// Retrieve the current identity, or `None` if running outside an auth scope.
36pub fn current() -> Option<AuthenticatedIdentity> {
37 CURRENT_AUTH.try_with(|id| id.clone()).ok().flatten()
38}