@routecraft/ai 0.4.0-canary.8 → 0.4.0

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.
package/dist/index.d.cts CHANGED
@@ -369,20 +369,44 @@ declare const MCP_STDIO_MANAGERS: unique symbol;
369
369
  declare module "@routecraft/routecraft" {
370
370
  interface StoreRegistry {
371
371
  [MCP_PLUGIN_REGISTERED]: boolean;
372
- [ADAPTER_MCP_CLIENT_SERVERS]: Map<string, McpClientHttpConfig$1 | McpClientStdioConfig | string>;
372
+ [ADAPTER_MCP_CLIENT_SERVERS]: Map<string, McpClientHttpConfig | McpClientStdioConfig | string>;
373
373
  [MCP_TOOL_REGISTRY]: McpToolRegistry;
374
374
  [MCP_STDIO_MANAGERS]: Map<string, {
375
375
  callTool(name: string, args: Record<string, unknown>): Promise<unknown>;
376
376
  }>;
377
377
  }
378
+ interface RoutecraftHeaders {
379
+ /** The MCP tool name that triggered this exchange. */
380
+ "routecraft.mcp.tool"?: string;
381
+ /** The MCP session identifier. */
382
+ "routecraft.mcp.session"?: string;
383
+ /** Authenticated subject (from AuthPrincipal). */
384
+ "routecraft.auth.subject"?: string;
385
+ /** Authentication scheme used. */
386
+ "routecraft.auth.scheme"?: string;
387
+ /** Roles assigned to the authenticated principal. */
388
+ "routecraft.auth.roles"?: string[];
389
+ /** Scopes granted to the authenticated principal. */
390
+ "routecraft.auth.scopes"?: string[];
391
+ /** Email of the authenticated principal. */
392
+ "routecraft.auth.email"?: string;
393
+ /** Display name of the authenticated principal. */
394
+ "routecraft.auth.name"?: string;
395
+ /** Token issuer (JWT `iss`). */
396
+ "routecraft.auth.issuer"?: string;
397
+ /** Intended audience (JWT `aud`). */
398
+ "routecraft.auth.audience"?: string[];
399
+ }
378
400
  }
379
401
  /**
380
402
  * HTTP client config for a remote MCP server (Streamable HTTP).
381
403
  * Used in mcpPlugin({ clients: { name: config } }).
382
404
  */
