@drawcall/design 0.5.12 → 0.6.0
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/README.md +2 -6
- package/dist/browser.d.ts +1 -1
- package/dist/browser.js +1 -1
- package/dist/mcp/file.d.ts +3 -2
- package/dist/mcp/file.js +9 -6
- package/dist/mcp/frame.d.ts +3 -2
- package/dist/mcp/frame.js +24 -11
- package/dist/mcp/index.d.ts +1 -2
- package/dist/mcp/index.js +0 -1
- package/dist/mcp/project.d.ts +3 -2
- package/dist/mcp/project.js +4 -8
- package/dist/mcp/register.d.ts +3 -2
- package/dist/mcp/register.js +4 -7
- package/dist/mcp/types.d.ts +2 -24
- package/package.json +1 -1
- package/dist/mcp/client.d.ts +0 -3
- package/dist/mcp/client.js +0 -38
package/README.md
CHANGED
|
@@ -46,17 +46,13 @@ program.addCommand(createDesignCommand());
|
|
|
46
46
|
The MCP tools can be mounted into a server owned by another package:
|
|
47
47
|
|
|
48
48
|
```ts
|
|
49
|
-
import {
|
|
50
|
-
createDesignMcpOperations,
|
|
51
|
-
registerDesignTools,
|
|
52
|
-
v1,
|
|
53
|
-
} from "@drawcall/design";
|
|
49
|
+
import { registerDesignTools, v1 } from "@drawcall/design";
|
|
54
50
|
import { McpServer } from "@modelcontextprotocol/server";
|
|
55
51
|
|
|
56
52
|
const client = v1.createClient({ authToken: process.env.DRAWCALL_AUTH_TOKEN });
|
|
57
53
|
const server = new McpServer({ name: "mcp.drawcall.ai", version: "1.0.0" });
|
|
58
54
|
|
|
59
|
-
registerDesignTools(server,
|
|
55
|
+
registerDesignTools(server, client);
|
|
60
56
|
```
|
|
61
57
|
|
|
62
58
|
The host owns the server identity, authentication, and transport. The MCP SDK
|
package/dist/browser.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export * as v1 from "./v1/index.js";
|
|
2
|
-
export {
|
|
2
|
+
export { registerDesignTools, type DesignMcpOptions, type DesignMcpServer, type DesignMcpToolResult, } from "./mcp/index.js";
|
|
3
3
|
export { cliDesignSkill, mcpDesignSkill } from "./skill.generated.js";
|
|
4
4
|
export { frameCreationCapabilities, type FrameCreationCapability, type FrameCreationCapabilityId, type FrameCreationInput, } from "./v1/capabilities.js";
|
|
5
5
|
export { cameraPoseSchema, IMAGE_GENERATION_MODEL, IMAGE_GENERATION_PROVIDER, } from "./v1/schemas.js";
|
package/dist/browser.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export * as v1 from "./v1/index.js";
|
|
2
|
-
export {
|
|
2
|
+
export { registerDesignTools, } from "./mcp/index.js";
|
|
3
3
|
export { cliDesignSkill, mcpDesignSkill } from "./skill.generated.js";
|
|
4
4
|
export { frameCreationCapabilities, } from "./v1/capabilities.js";
|
|
5
5
|
export { cameraPoseSchema, IMAGE_GENERATION_MODEL, IMAGE_GENERATION_PROVIDER, } from "./v1/schemas.js";
|
package/dist/mcp/file.d.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
1
|
+
import type { DesignV1Client } from "../v1/client.js";
|
|
2
|
+
import type { DesignMcpServer } from "./types.js";
|
|
3
|
+
export declare function registerFileTools(server: DesignMcpServer, client: DesignV1Client): void;
|
package/dist/mcp/file.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { fileTextSchema } from "../v1/schemas.js";
|
|
2
2
|
import { fileResult, result } from "./result.js";
|
|
3
3
|
import { directoryPathSchema, fileInput, projectInput } from "./schema.js";
|
|
4
|
-
export function registerFileTools(server,
|
|
4
|
+
export function registerFileTools(server, client) {
|
|
5
5
|
server.registerTool("list_files", {
|
|
6
6
|
description: "Return canonical project-absolute paths. Omit path to list the entire project; otherwise use /<frame-id> without a trailing slash. Pass returned file paths unchanged to file tools.",
|
|
7
7
|
inputSchema: projectInput.extend({
|
|
@@ -13,7 +13,10 @@ export function registerFileTools(server, design, run) {
|
|
|
13
13
|
openWorldHint: false,
|
|
14
14
|
idempotentHint: true,
|
|
15
15
|
},
|
|
16
|
-
}, async ({ project, path }) => result(await
|
|
16
|
+
}, async ({ project, path }) => result(await client.filesystem.list({
|
|
17
|
+
project,
|
|
18
|
+
...(path === undefined ? {} : { path }),
|
|
19
|
+
})));
|
|
17
20
|
server.registerTool("read_file", {
|
|
18
21
|
description: "Read one canonical project-absolute path returned by list_files. The path includes the frame ID; this tool does not accept a frame argument. Binary files return their hosted URL and media type.",
|
|
19
22
|
inputSchema: fileInput,
|
|
@@ -24,7 +27,7 @@ export function registerFileTools(server, design, run) {
|
|
|
24
27
|
idempotentHint: true,
|
|
25
28
|
},
|
|
26
29
|
}, async ({ project, path }) => {
|
|
27
|
-
const file = await
|
|
30
|
+
const file = await client.filesystem.read({ project, path });
|
|
28
31
|
return file.type === "text" ? fileResult(file) : result(file);
|
|
29
32
|
});
|
|
30
33
|
server.registerTool("write_file", {
|
|
@@ -35,7 +38,7 @@ export function registerFileTools(server, design, run) {
|
|
|
35
38
|
destructiveHint: true,
|
|
36
39
|
openWorldHint: true,
|
|
37
40
|
},
|
|
38
|
-
}, async ({ project, path, text }) => result(await
|
|
41
|
+
}, async ({ project, path, text }) => result(await client.filesystem.write({ project, path, text })));
|
|
39
42
|
server.registerTool("edit_file", {
|
|
40
43
|
description: "Replace oldText when it occurs exactly once at a canonical project-absolute .glts path. The path includes the frame ID; this tool does not accept a frame argument.",
|
|
41
44
|
inputSchema: fileInput.extend({
|
|
@@ -47,7 +50,7 @@ export function registerFileTools(server, design, run) {
|
|
|
47
50
|
destructiveHint: true,
|
|
48
51
|
openWorldHint: true,
|
|
49
52
|
},
|
|
50
|
-
}, async ({ project, path, oldText, newText }) => result(await
|
|
53
|
+
}, async ({ project, path, oldText, newText }) => result(await client.filesystem.edit({ project, path, oldText, newText })));
|
|
51
54
|
server.registerTool("delete_file", {
|
|
52
55
|
description: "Permanently delete one .glts file at a canonical project-absolute path. The path includes the frame ID; this tool does not accept a frame argument.",
|
|
53
56
|
inputSchema: fileInput,
|
|
@@ -56,5 +59,5 @@ export function registerFileTools(server, design, run) {
|
|
|
56
59
|
destructiveHint: true,
|
|
57
60
|
openWorldHint: true,
|
|
58
61
|
},
|
|
59
|
-
}, async ({ project, path }) => result(await
|
|
62
|
+
}, async ({ project, path }) => result(await client.filesystem.delete({ project, path })));
|
|
60
63
|
}
|
package/dist/mcp/frame.d.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
1
|
+
import type { DesignV1Client } from "../v1/client.js";
|
|
2
|
+
import type { DesignMcpServer } from "./types.js";
|
|
3
|
+
export declare function registerFrameTools(server: DesignMcpServer, client: DesignV1Client, fetcher: typeof globalThis.fetch): void;
|
package/dist/mcp/frame.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { frameNameSchema, generateImageFrameSchema } from "../v1/schemas.js";
|
|
1
|
+
import { frameNameSchema, generateImageFrameSchema, } from "../v1/schemas.js";
|
|
2
2
|
import { base64, result } from "./result.js";
|
|
3
3
|
import { createFrameSchema, frameCreationInput, frameInput, projectInput, } from "./schema.js";
|
|
4
|
-
export function registerFrameTools(server,
|
|
4
|
+
export function registerFrameTools(server, client, fetcher) {
|
|
5
5
|
server.registerTool("list_frames", {
|
|
6
6
|
description: "List frames. Use their immutable ids for frame commands and filesystem paths.",
|
|
7
7
|
inputSchema: projectInput,
|
|
@@ -11,9 +11,7 @@ export function registerFrameTools(server, design, run) {
|
|
|
11
11
|
openWorldHint: false,
|
|
12
12
|
idempotentHint: true,
|
|
13
13
|
},
|
|
14
|
-
}, async ({ project }) => result({
|
|
15
|
-
frames: await run("list_frames", () => design.listFrames(project)),
|
|
16
|
-
}));
|
|
14
|
+
}, async ({ project }) => result({ frames: await client.frame.list({ project }) }));
|
|
17
15
|
server.registerTool("create_frame", {
|
|
18
16
|
description: "Create a frame in a Drawcall Design project. Use type=glts for reusable 3D objects and scenes, then write its source with write_file. Use type=image only for an existing public image URL and type=market only for an exact public Market asset.",
|
|
19
17
|
inputSchema: createFrameSchema,
|
|
@@ -24,7 +22,7 @@ export function registerFrameTools(server, design, run) {
|
|
|
24
22
|
idempotentHint: false,
|
|
25
23
|
},
|
|
26
24
|
}, async (input) => result({
|
|
27
|
-
frame: await
|
|
25
|
+
frame: await client.frame.create(frameCreationInput(input)),
|
|
28
26
|
}));
|
|
29
27
|
server.registerTool("generate_image", {
|
|
30
28
|
description: "Generate a 2D image or reference frame from text and up to four same-project image frame references. Use only when the user asks for a 2D image, picture, concept, or reference; do not use for 3D objects, scenes, or reusable GLTS assets. For edit, target is reference 0. New frames are the default; result=replace explicitly replaces the target image while preserving its frame ID, name, and layout.",
|
|
@@ -36,7 +34,7 @@ export function registerFrameTools(server, design, run) {
|
|
|
36
34
|
idempotentHint: false,
|
|
37
35
|
},
|
|
38
36
|
}, async (input) => result({
|
|
39
|
-
frame: await
|
|
37
|
+
frame: await client.frame.generateImage(input),
|
|
40
38
|
}));
|
|
41
39
|
server.registerTool("rename_frame", {
|
|
42
40
|
description: "Rename a frame. Its immutable frame id does not change.",
|
|
@@ -47,7 +45,7 @@ export function registerFrameTools(server, design, run) {
|
|
|
47
45
|
openWorldHint: false,
|
|
48
46
|
},
|
|
49
47
|
}, async ({ project, frame, name }) => result({
|
|
50
|
-
frame: await
|
|
48
|
+
frame: await client.frame.rename({ project, frame, name }),
|
|
51
49
|
}));
|
|
52
50
|
server.registerTool("delete_frame", {
|
|
53
51
|
description: "Permanently delete a frame.",
|
|
@@ -58,7 +56,7 @@ export function registerFrameTools(server, design, run) {
|
|
|
58
56
|
openWorldHint: true,
|
|
59
57
|
idempotentHint: false,
|
|
60
58
|
},
|
|
61
|
-
}, async ({ project, frame }) => result(await
|
|
59
|
+
}, async ({ project, frame }) => result(await client.frame.delete({ project, frame })));
|
|
62
60
|
server.registerTool("get_frame_screenshot", {
|
|
63
61
|
description: "Render a DPR-1 PNG screenshot of a frame.",
|
|
64
62
|
inputSchema: frameInput,
|
|
@@ -69,7 +67,8 @@ export function registerFrameTools(server, design, run) {
|
|
|
69
67
|
idempotentHint: true,
|
|
70
68
|
},
|
|
71
69
|
}, async ({ project, frame }) => {
|
|
72
|
-
const screenshot = await
|
|
70
|
+
const screenshot = await client.frame.screenshot({ project, frame });
|
|
71
|
+
const png = await screenshotBytes(screenshot, fetcher);
|
|
73
72
|
const structuredContent = {
|
|
74
73
|
url: screenshot.url,
|
|
75
74
|
width: screenshot.width,
|
|
@@ -80,7 +79,7 @@ export function registerFrameTools(server, design, run) {
|
|
|
80
79
|
content: [
|
|
81
80
|
{
|
|
82
81
|
type: "image",
|
|
83
|
-
data: base64(
|
|
82
|
+
data: base64(png),
|
|
84
83
|
mimeType: screenshot.mediaType,
|
|
85
84
|
},
|
|
86
85
|
],
|
|
@@ -88,3 +87,17 @@ export function registerFrameTools(server, design, run) {
|
|
|
88
87
|
};
|
|
89
88
|
});
|
|
90
89
|
}
|
|
90
|
+
async function screenshotBytes(screenshot, fetcher) {
|
|
91
|
+
const response = await fetcher(screenshot.url);
|
|
92
|
+
if (!response.ok) {
|
|
93
|
+
throw new Error(`Could not read screenshot ${screenshot.url}: ${response.status} ${response.statusText}`);
|
|
94
|
+
}
|
|
95
|
+
const mediaType = response.headers
|
|
96
|
+
.get("content-type")
|
|
97
|
+
?.split(";", 1)[0]
|
|
98
|
+
?.trim();
|
|
99
|
+
if (mediaType !== screenshot.mediaType) {
|
|
100
|
+
throw new Error(`Screenshot ${screenshot.url} returned ${mediaType ?? "no media type"}; expected ${screenshot.mediaType}`);
|
|
101
|
+
}
|
|
102
|
+
return new Uint8Array(await response.arrayBuffer());
|
|
103
|
+
}
|
package/dist/mcp/index.d.ts
CHANGED
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
export { createDesignMcpOperations } from "./client.js";
|
|
2
1
|
export { registerDesignTools } from "./register.js";
|
|
3
|
-
export type {
|
|
2
|
+
export type { DesignMcpOptions, DesignMcpServer, DesignMcpToolResult, } from "./types.js";
|
package/dist/mcp/index.js
CHANGED
package/dist/mcp/project.d.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
1
|
+
import type { DesignV1Client } from "../v1/client.js";
|
|
2
|
+
import type { DesignMcpServer } from "./types.js";
|
|
3
|
+
export declare function registerProjectTools(server: DesignMcpServer, client: DesignV1Client): void;
|
package/dist/mcp/project.js
CHANGED
|
@@ -2,7 +2,7 @@ import { z } from "zod";
|
|
|
2
2
|
import { projectNameSchema } from "../v1/schemas.js";
|
|
3
3
|
import { result } from "./result.js";
|
|
4
4
|
import { projectInput } from "./schema.js";
|
|
5
|
-
export function registerProjectTools(server,
|
|
5
|
+
export function registerProjectTools(server, client) {
|
|
6
6
|
server.registerTool("list_projects", {
|
|
7
7
|
description: "List projects available to the current Drawcall account.",
|
|
8
8
|
annotations: {
|
|
@@ -11,9 +11,7 @@ export function registerProjectTools(server, design, run) {
|
|
|
11
11
|
openWorldHint: false,
|
|
12
12
|
idempotentHint: true,
|
|
13
13
|
},
|
|
14
|
-
}, async () => result({
|
|
15
|
-
projects: await run("list_projects", () => design.listProjects()),
|
|
16
|
-
}));
|
|
14
|
+
}, async () => result({ projects: await client.project.list() }));
|
|
17
15
|
server.registerTool("create_project", {
|
|
18
16
|
description: "Create a project. Use its returned immutable id in every later call.",
|
|
19
17
|
inputSchema: z.object({ name: projectNameSchema }).strict(),
|
|
@@ -23,9 +21,7 @@ export function registerProjectTools(server, design, run) {
|
|
|
23
21
|
openWorldHint: false,
|
|
24
22
|
idempotentHint: false,
|
|
25
23
|
},
|
|
26
|
-
}, async ({ name }) => result({
|
|
27
|
-
project: await run("create_project", () => design.createProject(name)),
|
|
28
|
-
}));
|
|
24
|
+
}, async ({ name }) => result({ project: await client.project.create({ name }) }));
|
|
29
25
|
server.registerTool("delete_project", {
|
|
30
26
|
description: "Permanently delete a project and its frames.",
|
|
31
27
|
inputSchema: projectInput,
|
|
@@ -35,5 +31,5 @@ export function registerProjectTools(server, design, run) {
|
|
|
35
31
|
openWorldHint: true,
|
|
36
32
|
idempotentHint: false,
|
|
37
33
|
},
|
|
38
|
-
}, async ({ project }) => result(await
|
|
34
|
+
}, async ({ project }) => result(await client.project.delete({ project })));
|
|
39
35
|
}
|
package/dist/mcp/register.d.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
1
|
+
import type { DesignV1Client } from "../v1/client.js";
|
|
2
|
+
import type { DesignMcpOptions, DesignMcpServer } from "./types.js";
|
|
3
|
+
export declare function registerDesignTools(server: DesignMcpServer, client: DesignV1Client, options?: DesignMcpOptions): void;
|
package/dist/mcp/register.js
CHANGED
|
@@ -2,12 +2,9 @@ import { registerFileTools } from "./file.js";
|
|
|
2
2
|
import { registerFrameTools } from "./frame.js";
|
|
3
3
|
import { registerProjectTools } from "./project.js";
|
|
4
4
|
import { registerSkillTool } from "./skill.js";
|
|
5
|
-
export function registerDesignTools(server,
|
|
5
|
+
export function registerDesignTools(server, client, options = {}) {
|
|
6
6
|
registerSkillTool(server);
|
|
7
|
-
registerProjectTools(server,
|
|
8
|
-
registerFrameTools(server,
|
|
9
|
-
registerFileTools(server,
|
|
10
|
-
}
|
|
11
|
-
function runOperation(_name, operation) {
|
|
12
|
-
return operation();
|
|
7
|
+
registerProjectTools(server, client);
|
|
8
|
+
registerFrameTools(server, client, options.fetch ?? globalThis.fetch);
|
|
9
|
+
registerFileTools(server, client);
|
|
13
10
|
}
|
package/dist/mcp/types.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { CreateFrame, DesignFile, FileList, FileMutation, Frame, GenerateImageFrame, Project, Screenshot } from "../v1/schemas.js";
|
|
2
1
|
import type { z } from "zod";
|
|
3
2
|
export interface DesignMcpToolResult {
|
|
4
3
|
[key: string]: unknown;
|
|
@@ -27,28 +26,7 @@ type DesignMcpToolHandler<Input extends z.ZodType | undefined> = Input extends z
|
|
|
27
26
|
export interface DesignMcpServer {
|
|
28
27
|
registerTool<Input extends z.ZodType | undefined = undefined>(name: string, config: DesignMcpToolConfig<Input>, handler: DesignMcpToolHandler<Input>): unknown;
|
|
29
28
|
}
|
|
30
|
-
export interface
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
export type DesignMcpOperationRunner = <Result>(name: string, operation: () => Promise<Result>) => Promise<Result>;
|
|
34
|
-
export interface DesignMcpOperations {
|
|
35
|
-
listProjects(): Promise<Project[]>;
|
|
36
|
-
createProject(name: string): Promise<Project>;
|
|
37
|
-
deleteProject(project: string): Promise<{
|
|
38
|
-
id: string;
|
|
39
|
-
}>;
|
|
40
|
-
listFrames(project: string): Promise<Frame[]>;
|
|
41
|
-
createFrame(input: CreateFrame): Promise<Frame>;
|
|
42
|
-
generateImage(input: GenerateImageFrame): Promise<Frame>;
|
|
43
|
-
renameFrame(project: string, frame: string, name: string): Promise<Frame>;
|
|
44
|
-
deleteFrame(project: string, frame: string): Promise<{
|
|
45
|
-
id: string;
|
|
46
|
-
}>;
|
|
47
|
-
listFiles(project: string, path?: string): Promise<FileList>;
|
|
48
|
-
readFile(project: string, path: string): Promise<DesignFile>;
|
|
49
|
-
writeFile(project: string, path: string, text: string): Promise<FileMutation>;
|
|
50
|
-
editFile(project: string, path: string, oldText: string, newText: string): Promise<FileMutation>;
|
|
51
|
-
deleteFile(project: string, path: string): Promise<FileMutation>;
|
|
52
|
-
screenshot(project: string, frame: string): Promise<DesignMcpScreenshot>;
|
|
29
|
+
export interface DesignMcpOptions {
|
|
30
|
+
fetch?: typeof globalThis.fetch;
|
|
53
31
|
}
|
|
54
32
|
export {};
|
package/package.json
CHANGED
package/dist/mcp/client.d.ts
DELETED
package/dist/mcp/client.js
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
export function createDesignMcpOperations(client, fetcher = globalThis.fetch) {
|
|
2
|
-
return {
|
|
3
|
-
listProjects: () => client.project.list(),
|
|
4
|
-
createProject: (name) => client.project.create({ name }),
|
|
5
|
-
deleteProject: (project) => client.project.delete({ project }),
|
|
6
|
-
listFrames: (project) => client.frame.list({ project }),
|
|
7
|
-
createFrame: (input) => client.frame.create(input),
|
|
8
|
-
generateImage: (input) => client.frame.generateImage(input),
|
|
9
|
-
renameFrame: (project, frame, name) => client.frame.rename({ project, frame, name }),
|
|
10
|
-
deleteFrame: (project, frame) => client.frame.delete({ project, frame }),
|
|
11
|
-
listFiles: (project, path) => client.filesystem.list({
|
|
12
|
-
project,
|
|
13
|
-
...(path === undefined ? {} : { path }),
|
|
14
|
-
}),
|
|
15
|
-
readFile: (project, path) => client.filesystem.read({ project, path }),
|
|
16
|
-
writeFile: (project, path, text) => client.filesystem.write({ project, path, text }),
|
|
17
|
-
editFile: (project, path, oldText, newText) => client.filesystem.edit({ project, path, oldText, newText }),
|
|
18
|
-
deleteFile: (project, path) => client.filesystem.delete({ project, path }),
|
|
19
|
-
screenshot: async (project, frame) => {
|
|
20
|
-
const screenshot = await client.frame.screenshot({ project, frame });
|
|
21
|
-
const response = await fetcher(screenshot.url);
|
|
22
|
-
if (!response.ok) {
|
|
23
|
-
throw new Error(`Could not read screenshot ${screenshot.url}: ${response.status} ${response.statusText}`);
|
|
24
|
-
}
|
|
25
|
-
const mediaType = response.headers
|
|
26
|
-
.get("content-type")
|
|
27
|
-
?.split(";", 1)[0]
|
|
28
|
-
?.trim();
|
|
29
|
-
if (mediaType !== screenshot.mediaType) {
|
|
30
|
-
throw new Error(`Screenshot ${screenshot.url} returned ${mediaType ?? "no media type"}; expected ${screenshot.mediaType}`);
|
|
31
|
-
}
|
|
32
|
-
return {
|
|
33
|
-
...screenshot,
|
|
34
|
-
png: new Uint8Array(await response.arrayBuffer()),
|
|
35
|
-
};
|
|
36
|
-
},
|
|
37
|
-
};
|
|
38
|
-
}
|