skybridge 0.0.0-dev.f57f202 → 0.0.0-dev.f58ff90

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.
Files changed (109) hide show
  1. package/README.md +9 -9
  2. package/dist/cli/build-helpers.d.ts +1 -1
  3. package/dist/cli/build-helpers.js +9 -1
  4. package/dist/cli/build-helpers.js.map +1 -1
  5. package/dist/cli/build-helpers.test.js +24 -0
  6. package/dist/cli/build-helpers.test.js.map +1 -1
  7. package/dist/cli/build-steps.js +16 -5
  8. package/dist/cli/build-steps.js.map +1 -1
  9. package/dist/cli/build-steps.test.js +20 -0
  10. package/dist/cli/build-steps.test.js.map +1 -1
  11. package/dist/cli/resolve-skybridge-config.d.ts +1 -0
  12. package/dist/cli/resolve-skybridge-config.js +11 -1
  13. package/dist/cli/resolve-skybridge-config.js.map +1 -1
  14. package/dist/cli/use-typescript-check.js +4 -2
  15. package/dist/cli/use-typescript-check.js.map +1 -1
  16. package/dist/server/app.d.ts +22 -5
  17. package/dist/server/app.js +24 -13
  18. package/dist/server/app.js.map +1 -1
  19. package/dist/server/app.test.js +81 -0
  20. package/dist/server/app.test.js.map +1 -1
  21. package/dist/server/events.d.ts +113 -0
  22. package/dist/server/events.js +318 -0
  23. package/dist/server/events.js.map +1 -0
  24. package/dist/server/events.test.d.ts +1 -0
  25. package/dist/server/events.test.js +172 -0
  26. package/dist/server/events.test.js.map +1 -0
  27. package/dist/server/express.d.ts +3 -2
  28. package/dist/server/express.js +17 -11
  29. package/dist/server/express.js.map +1 -1
  30. package/dist/server/express.test.js +45 -0
  31. package/dist/server/express.test.js.map +1 -1
  32. package/dist/server/form-input.d.ts +120 -0
  33. package/dist/server/form-input.js +89 -0
  34. package/dist/server/form-input.js.map +1 -0
  35. package/dist/server/index.d.ts +4 -2
  36. package/dist/server/index.js +3 -1
  37. package/dist/server/index.js.map +1 -1
  38. package/dist/server/mcp-errors.test.js +188 -0
  39. package/dist/server/mcp-errors.test.js.map +1 -1
  40. package/dist/server/metric.d.ts +5 -3
  41. package/dist/server/metric.js +5 -5
  42. package/dist/server/metric.js.map +1 -1
  43. package/dist/server/register-tool.test.js +153 -0
  44. package/dist/server/register-tool.test.js.map +1 -1
  45. package/dist/server/server.d.ts +179 -10
  46. package/dist/server/server.js +247 -23
  47. package/dist/server/server.js.map +1 -1
  48. package/dist/server/templateHelper.d.ts +1 -0
  49. package/dist/server/templateHelper.js.map +1 -1
  50. package/dist/server/templates.generated.js +26 -12
  51. package/dist/server/templates.generated.js.map +1 -1
  52. package/dist/server/tool-extra.test.js +79 -0
  53. package/dist/server/tool-extra.test.js.map +1 -1
  54. package/dist/server/view-resource-resolution.test.js +35 -0
  55. package/dist/server/view-resource-resolution.test.js.map +1 -1
  56. package/dist/web/bridges/adaptor.d.ts +9 -2
  57. package/dist/web/bridges/adaptor.js +113 -10
  58. package/dist/web/bridges/adaptor.js.map +1 -1
  59. package/dist/web/bridges/adaptor.test.js +66 -5
  60. package/dist/web/bridges/adaptor.test.js.map +1 -1
  61. package/dist/web/bridges/apps-sdk/bridge.js +1 -1
  62. package/dist/web/bridges/apps-sdk/bridge.js.map +1 -1
  63. package/dist/web/bridges/apps-sdk/types.d.ts +3 -4
  64. package/dist/web/bridges/apps-sdk/types.js.map +1 -1
  65. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.d.ts +3 -3
  66. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js +3 -3
  67. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js.map +1 -1
  68. package/dist/web/bridges/mcp-app/types.d.ts +5 -13
  69. package/dist/web/bridges/mcp-app/types.js.map +1 -1
  70. package/dist/web/bridges/mcp-app/use-mcp-app-context.d.ts +1 -1
  71. package/dist/web/bridges/mcp-app/use-mcp-app-context.js +1 -1
  72. package/dist/web/bridges/mcp-app/use-mcp-app-context.js.map +1 -1
  73. package/dist/web/bridges/types.d.ts +45 -6
  74. package/dist/web/bridges/types.js +1 -1
  75. package/dist/web/bridges/types.js.map +1 -1
  76. package/dist/web/hooks/index.d.ts +2 -0
  77. package/dist/web/hooks/index.js +2 -0
  78. package/dist/web/hooks/index.js.map +1 -1
  79. package/dist/web/hooks/openai-extensions.test.js +1 -8
  80. package/dist/web/hooks/openai-extensions.test.js.map +1 -1
  81. package/dist/web/hooks/use-call-tool.js +1 -1
  82. package/dist/web/hooks/use-call-tool.js.map +1 -1
  83. package/dist/web/hooks/use-call-tool.test.js +6 -2
  84. package/dist/web/hooks/use-call-tool.test.js.map +1 -1
  85. package/dist/web/hooks/use-deep-link.js +1 -27
  86. package/dist/web/hooks/use-deep-link.js.map +1 -1
  87. package/dist/web/hooks/use-file-resource.d.ts +37 -0
  88. package/dist/web/hooks/use-file-resource.js +98 -0
  89. package/dist/web/hooks/use-file-resource.js.map +1 -0
  90. package/dist/web/hooks/use-file-resource.test.d.ts +1 -0
  91. package/dist/web/hooks/use-file-resource.test.js +65 -0
  92. package/dist/web/hooks/use-file-resource.test.js.map +1 -0
  93. package/dist/web/hooks/use-host.d.ts +3 -3
  94. package/dist/web/hooks/use-host.js +4 -4
  95. package/dist/web/hooks/use-host.js.map +1 -1
  96. package/dist/web/hooks/use-model-context.js +3 -5
  97. package/dist/web/hooks/use-model-context.js.map +1 -1
  98. package/dist/web/hooks/use-open-file.d.ts +20 -0
  99. package/dist/web/hooks/use-open-file.js +25 -0
  100. package/dist/web/hooks/use-open-file.js.map +1 -0
  101. package/dist/web/hooks/use-register-view-tool.d.ts +1 -1
  102. package/dist/web/hooks/use-register-view-tool.js +1 -1
  103. package/dist/web/hooks/use-register-view-tool.js.map +1 -1
  104. package/dist/web/hooks/use-send-follow-up-message.d.ts +8 -2
  105. package/dist/web/hooks/use-send-follow-up-message.js +6 -0
  106. package/dist/web/hooks/use-send-follow-up-message.js.map +1 -1
  107. package/dist/web/mount-view.js +3 -5
  108. package/dist/web/mount-view.js.map +1 -1
  109. package/package.json +4 -2
