@plitzi/sdk-server 0.32.8 → 0.32.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.
Files changed (71) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/core/services/mcp.js +8 -6
  3. package/dist/mcp.d.ts +2 -0
  4. package/dist/mcp.js +6 -0
  5. package/dist/modules/mcp/apps/example/view.tsx +70 -0
  6. package/dist/modules/mcp/apps/index.js +12 -0
  7. package/dist/modules/mcp/apps/render/index.js +16 -0
  8. package/dist/modules/mcp/apps/render/view.tsx +108 -0
  9. package/dist/modules/mcp/apps/shared/bundle.js +22 -0
  10. package/dist/modules/mcp/apps/shared/page.js +23 -0
  11. package/dist/modules/mcp/apps/shared/registerApp.js +27 -0
  12. package/dist/modules/mcp/apps/shared/resolve.js +5 -0
  13. package/dist/modules/mcp/apps/shared/shell.ejs +37 -0
  14. package/dist/modules/mcp/apps/shared/zodEnglishOnly.js +23 -0
  15. package/dist/modules/mcp/handler.js +3 -6
  16. package/dist/modules/mcp/resources/register.js +1 -1
  17. package/dist/modules/mcp/server.js +21 -12
  18. package/dist/modules/mcp/tools/apply/index.js +1 -1
  19. package/dist/modules/mcp/tools/render.js +3 -3
  20. package/dist/modules/mcp/tools/shared/validator/index.js +2 -1
  21. package/dist/modules/ssr/registerExternalPlugins.js +1 -1
  22. package/dist/modules/ssr/template.js +1 -1
  23. package/dist/plugins/compile.js +1 -1
  24. package/dist/plugins/copy.js +1 -1
  25. package/dist/plugins/manager.js +1 -1
  26. package/dist/src/core/requestParser.d.ts +3 -0
  27. package/dist/src/index.d.ts +1 -1
  28. package/dist/src/mcp.d.ts +13 -0
  29. package/dist/src/modules/mcp/apps/apps.test.d.ts +1 -0
  30. package/dist/src/modules/mcp/apps/example/index.d.ts +8 -0
  31. package/dist/src/modules/mcp/apps/example/view.d.ts +1 -0
  32. package/dist/src/modules/mcp/apps/index.d.ts +8 -0
  33. package/dist/src/modules/mcp/apps/render/index.d.ts +3 -0
  34. package/dist/src/modules/mcp/apps/render/view.d.ts +1 -0
  35. package/dist/src/modules/mcp/apps/shared/bundle.d.ts +1 -0
  36. package/dist/src/modules/mcp/apps/shared/index.d.ts +2 -0
  37. package/dist/src/modules/mcp/apps/shared/page.d.ts +2 -0
  38. package/dist/src/modules/mcp/apps/shared/registerApp.d.ts +5 -0
  39. package/dist/src/modules/mcp/apps/shared/resolve.d.ts +1 -0
  40. package/dist/src/modules/mcp/apps/shared/zodEnglishOnly.d.ts +4 -0
  41. package/dist/src/modules/mcp/e2e/connector.test.d.ts +1 -0
  42. package/dist/src/modules/mcp/e2e/host.test.d.ts +1 -0
  43. package/dist/src/modules/mcp/e2e/index.d.ts +6 -0
  44. package/dist/src/modules/mcp/e2e/mcpEndpoint.d.ts +20 -0
  45. package/dist/src/modules/mcp/e2e/postMessageChannel.d.ts +22 -0
  46. package/dist/src/modules/mcp/e2e/renderingHost.d.ts +14 -0
  47. package/dist/src/modules/mcp/handler.d.ts +9 -5
  48. package/dist/src/modules/mcp/index.d.ts +1 -0
  49. package/dist/src/modules/mcp/resources/register.d.ts +1 -1
  50. package/dist/src/modules/mcp/resources/renderGuide.d.ts +1 -1
  51. package/dist/src/modules/mcp/server.d.ts +2 -10
  52. package/dist/src/modules/mcp/tools/apply/index.d.ts +3 -3
  53. package/dist/src/modules/mcp/tools/operations/index.d.ts +6 -6
  54. package/dist/src/modules/mcp/tools/operations/schema/operations.d.ts +1 -1
  55. package/dist/src/modules/mcp/tools/operations/schema/settings/patchSettings.d.ts +1 -1
  56. package/dist/src/modules/mcp/tools/operations/style/operations.d.ts +2 -2
  57. package/dist/src/modules/mcp/tools/operations/style/shared.d.ts +1 -1
  58. package/dist/src/modules/mcp/tools/operations/style/variables/deleteStyleVariable.d.ts +1 -1
  59. package/dist/src/modules/mcp/tools/operations/style/variables/upsertStyleVariable.d.ts +1 -1
  60. package/dist/src/modules/mcp/tools/preview.d.ts +3 -3
  61. package/dist/src/modules/mcp/tools/render.d.ts +3 -3
  62. package/dist/src/modules/mcp/tools/screenshot.d.ts +3 -3
  63. package/dist/src/modules/mcp/tools/shared/tool.d.ts +4 -7
  64. package/dist/src/modules/mcp/tools/validate.d.ts +3 -3
  65. package/dist/src/modules/mcp/types/appTypes.d.ts +13 -0
  66. package/dist/src/modules/mcp/types/index.d.ts +1 -0
  67. package/package.json +13 -4
  68. package/dist/modules/mcp/resources/renderApp.js +0 -174
  69. package/dist/server.d.ts +0 -1
  70. package/dist/server.js +0 -107
  71. package/dist/src/modules/mcp/resources/renderApp.d.ts +0 -3
