@ttoss/http-server-mcp 0.27.1 → 0.28.1

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
@@ -1,6 +1,6 @@
1
1
 
2
2
  /// <reference types="node" />
3
- import { CallToolResult, McpServer, McpServer as McpServer$1 } from "@modelcontextprotocol/server";
3
+ import { CallToolResult, McpServer, McpServer as McpServer$1, McpServerFactory, RegisteredResource } from "@modelcontextprotocol/server";
4
4
  import { Router } from "@ttoss/http-server";
5
5
  import accepts from "accepts";
6
6
  import { AsyncLocalStorage } from "async_hooks";
@@ -675,6 +675,197 @@ declare namespace Application {
675
675
  */
676
676
  declare const getIdentity: <T = unknown>() => T | undefined;
677
677
  //#endregion
678
+ //#region src/registerAppResource.d.ts
679
+ /**
680
+ * Identifier of the MCP Apps extension (`io.modelcontextprotocol/ui`), used as
681
+ * the key under `capabilities.extensions` on both sides of the handshake.
682
+ *
683
+ * A client declares Apps support with it; a server may advertise the same key
684
+ * so a host can discover the support without inspecting tool metadata:
685
+ *
686
+ * ```typescript
687
+ * new McpServer(
688
+ * { name: 'weather', version: '1.0.0' },
689
+ * {
690
+ * capabilities: {
691
+ * extensions: {
692
+ * [UI_EXTENSION_ID]: { mimeTypes: [UI_RESOURCE_MIME_TYPE] },
693
+ * },
694
+ * },
695
+ * }
696
+ * );
697
+ * ```
698
+ */
699
+ declare const UI_EXTENSION_ID = "io.modelcontextprotocol/ui";
700
+ /** MIME type every MCP Apps HTML resource is served as. */
701
+ declare const UI_RESOURCE_MIME_TYPE = "text/html;profile=mcp-app";
702
+ /**
703
+ * Origins an app's view is allowed to reach, mapped by the host onto the
704
+ * iframe's Content Security Policy. Anything not declared is blocked: an
705
+ * omitted list is the restrictive default, not "no restriction".
706
+ */
707
+ interface UiResourceCsp {
708
+ /** Origins for network requests (`connect-src`). */
709
+ connectDomains?: string[];
710
+ /**
711
+ * Origins for scripts, styles, images, fonts and media (`script-src`,
712
+ * `style-src`, `img-src`, `font-src`, `media-src`).
713
+ */
714
+ resourceDomains?: string[];
715
+ /** Origins for nested iframes (`frame-src`). */
716
+ frameDomains?: string[];
717
+ /** Allowed document base URIs (`base-uri`). */
718
+ baseUriDomains?: string[];
719
+ }
720
+ /**
721
+ * Browser capabilities the view asks for. A host *may* grant them, so a view
722
+ * should feature-detect rather than assume: each key is a request, not a
723
+ * guarantee.
724
+ */
725
+ interface UiResourcePermissions {
726
+ camera?: Record<string, never>;
727
+ microphone?: Record<string, never>;
728
+ geolocation?: Record<string, never>;
729
+ clipboardWrite?: Record<string, never>;
730
+ }
731
+ /** Rendering and security configuration for an app's view (`_meta.ui`). */
732
+ interface UiResourceMeta {
733
+ /** Origins the view may reach; omitted means none. */
734
+ csp?: UiResourceCsp;
735
+ /** Browser capabilities requested for the view. */
736
+ permissions?: UiResourcePermissions;
737
+ /**
738
+ * Dedicated sandbox origin for the view, for cases needing a stable origin
739
+ * (OAuth callbacks, CORS, API key allowlists). The accepted format is
740
+ * host-specific; consult the host's documentation rather than deriving one.
741
+ */
742
+ domain?: string;
743
+ /** Whether the host should draw a border and background around the view. */
744
+ prefersBorder?: boolean;
745
+ }
746
+ /** Who may reach a tool. Defaults to both when left unset. */
747
+ type UiToolVisibility = 'model' | 'app';
748
+ /** Parameters for {@link registerAppResource}. */
749
+ interface RegisterAppResourceParams {
750
+ /** The `McpServer` instance to register the app resource on. */
751
+ server: McpServer$1;
752
+ /** Resource name, as listed by `resources/list`. */
753
+ name: string;
754
+ /** Resource URI. Must use the `ui://` scheme. */
755
+ uri: string;
756
+ /** What the view does and when a host should render it. */
757
+ description?: string;
758
+ /**
759
+ * The view's HTML5 document, or a builder invoked per `resources/read`.
760
+ * A builder receives the requested URI so one registration can serve
761
+ * variants of a document.
762
+ */
763
+ html: string | ((args: {
764
+ uri: URL;
765
+ }) => string | Promise<string>);
766
+ /** Rendering and security configuration relayed to the host as `_meta.ui`. */
767
+ ui?: UiResourceMeta;
768
+ }
769
+ /** Parameters for {@link RegisteredAppResource.toolMeta}. */
770
+ interface ToolMetaParams {
771
+ /**
772
+ * Who may reach the tool. Left unset, the spec's default applies — visible
773
+ * to the model *and* callable by the app.
774
+ */
775
+ visibility?: UiToolVisibility[];
776
+ /** Further `_meta` entries to merge in, e.g. vendor-namespaced keys. */
777
+ _meta?: Record<string, unknown>;
778
+ }
779
+ /** An app resource registered by {@link registerAppResource}. */
780
+ interface RegisteredAppResource {
781
+ /** The URI tools link to. */
782
+ uri: string;
783
+ /** The SDK's registration handle, for `update`/`disable`/`remove`. */
784
+ resource: RegisteredResource;
785
+ /**
786
+ * Builds the `_meta` bag that links a tool to this view. Pass it to
787
+ * `registerTool`, {@link registerToolFromSchema}, or a `GatedToolDef` —
788
+ * whichever registration path the tool uses.
789
+ */
790
+ toolMeta: (params?: ToolMetaParams) => Record<string, unknown>;
791
+ }
792
+ /**
793
+ * Registers an MCP Apps view: a `ui://` resource a tool result is rendered
794
+ * with, per the `io.modelcontextprotocol/ui` extension.
795
+ *
796
+ * The extension asks nothing of the transport — a view is an ordinary MCP
797
+ * resource, and the tool linkage is ordinary tool `_meta` — so this is
798
+ * registration sugar over `registerResource`, not new protocol surface. What
799
+ * it owns is the part that is easy to get wrong: the `ui://` scheme, the exact
800
+ * MIME type, `_meta.ui` on both the declaration and the read result, and
801
+ * writing the deprecated flat linkage key alongside the current one.
802
+ *
803
+ * **Register the linkage unconditionally.** The extension's negotiation is
804
+ * per-request and only reliably readable on the `2026-07-28` revision; in this
805
+ * package's default stateless 2025-era mode there is no remembered
806
+ * `initialize` to read a client capability from. Gating registration on that
807
+ * capability would therefore silently drop the view for every 2025-era client.
808
+ * A host without Apps support simply ignores `_meta`, so keep each tool's
809
+ * `content` meaningful on its own and let the text result be the fallback.
810
+ *
811
+ * @example
812
+ * ```typescript
813
+ * import {
814
+ * McpServer,
815
+ * registerAppResource,
816
+ * UI_EXTENSION_ID,
817
+ * UI_RESOURCE_MIME_TYPE,
818
+ * z,
819
+ * } from '@ttoss/http-server-mcp';
820
+ *
821
+ * const server = new McpServer(
822
+ * { name: 'weather', version: '1.0.0' },
823
+ * {
824
+ * capabilities: {
825
+ * extensions: { [UI_EXTENSION_ID]: { mimeTypes: [UI_RESOURCE_MIME_TYPE] } },
826
+ * },
827
+ * }
828
+ * );
829
+ *
830
+ * const dashboard = registerAppResource({
831
+ * server,
832
+ * name: 'weather_dashboard',
833
+ * uri: 'ui://weather/dashboard',
834
+ * description: 'Interactive weather dashboard',
835
+ * html: dashboardHtml,
836
+ * ui: {
837
+ * csp: { connectDomains: ['https://api.openweathermap.org'] },
838
+ * prefersBorder: true,
839
+ * },
840
+ * });
841
+ *
842
+ * server.registerTool(
843
+ * 'get-weather',
844
+ * {
845
+ * description: 'Get the weather for a location',
846
+ * inputSchema: { location: z.string() },
847
+ * _meta: dashboard.toolMeta(),
848
+ * },
849
+ * async ({ location }) => {
850
+ * const forecast = await fetchForecast(location);
851
+ * return {
852
+ * // Text stays meaningful: it is what a host without Apps renders.
853
+ * content: [{ type: 'text', text: summarise(forecast) }],
854
+ * structuredContent: forecast,
855
+ * };
856
+ * }
857
+ * );
858
+ * ```
859
+ */
860
+ declare const registerAppResource: ({
861
+ server,
862
+ name,
863
+ uri,
864
+ description,
865
+ html,
866
+ ui
867
+ }: RegisterAppResourceParams) => RegisteredAppResource;
868
+ //#endregion
678
869
  //#region src/registerToolFromSchema.d.ts
679
870
  /**
680
871
  * A plain JSON Schema object (draft-07 compatible) describing the shape of a
@@ -721,6 +912,19 @@ interface RegisterToolFromSchemaParams {
721
912
  * @default false
722
913
  */
723
914
  validateArguments?: boolean;
915
+ /**
916
+ * Tool metadata forwarded verbatim on `tools/list`.
917
+ *
918
+ * The MCP Apps extension links a tool to the view its result is rendered
919
+ * with through this field; build the bag with `toolMeta()` from
920
+ * `registerAppResource` rather than writing the keys by hand.
921
+ *
922
+ * @example
923
+ * ```typescript
924
+ * _meta: dashboard.toolMeta({ visibility: ['app'] }),
925
+ * ```
926
+ */
927
+ _meta?: Record<string, unknown>;
724
928
  /**
725
929
  * Tool handler invoked when the AI client calls the tool.
726
930
  * Receives the request arguments, validated against `inputSchema` only when
@@ -744,7 +948,7 @@ interface RegisterToolFromSchemaParams {
744
948
  *
745
949
  * @param server - The `McpServer` instance to register the tool on.
746
950
  * @param params - Tool configuration including name, description, inputSchema,
747
- * validateArguments, and handler.
951
+ * validateArguments, `_meta`, and handler.
748
952
  *
749
953
  * @example
750
954
  * ```typescript
@@ -801,7 +1005,12 @@ type GatedToolDef = {
801
1005
  * Each gate receives the full {@link ToolCallContext} (identity + args).
802
1006
  * Throw to reject the call; return (or resolve) to continue.
803
1007
  */
804
- gates?: Array<(ctx: ToolCallContext) => void | Promise<void>>; /** The tool handler. Receives merged call args + `buildContext` output. */
1008
+ gates?: Array<(ctx: ToolCallContext) => void | Promise<void>>;
1009
+ /**
1010
+ * Tool metadata forwarded verbatim on `tools/list` — how a gated tool links
1011
+ * to an MCP Apps view (`registerAppResource(...).toolMeta()`).
1012
+ */
1013
+ _meta?: Record<string, unknown>; /** The tool handler. Receives merged call args + `buildContext` output. */
805
1014
  method: (args: Record<string, unknown>) => Promise<unknown>;
806
1015
  };
