@drawcall/design 0.5.8 → 0.5.11

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.
@@ -0,0 +1,33 @@
1
+ import { z } from "zod";
2
+ import { type CreateFrame } from "../v1/schemas.js";
3
+ export declare const projectIdSchema: z.ZodString;
4
+ export declare const frameIdSchema: z.ZodString;
5
+ export declare const directoryPathSchema: z.ZodUnion<readonly [z.ZodLiteral<"/">, z.ZodString]>;
6
+ export declare const filePathSchema: z.ZodString;
7
+ export declare const createFrameSchema: z.ZodObject<{
8
+ project: z.ZodString;
9
+ name: z.ZodString;
10
+ type: z.ZodEnum<{
11
+ image: "image";
12
+ glts: "glts";
13
+ market: "market";
14
+ }>;
15
+ width: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
16
+ height: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
17
+ image: z.ZodOptional<z.ZodString>;
18
+ asset: z.ZodOptional<z.ZodString>;
19
+ x: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
20
+ y: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
21
+ }, z.core.$strict>;
22
+ export declare const projectInput: z.ZodObject<{
23
+ project: z.ZodString;
24
+ }, z.core.$strict>;
25
+ export declare const frameInput: z.ZodObject<{
26
+ project: z.ZodString;
27
+ frame: z.ZodString;
28
+ }, z.core.$strict>;
29
+ export declare const fileInput: z.ZodObject<{
30
+ project: z.ZodString;
31
+ path: z.ZodString;
32
+ }, z.core.$strict>;
33
+ export declare function frameCreationInput(input: z.infer<typeof createFrameSchema>): CreateFrame;
@@ -0,0 +1,108 @@
1
+ import { z } from "zod";
2
+ import { MAX_FRAME_DIMENSION, designIdSchema, frameNameSchema, imageUrlSchema, marketAssetSchema, projectDirectoryPathSchema, projectFilePathSchema, } from "../v1/schemas.js";
3
+ export const projectIdSchema = designIdSchema.describe("Exact project ID returned by list_projects");
4
+ export const frameIdSchema = designIdSchema.describe("Exact frame ID returned by list_frames");
5
+ export const directoryPathSchema = projectDirectoryPathSchema.describe("Project-absolute directory path without a trailing slash; omit it to list the entire project");
6
+ export const filePathSchema = projectFilePathSchema.describe("Project-absolute file path returned by list_files, including the frame ID; pass it unchanged");
7
+ const sizeSchema = z.coerce.number().int().min(1).max(MAX_FRAME_DIMENSION);
8
+ const positionSchema = z.coerce.number().finite();
9
+ // Some MCP clients lose property types in discriminated unions and serialize
10
+ // every create_frame argument as a string. Keep the wire schema flat.
11
+ export const createFrameSchema = z
12
+ .object({
13
+ project: projectIdSchema,
14
+ name: frameNameSchema,
15
+ type: z.enum(["glts", "image", "market"]),
16
+ width: sizeSchema.optional(),
17
+ height: sizeSchema.optional(),
18
+ image: imageUrlSchema.optional(),
19
+ asset: marketAssetSchema.optional(),
20
+ x: positionSchema.optional(),
21
+ y: positionSchema.optional(),
22
+ })
23
+ .strict()
24
+ .superRefine((input, context) => {
25
+ const require = (key) => {
26
+ if (input[key] !== undefined)
27
+ return;
28
+ context.addIssue({
29
+ code: "custom",
30
+ path: [key],
31
+ message: `${key} is required for a ${input.type} frame`,
32
+ });
33
+ };
34
+ const reject = (key) => {
35
+ if (input[key] === undefined)
36
+ return;
37
+ context.addIssue({
38
+ code: "custom",
39
+ path: [key],
40
+ message: `${key} is not valid for a ${input.type} frame`,
41
+ });
42
+ };
43
+ switch (input.type) {
44
+ case "glts":
45
+ require("width");
46
+ require("height");
47
+ reject("image");
48
+ reject("asset");
49
+ break;
50
+ case "image":
51
+ require("image");
52
+ reject("width");
53
+ reject("height");
54
+ reject("asset");
55
+ break;
56
+ case "market":
57
+ require("asset");
58
+ reject("width");
59
+ reject("height");
60
+ reject("image");
61
+ break;
62
+ }
63
+ });
64
+ export const projectInput = z.object({ project: projectIdSchema }).strict();
65
+ export const frameInput = projectInput.extend({ frame: frameIdSchema });
66
+ export const fileInput = projectInput.extend({ path: filePathSchema });
67
+ export function frameCreationInput(input) {
68
+ const position = {
69
+ ...(input.x === undefined ? {} : { x: input.x }),
70
+ ...(input.y === undefined ? {} : { y: input.y }),
71
+ };
72
+ switch (input.type) {
73
+ case "glts":
74
+ if (input.width === undefined || input.height === undefined) {
75
+ throw new Error("Validated GLTS frame input is missing dimensions");
76
+ }
77
+ return {
78
+ project: input.project,
79
+ name: input.name,
80
+ type: input.type,
81
+ width: input.width,
82
+ height: input.height,
83
+ ...position,
84
+ };
85
+ case "image":
86
+ if (input.image === undefined) {
87
+ throw new Error("Validated image frame input is missing an image");
88
+ }
89
+ return {
90
+ project: input.project,
91
+ name: input.name,
92
+ type: input.type,
93
+ image: input.image,
94
+ ...position,
95
+ };
96
+ case "market":
97
+ if (input.asset === undefined) {
98
+ throw new Error("Validated Market frame input is missing an asset");
99
+ }
100
+ return {
101
+ project: input.project,
102
+ name: input.name,
103
+ type: input.type,
104
+ asset: input.asset,
105
+ ...position,
106
+ };
107
+ }
108
+ }
@@ -0,0 +1,2 @@
1
+ import type { DesignMcpServer } from "./types.js";
2
+ export declare function registerSkillTool(server: DesignMcpServer): void;
@@ -0,0 +1,14 @@
1
+ import { z } from "zod";
2
+ import { mcpDesignSkill } from "../skill.generated.js";
3
+ export function registerSkillTool(server) {
4
+ server.registerTool("get_skill", {
5
+ description: "Return instructions for building and composing 3D GLTS assets in Drawcall Design. Read it before creating or changing GLTS files.",
6
+ inputSchema: z.object({}).strict(),
7
+ annotations: {
8
+ readOnlyHint: true,
9
+ destructiveHint: false,
10
+ openWorldHint: false,
11
+ idempotentHint: true,
12
+ },
13
+ }, async () => ({ content: [{ type: "text", text: mcpDesignSkill }] }));
14
+ }
@@ -0,0 +1,54 @@
1
+ import type { CreateFrame, DesignFile, FileList, FileMutation, Frame, GenerateImageFrame, Project, Screenshot } from "../v1/schemas.js";
2
+ import type { z } from "zod";
3
+ export interface DesignMcpToolResult {
4
+ [key: string]: unknown;
5
+ content: Array<{
6
+ type: "text";
7
+ text: string;
8
+ } | {
9
+ type: "image";
10
+ data: string;
11
+ mimeType: string;
12
+ }>;
13
+ structuredContent?: Record<string, unknown>;
14
+ }
15
+ interface DesignMcpToolAnnotations {
16
+ readOnlyHint?: boolean;
17
+ destructiveHint?: boolean;
18
+ idempotentHint?: boolean;
19
+ openWorldHint?: boolean;
20
+ }
21
+ interface DesignMcpToolConfig<Input extends z.ZodType | undefined> {
22
+ description?: string;
23
+ inputSchema?: Input;
24
+ annotations?: DesignMcpToolAnnotations;
25
+ }
26
+ type DesignMcpToolHandler<Input extends z.ZodType | undefined> = Input extends z.ZodType ? (input: z.output<Input>) => Promise<DesignMcpToolResult> : () => Promise<DesignMcpToolResult>;
27
+ export interface DesignMcpServer {
28
+ registerTool<Input extends z.ZodType | undefined = undefined>(name: string, config: DesignMcpToolConfig<Input>, handler: DesignMcpToolHandler<Input>): unknown;
29
+ }
30
+ export interface DesignMcpScreenshot extends Screenshot {
31
+ png: Uint8Array;
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>;
53
+ }
54
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -65,8 +65,8 @@ export declare const projectImageFrameRecordSchema: z.ZodObject<{
65
65
  frameUpdatedAt: z.ZodString;
66
66
  }, z.core.$strip>>;