383
- interface McpClientHttpConfig$1 {
405
+ interface McpClientHttpConfig {
384
406
  transport?: "streamable-http";
385
407
  url: string;
408
+ /** Auth credentials sent on every request to this server. */
409
+ auth?: McpClientAuthOptions;
386
410
  }
387
411
  /**
388
412
  * Stdio client config for a local MCP server subprocess.
@@ -401,7 +425,155 @@ interface McpClientStdioConfig {
401
425
  cwd?: string;
402
426
  }
403
427
  /** Union of client configs accepted by mcpPlugin({ clients }). */
404
- type McpClientServerConfig = McpClientHttpConfig$1 | McpClientStdioConfig;
428
+ type McpClientServerConfig = McpClientHttpConfig | McpClientStdioConfig;
429
+ /**
430
+ * Header keys set on exchanges created by the MCP server.
431
+ * Use these with `exchange.headers[McpHeadersKeys.AUTH_SUBJECT]` for type-safe access.
432
+ *
433
+ * @example
434
+ * ```ts
435
+ * import { McpHeadersKeys } from '@routecraft/ai'
436
+ *
437
+ * .process((ex) => {
438
+ * const user = ex.headers[McpHeadersKeys.AUTH_SUBJECT]
439
+ * const tool = ex.headers[McpHeadersKeys.TOOL]
440
+ * })
441
+ * ```
442
+ */
443
+ declare enum McpHeadersKeys {
444
+ /** The MCP tool name that triggered this exchange. */
445
+ TOOL = "routecraft.mcp.tool",
446
+ /** The MCP session identifier. */
447
+ SESSION = "routecraft.mcp.session",
448
+ /** Authenticated subject (from AuthPrincipal). */
449
+ AUTH_SUBJECT = "routecraft.auth.subject",
450
+ /** Authentication scheme used. */
451
+ AUTH_SCHEME = "routecraft.auth.scheme",
452
+ /** Roles assigned to the authenticated principal. */
453
+ AUTH_ROLES = "routecraft.auth.roles",
454
+ /** Scopes granted to the authenticated principal. */
455
+ AUTH_SCOPES = "routecraft.auth.scopes",
456
+ /** Email of the authenticated principal. */
457
+ AUTH_EMAIL = "routecraft.auth.email",
458
+ /** Display name of the authenticated principal. */
459
+ AUTH_NAME = "routecraft.auth.name",
460
+ /** Token issuer (JWT `iss`). */
461
+ AUTH_ISSUER = "routecraft.auth.issuer",
462
+ /** Intended audience (JWT `aud`). */
463
+ AUTH_AUDIENCE = "routecraft.auth.audience"
464
+ }
465
+ /**
466
+ * Authenticated user principal resolved from an incoming request.
467
+ * Returned by the auth validator to populate exchange headers for logging,
468
+ * filtering, and access control inside routes.
469
+ *
470
+ * `subject` and `scheme` are always required; everything else is
471
+ * scheme-dependent and may be absent.
472
+ *
473
+ * @experimental
474
+ */
475
+ interface AuthPrincipal {
476
+ /** Unique user/client identifier (JWT `sub`, username, API key ID, etc.). */
477
+ subject: string;
478
+ /** Authentication scheme that produced this principal. */
479
+ scheme: "bearer" | "basic" | "api-key" | (string & {});
480
+ /** Role names granted to this principal. */
481
+ roles?: string[];
482
+ /** OAuth 2.0 / JWT scopes. */
483
+ scopes?: string[];
484
+ /** Email address, if known. */
485
+ email?: string;
486
+ /** Display name, if known. */
487
+ name?: string;
488
+ /** Token issuer (JWT `iss`). */
489
+ issuer?: string;
490
+ /** Intended audiences (JWT `aud`). */
491
+ audience?: string[];
492
+ /** Expiry as Unix epoch seconds (JWT `exp`, session expiry). */
493
+ expiresAt?: number;
494
+ /** Arbitrary extra claims. For JWTs this holds the full decoded payload. */
495
+ claims?: Record<string, unknown>;
496
+ }
497
+ /**
498
+ * Authentication options for the MCP HTTP server.
499
+ * Only applies when `transport` is `"http"`. Ignored for stdio.
500
+ *
501
+ * The validator receives the raw bearer token from the `Authorization` header
502
+ * on every request and must return an {@link AuthPrincipal} on success or
503
+ * `null` / `false` to reject with 401. Use the built-in `jwt()` helper for
504
+ * HMAC-signed JWTs or supply a custom function for other schemes.
505
+ *
506
+ * @example
507
+ * ```ts
508
+ * // Built-in JWT helper (HMAC / HS256)
509
+ * import { jwt } from "@routecraft/ai";
510
+ * auth: jwt({ secret: process.env.JWT_SECRET! })
511
+ *
512
+ * // Custom validator
513
+ * auth: {
514
+ * validator: async (token) => {
515
+ * const user = await lookupApiKey(token);
516
+ * if (!user) return null;
517
+ * return { subject: user.id, scheme: "api-key", roles: user.roles };
518
+ * }
519
+ * }
520
+ * ```
521
+ *
522
+ * @experimental
523
+ */
524
+ interface McpHttpAuthOptions {
525
+ /**
526
+ * Validator function called with the raw bearer token on every request.
527
+ *
528
+ * Return an {@link AuthPrincipal} to allow access; return `null` or `false`
529
+ * to reject with 401. May be async.
530
+ *
531
+ * If the function throws, the server responds with 500.
532
+ * Validators should catch expected failures (e.g. JWT expiry) and return `null`.
533
+ */
534
+ validator: McpAuthValidator;
535
+ }
536
+ /**
537
+ * A function that validates a bearer token and resolves the authenticated principal.
538
+ * Called on every incoming HTTP request.
539
+ * May be synchronous or asynchronous.
540
+ *
541
+ * Return an {@link AuthPrincipal} to allow access, or `null` / `false` to reject with 401.
542
+ * If the function throws, the server responds with 500.
543
+ *
544
+ * @experimental
545
+ */
546
+ type McpAuthValidator = (token: string) => AuthPrincipal | null | false | Promise<AuthPrincipal | null | false>;
547
+ /**
548
+ * A function that provides a bearer token for outbound requests.
549
+ * Called on every request; may be synchronous or asynchronous.
550
+ * Useful for dynamic tokens (JWT refresh, rotating API keys, etc.).
551
+ *
552
+ * @experimental
553
+ */
554
+ type McpClientTokenProvider = () => string | Promise<string>;
555
+ /**
556
+ * Auth config for an outbound MCP HTTP client connection.
557
+ * Passed as request headers on every connection to the remote server.
558
+ *
559
+ * @experimental
560
+ */
561
+ interface McpClientAuthOptions {
562
+ /**
563
+ * Bearer token(s) or provider for the `Authorization` header.
564
+ * Builds `Authorization: Bearer <token>`.
565
+ *
566
+ * - `string` -- single static token.
567
+ * - `string[]` -- array of tokens; one is selected per request (round-robin).
568
+ * - `() => string | Promise<string>` -- called per request for dynamic tokens.
569
+ */
570
+ token?: string | string[] | McpClientTokenProvider;
571
+ /**
572
+ * Additional headers to include on every request to the remote server.
573
+ * If `Authorization` is set here, it overrides `token`.
574
+ */
575
+ headers?: Record<string, string>;
576
+ }
405
577
  /**
406
578
  * Options for the MCP plugin (mcpPlugin).
407
579
  * One plugin per adapter: this is the single options type for the MCP plugin.
@@ -417,6 +589,17 @@ interface McpPluginOptions {
417
589
  port?: number;
418
590
  /** Host to bind to. Default: "localhost" (only used with transport: "http") */
419
591
  host?: string;
592
+ /**
593
+ * Authentication for the HTTP transport. When set, every request to `/mcp` must
594
+ * include a valid `Authorization: Bearer <token>` header. Ignored for stdio.
595
+ *
596
+ * @example
597
+ * ```ts
598
+ * import { jwt } from "@routecraft/ai";
599
+ * auth: jwt({ secret: process.env.JWT_SECRET! })
600
+ * ```
601
+ */
602
+ auth?: McpHttpAuthOptions;
420
603
  /**
421
604
  * Filter which tools to expose. Default: all mcp() routes.
422
605
  * Can be an array of endpoint names or a filter function.
@@ -428,7 +611,7 @@ interface McpPluginOptions {
428
611
  * Stdio clients are managed as subprocesses with auto-restart.
429
612
  * HTTP clients are used for ephemeral tool calls.
430
613
  */
431
- clients?: Record<string, McpClientHttpConfig$1 | McpClientStdioConfig>;
614
+ clients?: Record<string, McpClientHttpConfig | McpClientStdioConfig>;
432
615
  /**
433
616
  * Max auto-restart attempts for stdio clients before giving up.
434
617
  * Applies to all stdio clients. Default: 5.
@@ -485,6 +668,13 @@ interface McpClientOptions {
485
668
  * Default: body as object -> use as args; otherwise { input: body }.
486
669
  */
487
670
  args?: McpArgsExtractor$1;
671
+ /**
672
+ * Auth credentials for the outbound HTTP connection.
673
+ * When using `serverId`, auth flows automatically from `mcpPlugin({ clients })`
674
+ * so this field is rarely needed. Use it to override registered auth or to
675
+ * supply credentials when using inline `url`.
676
+ */
677
+ auth?: McpClientAuthOptions;
488
678
  }