807
1016
  /** Options for {@link createGatedToolRegistrar}. */
@@ -1101,6 +1310,31 @@ interface McpRouterOptions {
1101
1310
  * served statelessly regardless of this option.
1102
1311
  */
1103
1312
  sessionIdGenerator?: () => string;
1313
+ /**
1314
+ * Per-request factory for the `McpServer` serving one `2026-07-28` request.
1315
+ * Set it to serve that revision; without it, requests carrying its
1316
+ * per-request envelope get the unsupported-protocol-version error naming the
1317
+ * 2025-era revisions this endpoint does serve. Register the same tools here
1318
+ * as on `server`, so the two eras cannot drift apart.
1319
+ *
1320
+ * It cannot default to `server`: the negotiated revision is instance state,
1321
+ * so one instance serving both eras is pinned to `2026-07-28` by the first
1322
+ * client to speak it, and every 2025-era request after that is answered
1323
+ * `-32602 … missing the required _meta envelope` at HTTP 200. The SDK's own
1324
+ * serving entries take a factory and call it once per request.
1325
+ *
1326
+ * @example
1327
+ * ```typescript
1328
+ * const buildServer = () => {
1329
+ * const mcpServer = new McpServer({ name: 'my-server', version: '1.0.0' });
1330
+ * registerEverything(mcpServer);
1331
+ * return mcpServer;
1332
+ * };
1333
+ *
1334
+ * createMcpRouter(buildServer(), { createMcpServer: buildServer });
1335
+ * ```
1336
+ */
1337
+ createMcpServer?: McpServerFactory;
1104
1338
  /**
1105
1339
  * Base URL prepended to relative paths passed to `apiCall` (paths starting
1106
1340
  * with `/`). Tool handlers can then call `apiCall('GET', '/resource')` without
@@ -1210,4 +1444,4 @@ interface McpRouterOptions {
1210
1444
  */
1211
1445
  declare const createMcpRouter: (server: McpServer$1, options?: McpRouterOptions) => Router<Application.DefaultState, Application.DefaultContext>;
1212
1446
  //#endregion
1213
- export { ApiCallOptions, CognitoUserPoolConfig, type CreateGatedToolRegistrarOptions, type GatedToolDef, type JsonObjectSchema, McpAuthOptions, McpRouterOptions, McpServer, type RegisterToolFromSchemaParams, type ToolCallContext, type ToolIdentity, apiCall, checkScopes, createGatedToolRegistrar, createMcpRouter, getIdentity, registerToolFromSchema, z };
1447
+ export { ApiCallOptions, CognitoUserPoolConfig, type CreateGatedToolRegistrarOptions, type GatedToolDef, type JsonObjectSchema, McpAuthOptions, McpRouterOptions, McpServer, type RegisterAppResourceParams, type RegisterToolFromSchemaParams, type RegisteredAppResource, type ToolCallContext, type ToolIdentity, type ToolMetaParams, UI_EXTENSION_ID, UI_RESOURCE_MIME_TYPE, type UiResourceCsp, type UiResourceMeta, type UiResourcePermissions, type UiToolVisibility, apiCall, checkScopes, createGatedToolRegistrar, createMcpRouter, getIdentity, registerAppResource, registerToolFromSchema, z };
package/dist/index.d.mts CHANGED
@@ -2,7 +2,7 @@
2
2
  /// <reference types="node" />
3
3
  import { Router } from "@ttoss/http-server";
4
4
  import { AsyncLocalStorage } from "node:async_hooks";
5
- import { CallToolResult, McpServer, McpServer as McpServer$1 } from "@modelcontextprotocol/server";
5
+ import { CallToolResult, McpServer, McpServer as McpServer$1, McpServerFactory, RegisteredResource } from "@modelcontextprotocol/server";
6
6
  import { z } from "zod";
7
7
  import accepts from "accepts";
8
8
  import { AsyncLocalStorage as AsyncLocalStorage$1 } from "async_hooks";
@@ -676,6 +676,197 @@ declare namespace Application {
676
676
  */
677
677
  declare const getIdentity: <T = unknown>() => T | undefined;
678
678
  //#endregion
679
+ //#region src/registerAppResource.d.ts
680
+ /**
681
+ * Identifier of the MCP Apps extension (`io.modelcontextprotocol/ui`), used as
682
+ * the key under `capabilities.extensions` on both sides of the handshake.
683
+ *
684
+ * A client declares Apps support with it; a server may advertise the same key
685
+ * so a host can discover the support without inspecting tool metadata:
686
+ *
687
+ * ```typescript
688
+ * new McpServer(
689
+ * { name: 'weather', version: '1.0.0' },
690
+ * {
691
+ * capabilities: {
692
+ * extensions: {
693
+ * [UI_EXTENSION_ID]: { mimeTypes: [UI_RESOURCE_MIME_TYPE] },
694
+ * },
695
+ * },
696
+ * }
697
+ * );
698
+ * ```
699
+ */
700
+ declare const UI_EXTENSION_ID = "io.modelcontextprotocol/ui";
701
+ /** MIME type every MCP Apps HTML resource is served as. */
702
+ declare const UI_RESOURCE_MIME_TYPE = "text/html;profile=mcp-app";
703
+ /**
704
+ * Origins an app's view is allowed to reach, mapped by the host onto the
705
+ * iframe's Content Security Policy. Anything not declared is blocked: an
706
+ * omitted list is the restrictive default, not "no restriction".
707
+ */
708
+ interface UiResourceCsp {
709
+ /** Origins for network requests (`connect-src`). */
710
+ connectDomains?: string[];
711
+ /**
712
+ * Origins for scripts, styles, images, fonts and media (`script-src`,
713
+ * `style-src`, `img-src`, `font-src`, `media-src`).
714
+ */
715
+ resourceDomains?: string[];
716
+ /** Origins for nested iframes (`frame-src`). */
717
+ frameDomains?: string[];
718
+ /** Allowed document base URIs (`base-uri`). */
719
+ baseUriDomains?: string[];
720
+ }
721
+ /**
722
+ * Browser capabilities the view asks for. A host *may* grant them, so a view
723
+ * should feature-detect rather than assume: each key is a request, not a
724
+ * guarantee.
725
+ */
726
+ interface UiResourcePermissions {
727
+ camera?: Record<string, never>;
728
+ microphone?: Record<string, never>;
729
+ geolocation?: Record<string, never>;
730
+ clipboardWrite?: Record<string, never>;
731
+ }
732
+ /** Rendering and security configuration for an app's view (`_meta.ui`). */
733
+ interface UiResourceMeta {
734
+ /** Origins the view may reach; omitted means none. */
735
+ csp?: UiResourceCsp;
736
+ /** Browser capabilities requested for the view. */
737
+ permissions?: UiResourcePermissions;
738
+ /**
739
+ * Dedicated sandbox origin for the view, for cases needing a stable origin
740
+ * (OAuth callbacks, CORS, API key allowlists). The accepted format is
741
+ * host-specific; consult the host's documentation rather than deriving one.
742
+ */
743
+ domain?: string;
744
+ /** Whether the host should draw a border and background around the view. */
745
+ prefersBorder?: boolean;
746
+ }
747
+ /** Who may reach a tool. Defaults to both when left unset. */
748
+ type UiToolVisibility = 'model' | 'app';
749
+ /** Parameters for {@link registerAppResource}. */
750
+ interface RegisterAppResourceParams {
751
+ /** The `McpServer` instance to register the app resource on. */
752
+ server: McpServer$1;
753
+ /** Resource name, as listed by `resources/list`. */
754
+ name: string;
755
+ /** Resource URI. Must use the `ui://` scheme. */
756
+ uri: string;
757
+ /** What the view does and when a host should render it. */
758
+ description?: string;
759
+ /**
760
+ * The view's HTML5 document, or a builder invoked per `resources/read`.
761
+ * A builder receives the requested URI so one registration can serve
762
+ * variants of a document.
763
+ */
764
+ html: string | ((args: {
765
+ uri: URL;
766
+ }) => string | Promise<string>);
767
+ /** Rendering and security configuration relayed to the host as `_meta.ui`. */
768
+ ui?: UiResourceMeta;
769
+ }
770
+ /** Parameters for {@link RegisteredAppResource.toolMeta}. */
771
+ interface ToolMetaParams {
772
+ /**
773
+ * Who may reach the tool. Left unset, the spec's default applies — visible
774
+ * to the model *and* callable by the app.
775
+ */
776
+ visibility?: UiToolVisibility[];
777
+ /** Further `_meta` entries to merge in, e.g. vendor-namespaced keys. */
778
+ _meta?: Record<string, unknown>;
779
+ }
780
+ /** An app resource registered by {@link registerAppResource}. */
781
+ interface RegisteredAppResource {
782
+ /** The URI tools link to. */
783
+ uri: string;
784
+ /** The SDK's registration handle, for `update`/`disable`/`remove`. */
785
+ resource: RegisteredResource;
786
+ /**
787
+ * Builds the `_meta` bag that links a tool to this view. Pass it to
788
+ * `registerTool`, {@link registerToolFromSchema}, or a `GatedToolDef` —
789
+ * whichever registration path the tool uses.
790
+ */
791
+ toolMeta: (params?: ToolMetaParams) => Record<string, unknown>;
792
+ }
793
+ /**
794
+ * Registers an MCP Apps view: a `ui://` resource a tool result is rendered
795
+ * with, per the `io.modelcontextprotocol/ui` extension.
796
+ *
797
+ * The extension asks nothing of the transport — a view is an ordinary MCP
798
+ * resource, and the tool linkage is ordinary tool `_meta` — so this is
799
+ * registration sugar over `registerResource`, not new protocol surface. What
800
+ * it owns is the part that is easy to get wrong: the `ui://` scheme, the exact
801
+ * MIME type, `_meta.ui` on both the declaration and the read result, and
802
+ * writing the deprecated flat linkage key alongside the current one.
803
+ *
804
+ * **Register the linkage unconditionally.** The extension's negotiation is
805
+ * per-request and only reliably readable on the `2026-07-28` revision; in this
806
+ * package's default stateless 2025-era mode there is no remembered
807
+ * `initialize` to read a client capability from. Gating registration on that
808
+ * capability would therefore silently drop the view for every 2025-era client.
809
+ * A host without Apps support simply ignores `_meta`, so keep each tool's
810
+ * `content` meaningful on its own and let the text result be the fallback.
811
+ *
812
+ * @example
813
+ * ```typescript
814
+ * import {
815
+ * McpServer,
816
+ * registerAppResource,
817
+ * UI_EXTENSION_ID,
818
+ * UI_RESOURCE_MIME_TYPE,
819
+ * z,
820
+ * } from '@ttoss/http-server-mcp';
821
+ *
822
+ * const server = new McpServer(
823
+ * { name: 'weather', version: '1.0.0' },
824
+ * {
825
+ * capabilities: {
826
+ * extensions: { [UI_EXTENSION_ID]: { mimeTypes: [UI_RESOURCE_MIME_TYPE] } },
827
+ * },
828
+ * }
829
+ * );
830
+ *
831
+ * const dashboard = registerAppResource({
832
+ * server,
833
+ * name: 'weather_dashboard',
834
+ * uri: 'ui://weather/dashboard',
835
+ * description: 'Interactive weather dashboard',
836
+ * html: dashboardHtml,
837
+ * ui: {
838
+ * csp: { connectDomains: ['https://api.openweathermap.org'] },
839
+ * prefersBorder: true,
840
+ * },
841
+ * });
842
+ *
843
+ * server.registerTool(
844
+ * 'get-weather',
845
+ * {
846
+ * description: 'Get the weather for a location',
847
+ * inputSchema: { location: z.string() },
848
+ * _meta: dashboard.toolMeta(),
849
+ * },
850
+ * async ({ location }) => {
851
+ * const forecast = await fetchForecast(location);
852
+ * return {
853
+ * // Text stays meaningful: it is what a host without Apps renders.
854
+ * content: [{ type: 'text', text: summarise(forecast) }],
855
+ * structuredContent: forecast,
856
+ * };
857
+ * }
858
+ * );
859
+ * ```
860
+ */
861
+ declare const registerAppResource: ({
862
+ server,
863
+ name,
864
+ uri,
865
+ description,
866
+ html,
867
+ ui
868
+ }: RegisterAppResourceParams) => RegisteredAppResource;
869
+ //#endregion
679
870
  //#region src/registerToolFromSchema.d.ts
680
871
  /**
681
872
  * A plain JSON Schema object (draft-07 compatible) describing the shape of a
@@ -722,6 +913,19 @@ interface RegisterToolFromSchemaParams {
722
913
  * @default false
723
914
  */
724
915
  validateArguments?: boolean;
916
+ /**
917
+ * Tool metadata forwarded verbatim on `tools/list`.
918
+ *
919
+ * The MCP Apps extension links a tool to the view its result is rendered
920
+ * with through this field; build the bag with `toolMeta()` from
921
+ * `registerAppResource` rather than writing the keys by hand.
922
+ *
923
+ * @example
924
+ * ```typescript
925
+ * _meta: dashboard.toolMeta({ visibility: ['app'] }),
926
+ * ```
927
+ */
928
+ _meta?: Record<string, unknown>;
725
929
  /**
726
930
  * Tool handler invoked when the AI client calls the tool.
727
931
  * Receives the request arguments, validated against `inputSchema` only when
@@ -745,7 +949,7 @@ interface RegisterToolFromSchemaParams {
745
949
  *
746
950
  * @param server - The `McpServer` instance to register the tool on.
747
951
  * @param params - Tool configuration including name, description, inputSchema,
748
- * validateArguments, and handler.
952
+ * validateArguments, `_meta`, and handler.
749
953
  *
750
954
  * @example
751
955
  * ```typescript
@@ -802,7 +1006,12 @@ type GatedToolDef = {
802
1006
  * Each gate receives the full {@link ToolCallContext} (identity + args).
803
1007
  * Throw to reject the call; return (or resolve) to continue.
804
1008
  */
805
- gates?: Array<(ctx: ToolCallContext) => void | Promise<void>>; /** The tool handler. Receives merged call args + `buildContext` output. */
1009
+ gates?: Array<(ctx: ToolCallContext) => void | Promise<void>>;
1010
+ /**
1011
+ * Tool metadata forwarded verbatim on `tools/list` — how a gated tool links
1012
+ * to an MCP Apps view (`registerAppResource(...).toolMeta()`).
1013
+ */
1014
+ _meta?: Record<string, unknown>; /** The tool handler. Receives merged call args + `buildContext` output. */
806
1015
  method: (args: Record<string, unknown>) => Promise<unknown>;
807
1016
  };
808
1017
  /** Options for {@link createGatedToolRegistrar}. */
@@ -1102,6 +1311,31 @@ interface McpRouterOptions {
1102
1311
  * served statelessly regardless of this option.
1103
1312
  */
1104
1313
  sessionIdGenerator?: () => string;
1314
+ /**
1315
+ * Per-request factory for the `McpServer` serving one `2026-07-28` request.
1316
+ * Set it to serve that revision; without it, requests carrying its
1317
+ * per-request envelope get the unsupported-protocol-version error naming the
1318
+ * 2025-era revisions this endpoint does serve. Register the same tools here
1319
+ * as on `server`, so the two eras cannot drift apart.
1320
+ *
1321
+ * It cannot default to `server`: the negotiated revision is instance state,
1322
+ * so one instance serving both eras is pinned to `2026-07-28` by the first
1323
+ * client to speak it, and every 2025-era request after that is answered
1324
+ * `-32602 … missing the required _meta envelope` at HTTP 200. The SDK's own
1325
+ * serving entries take a factory and call it once per request.
1326
+ *
1327
+ * @example
1328
+ * ```typescript
1329
+ * const buildServer = () => {
1330
+ * const mcpServer = new McpServer({ name: 'my-server', version: '1.0.0' });
1331
+ * registerEverything(mcpServer);
1332
+ * return mcpServer;
1333
+ * };
1334
+ *
1335
+ * createMcpRouter(buildServer(), { createMcpServer: buildServer });
1336
+ * ```
1337
+ */
1338
+ createMcpServer?: McpServerFactory;
1105
1339
  /**
1106
1340
  * Base URL prepended to relative paths passed to `apiCall` (paths starting
1107
1341
  * with `/`). Tool handlers can then call `apiCall('GET', '/resource')` without
@@ -1211,4 +1445,4 @@ interface McpRouterOptions {
1211
1445
  */
1212
1446
  declare const createMcpRouter: (server: McpServer$1, options?: McpRouterOptions) => Router<Application.DefaultState, Application.DefaultContext>;
1213
1447
  //#endregion
1214
- export { ApiCallOptions, CognitoUserPoolConfig, type CreateGatedToolRegistrarOptions, type GatedToolDef, type JsonObjectSchema, McpAuthOptions, McpRouterOptions, McpServer, type RegisterToolFromSchemaParams, type ToolCallContext, type ToolIdentity, apiCall, checkScopes, createGatedToolRegistrar, createMcpRouter, getIdentity, registerToolFromSchema, z };
1448
+ export { ApiCallOptions, CognitoUserPoolConfig, type CreateGatedToolRegistrarOptions, type GatedToolDef, type JsonObjectSchema, McpAuthOptions, McpRouterOptions, McpServer, type RegisterAppResourceParams, type RegisterToolFromSchemaParams, type RegisteredAppResource, type ToolCallContext, type ToolIdentity, type ToolMetaParams, UI_EXTENSION_ID, UI_RESOURCE_MIME_TYPE, type UiResourceCsp, type UiResourceMeta, type UiResourcePermissions, type UiToolVisibility, apiCall, checkScopes, createGatedToolRegistrar, createMcpRouter, getIdentity, registerAppResource, registerToolFromSchema, z };