67
67
  result: z.ZodEnum<{
68
- replace: "replace";
69
68
  new: "new";
69
+ replace: "replace";
70
70
  }>;
71
71
  provider: z.ZodLiteral<"fal-ai">;
72
72
  model: z.ZodLiteral<"openai/gpt-image-2">;
@@ -82,8 +82,8 @@ export declare const projectImageFrameRecordSchema: z.ZodObject<{
82
82
  frameUpdatedAt: z.ZodString;
83
83
  }, z.core.$strip>>;
84
84
  result: z.ZodEnum<{
85
- replace: "replace";
86
85
  new: "new";
86
+ replace: "replace";
87
87
  }>;
88
88
  provider: z.ZodLiteral<"cloudflare-workers-ai">;
89
89
  model: z.ZodLiteral<"@cf/black-forest-labs/flux-2-klein-4b">;
@@ -177,8 +177,8 @@ export declare const projectFrameRecordSchema: z.ZodDiscriminatedUnion<[z.ZodObj
177
177
  frameUpdatedAt: z.ZodString;
178
178
  }, z.core.$strip>>;
179
179
  result: z.ZodEnum<{
180
- replace: "replace";
181
180
  new: "new";
181
+ replace: "replace";
182
182
  }>;
183
183
  provider: z.ZodLiteral<"fal-ai">;