@@ -1 +1 @@
1
- {"version":3,"file":"register-tool.test.js","sourceRoot":"","sources":["../../src/server/register-tool.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { Client, InMemoryTransport } from \"@modelcontextprotocol/client\";\nimport { describe, expect, it } from \"vitest\";\nimport { z } from \"zod\";\nimport { Skybridge } from \"./app.js\";\n\ndescribe(\"registerTool handler invocation\", () => {\n it(\"passes empty args and a usable extra to a schema-less tool handler\", async () => {\n let received: { args: unknown; extra: unknown } | undefined;\n const app = new Skybridge({\n name: \"test\",\n version: \"1.0.0\",\n handler: (server) =>\n server.registerTool(\n { name: \"no-input\", description: \"no-input\" },\n async (args, extra) => {\n received = { args, extra };\n return { content: [{ type: \"text\", text: \"ok\" }] };\n },\n ),\n });\n const instance = await app.createServerInstance();\n\n const client = new Client({ name: \"client\", version: \"1.0.0\" });\n const [clientTransport, serverTransport] =\n InMemoryTransport.createLinkedPair();\n await instance.connect(serverTransport);\n await client.connect(clientTransport);\n\n await client.callTool({ name: \"no-input\" });\n\n expect(received?.args).toEqual({});\n expect(received?.extra).toHaveProperty(\"mcpReq.send\");\n\n await client.close();\n await instance.close();\n });\n\n it(\"emits openai options as openai/ui metadata on the tool and its view\", async () => {\n const app = new Skybridge({\n name: \"test\",\n version: \"1.0.0\",\n handler: (server) =>\n server.registerTool(\n {\n name: \"library\",\n description: \"library\",\n view: { component: \"widget\" },\n openai: {\n entrypoints: [\n { type: \"global\" },\n { type: \"file\", extensions: [\".stl\"] },\n ],\n availableDisplayModes: [\"inline\", \"fullscreen\"],\n preferredDisplayMode: \"fullscreen\",\n },\n },\n async () => ({ content: \"ok\" }),\n ),\n });\n const instance = await app.createServerInstance();\n const client = new Client({ name: \"client\", version: \"1.0.0\" });\n const [clientTransport, serverTransport] =\n InMemoryTransport.createLinkedPair();\n await instance.connect(serverTransport);\n await client.connect(clientTransport);\n\n const { tools } = await client.listTools();\n const { resources } = await client.listResources();\n\n expect(tools[0]?._meta?.[\"openai/ui\"]).toEqual({\n entrypoints: [{ type: \"global\" }, { type: \"file\", extensions: [\".stl\"] }],\n });\n expect(resources[0]?._meta?.[\"openai/ui\"]).toEqual({\n availableDisplayModes: [\"inline\", \"fullscreen\"],\n preferredDisplayMode: \"fullscreen\",\n });\n\n await client.close();\n await instance.close();\n });\n\n it(\"rejects a global entrypoint on a tool that requires input\", async () => {\n const app = new Skybridge({\n name: \"test\",\n version: \"1.0.0\",\n handler: (server) =>\n server.registerTool(\n {\n name: \"search\",\n description: \"search\",\n inputSchema: { query: z.string() },\n view: { component: \"widget\" },\n openai: { entrypoints: [{ type: \"global\" }] },\n },\n async () => ({ content: \"ok\" }),\n ),\n });\n\n await expect(app.createServerInstance()).rejects.toThrow(/rejects `\\{\\}`/);\n });\n});\n"]}
1
+ {"version":3,"file":"register-tool.test.js","sourceRoot":"","sources":["../../src/server/register-tool.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { Client, InMemoryTransport } from \"@modelcontextprotocol/client\";\nimport { describe, expect, it } from \"vitest\";\nimport { z } from \"zod\";\nimport { Skybridge } from \"./app.js\";\n\ndescribe(\"registerTool handler invocation\", () => {\n it(\"passes empty args and a usable extra to a schema-less tool handler\", async () => {\n let received: { args: unknown; extra: unknown } | undefined;\n const app = new Skybridge({\n name: \"test\",\n version: \"1.0.0\",\n handler: (server) =>\n server.registerTool(\n { name: \"no-input\", description: \"no-input\" },\n async (args, extra) => {\n received = { args, extra };\n return { content: [{ type: \"text\", text: \"ok\" }] };\n },\n ),\n });\n const instance = await app.createServerInstance();\n\n const client = new Client({ name: \"client\", version: \"1.0.0\" });\n const [clientTransport, serverTransport] =\n InMemoryTransport.createLinkedPair();\n await instance.connect(serverTransport);\n await client.connect(clientTransport);\n\n await client.callTool({ name: \"no-input\" });\n\n expect(received?.args).toEqual({});\n expect(received?.extra).toHaveProperty(\"mcpReq.send\");\n\n await client.close();\n await instance.close();\n });\n\n it(\"emits openai options as openai/ui metadata on the tool and its view\", async () => {\n const app = new Skybridge({\n name: \"test\",\n version: \"1.0.0\",\n handler: (server) =>\n server.registerTool(\n {\n name: \"library\",\n description: \"library\",\n view: { component: \"widget\" },\n openai: {\n entrypoints: [\n { type: \"global\" },\n { type: \"file\", extensions: [\".stl\"] },\n ],\n availableDisplayModes: [\"inline\", \"fullscreen\"],\n preferredDisplayMode: \"fullscreen\",\n },\n },\n async () => ({ content: \"ok\" }),\n ),\n });\n const instance = await app.createServerInstance();\n const client = new Client({ name: \"client\", version: \"1.0.0\" });\n const [clientTransport, serverTransport] =\n InMemoryTransport.createLinkedPair();\n await instance.connect(serverTransport);\n await client.connect(clientTransport);\n\n const { tools } = await client.listTools();\n const { resources } = await client.listResources();\n\n expect(tools[0]?._meta?.[\"openai/ui\"]).toEqual({\n entrypoints: [{ type: \"global\" }, { type: \"file\", extensions: [\".stl\"] }],\n });\n expect(resources[0]?._meta?.[\"openai/ui\"]).toEqual({\n availableDisplayModes: [\"inline\", \"fullscreen\"],\n preferredDisplayMode: \"fullscreen\",\n });\n\n await client.close();\n await instance.close();\n });\n\n it(\"rejects a global entrypoint on a tool that requires input\", async () => {\n const app = new Skybridge({\n name: \"test\",\n version: \"1.0.0\",\n handler: (server) =>\n server.registerTool(\n {\n name: \"search\",\n description: \"search\",\n inputSchema: { query: z.string() },\n view: { component: \"widget\" },\n openai: { entrypoints: [{ type: \"global\" }] },\n },\n async () => ({ content: \"ok\" }),\n ),\n });\n\n await expect(app.createServerInstance()).rejects.toThrow(/rejects `\\{\\}`/);\n });\n\n it(\"registers mention search as an app-only tool advertising the extension\", async () => {\n const app = new Skybridge({\n name: \"test\",\n version: \"1.0.0\",\n handler: (server) =>\n server.registerMentions({\n name: \"search_parts\",\n handler: async ({ query }) => ({\n items: [\n { type: \"resource_link\", uri: `parts://${query}`, name: query },\n ],\n }),\n }),\n });\n const instance = await app.createServerInstance();\n const client = new Client({ name: \"client\", version: \"1.0.0\" });\n const [clientTransport, serverTransport] =\n InMemoryTransport.createLinkedPair();\n await instance.connect(serverTransport);\n await client.connect(clientTransport);\n\n const { tools } = await client.listTools();\n expect(tools[0]?._meta).toMatchObject({\n \"openai/extensions\": { \"mentions/search\": {} },\n ui: { visibility: [\"app\"] },\n });\n const result = await client.callTool({\n name: \"search_parts\",\n arguments: { query: \"bolt\" },\n });\n expect(result.structuredContent).toEqual({\n items: [{ type: \"resource_link\", uri: \"parts://bolt\", name: \"bolt\" }],\n });\n\n await client.close();\n await instance.close();\n });\n\n it(\"registers settings tools and advertises the settings capability\", async () => {\n let stored = { units: \"mm\" as \"mm\" | \"in\", zoom: 3 };\n const fields = {\n units: { title: \"Units\", schema: z.enum([\"mm\", \"in\"]) },\n zoom: { title: \"Zoom\", schema: z.number() },\n };\n const app = new Skybridge({\n name: \"test\",\n version: \"1.0.0\",\n handler: (server) =>\n server.registerSettings({\n fields,\n layout: [\n {\n kind: \"group\",\n title: \"Display\",\n items: [{ kind: \"property\", property: \"units\" }],\n },\n ],\n read: () => stored,\n update: (set) => {\n stored = { ...stored, ...set };\n return stored;\n },\n }),\n });\n const instance = await app.createServerInstance();\n const client = new Client({ name: \"client\", version: \"1.0.0\" });\n const [clientTransport, serverTransport] =\n InMemoryTransport.createLinkedPair();\n await instance.connect(serverTransport);\n await client.connect(clientTransport);\n\n const capability = {\n readTool: \"settings.read\",\n updateTool: \"settings.update\",\n };\n expect(client.getServerCapabilities()).toMatchObject({\n extensions: { \"openai/settings\": capability },\n experimental: { \"openai/settings\": capability },\n });\n const { tools } = await client.listTools();\n expect(tools).toMatchObject([\n {\n name: \"settings.read\",\n annotations: { readOnlyHint: true },\n outputSchema: { required: [\"schema\", \"values\"] },\n },\n {\n name: \"settings.update\",\n inputSchema: {\n properties: {\n set: { additionalProperties: false, minProperties: 1 },\n },\n },\n },\n ]);\n const read = await client.callTool({\n name: \"settings.read\",\n arguments: {},\n });\n expect(read.structuredContent).toMatchObject({\n schema: {\n type: \"object\",\n properties: {\n units: { type: \"string\", enum: [\"mm\", \"in\"], title: \"Units\" },\n zoom: { type: \"number\", title: \"Zoom\" },\n },\n required: [\"units\", \"zoom\"],\n },\n values: { units: \"mm\", zoom: 3 },\n layout: [{ kind: \"group\", title: \"Display\" }],\n });\n const updated = await client.callTool({\n name: \"settings.update\",\n arguments: { set: { units: \"in\" } },\n });\n expect(updated.structuredContent).toEqual({\n values: { units: \"in\", zoom: 3 },\n });\n const empty = await client.callTool({\n name: \"settings.update\",\n arguments: { set: {} },\n });\n expect(empty.isError).toBe(true);\n\n await client.close();\n await instance.close();\n\n const withDefault = new Skybridge({\n name: \"test\",\n version: \"1.0.0\",\n handler: (server) =>\n server.registerSettings({\n fields: {\n grid: { title: \"Grid\", schema: z.boolean().prefault(true) },\n },\n read: () => ({ grid: true }),\n update: () => ({ grid: true }),\n }),\n });\n await expect(withDefault.createServerInstance()).rejects.toThrow(\n /declares a default/,\n );\n });\n\n it(\"registers a file viewer with the file input and a file entrypoint\", async () => {\n const app = new Skybridge({\n name: \"test\",\n version: \"1.0.0\",\n handler: (server) =>\n server.registerFileViewer(\n {\n name: \"part-viewer\",\n extensions: [\".stl\"],\n view: { component: \"widget\" },\n },\n async ({ file }) => ({ content: file.name }),\n ),\n });\n const instance = await app.createServerInstance();\n const client = new Client({ name: \"client\", version: \"1.0.0\" });\n const [clientTransport, serverTransport] =\n InMemoryTransport.createLinkedPair();\n await instance.connect(serverTransport);\n await client.connect(clientTransport);\n\n const { tools } = await client.listTools();\n expect(tools[0]?._meta?.[\"openai/ui\"]).toEqual({\n entrypoints: [{ type: \"file\", extensions: [\".stl\"] }],\n });\n expect(tools[0]?.inputSchema.required).toEqual([\"file\"]);\n\n await client.close();\n await instance.close();\n });\n});\n"]}
@@ -1,8 +1,10 @@
1
1
  import type { McpUiToolMeta } from "@modelcontextprotocol/ext-apps";