@@ -0,0 +1,8 @@
1
+ import { McpApp } from '../../types';
2
+ /** The reference app: the smallest definition that works, kept as the template a new app is copied from.
3
+ *
4
+ * It is deliberately NOT in the `apps` list — nothing renders it, since no tool points at it — so it costs a
5
+ * real deployment nothing while the test suite still builds it, which is what keeps it from rotting. To turn it
6
+ * into a real app: add it to `apps` in ../index.ts and give a tool `ui: { resourceUri: EXAMPLE_APP_URI }`. */
7
+ export declare const EXAMPLE_APP_URI = "ui://plitzi/example.html";
8
+ export declare const exampleApp: McpApp;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,8 @@
1
+ import { McpApp } from '../types';
2
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ /** Every MCP App this server serves. A new one is a folder beside `render/` (its definition + its view) and one
4
+ * line here — the tool that opens it points at its `uri` through `ui: { resourceUri }`. Start from `example/`,
5
+ * which is that same shape stripped to the minimum. */
6
+ export declare const apps: McpApp[];
7
+ export declare const registerApps: (server: McpServer) => void;
8
+ export { RENDER_APP_URI } from './render';
@@ -0,0 +1,3 @@
1
+ import { McpApp } from '../../types';
2
+ export declare const RENDER_APP_URI = "ui://plitzi/render.html";
3
+ export declare const renderApp: McpApp;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export declare const bundle: (entry: string) => Promise<string>;
@@ -0,0 +1,2 @@
1
+ export { registerApp } from './registerApp';
2
+ export { require } from './resolve';
@@ -0,0 +1,2 @@
1
+ import { McpApp } from '../../types';
2
+ export declare const page: (app: McpApp) => Promise<string>;
@@ -0,0 +1,5 @@
1
+ import { McpApp } from '../../types';
2
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ /** Serves the app as a self-contained page: no import map, no asset mounts, no cross-origin fetches, so the
4
+ * strictest host sandbox runs it and no deployment has to serve anything extra. */
5
+ export declare const registerApp: (server: McpServer, app: McpApp) => void;
@@ -0,0 +1 @@
1
+ export declare const require: NodeJS.Require;
@@ -0,0 +1,4 @@
1
+ import { Plugin } from 'esbuild';
2
+ /** Drops zod's ~40 translations (194 KB): they are re-exported as a namespace, which no bundler can tree-shake.
3
+ * English survives because zod imports `locales/en.js` directly, not through this index. */
4
+ export declare const zodEnglishOnly: Plugin;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,6 @@
1
+ /** An MCP Apps host in two halves, so the App can be exercised without Claude Desktop or ChatGPT: the CONNECTOR
2
+ * (a real MCP client over Streamable HTTP) and the RENDERER (the ui:// page in a DOM, driven by AppBridge). */
3
+ export { readAppPage, startMcpEndpoint } from './mcpEndpoint';
4
+ export { startRenderingHost } from './renderingHost';
5
+ export type { AppPage, McpEndpoint } from './mcpEndpoint';
6
+ export type { RenderingHost } from './renderingHost';
@@ -0,0 +1,20 @@
1
+ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
2
+ /** A live MCP endpoint on loopback — the same handler a deployment serves, transport and all. */
3
+ export interface McpEndpoint {
4
+ url: string;
5
+ client: Client;
6
+ /** Raw fetch, for the probes a connector fires outside the JSON-RPC session. */
7
+ request: (init?: RequestInit & {
8
+ path?: string;
9
+ }) => Promise<Response>;
10
+ close: () => Promise<void>;
11
+ }
12
+ export interface AppPage {
13
+ html: string;
14
+ mimeType?: string;
15
+ meta?: Record<string, unknown>;
16
+ }
17
+ /** Start the endpoint and connect a real MCP client to it, as a remote connector does. */
18
+ export declare const startMcpEndpoint: () => Promise<McpEndpoint>;
19
+ /** Read a ui:// resource. A page that came back as a blob is a bug a host would meet as a blank frame. */
20
+ export declare const readAppPage: (endpoint: McpEndpoint, uri: string) => Promise<AppPage>;
@@ -0,0 +1,22 @@
1
+ import { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';
2
+ import { JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js';
3
+ import { JSDOM } from 'jsdom';
4
+ export interface ParentStub {
5
+ postMessage: (message: unknown) => void;
6
+ attach: (deliver: (message: unknown) => void) => void;
7
+ }
8
+ /** Stands in for the window an iframe posts to. It BUFFERS: the page starts parsing the moment the DOM is built,
9
+ * so without the queue its `ui/initialize` is dropped and the handshake silently never completes. */
10
+ export declare const parentStub: () => ParentStub;
11
+ /** The host end of that channel, as a transport an AppBridge can connect to. */
12
+ export declare class HostBridgeTransport implements Transport {
13
+ private readonly window;
14
+ private readonly parent;
15
+ onmessage?: (message: JSONRPCMessage) => void;
16
+ onclose?: () => void;
17
+ onerror?: (error: Error) => void;
18
+ constructor(window: JSDOM['window'], parent: ParentStub);
19
+ start(): Promise<void>;
20
+ send(message: JSONRPCMessage): Promise<void>;
21
+ close(): Promise<void>;
22
+ }
@@ -0,0 +1,14 @@
1
+ import { AppBridge } from '@modelcontextprotocol/ext-apps/app-bridge';
2
+ import { JSDOM } from 'jsdom';
3
+ import { McpUiHostContext, McpUiToolResultNotification } from '@modelcontextprotocol/ext-apps';
4
+ export interface RenderingHost {
5
+ bridge: AppBridge;
6
+ window: JSDOM['window'];
7
+ /** Deliver a tool result and let the App paint before assertions run. */
8
+ showResult: (result: McpUiToolResultNotification['params']) => Promise<void>;
9
+ text: () => string;
10
+ close: () => void;
11
+ }
12
+ /** Load a ui:// page into a DOM and complete the MCP Apps handshake against it, through the official AppBridge.
13
+ * Resolves once the App is connected, so a test can push a tool result straight away. */
14
+ export declare const startRenderingHost: (html: string, hostContext?: McpUiHostContext) => Promise<RenderingHost>;
@@ -1,12 +1,16 @@
1
1
  import { createMcpServer } from './server';
2
2
  import { PreviewClient, ScreenshotClient } from './types';
3
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp';
3
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
4
4
  import { SSRAdapters, SSRRequest, McpLogger } from '@plitzi/sdk-shared';
5
5
  import { IncomingMessage, ServerResponse } from 'node:http';
6
+ /** Per-request wiring the MCP service does not resolve itself: the renderer clients and the log sink. Everything
7
+ * here is optional — the service degrades feature by feature. */
8
+ export type McpRequestOptions = {
9
+ preview?: PreviewClient;
10
+ screenshot?: ScreenshotClient;
11
+ logger?: McpLogger;
12
+ };
6
13
  export declare const readMcpBody: (req: IncomingMessage) => Promise<unknown>;
7
14
  export declare const serveMcp: (raw: IncomingMessage, res: ServerResponse, server: McpServer) => Promise<void>;
8
- export declare const handleMcp: (raw: IncomingMessage, res: ServerResponse, req: SSRRequest, adapters: SSRAdapters, preview?: PreviewClient, screenshot?: ScreenshotClient, logger?: McpLogger, renderApp?: {
9
- sdkBase: string;
10
- devMode?: boolean;
11
- }) => Promise<void>;
15
+ export declare const handleMcp: (raw: IncomingMessage, res: ServerResponse, req: SSRRequest, adapters: SSRAdapters, options?: McpRequestOptions) => Promise<void>;
12
16
  export { createMcpServer };
@@ -4,6 +4,7 @@ export { apply, validate, search, read, validateOperations, operation, tools } f
4
4
  export { computeVersion, buildAgentGuide } from './helpers';
5
5
  export { createHttpPreviewClient } from './previewClient';
6
6
  export { createHttpScreenshotClient } from './screenshotClient';
7
+ export type { McpRequestOptions } from './handler';
7
8
  export type { HttpPreviewClientConfig } from './previewClient';
8
9
  export type { HttpScreenshotClientConfig } from './screenshotClient';
9
10
  export type { McpServerContext } from './server';
@@ -1,6 +1,6 @@
1
1
  import { McpLog, Space } from '../helpers';
2
2
  import { Env } from '../types';
3
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp';
3
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
4
4
  /** Register every resource on the MCP server: fixed listings plus templated per-item reads. The space is
5
5
  * loaded lazily via getSpace, so listing resources never touches the store — only reading one does. */
6
6
  export declare const registerResources: (server: McpServer, getSpace: () => Promise<Space>, env: Env, log: McpLog) => void;
@@ -1,4 +1,4 @@
1
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp';
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
2
  export declare const RENDER_GUIDE_URI = "plitzi://render/guide";
3
3
  export declare const RENDER_TYPES_URI = "plitzi://render/types";
4
4
  export declare const registerRenderResources: (server: McpServer) => void;
@@ -1,4 +1,4 @@
1
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp';
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
2
  import { PreviewClient, ScreenshotClient } from './types';
3
3
  import { SSRAdapters, McpLogger } from '@plitzi/sdk-shared';
4
4
  /** The MCP service is stateless: every request resolves its own `spaceId` (from the request JWT) and reads the
@@ -18,13 +18,5 @@ export interface McpServerContext {
18
18
  /** Structured request-log sink. When set, every tool call and resource read emits an McpLogEvent to it (the
19
19
  * consumer renders them); otherwise logging falls back to the console when MCP_DEBUG=1. */
20
20
  logger?: McpLogger;
21
- /** MCP Apps: the interactive render view for plitzi_render. `sdkBase` is this server's absolute origin, which
22
- * serves the Plitzi SDK bundle under /sdk-assets; the iframe imports it and renders the widget client-side.
23
- * `devMode` picks the SDK vendor bundle name (dev vs prod split) to match the served bundle. Absent → the
24
- * ui:// view is not registered (the tool still returns its text summary + offlineData). */
25
- renderApp?: {
26
- sdkBase: string;
27
- devMode?: boolean;
28
- };
29
21
  }
30
- export declare const createMcpServer: ({ adapters, getSpaceId, preview, screenshot, logger, renderApp }: McpServerContext) => McpServer;
22
+ export declare const createMcpServer: ({ adapters, getSpaceId, preview, screenshot, logger }: McpServerContext) => McpServer;
@@ -179,8 +179,8 @@ export declare const applyShape: {
179
179
  userProvider: z.ZodOptional<z.ZodEnum<{
180
180
  "": "";
181
181
  custom: "custom";
182
- basic: "basic";
183
182
  auth0: "auth0";
183
+ basic: "basic";
184
184
  }>>;
185
185
  auth0Domain: z.ZodOptional<z.ZodString>;
186
186
  auth0ClientId: z.ZodOptional<z.ZodString>;
@@ -395,9 +395,9 @@ export declare const applyShape: {
395
395
  type: z.ZodLiteral<"upsertStyleVariable">;
396
396
  category: z.ZodEnum<{
397
397
  color: "color";
398
- custom: "custom";
399
398
  spacing: "spacing";
400
399
  shadow: "shadow";
400
+ custom: "custom";
401
401
  }>;
402
402
  name: z.ZodString;
403
403
  value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodObject<{
@@ -409,9 +409,9 @@ export declare const applyShape: {
409
409
  type: z.ZodLiteral<"deleteStyleVariable">;
410
410
  category: z.ZodEnum<{
411
411
  color: "color";
412
- custom: "custom";
413
412
  spacing: "spacing";
414
413
  shadow: "shadow";
414
+ custom: "custom";
415
415
  }>;
416
416
  name: z.ZodString;
417
417
  }, z.core.$strip>], "type">>;
@@ -175,8 +175,8 @@ export declare const operation: z.ZodDiscriminatedUnion<[z.ZodObject<{
175
175
  userProvider: z.ZodOptional<z.ZodEnum<{
176
176
  "": "";
177
177
  custom: "custom";
178
- basic: "basic";
179
178
  auth0: "auth0";
179
+ basic: "basic";
180
180
  }>>;
181
181
  auth0Domain: z.ZodOptional<z.ZodString>;
182
182
  auth0ClientId: z.ZodOptional<z.ZodString>;
@@ -391,9 +391,9 @@ export declare const operation: z.ZodDiscriminatedUnion<[z.ZodObject<{
391
391
  type: z.ZodLiteral<"upsertStyleVariable">;
392
392
  category: z.ZodEnum<{
393
393
  color: "color";
394
- custom: "custom";
395
394
  spacing: "spacing";
396
395
  shadow: "shadow";
396
+ custom: "custom";
397
397
  }>;
398
398
  name: z.ZodString;
399
399
  value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodObject<{
@@ -405,9 +405,9 @@ export declare const operation: z.ZodDiscriminatedUnion<[z.ZodObject<{
405
405
  type: z.ZodLiteral<"deleteStyleVariable">;
406
406
  category: z.ZodEnum<{
407
407
  color: "color";
408
- custom: "custom";
409
408
  spacing: "spacing";
410
409
  shadow: "shadow";
410
+ custom: "custom";
411
411
  }>;
412
412
  name: z.ZodString;
413
413
  }, z.core.$strip>], "type">;
@@ -590,8 +590,8 @@ export declare const operations: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject
590
590
  userProvider: z.ZodOptional<z.ZodEnum<{
591
591
  "": "";
592
592
  custom: "custom";
593
- basic: "basic";
594
593
  auth0: "auth0";
594
+ basic: "basic";
595
595
  }>>;
596
596
  auth0Domain: z.ZodOptional<z.ZodString>;
597
597
  auth0ClientId: z.ZodOptional<z.ZodString>;
@@ -806,9 +806,9 @@ export declare const operations: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject
806
806
  type: z.ZodLiteral<"upsertStyleVariable">;
807
807
  category: z.ZodEnum<{
808
808
  color: "color";
809
- custom: "custom";
810
809
  spacing: "spacing";
811
810
  shadow: "shadow";
811
+ custom: "custom";
812
812
  }>;
813
813
  name: z.ZodString;
814
814
  value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodObject<{
@@ -820,9 +820,9 @@ export declare const operations: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject
820
820
  type: z.ZodLiteral<"deleteStyleVariable">;
821
821
  category: z.ZodEnum<{
822
822
  color: "color";
823
- custom: "custom";
824
823
  spacing: "spacing";
825
824
  shadow: "shadow";
825
+ custom: "custom";
826
826
  }>;
827
827
  name: z.ZodString;
828
828
  }, z.core.$strip>], "type">>;
@@ -189,8 +189,8 @@ export declare const elementOps: {
189
189
  userProvider: import('zod').ZodOptional<import('zod').ZodEnum<{
190
190
  "": "";
191
191
  custom: "custom";
192
- basic: "basic";
193
192
  auth0: "auth0";
193
+ basic: "basic";
194
194
  }>>;
195
195
  auth0Domain: import('zod').ZodOptional<import('zod').ZodString>;
196
196
  auth0ClientId: import('zod').ZodOptional<import('zod').ZodString>;
@@ -12,8 +12,8 @@ export declare const patchSettingsOp: z.ZodObject<{
12
12
  userProvider: z.ZodOptional<z.ZodEnum<{
13
13
  "": "";
14
14
  custom: "custom";
15
- basic: "basic";
16
15
  auth0: "auth0";
16
+ basic: "basic";
17
17
  }>>;
18
18
  auth0Domain: z.ZodOptional<z.ZodString>;
19
19
  auth0ClientId: z.ZodOptional<z.ZodString>;
@@ -207,9 +207,9 @@ export declare const styleOps: {
207
207
  type: import('zod').ZodLiteral<"upsertStyleVariable">;
208
208
  category: import('zod').ZodEnum<{
209
209
  color: "color";
210
- custom: "custom";
211
210
  spacing: "spacing";
212
211
  shadow: "shadow";
212
+ custom: "custom";
213
213
  }>;
214
214
  name: import('zod').ZodString;
215
215
  value: import('zod').ZodUnion<readonly [import('zod').ZodString, import('zod').ZodNumber, import('zod').ZodObject<{
@@ -222,9 +222,9 @@ export declare const styleOps: {
222
222
  type: import('zod').ZodLiteral<"deleteStyleVariable">;
223
223
  category: import('zod').ZodEnum<{
224
224
  color: "color";
225
- custom: "custom";
226
225
  spacing: "spacing";
227
226
  shadow: "shadow";
227
+ custom: "custom";
228
228
  }>;
229
229
  name: import('zod').ZodString;
230
230
  }, import('zod/v4/core').$strip>;
@@ -43,9 +43,9 @@ declare const definitionSlotPatch: z.ZodObject<{
43
43
  export type DefinitionSlotPatch = z.infer<typeof definitionSlotPatch>;
44
44
  export declare const styleCategory: z.ZodEnum<{
45
45
  color: "color";
46
- custom: "custom";
47
46
  spacing: "spacing";
48
47
  shadow: "shadow";
48
+ custom: "custom";
49
49
  }>;
50
50
  export declare const themeValue: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodObject<{
51
51
  light: z.ZodOptional<z.ZodString>;
@@ -5,9 +5,9 @@ export declare const deleteStyleVariableOp: z.ZodObject<{
5
5
  type: z.ZodLiteral<"deleteStyleVariable">;
6
6
  category: z.ZodEnum<{
7
7
  color: "color";
8
- custom: "custom";
9
8
  spacing: "spacing";
10
9
  shadow: "shadow";
10
+ custom: "custom";
11
11
  }>;
12
12
  name: z.ZodString;
13
13
  }, z.core.$strip>;
@@ -5,9 +5,9 @@ export declare const upsertStyleVariableOp: z.ZodObject<{
5
5
  type: z.ZodLiteral<"upsertStyleVariable">;
6
6
  category: z.ZodEnum<{
7
7
  color: "color";
8
- custom: "custom";
9
8
  spacing: "spacing";
10
9
  shadow: "shadow";
10
+ custom: "custom";
11
11
  }>;
12
12
  name: z.ZodString;
13
13
  value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodObject<{
@@ -175,8 +175,8 @@ export declare const previewShape: {
175
175
  userProvider: z.ZodOptional<z.ZodEnum<{
176
176
  "": "";
177
177
  custom: "custom";
178
- basic: "basic";
179
178
  auth0: "auth0";
179
+ basic: "basic";
180
180
  }>>;
181
181
  auth0Domain: z.ZodOptional<z.ZodString>;
182
182
  auth0ClientId: z.ZodOptional<z.ZodString>;
@@ -391,9 +391,9 @@ export declare const previewShape: {
391
391
  type: z.ZodLiteral<"upsertStyleVariable">;
392
392
  category: z.ZodEnum<{
393
393
  color: "color";
394
- custom: "custom";
395
394
  spacing: "spacing";
396
395
  shadow: "shadow";
396
+ custom: "custom";
397
397
  }>;
398
398
  name: z.ZodString;
399
399
  value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodObject<{
@@ -405,9 +405,9 @@ export declare const previewShape: {
405
405
  type: z.ZodLiteral<"deleteStyleVariable">;
406
406
  category: z.ZodEnum<{
407
407
  color: "color";
408
- custom: "custom";
409
408
  spacing: "spacing";
410
409
  shadow: "shadow";
410
+ custom: "custom";
411
411
  }>;
412
412
  name: z.ZodString;
413
413
  }, z.core.$strip>], "type">>>;
@@ -175,8 +175,8 @@ export declare const renderShape: {
175
175
  userProvider: import('zod').ZodOptional<import('zod').ZodEnum<{
176
176
  "": "";
177
177
  custom: "custom";
178
- basic: "basic";
179
178
  auth0: "auth0";
179
+ basic: "basic";
180
180
  }>>;
181
181
  auth0Domain: import('zod').ZodOptional<import('zod').ZodString>;
182
182
  auth0ClientId: import('zod').ZodOptional<import('zod').ZodString>;
@@ -391,9 +391,9 @@ export declare const renderShape: {
391
391
  type: import('zod').ZodLiteral<"upsertStyleVariable">;
392
392
  category: import('zod').ZodEnum<{
393
393
  color: "color";
394
- custom: "custom";
395
394
  spacing: "spacing";
396
395
  shadow: "shadow";
396
+ custom: "custom";
397
397
  }>;
398
398
  name: import('zod').ZodString;
399
399
  value: import('zod').ZodUnion<readonly [import('zod').ZodString, import('zod').ZodNumber, import('zod').ZodObject<{
@@ -405,9 +405,9 @@ export declare const renderShape: {
405
405
  type: import('zod').ZodLiteral<"deleteStyleVariable">;
406
406
  category: import('zod').ZodEnum<{
407
407
  color: "color";
408
- custom: "custom";
409
408
  spacing: "spacing";
410
409
  shadow: "shadow";
410
+ custom: "custom";
411
411
  }>;
412
412
  name: import('zod').ZodString;
413
413
  }, import('zod/v4/core').$strip>], "type">>;
@@ -175,8 +175,8 @@ export declare const screenshotShape: {
175
175
  userProvider: z.ZodOptional<z.ZodEnum<{
176
176
  "": "";
177
177
  custom: "custom";
178
- basic: "basic";
179
178
  auth0: "auth0";
179
+ basic: "basic";
180
180
  }>>;
181
181
  auth0Domain: z.ZodOptional<z.ZodString>;
182
182
  auth0ClientId: z.ZodOptional<z.ZodString>;
@@ -391,9 +391,9 @@ export declare const screenshotShape: {
391
391
  type: z.ZodLiteral<"upsertStyleVariable">;
392
392
  category: z.ZodEnum<{
393
393
  color: "color";
394
- custom: "custom";
395
394
  spacing: "spacing";
396
395
  shadow: "shadow";
396
+ custom: "custom";
397
397
  }>;
398
398
  name: z.ZodString;
399
399
  value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodObject<{
@@ -405,9 +405,9 @@ export declare const screenshotShape: {
405
405
  type: z.ZodLiteral<"deleteStyleVariable">;
406
406
  category: z.ZodEnum<{
407
407
  color: "color";
408
- custom: "custom";
409
408
  spacing: "spacing";
410
409
  shadow: "shadow";
410
+ custom: "custom";
411
411
  }>;
412
412
  name: z.ZodString;
413
413
  }, z.core.$strip>], "type">>>;
@@ -1,6 +1,7 @@
1
1
  import { z, ZodObject, ZodRawShape } from 'zod';
2
2
  import { Space } from '../../helpers';
3
3
  import { PreviewClient, ScreenshotClient, ScreenshotImage, Env, Persisters } from '../../types';
4
+ import { McpUiToolMeta } from '@modelcontextprotocol/ext-apps';
4
5
  import { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
5
6
  /** Everything a tool needs at call time: the loaded space, the target environment, and the persisters (only the
6
7
  * write tools use them). Built by whoever hosts the tools — the standalone MCP server or the in-process AI
@@ -35,10 +36,8 @@ export interface ToolSpec<Shape extends ZodRawShape> {
35
36
  * or load a space for it — that keeps it callable with no auth, on the public surface. */
36
37
  spaceless?: boolean;
37
38
  /** MCP Apps: link this tool to an interactive UI resource (a `ui://` HTML page the host renders in a sandboxed
38
- * iframe, receiving the tool result). The `_meta.ui` the host reads is built from this. */
39
- ui?: {
40
- resourceUri: string;
41
- };
39
+ * iframe, receiving the tool result). Registered as the tool's `_meta.ui` see registerAppTool. */
40
+ ui?: McpUiToolMeta;
42
41
  run: (input: z.infer<ZodObject<Shape>>, ctx: ToolContext) => unknown;
43
42
  }
44
43
  /** What the registry holds and the hosts register from: the same metadata plus a type-erased `execute` that
@@ -51,9 +50,7 @@ export interface ToolDef {
51
50
  access: 'read' | 'write';
52
51
  requires?: ToolRequires;
53
52
  spaceless?: boolean;
54
- ui?: {
55
- resourceUri: string;
56
- };
53
+ ui?: McpUiToolMeta;
57
54
  execute: (args: unknown, ctx: ToolContext) => unknown;
58
55
  }
59
56
  /** Author a tool: give it its metadata, its input shape and a typed `run`. The returned descriptor parses the
@@ -176,8 +176,8 @@ export declare const validateShape: {
176
176
  userProvider: import('zod').ZodOptional<import('zod').ZodEnum<{
177
177
  "": "";
178
178
  custom: "custom";
179
- basic: "basic";
180
179
  auth0: "auth0";
180
+ basic: "basic";
181
181
  }>>;
182
182
  auth0Domain: import('zod').ZodOptional<import('zod').ZodString>;
183
183
  auth0ClientId: import('zod').ZodOptional<import('zod').ZodString>;
@@ -392,9 +392,9 @@ export declare const validateShape: {
392
392
  type: import('zod').ZodLiteral<"upsertStyleVariable">;
393
393
  category: import('zod').ZodEnum<{
394
394
  color: "color";
395
- custom: "custom";
396
395
  spacing: "spacing";
397
396
  shadow: "shadow";
397
+ custom: "custom";
398
398
  }>;
399
399
  name: import('zod').ZodString;
400
400
  value: import('zod').ZodUnion<readonly [import('zod').ZodString, import('zod').ZodNumber, import('zod').ZodObject<{
@@ -406,9 +406,9 @@ export declare const validateShape: {
406
406
  type: import('zod').ZodLiteral<"deleteStyleVariable">;
407
407
  category: import('zod').ZodEnum<{
408
408
  color: "color";
409
- custom: "custom";
410
409
  spacing: "spacing";
411
410
  shadow: "shadow";
411
+ custom: "custom";
412
412
  }>;
413
413
  name: import('zod').ZodString;
414
414
  }, import('zod/v4/core').$strip>], "type">>;
@@ -0,0 +1,13 @@
1
+ import { McpUiResourceCsp } from '@modelcontextprotocol/ext-apps';
2
+ /** A `ui://` page the host renders in a sandboxed iframe, linked from a tool through `_meta.ui.resourceUri`. */
3
+ export interface McpApp {
4
+ uri: string;
5
+ name: string;
6
+ description: string;
7
+ title: string;
8
+ /** Absolute path to the view: the app's browser entry. */
9
+ entry: string;
10
+ /** Stylesheets to inline, by absolute path — lazy so a missing one only fails on read. */
11
+ styles?: () => string[];
12
+ csp?: McpUiResourceCsp;
13
+ }
@@ -1,4 +1,5 @@
1
1
  export type * from './aiSchema';
2
+ export type * from './appTypes';
2
3
  export type * from './toolTypes';
3
4
  export type * from './previewTypes';
4
5
  export type * from './screenshotTypes';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plitzi/sdk-server",
3
- "version": "0.32.8",
3
+ "version": "0.32.10",
4
4
  "license": "AGPL-3.0",
5
5
  "files": [
6
6
  "dist"
@@ -13,6 +13,11 @@
13
13
  "types": "./dist/index.d.ts",
14
14
  "import": "./dist/index.js",
15
15
  "default": "./dist/index.js"
16
+ },
17
+ "./mcp": {
18
+ "types": "./dist/mcp.d.ts",
19
+ "import": "./dist/mcp.js",
20
+ "default": "./dist/mcp.js"
16
21
  }
17
22
  },
18
23
  "repository": {
@@ -22,10 +27,11 @@
22
27
  "type": "module",
23
28
  "sideEffects": false,
24
29
  "dependencies": {
30
+ "@modelcontextprotocol/ext-apps": "^1.7.5",
25
31
  "@modelcontextprotocol/sdk": "^1.29.0",
26
- "@plitzi/plitzi-sdk": "0.32.8",
27
- "@plitzi/sdk-schema": "0.32.8",
28
- "@plitzi/sdk-shared": "0.32.8",
32
+ "@plitzi/plitzi-sdk": "0.32.10",
33
+ "@plitzi/sdk-schema": "0.32.10",
34
+ "@plitzi/sdk-shared": "0.32.10",
29
35
  "ejs": "^6.0.1",
30
36
  "esbuild": "^0.28.1",
31
37
  "zod": "^4.4.3"
@@ -36,12 +42,14 @@
36
42
  },
37
43
  "devDependencies": {
38
44
  "@types/ejs": "^3.1.5",
45
+ "@types/jsdom": "^28.0.3",
39
46
  "@types/node": "^26.1.1",
40
47
  "@types/react": "^19.2.17",
41
48
  "@vitejs/plugin-react": "^6.0.4",
42
49
  "@vitest/coverage-v8": "^4.1.10",
43
50
  "eslint": "^9.39.5",
44
51
  "eslint-plugin-import": "^2.32.0",
52
+ "jsdom": "^29.1.1",
45
53
  "react": "^19.2.8",
46
54
  "react-dom": "^19.2.8",
47
55
  "tsx": "^4.23.1",
@@ -60,6 +68,7 @@
60
68
  "lint": "TIMING=1 eslint ./src",
61
69
  "typecheck": "tsc -p tsconfig.app.json --noEmit",
62
70
  "test": "vitest run",
71
+ "test:e2e": "vitest run src/modules/mcp/e2e",
63
72
  "test:coverage": "vitest run --coverage",
64
73
  "bench": "vitest bench --run"
65
74
  }