@plitzi/sdk-mcp 0.38.3 → 0.38.5

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 (83) hide show
  1. package/CHANGELOG.md +540 -0
  2. package/README.md +38 -12
  3. package/dist/createServer.d.ts +1 -1
  4. package/dist/createServer.js +1 -1
  5. package/dist/index.d.ts +3 -4
  6. package/dist/index.js +1 -4
  7. package/dist/modules/mcp/apps/render/styles.d.ts +4 -8
  8. package/dist/modules/mcp/apps/render/styles.js +16 -47
  9. package/dist/modules/mcp/apps/render/view/index.tsx +1 -1
  10. package/dist/modules/mcp/catalogs/index.js +2 -2
  11. package/dist/modules/mcp/catalogs/pluginCatalog.js +2 -2
  12. package/dist/modules/mcp/e2e/mcpEndpoint.d.ts +2 -1
  13. package/dist/modules/mcp/handler.d.ts +2 -2
  14. package/dist/modules/mcp/helpers/callToolResult.d.ts +2 -0
  15. package/dist/modules/mcp/helpers/callToolResult.js +4 -0
  16. package/dist/modules/mcp/helpers/guide.js +68 -14
  17. package/dist/modules/mcp/helpers/index.d.ts +1 -1
  18. package/dist/modules/mcp/helpers/space.d.ts +4 -1
  19. package/dist/modules/mcp/helpers/space.js +1 -0
  20. package/dist/modules/mcp/helpers/uris.d.ts +2 -0
  21. package/dist/modules/mcp/helpers/uris.js +3 -1
  22. package/dist/modules/mcp/index.d.ts +1 -1
  23. package/dist/modules/mcp/localScreenshotClient.d.ts +3 -0
  24. package/dist/modules/mcp/localScreenshotClient.js +2 -0
  25. package/dist/modules/mcp/resources/connectors.d.ts +1 -1
  26. package/dist/modules/mcp/resources/core.js +2 -2
  27. package/dist/modules/mcp/resources/data.d.ts +8 -0
  28. package/dist/modules/mcp/resources/data.js +46 -0
  29. package/dist/modules/mcp/resources/explain.js +1 -1
  30. package/dist/modules/mcp/resources/primer.js +3 -3
  31. package/dist/modules/mcp/resources/register.js +12 -2
  32. package/dist/modules/mcp/resources/renderGuide.js +6 -6
  33. package/dist/modules/mcp/resources/router.js +3 -1
  34. package/dist/modules/mcp/resources/schema.js +1 -1
  35. package/dist/modules/mcp/server.d.ts +3 -3
  36. package/dist/modules/mcp/server.js +12 -8
  37. package/dist/modules/mcp/tools/apply/dispatch.js +9 -1
  38. package/dist/modules/mcp/tools/apply/index.d.ts +12 -2
  39. package/dist/modules/mcp/tools/apply/index.js +27 -1
  40. package/dist/modules/mcp/tools/index.d.ts +2 -2
  41. package/dist/modules/mcp/tools/index.js +2 -2
  42. package/dist/modules/mcp/tools/operations/connectors/index.d.ts +2 -2
  43. package/dist/modules/mcp/tools/operations/connectors/manifest.d.ts +1 -1
  44. package/dist/modules/mcp/tools/operations/connectors/patchConnector.d.ts +1 -1
  45. package/dist/modules/mcp/tools/operations/connectors/upsertConnector.d.ts +1 -1
  46. package/dist/modules/mcp/tools/operations/data/data.test.d.ts +1 -0
  47. package/dist/modules/mcp/tools/operations/data/index.d.ts +32 -0
  48. package/dist/modules/mcp/tools/operations/data/index.js +54 -0
  49. package/dist/modules/mcp/tools/operations/index.d.ts +30 -4
  50. package/dist/modules/mcp/tools/operations/index.js +4 -1
  51. package/dist/modules/mcp/tools/operations/schema/elements/patchElement.d.ts +1 -0
  52. package/dist/modules/mcp/tools/operations/schema/elements/patchElement.js +5 -2
  53. package/dist/modules/mcp/tools/operations/schema/elements/upsertElement.js +1 -0
  54. package/dist/modules/mcp/tools/operations/schema/interactions/patchInteractionNode.d.ts +1 -0
  55. package/dist/modules/mcp/tools/operations/schema/interactions/upsertInteractionFlow.d.ts +1 -0
  56. package/dist/modules/mcp/tools/operations/schema/operations.d.ts +3 -0
  57. package/dist/modules/mcp/tools/operations/schema/shared.d.ts +5 -0
  58. package/dist/modules/mcp/tools/operations/schema/shared.js +13 -7
  59. package/dist/modules/mcp/tools/operations/schema/translator.js +1 -1
  60. package/dist/modules/mcp/tools/operations/schema/write.js +3 -2
  61. package/dist/modules/mcp/tools/operations/schemaIds.js +3 -3
  62. package/dist/modules/mcp/tools/operations/style/write.js +1 -1
  63. package/dist/modules/mcp/tools/preview.d.ts +3 -0
  64. package/dist/modules/mcp/tools/render.d.ts +3 -0
  65. package/dist/modules/mcp/tools/screenshot.d.ts +12 -2
  66. package/dist/modules/mcp/tools/shared/newSuggestions.d.ts +2 -2
  67. package/dist/modules/mcp/tools/shared/newSuggestions.js +10 -5
  68. package/dist/modules/mcp/tools/shared/newSuggestions.test.d.ts +1 -0
  69. package/dist/modules/mcp/tools/shared/tool.d.ts +7 -6
  70. package/dist/modules/mcp/tools/shared/validator/index.js +2 -2
  71. package/dist/modules/mcp/tools/tryFunction.js +1 -1
  72. package/dist/modules/mcp/tools/validate.d.ts +12 -2
  73. package/dist/modules/mcp/types/appTypes.d.ts +2 -2
  74. package/dist/modules/mcp/types/toolTypes.d.ts +5 -1
  75. package/package.json +7 -9
  76. package/dist/modules/ai/AIEngine.d.ts +0 -20
  77. package/dist/modules/ai/AIEngine.js +0 -120
  78. package/dist/modules/ai/index.d.ts +0 -4
  79. package/dist/modules/ai/toolkit.d.ts +0 -17
  80. package/dist/modules/ai/toolkit.js +0 -59
  81. package/dist/modules/mcp/helpers/agentPrompt.d.ts +0 -4
  82. package/dist/modules/mcp/helpers/agentPrompt.js +0 -123
  83. /package/dist/modules/{ai/toolkit.test.d.ts → mcp/helpers/callToolResult.test.d.ts} +0 -0