2
- import { type ContentBlock, type Icon, type Implementation, McpServer as McpServerBase, type RequestMeta, type ServerOptions, type ServerResult, type StandardSchemaV1, type StandardSchemaWithJSON, type ToolAnnotations } from "@modelcontextprotocol/server";
2
+ import { type ContentBlock, type Icon, type Implementation, type InputRequiredResult, McpServer as McpServerBase, type RequestMeta, type ResourceLink, type ServerOptions, type ServerResult, type StandardSchemaV1, type StandardSchemaWithJSON, type ToolAnnotations } from "@modelcontextprotocol/server";
3
3
  import type express from "express";
4
+ import { z } from "zod/v4";
4
5
  import type { ResourceMetadataUrlResolver } from "./auth/setup.js";
5
6
  import type { ExtraClaims } from "./auth.js";
7
+ import { type EventConfig, type EventHooks, type InferEventSchema } from "./events.js";
6
8
  import type { McpExtra, McpExtraFor, McpMethodString, McpMiddlewareEntry, McpMiddlewareFilter, McpMiddlewareFn, McpResultFor, McpTypedMiddlewareFn, McpWildcard } from "./middleware.js";
7
9
  import { type SkillsManifest } from "./skills.js";
8
10
  /**
@@ -27,7 +29,7 @@ export interface ViewCsp {
27
29
  resourceDomains?: string[];
28
30
  /** Origins the view may contact via fetch/XHR. */