489
679
  /**
490
680
  * Represents a tool exposed via MCP
@@ -534,14 +724,6 @@ type McpMessage<S extends StandardSchemaV1 | undefined> = S extends StandardSche
534
724
  * Extracts MCP tool arguments from an exchange. Default implementation uses exchange.body.
535
725
  */
536
726
  type McpArgsExtractor = (exchange: Exchange<unknown>) => Record<string, unknown>;
537
- /**
538
- * HTTP client config for a remote MCP server (Streamable HTTP).
539
- * Used in mcpPlugin({ clients: { name: config } }).
540
- */
541
- interface McpClientHttpConfig {
542
- transport?: "streamable-http";
543
- url: string;
544
- }
545
727
 
546
728
  /**
547
729
  * Brand symbol for MCP adapter type checking.
@@ -598,6 +780,109 @@ declare function mcp(shorthand: RegisteredMcpShorthand, options?: {
598
780
  args?: McpArgsExtractor$1;
599
781
  }): Destination<unknown, unknown>;
600
782
 
783
+ /**
784
+ * Supported HMAC algorithms for JWT signature verification.
785
+ * Maps JWT `alg` header values to Node.js `crypto.createHmac` digest names.
786
+ */
787
+ declare const HMAC_ALGORITHMS: {
788
+ readonly HS256: "sha256";
789
+ readonly HS384: "sha384";
790
+ readonly HS512: "sha512";
791
+ };
792
+ /**
793
+ * Supported RSA algorithms for JWT signature verification.
794
+ * Maps JWT `alg` header values to Node.js `crypto.createVerify` algorithm names.
795
+ */
796
+ declare const RSA_ALGORITHMS: {
797
+ readonly RS256: "RSA-SHA256";
798
+ readonly RS384: "RSA-SHA384";
799
+ readonly RS512: "RSA-SHA512";
800
+ };
801
+ type HmacAlgorithm = keyof typeof HMAC_ALGORITHMS;
802
+ type RsaAlgorithm = keyof typeof RSA_ALGORITHMS;
803
+ /**
804
+ * HMAC (symmetric) JWT options.
805
+ * Uses a shared secret to sign and verify tokens.
806
+ *
807
+ * @experimental
808
+ */
809
+ interface JwtHmacOptions {
810
+ /** Shared secret used to verify HMAC signatures. */
811
+ secret: string;
812
+ /**
813
+ * HMAC algorithm to accept. Default: `"HS256"`.
814
+ * The helper rejects tokens whose `alg` header does not match.
815
+ */
816
+ algorithm?: HmacAlgorithm;
817
+ /**
818
+ * Clock skew tolerance in seconds for `exp` and `nbf` checks.
819
+ * Default: `0` (no tolerance).
820
+ */
821
+ clockToleranceSec?: number;
822
+ }
823
+ /**
824
+ * RSA (asymmetric) JWT options.
825
+ * Uses a public key to verify signatures. Only the public key is needed
826
+ * since the server only verifies, never signs.
827
+ *
828
+ * @experimental
829
+ */
830
+ interface JwtRsaOptions {
831
+ /** PEM-encoded public key or certificate used to verify RSA signatures. */
832
+ publicKey: string;
833
+ /**
834
+ * RSA algorithm to accept. Default: `"RS256"`.
835
+ * The helper rejects tokens whose `alg` header does not match.
836
+ */
837
+ algorithm?: RsaAlgorithm;
838
+ /**
839
+ * Clock skew tolerance in seconds for `exp` and `nbf` checks.
840
+ * Default: `0` (no tolerance).
841
+ */
842
+ clockToleranceSec?: number;
843
+ }
844
+ /**
845
+ * Options for the built-in JWT auth helper.
846
+ * Supports HMAC (symmetric) and RSA (asymmetric) signing.
847
+ *
848
+ * Discriminated by key: pass `secret` for HMAC, `publicKey` for RSA.
849
+ *
850
+ * @experimental
851
+ */
852
+ type JwtAuthOptions = JwtHmacOptions | JwtRsaOptions;
853
+ /**
854
+ * Built-in JWT authentication helper for MCP HTTP servers.
855
+ * Verifies HMAC or RSA signed JWTs using only `node:crypto` (no external
856
+ * dependencies).
857
+ *
858
+ * Returns an {@link McpHttpAuthOptions} that can be passed directly to
859
+ * `mcpPlugin({ auth: jwt({ ... }) })`.
860
+ *
861
+ * On success the validator returns an {@link AuthPrincipal} populated from
862
+ * standard JWT claims (`sub`, `iss`, `aud`, `exp`, `scope`, etc.) with the
863
+ * full decoded payload available in `claims`.
864
+ *
865
+ * @example
866
+ * ```ts
867
+ * import { mcpPlugin, jwt } from "@routecraft/ai";
868
+ *
869
+ * // HMAC (symmetric) - shared secret
870
+ * mcpPlugin({
871
+ * transport: "http",
872
+ * auth: jwt({ secret: process.env.JWT_SECRET! }),
873
+ * });
874
+ *
875
+ * // RSA (asymmetric) - public key only
876
+ * mcpPlugin({
877
+ * transport: "http",
878
+ * auth: jwt({ algorithm: "RS256", publicKey: process.env.JWT_PUBLIC_KEY! }),
879
+ * });
880
+ * ```
881
+ *
882
+ * @experimental
883
+ */
884
+ declare function jwt(options: JwtAuthOptions): McpHttpAuthOptions;
885
+
601
886
  /**
602
887
  * MCP plugin: one plugin per adapter. Starts the MCP server during plugin apply (before routes start) so startup failures fail context build. Exposes mcp() routes to external MCP clients.
603
888
  * Optional clients: register named remote MCP servers so routes can use .to(mcp("name:tool")) without passing url.
@@ -625,6 +910,8 @@ declare class McpServer {
625
910
  private transport;
626
911
  /** Node HTTP server when transport is http; used to listen on port and close on stop. */
