@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.
- package/CHANGELOG.md +540 -0
- package/README.md +38 -12
- package/dist/createServer.d.ts +1 -1
- package/dist/createServer.js +1 -1
- package/dist/index.d.ts +3 -4
- package/dist/index.js +1 -4
- package/dist/modules/mcp/apps/render/styles.d.ts +4 -8
- package/dist/modules/mcp/apps/render/styles.js +16 -47
- package/dist/modules/mcp/apps/render/view/index.tsx +1 -1
- package/dist/modules/mcp/catalogs/index.js +2 -2
- package/dist/modules/mcp/catalogs/pluginCatalog.js +2 -2
- package/dist/modules/mcp/e2e/mcpEndpoint.d.ts +2 -1
- package/dist/modules/mcp/handler.d.ts +2 -2
- package/dist/modules/mcp/helpers/callToolResult.d.ts +2 -0
- package/dist/modules/mcp/helpers/callToolResult.js +4 -0
- package/dist/modules/mcp/helpers/guide.js +68 -14
- package/dist/modules/mcp/helpers/index.d.ts +1 -1
- package/dist/modules/mcp/helpers/space.d.ts +4 -1
- package/dist/modules/mcp/helpers/space.js +1 -0
- package/dist/modules/mcp/helpers/uris.d.ts +2 -0
- package/dist/modules/mcp/helpers/uris.js +3 -1
- package/dist/modules/mcp/index.d.ts +1 -1
- package/dist/modules/mcp/localScreenshotClient.d.ts +3 -0
- package/dist/modules/mcp/localScreenshotClient.js +2 -0
- package/dist/modules/mcp/resources/connectors.d.ts +1 -1
- package/dist/modules/mcp/resources/core.js +2 -2
- package/dist/modules/mcp/resources/data.d.ts +8 -0
- package/dist/modules/mcp/resources/data.js +46 -0
- package/dist/modules/mcp/resources/explain.js +1 -1
- package/dist/modules/mcp/resources/primer.js +3 -3
- package/dist/modules/mcp/resources/register.js +12 -2
- package/dist/modules/mcp/resources/renderGuide.js +6 -6
- package/dist/modules/mcp/resources/router.js +3 -1
- package/dist/modules/mcp/resources/schema.js +1 -1
- package/dist/modules/mcp/server.d.ts +3 -3
- package/dist/modules/mcp/server.js +12 -8
- package/dist/modules/mcp/tools/apply/dispatch.js +9 -1
- package/dist/modules/mcp/tools/apply/index.d.ts +12 -2
- package/dist/modules/mcp/tools/apply/index.js +27 -1
- package/dist/modules/mcp/tools/index.d.ts +2 -2
- package/dist/modules/mcp/tools/index.js +2 -2
- package/dist/modules/mcp/tools/operations/connectors/index.d.ts +2 -2
- package/dist/modules/mcp/tools/operations/connectors/manifest.d.ts +1 -1
- package/dist/modules/mcp/tools/operations/connectors/patchConnector.d.ts +1 -1
- package/dist/modules/mcp/tools/operations/connectors/upsertConnector.d.ts +1 -1
- package/dist/modules/mcp/tools/operations/data/data.test.d.ts +1 -0
- package/dist/modules/mcp/tools/operations/data/index.d.ts +32 -0
- package/dist/modules/mcp/tools/operations/data/index.js +54 -0
- package/dist/modules/mcp/tools/operations/index.d.ts +30 -4
- package/dist/modules/mcp/tools/operations/index.js +4 -1
- package/dist/modules/mcp/tools/operations/schema/elements/patchElement.d.ts +1 -0
- package/dist/modules/mcp/tools/operations/schema/elements/patchElement.js +5 -2
- package/dist/modules/mcp/tools/operations/schema/elements/upsertElement.js +1 -0
- package/dist/modules/mcp/tools/operations/schema/interactions/patchInteractionNode.d.ts +1 -0
- package/dist/modules/mcp/tools/operations/schema/interactions/upsertInteractionFlow.d.ts +1 -0
- package/dist/modules/mcp/tools/operations/schema/operations.d.ts +3 -0
- package/dist/modules/mcp/tools/operations/schema/shared.d.ts +5 -0
- package/dist/modules/mcp/tools/operations/schema/shared.js +13 -7
- package/dist/modules/mcp/tools/operations/schema/translator.js +1 -1
- package/dist/modules/mcp/tools/operations/schema/write.js +3 -2
- package/dist/modules/mcp/tools/operations/schemaIds.js +3 -3
- package/dist/modules/mcp/tools/operations/style/write.js +1 -1
- package/dist/modules/mcp/tools/preview.d.ts +3 -0
- package/dist/modules/mcp/tools/render.d.ts +3 -0
- package/dist/modules/mcp/tools/screenshot.d.ts +12 -2
- package/dist/modules/mcp/tools/shared/newSuggestions.d.ts +2 -2
- package/dist/modules/mcp/tools/shared/newSuggestions.js +10 -5
- package/dist/modules/mcp/tools/shared/newSuggestions.test.d.ts +1 -0
- package/dist/modules/mcp/tools/shared/tool.d.ts +7 -6
- package/dist/modules/mcp/tools/shared/validator/index.js +2 -2
- package/dist/modules/mcp/tools/tryFunction.js +1 -1
- package/dist/modules/mcp/tools/validate.d.ts +12 -2
- package/dist/modules/mcp/types/appTypes.d.ts +2 -2
- package/dist/modules/mcp/types/toolTypes.d.ts +5 -1
- package/package.json +7 -9
- package/dist/modules/ai/AIEngine.d.ts +0 -20
- package/dist/modules/ai/AIEngine.js +0 -120
- package/dist/modules/ai/index.d.ts +0 -4
- package/dist/modules/ai/toolkit.d.ts +0 -17
- package/dist/modules/ai/toolkit.js +0 -59
- package/dist/modules/mcp/helpers/agentPrompt.d.ts +0 -4
- package/dist/modules/mcp/helpers/agentPrompt.js +0 -123
- /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" | "
|
|
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
|
|
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
|
|
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
|
|
201
|
-
|
|
202
|
-
|
|
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
|
|
232
|
-
|
|
233
|
-
|
|
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
|
|
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 `
|
|
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.
|
|
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
|
|
13
|
-
*
|
|
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
|
|
14
|
-
*
|
|
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 @@
|
|
|
1
|
+
export {};
|
|
@@ -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 };
|