29
31
  connectDomains?: string[];
30
- /** Origins allowed for iframe embeds (opts into stricter app review). */
32
+ /** Origins allowed for iframe embeds (opts into stricter plugin review). */
31
33
  frameDomains?: string[];
32
34
  /** Origins that can receive openExternal redirects without the safe-link modal. */
33
35
  redirectDomains?: string[];
@@ -171,16 +173,16 @@ export interface SkybridgeServerOptions {
171
173
  * Well-known keys recognized by host runtimes when set on a tool's `_meta`.
172
174
  * Use {@link ToolMeta} to also pass arbitrary custom metadata alongside these.
173
175
  *
174
- * @see https://developers.openai.com/apps-sdk/reference#tool-descriptor-parameters
176
+ * @see https://developers.openai.com/plugins/reference#tool-descriptor-parameters
175
177
  */
176
178
  export interface KnownToolMeta {
177
- /** Apps SDK: allow the rendered view to call this tool from inside its iframe. */
179
+ /** ChatGPT: allow the rendered view to call this tool from inside its iframe. */
178
180
  "openai/widgetAccessible"?: boolean;
179
- /** Apps SDK: status text shown while the tool is running (e.g. `"Searching trips"`). */
181
+ /** ChatGPT: status text shown while the tool is running (e.g. `"Searching trips"`). */
180
182
  "openai/toolInvocation/invoking"?: string;
181
- /** Apps SDK: status text shown once the tool returns (e.g. `"Found 3 trips"`). */
183
+ /** ChatGPT: status text shown once the tool returns (e.g. `"Found 3 trips"`). */
182
184
  "openai/toolInvocation/invoked"?: string;
183
- /** Apps SDK: input parameters that hold file references — the host attaches uploaded files to them. */
185
+ /** ChatGPT: input parameters that hold file references — the host attaches uploaded files to them. */
184
186
  "openai/fileParams"?: string[];
185
187
  /** MCP Apps: control whether the tool is exposed to the model, the app, or both. */
186
188
  ui?: Pick<McpUiToolMeta, "visibility">;
@@ -264,11 +266,27 @@ type ToolAuthConfig = {
264
266
  securitySchemes?: SecurityScheme[];
265
267
  };
266
268
  type ToolConfig<TInput extends Record<string, StandardSchemaWithJSON> | StandardSchemaWithJSON> = ToolConfigBase<TInput> & ToolAuthConfig;
269
+ declare const fileEntrypointInput: {
270
+ file: z.ZodObject<{
271
+ name: z.ZodString;
272
+ resourceUri: z.ZodString;
273
+ }, z.core.$strip>;
274
+ };
275
+ type FileEntrypointInput = typeof fileEntrypointInput;
276
+ /** A ChatGPT file viewer, registered with `server.registerFileViewer`. */
277
+ export type OpenAIFileViewerConfig<TName extends string = string> = Omit<ToolConfigBase<FileEntrypointInput>, "inputSchema" | "openai" | "view"> & ToolAuthConfig & {
278
+ name: TName;
279
+ /** File extensions the viewer opens, each starting with `.`. */
280
+ extensions: string[];
281
+ view: ViewConfig;
282
+ /** Display modes. The file entrypoint is set from `extensions`. */
283
+ openai?: Omit<OpenAIToolConfig, "entrypoints">;
284
+ };
267
285
  /**
268
286
  * Optional client-supplied hints attached to `params._meta` on every tool call
269
- * by the Apps SDK host. Hints only: never use for authorization, and tolerate
287
+ * by the ChatGPT host. Hints only: never use for authorization, and tolerate
270
288
  * absence.
271
- * @see https://developers.openai.com/apps-sdk/reference#_meta-fields-the-client-provides
289
+ * @see https://developers.openai.com/plugins/reference#_meta-fields-the-client-provides
272
290
  */
273
291
  export interface ClientHintsMeta {
274
292
  /** Requested locale (BCP-47, e.g. `"en-US"`). */
@@ -307,11 +325,62 @@ type ToolHandlerExtra<TAuthExtra extends ExtraClaims = ExtraClaims> = Omit<McpEx
307
325
  _meta?: RequestMeta & ClientHintsMeta;
308
326
  };
309
327
  };
328
+ /** Composer at-mention search, registered with `server.registerMentions`. */
329
+ export interface OpenAIMentionsConfig<TAuthExtra extends ExtraClaims = ExtraClaims> {
330
+ /** Name of the tool ChatGPT calls for each search. */
331
+ name: string;
332
+ description?: string;
333
+ /** Returns the items matching the typed text, which may be empty. */
334
+ handler: (params: {
335
+ query: string;
336
+ }, extra: ToolHandlerExtra<TAuthExtra>) => Promise<{
337
+ items: ResourceLink[];
338
+ }> | {
339
+ items: ResourceLink[];
340
+ };
341
+ }
342
+ /** One setting, registered with `server.registerSettings`. */
343
+ export interface OpenAISettingsField {
344
+ /** A boolean, string, string enum, number or integer schema, without a default. */
345
+ schema: z.ZodType<boolean | string | number>;
346
+ title: string;
347
+ description?: string;
348
+ }
349
+ /** Values of every setting, keyed by field name. */
350
+ export type OpenAISettingsValues<TFields extends Record<string, OpenAISettingsField>> = {
351
+ [K in keyof TFields]-?: Exclude<z.output<TFields[K]["schema"]>, undefined>;
352
+ };
353
+ /** App settings in ChatGPT, registered with `server.registerSettings`. */
354
+ export interface OpenAISettingsConfig<TFields extends Record<string, OpenAISettingsField>, TAuthExtra extends ExtraClaims = ExtraClaims> {
355
+ fields: TFields;
356
+ /** Sections of the settings page. Fields left out appear under "Other settings". */
357
+ layout?: {
358
+ kind: "group";
359
+ title: string;
360
+ items: ({
361
+ kind: "property";
362
+ property: Extract<keyof TFields, string>;
363
+ } | {
364
+ kind: "tool";
365
+ tool: string;
366
+ title: string;
367
+ description?: string;
368
+ })[];
369
+ }[];
370
+ /** Returns the current value of every field. */
371
+ read: (extra: ToolHandlerExtra<TAuthExtra>) => OpenAISettingsValues<TFields> | Promise<OpenAISettingsValues<TFields>>;
372
+ /** Saves the changed fields and returns the value of every field. */
373
+ update: (set: Partial<OpenAISettingsValues<TFields>>, extra: ToolHandlerExtra<TAuthExtra>) => OpenAISettingsValues<TFields> | Promise<OpenAISettingsValues<TFields>>;
374
+ /** Name of the read tool. Defaults to `settings.read`. */
375
+ readTool?: string;
376
+ /** Name of the update tool. Defaults to `settings.update`. */
377
+ updateTool?: string;
378
+ }
310
379
  type ToolHandler<TInput extends Record<string, StandardSchemaWithJSON>, TReturn extends {
311
380
  content?: HandlerContent;
312
381
  } = {
313
382
  content?: HandlerContent;
314
- }, TAuthExtra extends ExtraClaims = ExtraClaims> = (args: ShapeOutput<TInput>, extra: ToolHandlerExtra<TAuthExtra>) => TReturn | Promise<TReturn>;
383
+ }, TAuthExtra extends ExtraClaims = ExtraClaims> = (args: ShapeOutput<TInput>, extra: ToolHandlerExtra<TAuthExtra>) => TReturn | InputRequiredResult | Promise<TReturn | InputRequiredResult>;
315
384
  /**
316
385
  * Coerce a tool handler's return value into an MCP `content` array. Strings
317
386
  * become a single `TextContent`; a single block is wrapped in an array;
@@ -379,6 +448,7 @@ export declare class McpServer<TTools extends Record<string, ToolDef> = Record<n
379
448
  private resolveResourceMetadataUrl?;
380
449
  private readonly toolSecuritySchemes;
381
450
  private readonly userMiddlewareEntries;
451
+ private eventRegistry?;
382
452
  constructor(serverInfo: Implementation, options?: ServerOptions, skybridgeOptions?: SkybridgeServerOptions);
383
453
  /**
384
454
  * The per-tool security schemes collected during registration, keyed by tool
@@ -444,6 +514,7 @@ export declare class McpServer<TTools extends Record<string, ToolDef> = Record<n
444
514
  private decorateToolHandler;
445
515
  private computeViewVersionParam;
446
516
  private lookupViewFile;
517
+ private lookupViewPreloadFiles;
447
518
  private lookupDistFile;
448
519
  /**
449
520
  * Inject the Vite manifest as a value rather than letting `readManifest()`
@@ -455,6 +526,104 @@ export declare class McpServer<TTools extends Record<string, ToolDef> = Record<n
455
526
  file: string;
456
527
  }>): this;
457
528
  private readManifest;
529
+ /**
530
+ * @experimental Register an MCP Events type that hosts can subscribe to, per
531
+ * the Triggers & Events working group draft. Skybridge serves `events/list`,
532
+ * `events/subscribe` and `events/unsubscribe`, checks auth and arguments,
533
+ * verifies the callback URL, then hands each subscription to `onSubscribe`.
534
+ * Delivering the events is up to you, for example with {@link deliverEvent}.
535
+ * API may change.
536
+ *
537
+ * @example
538
+ * ```ts
539
+ * server.registerEvent(
540
+ * {
541
+ * name: "comment.created",
542
+ * description: "Fires when someone comments on a document",
543
+ * inputSchema: { documentId: z.string() },
544
+ * payloadSchema: { documentId: z.string(), excerpt: z.string() },
545
+ * },
546
+ * {
547
+ * onSubscribe: ({ documentId }, { subscription }) =>
548
+ * webhooks.upsert({ ...subscription, filter: { documentId } }),
549
+ * onUnsubscribe: (_args, { subscription }) =>
550
+ * webhooks.remove(subscription.id),
551
+ * },
552
+ * );
553
+ * ```
554
+ *
555
+ * @see https://docs.skybridge.tech/api-reference/register-event
556
+ */
557
+ registerEvent<TInput extends Record<string, StandardSchemaWithJSON> | StandardSchemaWithJSON = Record<never, StandardSchemaWithJSON>>(config: EventConfig<TInput>, hooks: EventHooks<InferEventSchema<TInput>, McpExtra<TAuthExtra>>): this;
558
+ /**
559
+ * Register a ChatGPT file viewer, from the OpenAI MCP extensions: a tool
560
+ * with a file entrypoint for `extensions` and a view. ChatGPT desktop calls
561
+ * it with the file the user opened, as `{ file: { name, resourceUri } }`.
562
+ * Read and save the file from the view with `useFileResource`.
563
+ *
564
+ * @example
565
+ * ```ts
566
+ * server.registerFileViewer(
567
+ * {
568
+ * name: "part-viewer",
569
+ * title: "Part Viewer",
570
+ * extensions: [".stl", ".step"],
571
+ * view: { component: "part-viewer" },
572
+ * },
573
+ * async ({ file }) => ({ structuredContent: { name: file.name } }),
574
+ * );
575
+ * ```
576
+ *
577
+ * @see https://docs.skybridge.tech/api-reference/register-file-viewer
578
+ */
579
+ registerFileViewer<TName extends string, TReturn extends {
580
+ content?: HandlerContent;
581
+ }>(config: OpenAIFileViewerConfig<TName>, cb: ToolHandler<FileEntrypointInput, TReturn, TAuthExtra>): AddTool<TTools, TName, FileEntrypointInput, ExtractStructuredContent<TReturn>, ExtractMeta<TReturn>, TAuthExtra>;
582
+ /**
583
+ * Register the composer at-mention search for ChatGPT, from the OpenAI MCP
584
+ * extensions. When the user types `@` and your app name, ChatGPT calls
585
+ * `handler` with the typed text and lists the returned resource links.
586
+ * Skybridge registers it as a tool hidden from the model.
587
+ *
588
+ * @example
589
+ * ```ts
590
+ * server.registerMentions({
591
+ * name: "search_parts",
592
+ * handler: async ({ query }) => ({
593
+ * items: findParts(query).map((part) => ({
594
+ * type: "resource_link",
595
+ * uri: `parts://${part.id}`,
596
+ * name: part.name,
597
+ * })),
598
+ * }),
599
+ * });
600
+ * ```
601
+ *
602
+ * @see https://docs.skybridge.tech/api-reference/register-mentions
603
+ */
604
+ registerMentions(config: OpenAIMentionsConfig<TAuthExtra>): this;
605
+ /**
606
+ * Register app settings for ChatGPT, from the OpenAI MCP extensions.
607
+ * Skybridge registers a read tool and an update tool from `fields`, and
608
+ * advertises them in the `openai/settings` server capability. ChatGPT shows
609
+ * the settings page and calls `update` with the changed fields only. Store
610
+ * the values yourself, for example per user.
611
+ *
612
+ * @example
613
+ * ```ts
614
+ * server.registerSettings({
615
+ * fields: {
616
+ * units: { title: "Units", schema: z.enum(["mm", "in"]) },
617
+ * showGrid: { title: "Show grid", schema: z.boolean() },
618
+ * },
619
+ * read: (extra) => loadSettings(extra),
620
+ * update: (set, extra) => saveSettings(set, extra),
621
+ * });
622
+ * ```
623
+ *
624
+ * @see https://docs.skybridge.tech/api-reference/register-settings
625
+ */
626
+ registerSettings<TFields extends Record<string, OpenAISettingsField>>(config: OpenAISettingsConfig<TFields, TAuthExtra>): this;
458
627
  /**
459
628
  * Register a tool. Pass a `config` describing the tool (name, schemas,
460
629
  * optional {@link ViewConfig}, optional {@link ToolMeta}) and a handler that