@@ -37,6 +37,9 @@ type Page = {
37
37
  value: string;
38
38
  }[]) => Promise<void>;
39
39
  evaluate: <T>(fn: () => T) => Promise<T>;
40
+ addStyleTag: (options: {
41
+ content: string;
42
+ }) => Promise<unknown>;
40
43
  screenshot: (options: Record<string, unknown>) => Promise<Buffer | Uint8Array>;
41
44
  /** Playwright's: the page's accessibility tree, already written as an outline. */
42
45
  locator?: (selector: string) => {
@@ -1,5 +1,6 @@
1
1
  import { outlineOfSnapshot, outlineOfTree } from "./accessibilityOutline.js";
2
2
  import { PREVIEW_TOKEN_PARAM } from "@plitzi/sdk-server/kernel";
3
+ import { MOTION_STILL_CSS } from "@plitzi/sdk-shared/schema/motion";
3
4
  //#region src/modules/mcp/localScreenshotClient.ts
4
5
  /**
5
6
  * Grow the window to whatever actually scrolls before shooting.
@@ -90,6 +91,7 @@ var createLocalScreenshotClient = async ({ renderBaseUrl, ignoreHttpsErrors = tr
90
91
  message: `The page answered ${response.status()}.`
91
92
  };
92
93
  await page.evaluate(FONTS_READY);
94
+ await page.addStyleTag({ content: MOTION_STILL_CSS });
93
95
  if (fullPage) {
94
96
  const height = Math.min(await page.evaluate(CONTENT_HEIGHT), MAX_HEIGHT);
95
97
  if (height > viewport.height) await setViewport(page, {
@@ -10,7 +10,7 @@ export declare const connectorSummaries: (space: Space) => {
10
10
  operators: string[];
11
11
  pagination: import('@plitzi/sdk-shared').ConnectorPagination | undefined;
12
12
  credential: string | undefined;
13
- fields: Record<string, "number" | "file" | "text" | "color" | "switch" | "email" | "date" | "richText" | "image" | "multiImage" | "video" | "link" | "phone" | "option"> | undefined;
13
+ fields: Record<string, "number" | "file" | "text" | "color" | "image" | "switch" | "email" | "date" | "richText" | "multiImage" | "video" | "link" | "phone" | "option"> | undefined;
14
14
  }[];
15
15
  };
16
16
  /** Connector reads: the space's connector listing and one full manifest. Undefined when the URI belongs to
@@ -1,7 +1,7 @@
1
- import { buildTypeRegistry } from "../catalogs/registry.js";
2
- import { cssProperties, cssShorthands } from "../catalogs/index.js";
3
1
  import "../helpers/uris.js";
4
2
  import { guideText } from "../helpers/guide.js";
3
+ import { buildTypeRegistry } from "../catalogs/registry.js";
4
+ import { cssProperties, cssShorthands } from "../catalogs/index.js";
5
5
  import { envelope } from "./envelope.js";
6
6
  //#region src/modules/mcp/resources/core.ts
7
7
  /** Space-independent singletons: the usage guide, the observed type registry and the CSS property catalog.
@@ -0,0 +1,8 @@
1
+ import { Space } from '../helpers';
2
+ import { Env, ResourceEnvelope } from '../types';
3
+ /**
4
+ * The space's own data: JSON its server providers read (`query: '/data/<file>'`, `runtime: 'server'`), never served.
5
+ * The listing says which files there are, so an agent reads the one it needs; a file reads whole — parsed, so its
6
+ * shape is what a binding onto it reads.
7
+ */
8
+ export declare const readDataResource: (space: Space, env: Env, uri: string) => ResourceEnvelope<unknown> | null | undefined;
@@ -0,0 +1,46 @@
1
+ import { afterPrefix, dataFileUri, dataUri } from "../helpers/uris.js";
2
+ import { envelope } from "./envelope.js";
3
+ //#region src/modules/mcp/resources/data.ts
4
+ /**
5
+ * The space's own data: JSON its server providers read (`query: '/data/<file>'`, `runtime: 'server'`), never served.
6
+ * The listing says which files there are, so an agent reads the one it needs; a file reads whole — parsed, so its
7
+ * shape is what a binding onto it reads.
8
+ */
9
+ var readDataResource = (space, env, uri) => {
10
+ if (uri === dataUri(env)) {
11
+ if (!space.data) return envelope({
12
+ available: false,
13
+ reason: "This deployment keeps no space data"
14
+ });
15
+ const { files, version } = space.data;
16
+ return envelope({
17
+ available: true,
18
+ version,
19
+ files: Object.entries(files).map(([path, content]) => ({
20
+ path,
21
+ query: `/data/${path}`,
22
+ bytes: content.length
23
+ }))
24
+ });
25
+ }
26
+ const path = afterPrefix(uri, dataFileUri(env, ""));
27
+ if (path === void 0) return;
28
+ const content = space.data && Object.hasOwn(space.data.files, path) ? space.data.files[path] : void 0;
29
+ if (content === void 0) return null;
30
+ try {
31
+ return envelope({
32
+ path,
33
+ query: `/data/${path}`,
34
+ content: JSON.parse(content)
35
+ });
36
+ } catch {
37
+ return envelope({
38
+ path,
39
+ query: `/data/${path}`,
40
+ text: content,
41
+ problem: "It is not JSON"
42
+ });
43
+ }
44
+ };
45
+ //#endregion
46
+ export { readDataResource };
@@ -11,7 +11,7 @@ var explainResource = (uri) => {
11
11
  names: explainList(kind)
12
12
  };
13
13
  const explanations = explain(name);
14
- if (explanations.length === 0) throw new Error(`"${name}" is no element, step, trigger, code or transformer. List what there is: ${Object.values(EXPLAIN_KINDS).map((plural) => `${PREFIX}${plural}`).join(", ")}.`);
14
+ if (explanations.length === 0) throw new Error(`"${name}" is no element, step, trigger, code, transformer or helper. List what there is: ${Object.values(EXPLAIN_KINDS).map((plural) => `${PREFIX}${plural}`).join(", ")}.`);
15
15
  return {
16
16
  name,
17
17
  explanations,
@@ -1,9 +1,9 @@
1
- import { buildDataSourceCatalog, buildInteractionCatalog } from "../catalogs/observed.js";
2
- import { buildTypeRegistry } from "../catalogs/registry.js";
3
- import { cssProperties, cssShorthands } from "../catalogs/index.js";
4
1
  import { componentSummariesToAI } from "../helpers/components.js";
5
2
  import { componentsUri, connectorsUri, dataSourcesUri, defsUri, flagsUri, foldersUri, fontsUri, interactionsUri, layoutsUri, pagesUri, primerUri, schemaVarsUri, settingsUri, styleVarsUri, typesUri } from "../helpers/uris.js";
6
3
  import { guideQuickstart } from "../helpers/guide.js";
4
+ import { buildDataSourceCatalog, buildInteractionCatalog } from "../catalogs/observed.js";
5
+ import { buildTypeRegistry } from "../catalogs/registry.js";
6
+ import { cssProperties, cssShorthands } from "../catalogs/index.js";
7
7
  import { envelope } from "./envelope.js";
8
8
  import { connectorSummaries } from "./connectors.js";
9
9
  import { definitionRefs, fontsToAI, styleVariablesToAI } from "../tools/operations/style/translator.js";
@@ -1,6 +1,6 @@
1
- import { cssProperties, cssShorthands } from "../catalogs/index.js";
2
1
  import { changesUri } from "../helpers/uris.js";
3
2
  import { guideText } from "../helpers/guide.js";
3
+ import { cssProperties, cssShorthands } from "../catalogs/index.js";
4
4
  import { envelope, jsonContents } from "./envelope.js";
5
5
  import { resourceErrorMessage } from "./canonical.js";
6
6
  import { registerRenderResources } from "./renderGuide.js";
@@ -36,7 +36,7 @@ var registerResources = (server, getSpace, env, log, hasSpace, readChanges) => {
36
36
  return result;
37
37
  };
38
38
  server.registerResource("Guide", "plitzi://guide", {
39
- description: "How to read and write this space with mcp-ai",
39
+ description: "How to read and write this space through this server",
40
40
  mimeType: "text/markdown"
41
41
  }, () => emitStatic("plitzi://guide", () => ({ contents: [{
42
42
  uri: "plitzi://guide",
@@ -157,6 +157,11 @@ var registerResources = (server, getSpace, env, log, hasSpace, readChanges) => {
157
157
  `plitzi://functions/${env}`,
158
158
  "The space’s own server code: which files it is, and the tasks, routes and hosts it declares — its tasks are steps like any server task"
159
159
  ],
160
+ [
161
+ "Data",
162
+ `plitzi://data/${env}`,
163
+ "The space’s own data: JSON files its server providers read as `/data/<file>`, never served — which files there are"
164
+ ],
160
165
  [
161
166
  "Style definitions (schema alias)",
162
167
  `plitzi://schema/${env}/definitions`,
@@ -237,6 +242,11 @@ var registerResources = (server, getSpace, env, log, hasSpace, readChanges) => {
237
242
  `plitzi://functions/${env}/{+path}`,
238
243
  "One file of the space’s functions, whole"
239
244
  ],
245
+ [
246
+ "Data file",
247
+ `plitzi://data/${env}/{+path}`,
248
+ "One file of the space’s data, parsed"
249
+ ],
240
250
  [
241
251
  "Style definition",
242
252
  `plitzi://definitions/${env}/{ref}`,
@@ -197,9 +197,9 @@ and \`patchDefinition\` still changes only some CSS of one class.
197
197
 
198
198
  ## Fit the panel — go wide, stay short
199
199
 
200
- The widget renders in a **side panel** (Claude Desktop, ChatGPT, the Plitzi builder), so it gets a usable width but
201
- very little height: everything past the first screenful costs the user a scroll. Height is the scarce resource —
202
- spend width instead.
200
+ The widget renders in a **side panel** (Claude Desktop, ChatGPT), so it gets a usable width but very little
201
+ height: everything past the first screenful costs the user a scroll. Height is the scarce resource — spend width
202
+ instead.
203
203
 
204
204
  Plain containers are blocks, so doing nothing stacks children **vertically** and produces exactly the tall,
205
205
  half-empty widget to avoid. Choose the axis every time:
@@ -228,9 +228,9 @@ it — and reach for \`max-width\` only to stop one lone card from stretching ac
228
228
 
229
229
  ## Match the host theme — never hardcode a light palette
230
230
 
231
- The widget is embedded in the host's own UI (Claude Desktop, ChatGPT, the builder), and that UI **may be in dark
232
- mode**. A widget painted with fixed light colours is the most common way to ship something unusable: a white card
233
- in a dark chat glares, and — worse — text left at a dark default disappears against the host's dark background.
231
+ The widget is embedded in the host's own UI (Claude Desktop, ChatGPT), and that UI **may be in dark mode**. A
232
+ widget painted with fixed light colours is the most common way to ship something unusable: a white card in a dark
233
+ chat glares, and — worse — text left at a dark default disappears against the host's dark background.
234
234
 
235
235
  The host publishes its palette as CSS variables on the page, so use them for every colour, with a
236
236
  \`light-dark(<light>, <dark>)\` fallback for hosts that send none:
@@ -4,6 +4,7 @@ import { readActionResource } from "./actions.js";
4
4
  import { canonicalUri } from "./canonical.js";
5
5
  import { readConnectorResource } from "./connectors.js";
6
6
  import { readCoreResource } from "./core.js";
7
+ import { readDataResource } from "./data.js";
7
8
  import { readFunctionsResource } from "./functions.js";
8
9
  import { readPrimerResource } from "./primer.js";
9
10
  import { readRenderResource } from "./renderGuide.js";
@@ -18,7 +19,8 @@ var resolvers = [
18
19
  readStyleResource,
19
20
  readConnectorResource,
20
21
  readActionResource,
21
- readFunctionsResource
22
+ readFunctionsResource,
23
+ readDataResource
22
24
  ];
23
25
  /** Resolve a resource URI to its versioned envelope, or null if unknown / not found. */
24
26
  var readResource = (space, env, rawUri) => {
@@ -1,7 +1,7 @@
1
- import { buildDataSourceCatalog, buildInteractionCatalog } from "../catalogs/observed.js";
2
1
  import { componentSummariesToAI, componentView, findComponentByRef } from "../helpers/components.js";
3
2
  import { findElementByRef, findRootByRef } from "../helpers/space.js";
4
3
  import { afterPrefix, componentsUri, dataSourcesUri, elementUri, flagsUri, folderUri, foldersUri, interactionsUri, layoutsUri, pageUri, pagesUri, schemaVarsUri, settingsUri } from "../helpers/uris.js";
4
+ import { buildDataSourceCatalog, buildInteractionCatalog } from "../catalogs/observed.js";
5
5
  import { envelope } from "./envelope.js";
6
6
  import { elementView, folderRefToAI, foldersToAI, layoutSummariesToAI, pageSkeletonToAI, pageStylesToAI, pageSummariesToAI, schemaVariablesToAI, settingsToAI } from "../tools/operations/schema/translator.js";
7
7
  import { treeOf } from "@plitzi/sdk-schema/helpers/components";
@@ -20,10 +20,10 @@ export interface McpServerContext {
20
20
  /** Structured request-log sink. When set, every tool call and resource read emits an McpLogEvent to it (the
21
21
  * consumer renders them); otherwise logging falls back to the console when MCP_DEBUG=1. */
22
22
  logger?: ServerLogger;
23
- /** May the plitzi_render view paint from tool arguments the host is still streaming (see `mcpAi.renderStreaming`)?
24
- * Defaults to true. */
23
+ /** May the plitzi_render view paint from tool arguments the host is still streaming (see
24
+ * `McpOptions.renderStreaming`)? Defaults to true. */
25
25
  renderStreaming?: boolean;
26
- /** Where a rendered widget loads everything external from (see `mcpAi.proxy`). It reaches two places: the render
26
+ /** Where a rendered widget loads everything external from (see `McpOptions.proxy`). It reaches two places: the render
27
27
  * tool, which rewrites the URLs the agent authored, and the App's CSP, which declares the origin those URLs
28
28
  * point at. Absent → neither happens, and a widget's resources load only where the host allows their origin. */
29
29
  proxy?: ResourceProxy;
@@ -1,11 +1,11 @@
1
1
  import { registerApps } from "./apps/index.js";
2
+ import { isCallToolResult } from "./helpers/callToolResult.js";
2
3
  import { NoSpaceError, ReadOnlyGrantError, emptySpace, emptySpaceMessage, noSpaceErrorCode, readOnlyGrantErrorCode } from "./helpers/space.js";
3
4
  import { serverInstructions, widgetsOnlyInstructions } from "./helpers/guide.js";
4
5
  import { createMcpLog } from "./helpers/log.js";
5
6
  import { proxyForTool } from "./proxy/config.js";
6
7
  import { registerResources } from "./resources/register.js";
7
8
  import { tools } from "./tools/index.js";
8
- import { isCallToolResult } from "../ai/toolkit.js";
9
9
  import { randomUUID } from "node:crypto";
10
10
  import { registerAppTool } from "@modelcontextprotocol/ext-apps/server";
11
11
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
@@ -31,14 +31,15 @@ var createMcpServer = async ({ adapters, getGrant, preview, screenshot, logger,
31
31
  };
32
32
  const loadSpace = async () => {
33
33
  const id = requireSpaceId();
34
- const [schema, style, catalog, connectors, actions, actionTasks, functions] = await Promise.all([
34
+ const [schema, style, catalog, connectors, actions, actionTasks, functions, data] = await Promise.all([
35
35
  adapters.getSchema?.(id, MCP_ENV),
36
36
  adapters.getStyle?.(id, MCP_ENV),
37
37
  adapters.getComponentCatalog?.(id, MCP_ENV).catch(() => void 0),
38
38
  adapters.getConnectors?.(id).catch(() => void 0),
39
39
  adapters.getActions?.(id).catch(() => void 0),
40
40
  adapters.getActionTasks?.(id).catch(() => void 0),
41
- adapters.getFunctions?.(id).catch(() => void 0)
41
+ adapters.getFunctions?.(id).catch(() => void 0),
42
+ adapters.getData?.(id).catch(() => void 0)
42
43
  ]);
43
44
  if (!schema || !style) throw new Error(emptySpaceMessage);
44
45
  return {
@@ -48,10 +49,11 @@ var createMcpServer = async ({ adapters, getGrant, preview, screenshot, logger,
48
49
  connectors: connectors ?? [],
49
50
  actions: actions ?? [],
50
51
  actionTasks,
51
- ...functions ? { functions } : {}
52
+ ...functions ? { functions } : {},
53
+ ...data ? { data } : {}
52
54
  };
53
55
  };
54
- const { saveSchema, saveStyle, saveConnector, deleteConnector, saveAction, deleteAction, saveFunctions, tryFunction } = adapters;
56
+ const { saveSchema, saveStyle, saveConnector, deleteConnector, saveAction, deleteAction, saveFunctions, tryFunction, saveData } = adapters;
55
57
  const write = {
56
58
  userId: grant?.userId,
57
59
  batch: randomUUID()
@@ -63,13 +65,14 @@ var createMcpServer = async ({ adapters, getGrant, preview, screenshot, logger,
63
65
  deleteConnector: deleteConnector ? (id) => deleteConnector(requireWritableSpaceId(), id) : void 0,
64
66
  saveAction: saveAction ? (entry) => saveAction(requireWritableSpaceId(), entry) : void 0,
65
67
  deleteAction: deleteAction ? (id) => deleteAction(requireWritableSpaceId(), id) : void 0,
66
- saveFunctions: saveFunctions ? (files, base) => saveFunctions(requireWritableSpaceId(), files, base, write) : void 0
68
+ saveFunctions: saveFunctions ? (files, base) => saveFunctions(requireWritableSpaceId(), files, base, write) : void 0,
69
+ saveData: saveData ? (files, base) => saveData(requireWritableSpaceId(), files, base, write) : void 0
67
70
  };
68
71
  let spacePromise;
69
72
  const getSpace = () => spacePromise ??= loadSpace();
70
73
  const server = new McpServer({
71
74
  name: "plitzi-mcp",
72
- version: "0.38.3"
75
+ version: "0.38.5"
73
76
  }, { instructions: hasSpace ? serverInstructions : widgetsOnlyInstructions });
74
77
  const { getChanges } = adapters;
75
78
  registerResources(server, getSpace, MCP_ENV, log, hasSpace, getChanges ? (query) => getChanges(requireSpaceId(), MCP_ENV, query) : void 0);
@@ -126,7 +129,8 @@ var createMcpServer = async ({ adapters, getGrant, preview, screenshot, logger,
126
129
  const config = {
127
130
  title: tool.title,
128
131
  description: tool.description,
129
- inputSchema: tool.inputShape
132
+ inputSchema: tool.inputShape,
133
+ annotations: { readOnlyHint: tool.access === "read" }
130
134
  };
131
135
  if (tool.ui) {
132
136
  registerAppTool(server, tool.name, {
@@ -7,6 +7,7 @@ import { upsertAction } from "../operations/actions/upsertAction.js";
7
7
  import { deleteConnector } from "../operations/connectors/deleteConnector.js";
8
8
  import { patchConnector } from "../operations/connectors/patchConnector.js";
9
9
  import { upsertConnector } from "../operations/connectors/upsertConnector.js";
10
+ import { deleteDataFile, upsertDataFile } from "../operations/data/index.js";
10
11
  import { deleteFunctionFile, upsertFunctionFile } from "../operations/functions/index.js";
11
12
  import { deleteBinding } from "../operations/schema/bindings/deleteBinding.js";
12
13
  import { patchBinding } from "../operations/schema/bindings/patchBinding.js";
@@ -113,6 +114,8 @@ var executeOp = (space, env, op) => {
113
114
  case "deleteAction": return deleteAction(space, env, op);
114
115
  case "upsertFunctionFile": return upsertFunctionFile(space, env, op);
115
116
  case "deleteFunctionFile": return deleteFunctionFile(space, env, op);
117
+ case "upsertDataFile": return upsertDataFile(space, env, op);
118
+ case "deleteDataFile": return deleteDataFile(space, env, op);
116
119
  default: return fail("type", `Unknown operation "${op.type}"`, "See the Operation union");
117
120
  }
118
121
  };
@@ -132,7 +135,8 @@ var applyOperations = (space, env, ops) => {
132
135
  deletedConnectors: [],
133
136
  changedActions: [],
134
137
  deletedActions: [],
135
- changedFunctions: false
138
+ changedFunctions: false,
139
+ changedData: false
136
140
  };
137
141
  const stale = /* @__PURE__ */ new Set();
138
142
  const elements = /* @__PURE__ */ new Set();
@@ -173,6 +177,10 @@ var applyOperations = (space, env, ops) => {
173
177
  case "deleteFunctionFile":
174
178
  outcome.changedFunctions = true;
175
179
  break;
180
+ case "upsertDataFile":
181
+ case "deleteDataFile":
182
+ outcome.changedData = true;
183
+ break;
176
184
  default: if (isStyleOp(op.type)) outcome.changedStyle = true;
177
185
  else outcome.changedSchema = true;
178
186
  }
@@ -57,6 +57,7 @@ export declare const applyShape: {
57
57
  flag: z.ZodOptional<z.ZodNullable<z.ZodString>>;
58
58
  anchor: z.ZodOptional<z.ZodNullable<z.ZodString>>;
59
59
  motion: z.ZodOptional<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
60
+ quiet: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString>>>;
60
61
  }, z.core.$strip>, z.ZodObject<{
61
62
  type: z.ZodLiteral<"deleteElement">;
62
63
  pageRef: z.ZodString;
@@ -211,6 +212,7 @@ export declare const applyShape: {
211
212
  skip: "skip";
212
213
  parallel: "parallel";
213
214
  queue: "queue";
215
+ latest: "latest";
214
216
  }>>;
215
217
  elementId: z.ZodOptional<z.ZodString>;
216
218
  preview: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
@@ -229,6 +231,7 @@ export declare const applyShape: {
229
231
  skip: "skip";
230
232
  parallel: "parallel";
231
233
  queue: "queue";
234
+ latest: "latest";
232
235
  }>>;
233
236
  elementId: z.ZodOptional<z.ZodString>;
234
237
  preview: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
@@ -817,11 +820,11 @@ export declare const applyShape: {
817
820
  file: "file";
818
821
  text: "text";
819
822
  color: "color";
823
+ image: "image";
820
824
  switch: "switch";
821
825
  email: "email";
822
826
  date: "date";
823
827
  richText: "richText";
824
- image: "image";
825
828
  multiImage: "multiImage";
826
829
  video: "video";
827
830
  link: "link";
@@ -905,11 +908,11 @@ export declare const applyShape: {
905
908
  file: "file";
906
909
  text: "text";
907
910
  color: "color";
911
+ image: "image";
908
912
  switch: "switch";
909
913
  email: "email";
910
914
  date: "date";
911
915
  richText: "richText";
912
- image: "image";
913
916
  multiImage: "multiImage";
914
917
  video: "video";
915
918
  link: "link";
@@ -1056,6 +1059,13 @@ export declare const applyShape: {
1056
1059
  }, z.core.$strip>, z.ZodObject<{
1057
1060
  type: z.ZodLiteral<"deleteFunctionFile">;
1058
1061
  path: z.ZodString;
1062
+ }, z.core.$strip>, z.ZodObject<{
1063
+ type: z.ZodLiteral<"upsertDataFile">;
1064
+ path: z.ZodString;
1065
+ content: z.ZodString;
1066
+ }, z.core.$strip>, z.ZodObject<{
1067
+ type: z.ZodLiteral<"deleteDataFile">;
1068
+ path: z.ZodString;
1059
1069
  }, z.core.$strip>], "type">>;
1060
1070
  };
1061
1071
  export declare const apply: (input: ApplyInput, space: Space, persisters?: Persisters) => Promise<WriteResponse>;
@@ -1,4 +1,4 @@
1
- import { functionFileUri, functionsUri } from "../../helpers/uris.js";
1
+ import { dataFileUri, dataUri, functionFileUri, functionsUri } from "../../helpers/uris.js";
2
2
  import { changedResources, conflictMessage, detectConflicts, resolvedElements } from "./writeResult.js";
3
3
  import { environment, operations } from "../operations/index.js";
4
4
  import { draftBatch } from "../shared/draftBatch.js";
@@ -23,6 +23,15 @@ var functionsErrors = (saved, env) => "problems" in saved ? saved.problems.map((
23
23
  message: saved.refusal.error,
24
24
  hint: `Read ${functionsUri(env)} again and redo the change on the current files`
25
25
  }];
26
+ var dataErrors = (saved, env) => "problems" in saved ? saved.problems.map((problem) => ({
27
+ path: `data/${problem.file}`,
28
+ message: problem.message,
29
+ hint: `Fix it with upsertDataFile, or deleteDataFile; read ${dataFileUri(env, problem.file)} for the file`
30
+ })) : [{
31
+ path: "data",
32
+ message: saved.refusal.error,
33
+ hint: `Read ${dataUri(env)} again and redo the change on the current files`
34
+ }];
26
35
  var apply = async (input, space, persisters) => {
27
36
  const env = input.environment ?? "main";
28
37
  const conflicts = detectConflicts(space, env, input.expectedResourceVersions);
@@ -85,6 +94,23 @@ var apply = async (input, space, persisters) => {
85
94
  };
86
95
  } else persisted = false;
87
96
  }
97
+ if (outcome.changedData && draft.data) {
98
+ if (persisters?.saveData) {
99
+ const saved = await persisters.saveData(draft.data.files, space.data?.version ?? "");
100
+ if (!saved.ok) return {
101
+ applied: false,
102
+ persisted: false,
103
+ summary: {
104
+ created: 0,
105
+ updated: 0,
106
+ deleted: 0
107
+ },
108
+ changed: [],
109
+ errors: dataErrors(saved, env),
110
+ warnings: noWarnings([...outcome.changedFunctions && persisters.saveFunctions ? ["The functions of this batch were saved; the data was not — apply the data again once fixed"] : [], ...warnings])
111
+ };
112
+ } else persisted = false;
113
+ }
88
114
  if (outcome.changedSchema) {
89
115
  if (persisters?.schema) await persisters.schema(draft.schema);
90
116
  else persisted = false;
@@ -9,8 +9,8 @@ export { screenshotShape } from './screenshot';
9
9
  export { applyOperations } from './apply/dispatch';
10
10
  export { validateOperations } from './shared/validator';
11
11
  export { operation } from './operations';
12
- /** The MCP tool registry — the single source both hosts (the standalone server and the in-process AI bridge)
13
- * register from. Adding a tool is: create its file with a ToolDef descriptor and append it here. */
12
+ /** The MCP tool registry — the single source the server registers from. Adding a tool is: create its file with a
13
+ * ToolDef descriptor and append it here. */
14
14
  export declare const tools: ToolDef[];
15
15
  export type { ToolContext, ToolDef } from './shared/tool';
16
16
  export type { OpResult } from '../helpers';
@@ -10,8 +10,8 @@ import { search, searchShape, searchTool } from "./search.js";
10
10
  import { tryFunctionTool } from "./tryFunction.js";
11
11
  import { validate, validateShape, validateTool } from "./validate.js";
12
12
  //#region src/modules/mcp/tools/index.ts
13
- /** The MCP tool registry — the single source both hosts (the standalone server and the in-process AI bridge)
14
- * register from. Adding a tool is: create its file with a ToolDef descriptor and append it here. */
13
+ /** The MCP tool registry — the single source the server registers from. Adding a tool is: create its file with a
14
+ * ToolDef descriptor and append it here. */
15
15
  var tools = [
16
16
  applyTool,
17
17
  validateTool,
@@ -31,11 +31,11 @@ export declare const connectorOps: {
31
31
  file: "file";
32
32
  text: "text";
33
33
  color: "color";
34
+ image: "image";
34
35
  switch: "switch";
35
36
  email: "email";
36
37
  date: "date";
37
38
  richText: "richText";
38
- image: "image";
39
39
  multiImage: "multiImage";
40
40
  video: "video";
41
41
  link: "link";
@@ -120,11 +120,11 @@ export declare const connectorOps: {
120
120
  file: "file";
121
121
  text: "text";
122
122
  color: "color";
123
+ image: "image";
123
124
  switch: "switch";
124
125
  email: "email";
125
126
  date: "date";
126
127
  richText: "richText";
127
- image: "image";
128
128
  multiImage: "multiImage";
129
129
  video: "video";
130
130
  link: "link";
@@ -73,11 +73,11 @@ export declare const connectorConnection: z.ZodObject<{
73
73
  file: "file";
74
74
  text: "text";
75
75
  color: "color";
76
+ image: "image";
76
77
  switch: "switch";
77
78
  email: "email";
78
79
  date: "date";
79
80
  richText: "richText";
80
- image: "image";
81
81
  multiImage: "multiImage";
82
82
  video: "video";
83
83
  link: "link";
@@ -29,11 +29,11 @@ export declare const patchConnectorOp: z.ZodObject<{
29
29
  file: "file";
30
30
  text: "text";
31
31
  color: "color";
32
+ image: "image";
32
33
  switch: "switch";
33
34
  email: "email";
34
35
  date: "date";
35
36
  richText: "richText";
36
- image: "image";
37
37
  multiImage: "multiImage";
38
38
  video: "video";
39
39
  link: "link";
@@ -30,11 +30,11 @@ export declare const upsertConnectorOp: z.ZodObject<{
30
30
  file: "file";
31
31
  text: "text";
32
32
  color: "color";
33
+ image: "image";
33
34
  switch: "switch";
34
35
  email: "email";
35
36
  date: "date";
36
37
  richText: "richText";
37
- image: "image";
38
38
  multiImage: "multiImage";
39
39
  video: "video";
40
40
  link: "link";
@@ -0,0 +1,32 @@
1
+ import { z } from 'zod';
2
+ import { OpResult, Space } from '../../../helpers';
3
+ import { Env } from '../../../types';
4
+ export declare const upsertDataFileOp: z.ZodObject<{
5
+ type: z.ZodLiteral<"upsertDataFile">;
6
+ path: z.ZodString;
7
+ content: z.ZodString;
8
+ }, z.core.$strip>;
9
+ export declare const deleteDataFileOp: z.ZodObject<{
10
+ type: z.ZodLiteral<"deleteDataFile">;
11
+ path: z.ZodString;
12
+ }, z.core.$strip>;
13
+ export type UpsertDataFile = z.infer<typeof upsertDataFileOp>;
14
+ export type DeleteDataFile = z.infer<typeof deleteDataFileOp>;
15
+ /**
16
+ * The data is one store of files, saved whole: an op edits the draft's copy, and the batch saves the files it leaves —
17
+ * checked by the platform then (each path, the weight), which answers by file. A file that is not JSON is refused here,
18
+ * where it is written: it is what makes it data.
19
+ */
20
+ export declare const upsertDataFile: (space: Space, env: Env, op: UpsertDataFile) => OpResult;
21
+ export declare const deleteDataFile: (space: Space, env: Env, op: DeleteDataFile) => OpResult;
22
+ export declare const dataOps: {
23
+ upsertDataFile: z.ZodObject<{
24
+ type: z.ZodLiteral<"upsertDataFile">;
25
+ path: z.ZodString;
26
+ content: z.ZodString;
27
+ }, z.core.$strip>;
28
+ deleteDataFile: z.ZodObject<{
29
+ type: z.ZodLiteral<"deleteDataFile">;
30
+ path: z.ZodString;
31
+ }, z.core.$strip>;
32
+ };
@@ -0,0 +1,54 @@
1
+ import { dataFileUri, dataUri } from "../../../helpers/uris.js";
2
+ import { empty, fail } from "../../../helpers/opResult.js";
3
+ import { z } from "zod";
4
+ //#region src/modules/mcp/tools/operations/data/index.ts
5
+ var upsertDataFileOp = z.object({
6
+ type: z.literal("upsertDataFile"),
7
+ path: z.string().describe("e.g. \"products.json\" — read as query \"/data/<path>\""),
8
+ content: z.string().describe("The whole file, as JSON text")
9
+ }).describe("Write one file of the space’s data (JSON its server providers read), whole.");
10
+ var deleteDataFileOp = z.object({
11
+ type: z.literal("deleteDataFile"),
12
+ path: z.string()
13
+ }).describe("Remove one file of the space’s data.");
14
+ var unavailable = () => fail("type", "This deployment keeps no space data", "Read the data through a connector or a server action instead");
15
+ /**
16
+ * The data is one store of files, saved whole: an op edits the draft's copy, and the batch saves the files it leaves —
17
+ * checked by the platform then (each path, the weight), which answers by file. A file that is not JSON is refused here,
18
+ * where it is written: it is what makes it data.
19
+ */
20
+ var upsertDataFile = (space, env, op) => {
21
+ if (!space.data) return unavailable();
22
+ try {
23
+ JSON.parse(op.content);
24
+ } catch (error) {
25
+ return fail("content", `"${op.path}" is not JSON: ${error instanceof Error ? error.message : String(error)}`, "Write the whole file as JSON text — an object or a list");
26
+ }
27
+ const exists = Object.hasOwn(space.data.files, op.path);
28
+ space.data.files = {
29
+ ...space.data.files,
30
+ [op.path]: op.content
31
+ };
32
+ return {
33
+ ...empty(),
34
+ ...exists ? { updated: 1 } : { created: 1 },
35
+ staleResources: [dataUri(env), dataFileUri(env, op.path)]
36
+ };
37
+ };
38
+ var deleteDataFile = (space, env, op) => {
39
+ if (!space.data) return unavailable();
40
+ if (!Object.hasOwn(space.data.files, op.path)) return fail("path", `The data has no file "${op.path}"`, `Read ${dataUri(env)} for the files it has`, Object.keys(space.data.files));
41
+ const { [op.path]: _removed, ...files } = space.data.files;
42
+ space.data.files = files;
43
+ return {
44
+ ...empty(),
45
+ deleted: 1,
46
+ staleResources: [dataUri(env), dataFileUri(env, op.path)]
47
+ };
48
+ };
49
+ var dataOps = {
50
+ upsertDataFile: upsertDataFileOp,
51
+ deleteDataFile: deleteDataFileOp
52
+ };
53
+ //#endregion
54
+ export { dataOps, deleteDataFile, deleteDataFileOp, upsertDataFile, upsertDataFileOp };