627
912
  private httpServer;
913
+ /** Active HTTP sessions keyed by session ID (each session has its own server+transport pair). */
914
+ private httpSessions;
628
915
  private running;
629
916
  private toolsListLogged;
630
917
  constructor(context: CraftContext, options?: McpPluginOptions);
@@ -638,8 +925,10 @@ declare class McpServer {
638
925
  private startStdio;
639
926
  /**
640
927
  * Start HTTP transport (streamable-http).
641
- * The SDK transport does not create or listen on a port; we create a Node HTTP server
642
- * and call transport.handleRequest(req, res) for each request to /mcp.
928
+ * Creates a Node HTTP server that manages per-session MCP server+transport pairs.
929
+ * Each client session (identified by the `mcp-session-id` header) gets its own
930
+ * Server and StreamableHTTPServerTransport so that reconnecting clients can
931
+ * establish fresh sessions without restarting the process.
643
932
  */
644
933
  private startHttp;
645
934
  /**
@@ -647,10 +936,19 @@ declare class McpServer {
647
936
  */
648
937
  getHttpPort(): number | undefined;
649
938
  /**
650
- * Set up request handlers (shared by both transports).
651
- * Uses SDK request schemas so setRequestHandler receives a proper schema (method literal).
939
+ * Validate the Authorization header using the configured validator.
940
+ * Returns the authenticated principal on success, or `null` to reject with 401.
941
+ */
942
+ private validateAuth;
943
+ /**
944
+ * Set up request handlers on this.server (used by stdio transport).
652
945
  */
653
946
  private setupRequestHandlers;
947
+ /**
948
+ * Set up request handlers on the given server instance.
949
+ * Uses SDK request schemas so setRequestHandler receives a proper schema (method literal).
950
+ */
951
+ private setupRequestHandlersOn;
654
952
  /**
655
953
  * Stop the MCP server
656
954
  */
@@ -857,4 +1155,4 @@ declare function embeddingPlugin(options?: EmbeddingPluginOptions): CraftPlugin;
857
1155
  */
858
1156
  declare function disposeEmbeddingPipelineCache(): Promise<void>;
859
1157
 
860
- export { ADAPTER_LLM_OPTIONS, ADAPTER_LLM_PROVIDERS, ADAPTER_MCP_CLIENT_SERVERS, AgentDestinationAdapter, type AgentModelId, type AgentOptions, type AgentPromptSource, type AgentResult, BRAND, BRAND_MCP_ADAPTER, EmbeddingDestinationAdapter, type EmbeddingModelConfig, type EmbeddingModelConfigHuggingFace, type EmbeddingModelConfigOllama, type EmbeddingModelConfigOpenAI, type EmbeddingModelId, type EmbeddingOptions, type EmbeddingPluginOptions, type EmbeddingPluginProviders, type EmbeddingProviderType, type EmbeddingResult, type LlmAnthropicProviderOptions, LlmDestinationAdapter, type LlmGeminiProviderOptions, type LlmModelConfig, type LlmModelConfigAnthropic, type LlmModelConfigGemini, type LlmModelConfigOllama, type LlmModelConfigOpenAI, type LlmModelConfigOpenRouter, type LlmModelId, type LlmOllamaProviderOptions, type LlmOpenAIProviderOptions, type LlmOpenRouterProviderOptions, type LlmOptions, type LlmPluginOptions, type LlmPluginProviders, type LlmPromptSource, type LlmProviderRegistry, type LlmProviderType, type LlmResult, type LlmUsage, MCP_PLUGIN_REGISTERED, MCP_STDIO_MANAGERS, MCP_TOOL_REGISTRY, type McpArgsExtractor, type McpClientHttpConfig, type McpClientOptions, type McpClientServerConfig, type McpClientStdioConfig, type McpMessage, type McpOptions, type McpPluginOptions, McpServer, type McpServerOptions, type McpServerRegistry, type McpTool, McpToolRegistry, type McpToolRegistryEntry, type McpToolResult, type RegisteredLlmModelId, type RegisteredMcpServer, type RegisteredMcpShorthand, agent, defaultArgs, disposeEmbeddingPipelineCache, embedding, embeddingPlugin, isMcpAdapter, llm, llmPlugin, mcp, mcpPlugin, validateLlmPluginOptions, validateWithSchema };
1158
+ export { ADAPTER_LLM_OPTIONS, ADAPTER_LLM_PROVIDERS, ADAPTER_MCP_CLIENT_SERVERS, AgentDestinationAdapter, type AgentModelId, type AgentOptions, type AgentPromptSource, type AgentResult, type AuthPrincipal, BRAND, BRAND_MCP_ADAPTER, EmbeddingDestinationAdapter, type EmbeddingModelConfig, type EmbeddingModelConfigHuggingFace, type EmbeddingModelConfigOllama, type EmbeddingModelConfigOpenAI, type EmbeddingModelId, type EmbeddingOptions, type EmbeddingPluginOptions, type EmbeddingPluginProviders, type EmbeddingProviderType, type EmbeddingResult, type JwtAuthOptions, type JwtHmacOptions, type JwtRsaOptions, type LlmAnthropicProviderOptions, LlmDestinationAdapter, type LlmGeminiProviderOptions, type LlmModelConfig, type LlmModelConfigAnthropic, type LlmModelConfigGemini, type LlmModelConfigOllama, type LlmModelConfigOpenAI, type LlmModelConfigOpenRouter, type LlmModelId, type LlmOllamaProviderOptions, type LlmOpenAIProviderOptions, type LlmOpenRouterProviderOptions, type LlmOptions, type LlmPluginOptions, type LlmPluginProviders, type LlmPromptSource, type LlmProviderRegistry, type LlmProviderType, type LlmResult, type LlmUsage, MCP_PLUGIN_REGISTERED, MCP_STDIO_MANAGERS, MCP_TOOL_REGISTRY, type McpArgsExtractor, type McpAuthValidator, type McpClientAuthOptions, type McpClientHttpConfig, type McpClientOptions, type McpClientServerConfig, type McpClientStdioConfig, type McpClientTokenProvider, McpHeadersKeys, type McpHttpAuthOptions, type McpMessage, type McpOptions, type McpPluginOptions, McpServer, type McpServerOptions, type McpServerRegistry, type McpTool, McpToolRegistry, type McpToolRegistryEntry, type McpToolResult, type RegisteredLlmModelId, type RegisteredMcpServer, type RegisteredMcpShorthand, agent, defaultArgs, disposeEmbeddingPipelineCache, embedding, embeddingPlugin, isMcpAdapter, jwt, llm, llmPlugin, mcp, mcpPlugin, validateLlmPluginOptions, validateWithSchema };