@genart-dev/mcp-server 0.4.1 → 0.4.3

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/dist/lib.d.cts CHANGED
@@ -116,7 +116,11 @@ declare class EditorState extends EventEmitter {
116
116
  * Creates a McpServer instance with all tools, resources, and prompts.
117
117
  */
118
118
 
119
+ interface CreateServerOptions {
120
+ /** Only register capture tools (for local-only capture companion server). */
121
+ captureOnly?: boolean;
122
+ }
119
123
  /** Create and configure the MCP server with all tools. */
120
- declare function createServer(state: EditorState): McpServer;
124
+ declare function createServer(state: EditorState, options?: CreateServerOptions): McpServer;
121
125
 
122
- export { type EditorMutationEvent, type EditorMutationType, EditorState, type EditorStateSnapshot, type LoadedSketch, createServer };
126
+ export { type CreateServerOptions, type EditorMutationEvent, type EditorMutationType, EditorState, type EditorStateSnapshot, type LoadedSketch, createServer };
package/dist/lib.d.ts CHANGED
@@ -116,7 +116,11 @@ declare class EditorState extends EventEmitter {
116
116
  * Creates a McpServer instance with all tools, resources, and prompts.
117
117
  */
118
118
 
119
+ interface CreateServerOptions {
120
+ /** Only register capture tools (for local-only capture companion server). */
121
+ captureOnly?: boolean;
122
+ }
119
123
  /** Create and configure the MCP server with all tools. */
120
- declare function createServer(state: EditorState): McpServer;
124
+ declare function createServer(state: EditorState, options?: CreateServerOptions): McpServer;
121
125
 
122
- export { type EditorMutationEvent, type EditorMutationType, EditorState, type EditorStateSnapshot, type LoadedSketch, createServer };
126
+ export { type CreateServerOptions, type EditorMutationEvent, type EditorMutationType, EditorState, type EditorStateSnapshot, type LoadedSketch, createServer };
package/dist/lib.js CHANGED
@@ -2424,32 +2424,19 @@ function isDirectComponent(name, components) {
2424
2424
  }
2425
2425
 
2426
2426
  // src/tools/capture.ts
2427
- import { writeFile as writeFile5 } from "fs/promises";
2427
+ import { mkdir, writeFile as writeFile5 } from "fs/promises";
2428
+ import { dirname as dirname5, join as join3 } from "path";
2428
2429
  import {
2429
2430
  createDefaultRegistry as createDefaultRegistry2
2430
2431
  } from "@genart-dev/core";
2431
2432
 
2432
2433
  // src/capture/headless.ts
2433
- var cachedModule = null;
2434
- async function loadPuppeteer() {
2435
- if (!cachedModule) {
2436
- try {
2437
- const mod = await import("puppeteer");
2438
- cachedModule = mod.default ?? mod;
2439
- } catch {
2440
- throw new Error(
2441
- "Puppeteer is required for screenshot capture. Install it with: npm install puppeteer"
2442
- );
2443
- }
2444
- }
2445
- return cachedModule;
2446
- }
2434
+ import puppeteer from "puppeteer";
2447
2435
  var browserInstance = null;
2448
2436
  async function getBrowser() {
2449
2437
  if (browserInstance && browserInstance.connected) {
2450
2438
  return browserInstance;
2451
2439
  }
2452
- const puppeteer = await loadPuppeteer();
2453
2440
  browserInstance = await puppeteer.launch({
2454
2441
  headless: true,
2455
2442
  executablePath: process.env.PUPPETEER_EXECUTABLE_PATH || void 0,
@@ -2543,8 +2530,9 @@ function generateSketchHtml(sketch, opts) {
2543
2530
  }
2544
2531
  return adapter.generateStandaloneHTML(effective);
2545
2532
  }
2546
- function derivePreviewPath(sketchPath) {
2547
- return sketchPath.replace(/\.genart$/, ".png");
2533
+ function deriveSnapshotPath(sketchPath, sketchId, seed) {
2534
+ const wsDir = dirname5(sketchPath);
2535
+ return join3(wsDir, "snapshots", `${sketchId}-${seed}-preview.png`);
2548
2536
  }
2549
2537
  async function captureScreenshot(state, input) {
2550
2538
  state.requireWorkspace();
@@ -2577,11 +2565,12 @@ async function captureScreenshot(state, input) {
2577
2565
  height,
2578
2566
  inlineSize
2579
2567
  });
2580
- const previewPath = derivePreviewPath(loaded.path);
2568
+ const effectiveSeed = input.seed ?? sketch.state.seed;
2569
+ const previewPath = deriveSnapshotPath(loaded.path, sketchId, effectiveSeed);
2581
2570
  const metadata = await buildScreenshotMetadata(state, multi, {
2582
2571
  target,
2583
2572
  sketchId,
2584
- seed: input.seed ?? sketch.state.seed,
2573
+ seed: effectiveSeed,
2585
2574
  previewPath
2586
2575
  });
2587
2576
  const previewJpegBase64 = Buffer.from(multi.inlineJpeg).toString("base64");
@@ -2602,8 +2591,10 @@ async function buildScreenshotMetadata(state, multi, info) {
2602
2591
  previewPath: info.previewPath
2603
2592
  };
2604
2593
  if (!state.remoteMode) {
2594
+ await mkdir(dirname5(info.previewPath), { recursive: true });
2605
2595
  await writeFile5(info.previewPath, multi.previewPng);
2606
2596
  metadata.savedPreviewTo = info.previewPath;
2597
+ metadata.previewWritten = true;
2607
2598
  }
2608
2599
  return metadata;
2609
2600
  }
@@ -2632,11 +2623,12 @@ async function captureBatch(state, input) {
2632
2623
  height,
2633
2624
  inlineSize
2634
2625
  });
2635
- const previewPath = derivePreviewPath(loaded.path);
2626
+ const effectiveSeed = input.seed ?? sketch.state.seed;
2627
+ const previewPath = deriveSnapshotPath(loaded.path, id, effectiveSeed);
2636
2628
  const itemMetadata = await buildScreenshotMetadata(state, multi, {
2637
2629
  target: "sketch",
2638
2630
  sketchId: id,
2639
- seed: input.seed ?? sketch.state.seed,
2631
+ seed: effectiveSeed,
2640
2632
  previewPath
2641
2633
  });
2642
2634
  items.push({
@@ -2996,7 +2988,7 @@ function gatherRelevantSkills(aspects) {
2996
2988
 
2997
2989
  // src/tools/series.ts
2998
2990
  import { writeFile as writeFile6 } from "fs/promises";
2999
- import { basename as basename8, dirname as dirname5, resolve as resolve2 } from "path";
2991
+ import { basename as basename8, dirname as dirname6, resolve as resolve2 } from "path";
3000
2992
  import {
3001
2993
  serializeGenart as serializeGenart4,
3002
2994
  serializeWorkspace as serializeWorkspace3
@@ -3276,7 +3268,7 @@ async function promoteSketch(state, input) {
3276
3268
  ...input.agent ? { agent: input.agent } : {},
3277
3269
  ...input.model ? { model: input.model } : {}
3278
3270
  };
3279
- const sourceDir = dirname5(source.path);
3271
+ const sourceDir = dirname6(source.path);
3280
3272
  const newPath = resolve2(sourceDir, `${newId}.genart`);
3281
3273
  const json = serializeGenart4(promotedDef);
3282
3274
  if (!state.remoteMode) {
@@ -3346,8 +3338,8 @@ function countBy(items) {
3346
3338
  }
3347
3339
 
3348
3340
  // src/tools/reference.ts
3349
- import { copyFile, mkdir, readFile as readFile4 } from "fs/promises";
3350
- import { basename as basename9, dirname as dirname6, extname, resolve as resolve3 } from "path";
3341
+ import { copyFile, mkdir as mkdir2, readFile as readFile4 } from "fs/promises";
3342
+ import { basename as basename9, dirname as dirname7, extname, resolve as resolve3 } from "path";
3351
3343
  import {
3352
3344
  serializeGenart as serializeGenart5,
3353
3345
  serializeWorkspace as serializeWorkspace4
@@ -3402,9 +3394,9 @@ async function addReference(state, input) {
3402
3394
  `Invalid reference type: '${refType}'. Valid types: ${VALID_REFERENCE_TYPES.join(", ")}`
3403
3395
  );
3404
3396
  }
3405
- const workspaceDir = dirname6(state.workspacePath);
3397
+ const workspaceDir = dirname7(state.workspacePath);
3406
3398
  const refsDir = resolve3(workspaceDir, "references");
3407
- await mkdir(refsDir, { recursive: true });
3399
+ await mkdir2(refsDir, { recursive: true });
3408
3400
  const ext = extname(input.image);
3409
3401
  const destFilename = `${id}${ext}`;
3410
3402
  const destPath = resolve3(refsDir, destFilename);
@@ -3492,7 +3484,7 @@ async function addReference(state, input) {
3492
3484
  async function analyzeReference(state, input) {
3493
3485
  state.requireWorkspace();
3494
3486
  const { ref, location } = findReference(state, input.referenceId, input.seriesId, input.sketchId);
3495
- const workspaceDir = dirname6(state.workspacePath);
3487
+ const workspaceDir = dirname7(state.workspacePath);
3496
3488
  const imagePath = resolve3(workspaceDir, ref.path);
3497
3489
  let previewJpegBase64;
3498
3490
  try {
@@ -3652,7 +3644,7 @@ async function extractPalette(state, input) {
3652
3644
  input.sketchId
3653
3645
  );
3654
3646
  const count = input.count ?? 6;
3655
- const workspaceDir = dirname6(state.workspacePath);
3647
+ const workspaceDir = dirname7(state.workspacePath);
3656
3648
  const imagePath = resolve3(workspaceDir, ref.path);
3657
3649
  let previewJpegBase64;
3658
3650
  try {
@@ -3729,7 +3721,7 @@ function findReference(state, referenceId, seriesId, sketchId) {
3729
3721
  // src/tools/export.ts
3730
3722
  import { createWriteStream } from "fs";
3731
3723
  import { stat as stat4, writeFile as writeFile8 } from "fs/promises";
3732
- import { dirname as dirname7 } from "path";
3724
+ import { dirname as dirname8 } from "path";
3733
3725
  import archiver from "archiver";
3734
3726
  import {
3735
3727
  createDefaultRegistry as createDefaultRegistry3,
@@ -3737,7 +3729,7 @@ import {
3737
3729
  } from "@genart-dev/core";
3738
3730
  var registry4 = createDefaultRegistry3();
3739
3731
  async function validateOutputPath(outputPath) {
3740
- const parentDir = dirname7(outputPath);
3732
+ const parentDir = dirname8(outputPath);
3741
3733
  try {
3742
3734
  const s = await stat4(parentDir);
3743
3735
  if (!s.isDirectory()) {
@@ -5007,20 +4999,24 @@ async function initializePluginRegistry() {
5007
4999
  await registry5.register(tracePlugin);
5008
5000
  return registry5;
5009
5001
  }
5010
- function createServer(state) {
5002
+ function createServer(state, options) {
5003
+ const captureOnly = options?.captureOnly ?? false;
5011
5004
  const server = new McpServer(
5012
5005
  {
5013
- name: "@genart/mcp-server",
5006
+ name: captureOnly ? "@genart/mcp-capture" : "@genart/mcp-server",
5014
5007
  version: "0.4.0"
5015
5008
  },
5016
5009
  {
5017
5010
  capabilities: {
5018
5011
  tools: {},
5019
- resources: {},
5020
- prompts: {}
5012
+ ...!captureOnly && { resources: {}, prompts: {} }
5021
5013
  }
5022
5014
  }
5023
5015
  );
5016
+ if (captureOnly) {
5017
+ registerCaptureTools(server, state);
5018
+ return server;
5019
+ }
5024
5020
  const registryReady = initializePluginRegistry().then((registry5) => {
5025
5021
  state.pluginRegistry = registry5;
5026
5022
  registerPluginMcpTools(server, registry5, state);
@@ -5037,7 +5033,9 @@ function createServer(state) {
5037
5033
  registerSnapshotTools(server, state);
5038
5034
  registerKnowledgeTools(server, state);
5039
5035
  registerDesignTools(server, state);
5040
- registerCaptureTools(server, state);
5036
+ if (!state.remoteMode) {
5037
+ registerCaptureTools(server, state);
5038
+ }
5041
5039
  registerCritiqueTools(server, state);
5042
5040
  registerSeriesTools(server, state);
5043
5041
  registerReferenceTools(server, state);
@@ -5747,7 +5745,7 @@ function registerSnapshotTools(server, state) {
5747
5745
  function registerCaptureTools(server, state) {
5748
5746
  server.tool(
5749
5747
  "capture_screenshot",
5750
- "Capture a screenshot of a sketch. Returns metadata as text + a small inline JPEG image for visual review. In remote mode, metadata includes previewFileContent (base64 PNG) to Write locally.",
5748
+ "Capture a screenshot of a sketch. Returns metadata as text + a small inline JPEG image for visual review. In local mode, writes a full-res PNG to snapshots/<sketchId>-<seed>-preview.png next to the workspace. The savedPreviewTo path in metadata points to the file on disk.",
5751
5749
  {
5752
5750
  target: z2.enum(["selected", "sketch"]).optional().describe("What to capture (default: selected)"),
5753
5751
  sketchId: z2.string().optional().describe("Required when target is 'sketch'"),
@@ -5760,6 +5758,7 @@ function registerCaptureTools(server, state) {
5760
5758
  async (args) => {
5761
5759
  try {
5762
5760
  const result = await captureScreenshot(state, args);
5761
+ console.error(`[capture_screenshot] jpeg base64 length: ${result.previewJpegBase64.length}, metadata: ${JSON.stringify(result.metadata)}`);
5763
5762
  return {
5764
5763
  content: [
5765
5764
  { type: "text", text: JSON.stringify(result.metadata, null, 2) },
@@ -5767,6 +5766,7 @@ function registerCaptureTools(server, state) {
5767
5766
  ]
5768
5767
  };
5769
5768
  } catch (e) {
5769
+ console.error(`[capture_screenshot] error: ${e instanceof Error ? e.message : String(e)}`);
5770
5770
  return toolError(e instanceof Error ? e.message : String(e));
5771
5771
  }
5772
5772
  }
@@ -6408,7 +6408,7 @@ function registerKnowledgeTools(server, state) {
6408
6408
  // src/state.ts
6409
6409
  import { EventEmitter } from "events";
6410
6410
  import { readFile as readFile5 } from "fs/promises";
6411
- import { dirname as dirname8, isAbsolute, resolve as resolve4 } from "path";
6411
+ import { dirname as dirname9, isAbsolute, resolve as resolve4 } from "path";
6412
6412
 
6413
6413
  // src/sidecar.ts
6414
6414
  function isSidecarMode() {
@@ -6502,7 +6502,7 @@ var EditorState = class extends EventEmitter {
6502
6502
  }
6503
6503
  throw new Error("No workspace is currently open");
6504
6504
  }
6505
- const resolved = resolve4(dirname8(this.workspacePath), file);
6505
+ const resolved = resolve4(dirname9(this.workspacePath), file);
6506
6506
  if (this.basePath && !resolved.startsWith(this.basePath)) {
6507
6507
  throw new Error(`Path escapes sandbox: ${resolved}`);
6508
6508
  }