@orkestrel/mcp 0.0.9 → 0.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -14,6 +14,7 @@ import { MCPTransportInterface } from '../core/index.ts';
14
14
  import { MCPVersion } from '../core/index.ts';
15
15
  import { MiddlewareHandler } from '@orkestrel/server';
16
16
  import { NodeWebSocketInterface } from '@orkestrel/websocket';
17
+ import { RouteContext } from '@orkestrel/router';
17
18
  import { RouteInput } from '@orkestrel/router';
18
19
  import { StreamInterface } from '@orkestrel/server';
19
20
  import { UpgradeHandler } from '@orkestrel/server';
@@ -140,10 +141,13 @@ export declare function createHTTPClientTransport(options: HTTPClientTransportOp
140
141
  * explicitly delegated upstream. Modern dispatch errors use their protocol status map; legacy
141
142
  * errors remain in-band at HTTP `200`. A streamed response composes the fetch-standard request
142
143
  * signal with response-body cancellation and supplies the result to every dispatched modern
143
- * handler through `MCPDispatchOptions.signal`.
144
+ * handler through `MCPDispatchOptions.signal`. After every transport validation and immediately
145
+ * before dispatch, the optional synchronous `caller` extractor reads front-middleware state; a
146
+ * defined value is added to `MCPDispatchOptions`, while `undefined` is omitted.
144
147
  *
148
+ * @typeParam TState - The consumer's opaque per-request route state type
145
149
  * @param mcp - The transport-agnostic MCP server to dispatch through
146
- * @param options - Optional streaming, origin-validation, and SSE keepalive options
150
+ * @param options - Optional streaming, origin-validation, SSE keepalive, and caller-extraction options
147
151
  * @returns A request handler for the stateless MCP POST route
148
152
  *
149
153
  * @example
@@ -160,11 +164,7 @@ export declare function createHTTPClientTransport(options: HTTPClientTransportOp
160
164
  * }))
161
165
  * ```
162
166
  */
163
- export declare function createMCPPostHandler(mcp: MCPServerInterface, options?: {
164
- readonly streaming?: boolean;
165
- readonly origin?: MCPOriginOptions;
166
- readonly keepalive?: MCPKeepaliveOptions;
167
- }): (request: Request) => Promise<Response>;
167
+ export declare function createMCPPostHandler<TState = unknown>(mcp: MCPServerInterface, options?: HTTPHandlerOptions<TState>): (request: Request, context?: RouteContext<string, TState>) => Promise<Response>;
168
168
 
169
169
  /**
170
170
  * Create the MCP Streamable-HTTP transport routes — mounts a transport-agnostic
@@ -207,7 +207,7 @@ export declare function createMCPPostHandler(mcp: MCPServerInterface, options?:
207
207
  * @typeParam TState - The consumer's opaque per-request state type
208
208
  * @param mcp - The transport-agnostic {@link MCPServerInterface} to expose over HTTP
209
209
  * @param options - Optional `path` (default {@link DEFAULT_MCP_PATH}) and `streaming`
210
- * (default `true`), plus the shared `origin` validation options; see
210
+ * (default `true`), plus shared origin, keepalive, and synchronous caller-extraction options; see
211
211
  * {@link HTTPTransportOptions}
212
212
  * @returns The {@link RouteInput}s to register with the router
213
213
  *
@@ -220,7 +220,7 @@ export declare function createMCPPostHandler(mcp: MCPServerInterface, options?:
220
220
  * const routes = createMCPRoutes(mcp) // POST /mcp dispatches JSON-RPC (JSON or SSE per Accept)
221
221
  * ```
222
222
  */
223
- export declare function createMCPRoutes<TState = unknown>(mcp: MCPServerInterface, options?: HTTPTransportOptions): readonly RouteInput<string, TState>[];
223
+ export declare function createMCPRoutes<TState = unknown>(mcp: MCPServerInterface, options?: HTTPTransportOptions<TState>): readonly RouteInput<string, TState>[];
224
224
 