184
184
  model: z.ZodLiteral<"openai/gpt-image-2">;
@@ -194,8 +194,8 @@ export declare const projectFrameRecordSchema: z.ZodDiscriminatedUnion<[z.ZodObj
194
194
  frameUpdatedAt: z.ZodString;
195
195
  }, z.core.$strip>>;
196
196
  result: z.ZodEnum<{
197
- replace: "replace";
198
197
  new: "new";
198
+ replace: "replace";
199
199
  }>;
200
200
  provider: z.ZodLiteral<"cloudflare-workers-ai">;
201
201
  model: z.ZodLiteral<"@cf/black-forest-labs/flux-2-klein-4b">;
@@ -287,8 +287,8 @@ export declare const projectStateSchema: z.ZodObject<{
287
287
  frameUpdatedAt: z.ZodString;
288
288
  }, z.core.$strip>>;
289
289
  result: z.ZodEnum<{
290
- replace: "replace";
291
290
  new: "new";
291
+ replace: "replace";
292
292
  }>;
293
293
  provider: z.ZodLiteral<"fal-ai">;
294
294
  model: z.ZodLiteral<"openai/gpt-image-2">;
@@ -304,8 +304,8 @@ export declare const projectStateSchema: z.ZodObject<{
304
304
  frameUpdatedAt: z.ZodString;
305
305
  }, z.core.$strip>>;
306
306
  result: z.ZodEnum<{
307
- replace: "replace";
308
307
  new: "new";
308
+ replace: "replace";
309
309
  }>;
310
310
  provider: z.ZodLiteral<"cloudflare-workers-ai">;
311
311
  model: z.ZodLiteral<"@cf/black-forest-labs/flux-2-klein-4b">;
@@ -154,8 +154,8 @@ export declare const contract: {
154
154
  frameUpdatedAt: z.ZodString;
155
155
  }, z.core.$strip>>;
156
156
  result: z.ZodEnum<{
157
- replace: "replace";
158
157
  new: "new";
158
+ replace: "replace";
159
159
  }>;
