@@ -298,13 +298,41 @@ public actor Server {
298298
299299 // MARK: - Request Context
300300
301- /// The JSON-RPC request ID of the currently executing method handler.
301+ /// Per-dispatch context the SDK attaches to the currently executing handler.
302+ ///
303+ /// Exposed via the ``Server/currentHandlerContext`` task-local so method
304+ /// handlers can observe the originating HTTP request (headers, auth, path,
305+ /// body) without changing the `withMethodHandler` signature.
306+ public struct HandlerContext : Sendable {
307+ /// The JSON-RPC request id of the in-flight request. SDK-internal use
308+ /// (e.g. transports closing an SSE stream mid-call per SEP-1699).
309+ package let id : ID
310+
311+ /// The originating HTTP request, if the active transport conforms to
312+ /// ``HTTPContextProviding``. `nil` for transports that don't carry HTTP
313+ /// context (stdio, in-memory) or for handlers reached off the dispatch
314+ /// path.
315+ public let httpContext : HTTPRequest ?
316+
317+ package init ( id: ID , httpContext: HTTPRequest ? ) {
318+ self . id = id
319+ self . httpContext = httpContext
320+ }
321+ }
322+
323+ /// The handler context for the currently executing method handler.
302324 ///
303325 /// Set via `@TaskLocal` before dispatching each request, so it propagates
304- /// automatically into the handler task. Accessible package-wide for
305- /// transports that need to identify the active request (e.g. closing an
306- /// SSE stream mid-call for reconnection testing per SEP-1699).
307- @TaskLocal package static var currentRequestID : ID ? = nil
326+ /// automatically into the handler task. `nil` outside of a handler.
327+ ///
328+ /// When spawning `Task.detached { … }` from inside a handler, capture the
329+ /// value up front — detached tasks do not inherit task-locals:
330+ ///
331+ /// ```swift
332+ /// let ctx = Server.currentHandlerContext
333+ /// Task.detached { await doWork(with: ctx?.httpContext) }
334+ /// ```
335+ @TaskLocal public static var currentHandlerContext : HandlerContext ? = nil
308336
309337 // MARK: - Registration
310338
@@ -750,10 +778,17 @@ public actor Server {
750778 return response
751779 }
752780
781+ // Ask the transport for the originating HTTP request so handlers can observe
782+ // headers/auth via `Server.currentHandlerContext?.httpContext`. Transports
783+ // that don't carry HTTP context (stdio, in-memory) don't conform.
784+ let httpContext = await ( connection as? any HTTPContextProviding ) ?
785+ . httpRequestContext ( for: request. id)
786+ let handlerContext = HandlerContext ( id: request. id, httpContext: httpContext)
787+
753788 // Create a task to handle the request with cancellation support.
754- // Set currentRequestID as a task local so handlers can identify the active request .
789+ // Set currentHandlerContext as a task local so handlers see it .
755790 var handlerTask : Task < Response < AnyMethod > , Error > !
756- Server . $currentRequestID . withValue ( request . id ) {
791+ Server . $currentHandlerContext . withValue ( handlerContext ) {
757792 handlerTask = Task < Response < AnyMethod > , Error > {
758793 do {
759794 // Check if task was cancelled before starting
0 commit comments