225
225
  /**
226
226
  * Create the native MCP session {@link MiddlewareHandler} — the plug-and-play stateful layer
@@ -631,16 +631,9 @@ export declare interface HTTPClientTransportOptions {
631
631
  }
632
632
 
633
633
  /**
634
- * Options for `createMCPRoutes` the path the transport is mounted at and whether an SSE
635
- * response is allowed. `createMCPRoutes` is STATELESS; sessions are a separate middleware
636
- * ({@link import('./middlewares.js').createMCPSession}), composed via `server.use`.
634
+ * Options shared by the MCP Streamable-HTTP POST handler and route factory.
637
635
  *
638
636
  * @remarks
639
- * - `path` — the request path the single `POST` route answers; defaults to
640
- * {@link import('./constants.js').DEFAULT_MCP_PATH} (`'/mcp'`). `GET` / `DELETE` to this
641
- * path get the spine's automatic `405` unless a {@link
642
- * import('./middlewares.js').createMCPSession} middleware (which owns the same `path`) is
643
- * mounted IN FRONT to serve them.
644
637
  * - `streaming` — when `true` (the DEFAULT) the transport MAY answer with a
645
638
  * Server-Sent-Events response (one `data:` event carrying the JSON-RPC reply, then
646
639
  * the stream ends) whenever the client's `Accept` header includes
@@ -656,13 +649,32 @@ export declare interface HTTPClientTransportOptions {
656
649
  * - `keepalive` — the SSE liveness options for held-open responses. `interval` defaults to
657
650
  * {@link import('./constants.js').DEFAULT_MCP_KEEPALIVE_INTERVAL}. Keepalives never apply
658
651
  * to unary responses.
652
+ * - `caller` — the synchronous extractor for consumer-asserted caller context already resolved
653
+ * by front middleware. It runs only for a validated request that will dispatch. Returning
654
+ * `undefined` omits caller context; a throw propagates.
659
655
  */