160
160
  provider: z.ZodLiteral<"fal-ai">;
161
161
  model: z.ZodLiteral<"openai/gpt-image-2">;
@@ -171,8 +171,8 @@ export declare const contract: {
171
171
  frameUpdatedAt: z.ZodString;
172
172
  }, z.core.$strip>>;
173
173
  result: z.ZodEnum<{
174
- replace: "replace";
175
174
  new: "new";
175
+ replace: "replace";
176
176
  }>;
177
177
  provider: z.ZodLiteral<"cloudflare-workers-ai">;
178
178
  model: z.ZodLiteral<"@cf/black-forest-labs/flux-2-klein-4b">;
@@ -264,8 +264,8 @@ export declare const contract: {
264
264
  frameUpdatedAt: z.ZodString;
265
265
  }, z.core.$strip>>;
266
266
  result: z.ZodEnum<{
267
- replace: "replace";
268
267
  new: "new";
268
+ replace: "replace";
269
269
  }>;
270
270
  provider: z.ZodLiteral<"fal-ai">;
271
271
  model: z.ZodLiteral<"openai/gpt-image-2">;
@@ -281,8 +281,8 @@ export declare const contract: {
281
281
  frameUpdatedAt: z.ZodString;
282
282
  }, z.core.$strip>>;
283
283
  result: z.ZodEnum<{
284
- replace: "replace";
285
284
  new: "new";
285
+ replace: "replace";
286
286
  }>;
287
287
  provider: z.ZodLiteral<"cloudflare-workers-ai">;
288
288
  model: z.ZodLiteral<"@cf/black-forest-labs/flux-2-klein-4b">;
@@ -311,8 +311,8 @@ export declare const contract: {
311
311
  target: z.ZodOptional<z.ZodString>;
312
312
  references: z.ZodDefault<z.ZodArray<z.ZodString>>;
313
313
  result: z.ZodEnum<{
314
- replace: "replace";
315
314
  new: "new";
315
+ replace: "replace";
316
316
  }>;
317
317
  name: z.ZodOptional<z.ZodString>;
318
318
  x: z.ZodOptional<z.ZodNumber>;
@@ -368,8 +368,8 @@ export declare const contract: {
368
368
  frameUpdatedAt: z.ZodString;
369
369
  }, z.core.$strip>>;
370
370
  result: z.ZodEnum<{
371
- replace: "replace";
372
371
  new: "new";
372
+ replace: "replace";
373
373
  }>;
374
374
  provider: z.ZodLiteral<"fal-ai">;
375
375
  model: z.ZodLiteral<"openai/gpt-image-2">;
@@ -385,8 +385,8 @@ export declare const contract: {
385
385
  frameUpdatedAt: z.ZodString;
386
386
  }, z.core.$strip>>;
387
387
  result: z.ZodEnum<{
388
- replace: "replace";
389
388
  new: "new";
389
+ replace: "replace";
390
390
  }>;
391
391
  provider: z.ZodLiteral<"cloudflare-workers-ai">;
392
392
  model: z.ZodLiteral<"@cf/black-forest-labs/flux-2-klein-4b">;
@@ -460,8 +460,8 @@ export declare const contract: {
460
460
  frameUpdatedAt: z.ZodString;
461
461
  }, z.core.$strip>>;
462
462
  result: z.ZodEnum<{
463
- replace: "replace";
464
463
  new: "new";
464
+ replace: "replace";
465
465
  }>;
466
466
  provider: z.ZodLiteral<"fal-ai">;
467
467
  model: z.ZodLiteral<"openai/gpt-image-2">;
@@ -477,8 +477,8 @@ export declare const contract: {
477
477
  frameUpdatedAt: z.ZodString;
478
478
  }, z.core.$strip>>;
479
479
  result: z.ZodEnum<{
480
- replace: "replace";
481
480
  new: "new";
481
+ replace: "replace";
482
482
  }>;
483
483
  provider: z.ZodLiteral<"cloudflare-workers-ai">;
484
484
  model: z.ZodLiteral<"@cf/black-forest-labs/flux-2-klein-4b">;
@@ -566,8 +566,8 @@ export declare const contract: {
566
566
  frameUpdatedAt: z.ZodString;
567
567
  }, z.core.$strip>>;
568
568
  result: z.ZodEnum<{
569
- replace: "replace";
570
569
  new: "new";
570
+ replace: "replace";
571
571
  }>;
572
572
  provider: z.ZodLiteral<"fal-ai">;
573
573
  model: z.ZodLiteral<"openai/gpt-image-2">;
@@ -583,8 +583,8 @@ export declare const contract: {
583
583
  frameUpdatedAt: z.ZodString;
584
584
  }, z.core.$strip>>;
585
585
  result: z.ZodEnum<{
586
- replace: "replace";
587
586
  new: "new";
587
+ replace: "replace";
588
588
  }>;
589
589
  provider: z.ZodLiteral<"cloudflare-workers-ai">;
590
590
  model: z.ZodLiteral<"@cf/black-forest-labs/flux-2-klein-4b">;
@@ -661,8 +661,8 @@ export declare const contract: {
661
661
  frameUpdatedAt: z.ZodString;
662
662
  }, z.core.$strip>>;
663
663
  result: z.ZodEnum<{
664
- replace: "replace";
665
664
  new: "new";
665
+ replace: "replace";
666
666
  }>;
667
667
  provider: z.ZodLiteral<"fal-ai">;
668
668
  model: z.ZodLiteral<"openai/gpt-image-2">;
@@ -678,8 +678,8 @@ export declare const contract: {
678
678
  frameUpdatedAt: z.ZodString;
679
679
  }, z.core.$strip>>;
680
680
  result: z.ZodEnum<{
681
- replace: "replace";
682
681
  new: "new";
682
+ replace: "replace";
683
683
  }>;
684
684
  provider: z.ZodLiteral<"cloudflare-workers-ai">;
685
685
  model: z.ZodLiteral<"@cf/black-forest-labs/flux-2-klein-4b">;
@@ -97,8 +97,8 @@ export declare const imageGenerationOperationSchema: z.ZodEnum<{
97
97
  edit: "edit";
98
98
  }>;
99
99
  export declare const imageGenerationResultSchema: z.ZodEnum<{
100
- replace: "replace";
101
100
  new: "new";
101
+ replace: "replace";
102
102
  }>;
103
103
  export declare const imageGenerationReferenceSchema: z.ZodObject<{
104
104
  frameId: z.ZodString;
@@ -120,8 +120,8 @@ export declare const imageGenerationProvenanceSchema: z.ZodDiscriminatedUnion<[z
120
120
  frameUpdatedAt: z.ZodString;
121
121
  }, z.core.$strip>>;
122
122
  result: z.ZodEnum<{
123
- replace: "replace";
124
123
  new: "new";
124
+ replace: "replace";
125
125
  }>;
126
126
  provider: z.ZodLiteral<"fal-ai">;
127
127
  model: z.ZodLiteral<"openai/gpt-image-2">;
@@ -137,8 +137,8 @@ export declare const imageGenerationProvenanceSchema: z.ZodDiscriminatedUnion<[z
137
137
  frameUpdatedAt: z.ZodString;
138
138
  }, z.core.$strip>>;
139
139
  result: z.ZodEnum<{
140
- replace: "replace";
141
140
  new: "new";
141
+ replace: "replace";
142
142
  }>;
143
143
  provider: z.ZodLiteral<"cloudflare-workers-ai">;
144
144
  model: z.ZodLiteral<"@cf/black-forest-labs/flux-2-klein-4b">;
@@ -168,8 +168,8 @@ export declare const imageFrameSchema: z.ZodObject<{
168
168
  frameUpdatedAt: z.ZodString;
169
169
  }, z.core.$strip>>;
170
170
  result: z.ZodEnum<{
171
- replace: "replace";
172
171
  new: "new";
172
+ replace: "replace";
173
173
  }>;
174
174
  provider: z.ZodLiteral<"fal-ai">;
175
175
  model: z.ZodLiteral<"openai/gpt-image-2">;
@@ -185,8 +185,8 @@ export declare const imageFrameSchema: z.ZodObject<{
185
185
  frameUpdatedAt: z.ZodString;
186
186
  }, z.core.$strip>>;
187
187
  result: z.ZodEnum<{
188
- replace: "replace";
189
188
  new: "new";
189
+ replace: "replace";
190
190
  }>;
191
191
  provider: z.ZodLiteral<"cloudflare-workers-ai">;
192
192
  model: z.ZodLiteral<"@cf/black-forest-labs/flux-2-klein-4b">;
@@ -257,8 +257,8 @@ export declare const frameSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
257
257
  frameUpdatedAt: z.ZodString;
258
258
  }, z.core.$strip>>;
259
259
  result: z.ZodEnum<{
260
- replace: "replace";
261
260
  new: "new";
261
+ replace: "replace";
262
262
  }>;
263
263
  provider: z.ZodLiteral<"fal-ai">;
264
264
  model: z.ZodLiteral<"openai/gpt-image-2">;
@@ -274,8 +274,8 @@ export declare const frameSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
274
274
  frameUpdatedAt: z.ZodString;
275
275
  }, z.core.$strip>>;