660
- export declare interface HTTPTransportOptions {
661
- readonly path?: string;
656
+ export declare interface HTTPHandlerOptions<TState = unknown> {
662
657
  readonly streaming?: boolean;
663
658
  /** Must match the session layer's value; `origins` is ignored when `enabled` is `false`. */
664
659
  readonly origin?: MCPOriginOptions;
665
660
  readonly keepalive?: MCPKeepaliveOptions;
661
+ readonly caller?: MCPCallerHandler<TState>;
662
+ }
663
+
664
+ /**
665
+ * Options for `createMCPRoutes` — the mount path plus the shared POST-handler options.
666
+ * `createMCPRoutes` is STATELESS; sessions are a separate middleware ({@link
667
+ * import('./middlewares.js').createMCPSession}), composed via `server.use`.
668
+ *
669
+ * @remarks
670
+ * `path` is the request path the single `POST` route answers; it defaults to {@link
671
+ * import('./constants.js').DEFAULT_MCP_PATH} (`'/mcp'`). `GET` / `DELETE` to this path get
672
+ * the spine's automatic `405` unless a {@link import('./middlewares.js').createMCPSession}
673
+ * middleware owning the same path is mounted in front. The remaining options are inherited
674
+ * from {@link HTTPHandlerOptions}.
675
+ */
676
+ export declare interface HTTPTransportOptions<TState = unknown> extends HTTPHandlerOptions<TState> {
677
+ readonly path?: string;
666
678
  }
667
679
 
668
680
  /**
@@ -759,6 +771,23 @@ export declare const MCP_SESSION_HEADER = "mcp-session-id";
759
771
  */
760
772
  export declare const MCP_WEBSOCKET_SUBPROTOCOL = "mcp";
761
773
 
774
+ /**
775
+ * Synchronously extract consumer-asserted caller context from an HTTP request after the
776
+ * transport has validated it for dispatch.
777
+ *
778
+ * @remarks
779
+ * Authentication belongs to middleware composed in front of the MCP route. This handler only
780
+ * reads what that middleware already resolved. Returning `undefined` supplies no caller; a
781
+ * throw propagates as a route-handler throw. The result remains `unknown` because this package
782
+ * cannot verify caller identity.
783
+ *
784
+ * @typeParam TState - The consumer's opaque per-request route state type
785
+ * @param request - The validated Fetch request that will dispatch
786
+ * @param context - The router context, or `undefined` for direct handler invocation
787
+ * @returns Consumer-asserted caller context, or `undefined` for no caller
788
+ */
789
+ export declare type MCPCallerHandler<TState = unknown> = (request: Request, context: RouteContext<string, TState> | undefined) => unknown;
790
+
762
791
  /**
763
792
  * Shared SSE keepalive options for held-open HTTP responses.
764
793
  *
@@ -14,6 +14,7 @@ import { MCPTransportInterface } from '../core/index.ts';
14
14
  import { MCPVersion } from '../core/index.ts';
15
15
  import { MiddlewareHandler } from '@orkestrel/server';
16
16
  import { NodeWebSocketInterface } from '@orkestrel/websocket';
17
+ import { RouteContext } from '@orkestrel/router';
17
18
  import { RouteInput } from '@orkestrel/router';
18
19
  import { StreamInterface } from '@orkestrel/server';
19
20
  import { UpgradeHandler } from '@orkestrel/server';
@@ -140,10 +141,13 @@ export declare function createHTTPClientTransport(options: HTTPClientTransportOp
140
141
  * explicitly delegated upstream. Modern dispatch errors use their protocol status map; legacy
141
142
  * errors remain in-band at HTTP `200`. A streamed response composes the fetch-standard request
142
143
  * signal with response-body cancellation and supplies the result to every dispatched modern
143
- * handler through `MCPDispatchOptions.signal`.
144
+ * handler through `MCPDispatchOptions.signal`. After every transport validation and immediately
145
+ * before dispatch, the optional synchronous `caller` extractor reads front-middleware state; a
146
+ * defined value is added to `MCPDispatchOptions`, while `undefined` is omitted.
144
147
  *
148
+ * @typeParam TState - The consumer's opaque per-request route state type
145
149
  * @param mcp - The transport-agnostic MCP server to dispatch through
146
- * @param options - Optional streaming, origin-validation, and SSE keepalive options
150
+ * @param options - Optional streaming, origin-validation, SSE keepalive, and caller-extraction options
147
151
  * @returns A request handler for the stateless MCP POST route
148
152
  *
149
153
  * @example
@@ -160,11 +164,7 @@ export declare function createHTTPClientTransport(options: HTTPClientTransportOp
160
164
  * }))
161
165
  * ```
162
166
  */
163
- export declare function createMCPPostHandler(mcp: MCPServerInterface, options?: {
164
- readonly streaming?: boolean;
165
- readonly origin?: MCPOriginOptions;
166
- readonly keepalive?: MCPKeepaliveOptions;
167
- }): (request: Request) => Promise<Response>;
167
+ export declare function createMCPPostHandler<TState = unknown>(mcp: MCPServerInterface, options?: HTTPHandlerOptions<TState>): (request: Request, context?: RouteContext<string, TState>) => Promise<Response>;
168
168
 
169
169
  /**
170
170
  * Create the MCP Streamable-HTTP transport routes — mounts a transport-agnostic
@@ -207,7 +207,7 @@ export declare function createMCPPostHandler(mcp: MCPServerInterface, options?:
207
207
  * @typeParam TState - The consumer's opaque per-request state type
208
208
  * @param mcp - The transport-agnostic {@link MCPServerInterface} to expose over HTTP
209
209
  * @param options - Optional `path` (default {@link DEFAULT_MCP_PATH}) and `streaming`
210
- * (default `true`), plus the shared `origin` validation options; see
210
+ * (default `true`), plus shared origin, keepalive, and synchronous caller-extraction options; see
211
211
  * {@link HTTPTransportOptions}
212
212
  * @returns The {@link RouteInput}s to register with the router
213
213
  *
@@ -220,7 +220,7 @@ export declare function createMCPPostHandler(mcp: MCPServerInterface, options?:
220
220
  * const routes = createMCPRoutes(mcp) // POST /mcp dispatches JSON-RPC (JSON or SSE per Accept)
221
221
  * ```
222
222
  */
223
- export declare function createMCPRoutes<TState = unknown>(mcp: MCPServerInterface, options?: HTTPTransportOptions): readonly RouteInput<string, TState>[];
223
+ export declare function createMCPRoutes<TState = unknown>(mcp: MCPServerInterface, options?: HTTPTransportOptions<TState>): readonly RouteInput<string, TState>[];
224
224
 
225
225
  /**
226
226
  * Create the native MCP session {@link MiddlewareHandler} — the plug-and-play stateful layer
@@ -631,16 +631,9 @@ export declare interface HTTPClientTransportOptions {
631
631
  }
632
632
 
633
633
  /**
634
- * Options for `createMCPRoutes` the path the transport is mounted at and whether an SSE
635
- * response is allowed. `createMCPRoutes` is STATELESS; sessions are a separate middleware
636
- * ({@link import('./middlewares.js').createMCPSession}), composed via `server.use`.
634
+ * Options shared by the MCP Streamable-HTTP POST handler and route factory.
637
635
  *
638
636
  * @remarks
639
- * - `path` — the request path the single `POST` route answers; defaults to
640
- * {@link import('./constants.js').DEFAULT_MCP_PATH} (`'/mcp'`). `GET` / `DELETE` to this
641
- * path get the spine's automatic `405` unless a {@link
642
- * import('./middlewares.js').createMCPSession} middleware (which owns the same `path`) is
643
- * mounted IN FRONT to serve them.
644
637
  * - `streaming` — when `true` (the DEFAULT) the transport MAY answer with a
645
638
  * Server-Sent-Events response (one `data:` event carrying the JSON-RPC reply, then
646
639
  * the stream ends) whenever the client's `Accept` header includes
@@ -656,13 +649,32 @@ export declare interface HTTPClientTransportOptions {
656
649
  * - `keepalive` — the SSE liveness options for held-open responses. `interval` defaults to
657
650
  * {@link import('./constants.js').DEFAULT_MCP_KEEPALIVE_INTERVAL}. Keepalives never apply
658
651
  * to unary responses.
652
+ * - `caller` — the synchronous extractor for consumer-asserted caller context already resolved
653
+ * by front middleware. It runs only for a validated request that will dispatch. Returning
654
+ * `undefined` omits caller context; a throw propagates.
659
655
  */
660
- export declare interface HTTPTransportOptions {
661
- readonly path?: string;
656
+ export declare interface HTTPHandlerOptions<TState = unknown> {
662
657
  readonly streaming?: boolean;
663
658
  /** Must match the session layer's value; `origins` is ignored when `enabled` is `false`. */
664
659
  readonly origin?: MCPOriginOptions;
665
660
  readonly keepalive?: MCPKeepaliveOptions;
661
+ readonly caller?: MCPCallerHandler<TState>;
662
+ }
663
+
664
+ /**
665
+ * Options for `createMCPRoutes` — the mount path plus the shared POST-handler options.
666
+ * `createMCPRoutes` is STATELESS; sessions are a separate middleware ({@link
667
+ * import('./middlewares.js').createMCPSession}), composed via `server.use`.
668
+ *
669
+ * @remarks
670
+ * `path` is the request path the single `POST` route answers; it defaults to {@link
671
+ * import('./constants.js').DEFAULT_MCP_PATH} (`'/mcp'`). `GET` / `DELETE` to this path get
672
+ * the spine's automatic `405` unless a {@link import('./middlewares.js').createMCPSession}
673
+ * middleware owning the same path is mounted in front. The remaining options are inherited
674
+ * from {@link HTTPHandlerOptions}.
675
+ */
676
+ export declare interface HTTPTransportOptions<TState = unknown> extends HTTPHandlerOptions<TState> {
677
+ readonly path?: string;
666
678
  }
667
679
 
668
680
  /**
@@ -759,6 +771,23 @@ export declare const MCP_SESSION_HEADER = "mcp-session-id";
759
771
  */
760
772
  export declare const MCP_WEBSOCKET_SUBPROTOCOL = "mcp";
761
773
 
774
+ /**
775
+ * Synchronously extract consumer-asserted caller context from an HTTP request after the
776
+ * transport has validated it for dispatch.
777
+ *
778
+ * @remarks
779
+ * Authentication belongs to middleware composed in front of the MCP route. This handler only
780
+ * reads what that middleware already resolved. Returning `undefined` supplies no caller; a
781
+ * throw propagates as a route-handler throw. The result remains `unknown` because this package
782
+ * cannot verify caller identity.
783
+ *
784
+ * @typeParam TState - The consumer's opaque per-request route state type
785
+ * @param request - The validated Fetch request that will dispatch
786
+ * @param context - The router context, or `undefined` for direct handler invocation
787
+ * @returns Consumer-asserted caller context, or `undefined` for no caller
788
+ */
789
+ export declare type MCPCallerHandler<TState = unknown> = (request: Request, context: RouteContext<string, TState> | undefined) => unknown;
790
+
762
791
  /**
763
792
  * Shared SSE keepalive options for held-open HTTP responses.
764
793
  *
@@ -542,10 +542,13 @@ var HTTPDisconnect = class {
542
542
  * explicitly delegated upstream. Modern dispatch errors use their protocol status map; legacy
543
543
  * errors remain in-band at HTTP `200`. A streamed response composes the fetch-standard request
544
544
  * signal with response-body cancellation and supplies the result to every dispatched modern
545
- * handler through `MCPDispatchOptions.signal`.
545
+ * handler through `MCPDispatchOptions.signal`. After every transport validation and immediately
546
+ * before dispatch, the optional synchronous `caller` extractor reads front-middleware state; a
547
+ * defined value is added to `MCPDispatchOptions`, while `undefined` is omitted.
546
548
  *
549
+ * @typeParam TState - The consumer's opaque per-request route state type
547
550
  * @param mcp - The transport-agnostic MCP server to dispatch through
548
- * @param options - Optional streaming, origin-validation, and SSE keepalive options
551
+ * @param options - Optional streaming, origin-validation, SSE keepalive, and caller-extraction options
549
552
  * @returns A request handler for the stateless MCP POST route
550
553
  *
551
554
  * @example
@@ -565,7 +568,7 @@ var HTTPDisconnect = class {
565
568
  function createMCPPostHandler(mcp, options) {
566
569
  const streaming = options?.streaming ?? true;
567
570
  const origin = options?.origin;
568
- return async (request) => {
571
+ return async (request, context) => {
569
572
  if (!allowsOrigin(request, origin)) return new Response(null, { status: 403 });
570
573
  let text;
571
574
  try {
@@ -595,7 +598,11 @@ function createMCPPostHandler(mcp, options) {
595
598
  }), { status: 400 });
596
599
  }
597
600
  const disconnect = new HTTPDisconnect(request.signal, options?.keepalive);
598
- const response = await mcp.dispatch(rpcRequest, { signal: disconnect.signal });
601
+ const caller = options?.caller?.(request, context);
602
+ const response = await mcp.dispatch(rpcRequest, {
603
+ signal: disconnect.signal,
604
+ ...caller === void 0 ? {} : { caller }
605
+ });
599
606
  if (response !== void 0 && Symbol.asyncIterator in response) {
600
607
  const stream = openStream();
601
608
  stream.response.headers.set(SSE_BUFFERING_HEADER, "no");
@@ -1307,7 +1314,7 @@ var StdioServerTransport = class {
1307
1314
  * @typeParam TState - The consumer's opaque per-request state type
1308
1315
  * @param mcp - The transport-agnostic {@link MCPServerInterface} to expose over HTTP
1309
1316
  * @param options - Optional `path` (default {@link DEFAULT_MCP_PATH}) and `streaming`
1310
- * (default `true`), plus the shared `origin` validation options; see
1317
+ * (default `true`), plus shared origin, keepalive, and synchronous caller-extraction options; see
1311
1318
  * {@link HTTPTransportOptions}
1312
1319
  * @returns The {@link RouteInput}s to register with the router
1313
1320
  *