276
276
  result: z.ZodEnum<{
277
- replace: "replace";
278
277
  new: "new";
278
+ replace: "replace";
279
279
  }>;
280
280
  provider: z.ZodLiteral<"cloudflare-workers-ai">;
281
281
  model: z.ZodLiteral<"@cf/black-forest-labs/flux-2-klein-4b">;
@@ -352,8 +352,8 @@ export declare const generateImageFrameSchema: z.ZodObject<{
352
352
  target: z.ZodOptional<z.ZodString>;
353
353
  references: z.ZodDefault<z.ZodArray<z.ZodString>>;
354
354
  result: z.ZodEnum<{
355
- replace: "replace";
356
355
  new: "new";
356
+ replace: "replace";
357
357
  }>;
358
358
  name: z.ZodOptional<z.ZodString>;
359
359
  x: z.ZodOptional<z.ZodNumber>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drawcall/design",
3
- "version": "0.5.8",
3
+ "version": "0.5.11",
4
4
  "description": "Typed API and remote CLI for Drawcall Design",
5
5
  "repository": {
6
6
  "type": "git",
@@ -8,13 +8,9 @@
8
8
  "directory": "packages/design"
9
9
  },
10
10
  "type": "module",
11
+ "main": "./dist/index.js",
12
+ "browser": "./dist/browser.js",
11
13
  "types": "./dist/index.d.ts",
12
- "exports": {
13
- ".": {
14
- "types": "./dist/index.d.ts",
15
- "import": "./dist/index.js"
16
- }
17
- },
18
14
  "files": [
19
15
  "dist",
20
16
  "skills"
@@ -34,15 +30,23 @@
34
30
  "typecheck": "tsc --noEmit"
35
31
  },
36
32
  "dependencies": {
33
+ "@drawcall/auth": "^0.1.0",
37
34
  "@orpc/client": "^1.14.13",
38
35
  "@orpc/contract": "^1.14.13",
39
36
  "@orpc/openapi-client": "^1.14.13",
40
37
  "commander": "^14.0.3",
41
- "open": "^10.1.0",
42
- "openid-client": "^6.8.4",
43
38
  "zod": "^4.3.6"
44
39
  },
40
+ "peerDependencies": {
41
+ "@modelcontextprotocol/server": "^2.0.0"
42
+ },
43
+ "peerDependenciesMeta": {
44
+ "@modelcontextprotocol/server": {
45
+ "optional": true
46
+ }
47
+ },
45
48
  "devDependencies": {
49
+ "@modelcontextprotocol/server": "^2.0.0",
46
50
  "@types/node": "^25.6.0",
47
51
  "prettier": "^3.6.2",
48
52
  "tsx": "^4.21.0",