@genart-dev/mcp-server 0.4.2 → 0.4.4

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/index.js CHANGED
@@ -2743,7 +2743,8 @@ function isDirectComponent(name, components) {
2743
2743
  }
2744
2744
 
2745
2745
  // src/tools/capture.ts
2746
- import { writeFile as writeFile6 } from "fs/promises";
2746
+ import { mkdir, writeFile as writeFile6 } from "fs/promises";
2747
+ import { dirname as dirname6, join as join3 } from "path";
2747
2748
  import {
2748
2749
  createDefaultRegistry as createDefaultRegistry2
2749
2750
  } from "@genart-dev/core";
@@ -2848,8 +2849,9 @@ function generateSketchHtml(sketch, opts) {
2848
2849
  }
2849
2850
  return adapter.generateStandaloneHTML(effective);
2850
2851
  }
2851
- function derivePreviewPath(sketchPath) {
2852
- return sketchPath.replace(/\.genart$/, ".png");
2852
+ function deriveSnapshotPath(sketchPath, sketchId, seed) {
2853
+ const wsDir = dirname6(sketchPath);
2854
+ return join3(wsDir, "snapshots", `${sketchId}-${seed}-preview.png`);
2853
2855
  }
2854
2856
  async function captureScreenshot(state, input) {
2855
2857
  state.requireWorkspace();
@@ -2882,11 +2884,12 @@ async function captureScreenshot(state, input) {
2882
2884
  height,
2883
2885
  inlineSize
2884
2886
  });
2885
- const previewPath = derivePreviewPath(loaded.path);
2887
+ const effectiveSeed = input.seed ?? sketch.state.seed;
2888
+ const previewPath = deriveSnapshotPath(loaded.path, sketchId, effectiveSeed);
2886
2889
  const metadata = await buildScreenshotMetadata(state, multi, {
2887
2890
  target,
2888
2891
  sketchId,
2889
- seed: input.seed ?? sketch.state.seed,
2892
+ seed: effectiveSeed,
2890
2893
  previewPath
2891
2894
  });
2892
2895
  const previewJpegBase64 = Buffer.from(multi.inlineJpeg).toString("base64");
@@ -2907,8 +2910,10 @@ async function buildScreenshotMetadata(state, multi, info) {
2907
2910
  previewPath: info.previewPath
2908
2911
  };
2909
2912
  if (!state.remoteMode) {
2913
+ await mkdir(dirname6(info.previewPath), { recursive: true });
2910
2914
  await writeFile6(info.previewPath, multi.previewPng);
2911
2915
  metadata.savedPreviewTo = info.previewPath;
2916
+ metadata.previewWritten = true;
2912
2917
  }
2913
2918
  return metadata;
2914
2919
  }
@@ -2937,11 +2942,12 @@ async function captureBatch(state, input) {
2937
2942
  height,
2938
2943
  inlineSize
2939
2944
  });
2940
- const previewPath = derivePreviewPath(loaded.path);
2945
+ const effectiveSeed = input.seed ?? sketch.state.seed;
2946
+ const previewPath = deriveSnapshotPath(loaded.path, id, effectiveSeed);
2941
2947
  const itemMetadata = await buildScreenshotMetadata(state, multi, {
2942
2948
  target: "sketch",
2943
2949
  sketchId: id,
2944
- seed: input.seed ?? sketch.state.seed,
2950
+ seed: effectiveSeed,
2945
2951
  previewPath
2946
2952
  });
2947
2953
  items.push({
@@ -3301,7 +3307,7 @@ function gatherRelevantSkills(aspects) {
3301
3307
 
3302
3308
  // src/tools/series.ts
3303
3309
  import { writeFile as writeFile7 } from "fs/promises";
3304
- import { basename as basename8, dirname as dirname6, resolve as resolve3 } from "path";
3310
+ import { basename as basename8, dirname as dirname7, resolve as resolve3 } from "path";
3305
3311
  import {
3306
3312
  serializeGenart as serializeGenart5,
3307
3313
  serializeWorkspace as serializeWorkspace4
@@ -3581,7 +3587,7 @@ async function promoteSketch(state, input) {
3581
3587
  ...input.agent ? { agent: input.agent } : {},
3582
3588
  ...input.model ? { model: input.model } : {}
3583
3589
  };
3584
- const sourceDir = dirname6(source.path);
3590
+ const sourceDir = dirname7(source.path);
3585
3591
  const newPath = resolve3(sourceDir, `${newId}.genart`);
3586
3592
  const json = serializeGenart5(promotedDef);
3587
3593
  if (!state.remoteMode) {
@@ -3651,8 +3657,8 @@ function countBy(items) {
3651
3657
  }
3652
3658
 
3653
3659
  // src/tools/reference.ts
3654
- import { copyFile, mkdir, readFile as readFile5 } from "fs/promises";
3655
- import { basename as basename9, dirname as dirname7, extname, resolve as resolve4 } from "path";
3660
+ import { copyFile, mkdir as mkdir2, readFile as readFile5 } from "fs/promises";
3661
+ import { basename as basename9, dirname as dirname8, extname, resolve as resolve4 } from "path";
3656
3662
  import {
3657
3663
  serializeGenart as serializeGenart6,
3658
3664
  serializeWorkspace as serializeWorkspace5
@@ -3707,9 +3713,9 @@ async function addReference(state, input) {
3707
3713
  `Invalid reference type: '${refType}'. Valid types: ${VALID_REFERENCE_TYPES.join(", ")}`
3708
3714
  );
3709
3715
  }
3710
- const workspaceDir = dirname7(state.workspacePath);
3716
+ const workspaceDir = dirname8(state.workspacePath);
3711
3717
  const refsDir = resolve4(workspaceDir, "references");
3712
- await mkdir(refsDir, { recursive: true });
3718
+ await mkdir2(refsDir, { recursive: true });
3713
3719
  const ext = extname(input.image);
3714
3720
  const destFilename = `${id}${ext}`;
3715
3721
  const destPath = resolve4(refsDir, destFilename);
@@ -3797,7 +3803,7 @@ async function addReference(state, input) {
3797
3803
  async function analyzeReference(state, input) {
3798
3804
  state.requireWorkspace();
3799
3805
  const { ref, location } = findReference(state, input.referenceId, input.seriesId, input.sketchId);
3800
- const workspaceDir = dirname7(state.workspacePath);
3806
+ const workspaceDir = dirname8(state.workspacePath);
3801
3807
  const imagePath = resolve4(workspaceDir, ref.path);
3802
3808
  let previewJpegBase64;
3803
3809
  try {
@@ -3957,7 +3963,7 @@ async function extractPalette(state, input) {
3957
3963
  input.sketchId
3958
3964
  );
3959
3965
  const count = input.count ?? 6;
3960
- const workspaceDir = dirname7(state.workspacePath);
3966
+ const workspaceDir = dirname8(state.workspacePath);
3961
3967
  const imagePath = resolve4(workspaceDir, ref.path);
3962
3968
  let previewJpegBase64;
3963
3969
  try {
@@ -4034,7 +4040,7 @@ function findReference(state, referenceId, seriesId, sketchId) {
4034
4040
  // src/tools/export.ts
4035
4041
  import { createWriteStream } from "fs";
4036
4042
  import { stat as stat4, writeFile as writeFile9 } from "fs/promises";
4037
- import { dirname as dirname8 } from "path";
4043
+ import { dirname as dirname9 } from "path";
4038
4044
  import archiver from "archiver";
4039
4045
  import {
4040
4046
  createDefaultRegistry as createDefaultRegistry3,
@@ -4042,7 +4048,7 @@ import {
4042
4048
  } from "@genart-dev/core";
4043
4049
  var registry4 = createDefaultRegistry3();
4044
4050
  async function validateOutputPath(outputPath) {
4045
- const parentDir = dirname8(outputPath);
4051
+ const parentDir = dirname9(outputPath);
4046
4052
  try {
4047
4053
  const s = await stat4(parentDir);
4048
4054
  if (!s.isDirectory()) {
@@ -5312,20 +5318,24 @@ async function initializePluginRegistry() {
5312
5318
  await registry5.register(tracePlugin);
5313
5319
  return registry5;
5314
5320
  }
5315
- function createServer(state) {
5321
+ function createServer(state, options) {
5322
+ const captureOnly = options?.captureOnly ?? false;
5316
5323
  const server = new McpServer(
5317
5324
  {
5318
- name: "@genart/mcp-server",
5325
+ name: captureOnly ? "@genart/mcp-capture" : "@genart/mcp-server",
5319
5326
  version: "0.4.0"
5320
5327
  },
5321
5328
  {
5322
5329
  capabilities: {
5323
5330
  tools: {},
5324
- resources: {},
5325
- prompts: {}
5331
+ ...!captureOnly && { resources: {}, prompts: {} }
5326
5332
  }
5327
5333
  }
5328
5334
  );
5335
+ if (captureOnly) {
5336
+ registerCaptureTools(server, state);
5337
+ return server;
5338
+ }
5329
5339
  const registryReady = initializePluginRegistry().then((registry5) => {
5330
5340
  state.pluginRegistry = registry5;
5331
5341
  registerPluginMcpTools(server, registry5, state);
@@ -5342,7 +5352,9 @@ function createServer(state) {
5342
5352
  registerSnapshotTools(server, state);
5343
5353
  registerKnowledgeTools(server, state);
5344
5354
  registerDesignTools(server, state);
5345
- registerCaptureTools(server, state);
5355
+ if (!state.remoteMode) {
5356
+ registerCaptureTools(server, state);
5357
+ }
5346
5358
  registerCritiqueTools(server, state);
5347
5359
  registerSeriesTools(server, state);
5348
5360
  registerReferenceTools(server, state);
@@ -5491,11 +5503,31 @@ function registerSketchTools(server, state) {
5491
5503
  ).optional().describe('Component dependencies. Use list_components to see available. Keys are component names, values are semver ranges (e.g. "^1.0.0") or objects with version/code/exports.'),
5492
5504
  addToWorkspace: z2.string().optional().describe("Path to workspace to add sketch to after creation"),
5493
5505
  agent: z2.string().optional().describe("Your CLI agent name (e.g. 'claude-code', 'codex-cli', 'gemini-cli', 'opencode', 'kiro')"),
5494
- model: z2.string().optional().describe("Your AI model identifier (e.g. 'claude-opus-4-6', 'gpt-4o', 'gemini-2.5-pro')")
5506
+ model: z2.string().optional().describe("Your AI model identifier (e.g. 'claude-opus-4-6', 'gpt-4o', 'gemini-2.5-pro')"),
5507
+ capture: z2.boolean().optional().describe("When true, automatically capture a screenshot after creation and return it inline (avoids a separate capture_screenshot call)")
5495
5508
  },
5496
5509
  async (args) => {
5497
5510
  try {
5498
5511
  const result = await createSketch(state, args);
5512
+ if (args.capture && !state.remoteMode) {
5513
+ try {
5514
+ const captureResult = await captureScreenshot(state, {
5515
+ target: "sketch",
5516
+ sketchId: args.id
5517
+ });
5518
+ return {
5519
+ content: [
5520
+ { type: "text", text: JSON.stringify({ ...result, capture: captureResult.metadata }, null, 2) },
5521
+ { type: "image", data: captureResult.previewJpegBase64, mimeType: "image/jpeg" }
5522
+ ]
5523
+ };
5524
+ } catch (captureErr) {
5525
+ return jsonResult({
5526
+ ...result,
5527
+ captureError: captureErr instanceof Error ? captureErr.message : String(captureErr)
5528
+ });
5529
+ }
5530
+ }
5499
5531
  return jsonResult(result);
5500
5532
  } catch (e) {
5501
5533
  return toolError(e instanceof Error ? e.message : String(e));
@@ -6052,7 +6084,7 @@ function registerSnapshotTools(server, state) {
6052
6084
  function registerCaptureTools(server, state) {
6053
6085
  server.tool(
6054
6086
  "capture_screenshot",
6055
- "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.",
6087
+ "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.",
6056
6088
  {
6057
6089
  target: z2.enum(["selected", "sketch"]).optional().describe("What to capture (default: selected)"),
6058
6090
  sketchId: z2.string().optional().describe("Required when target is 'sketch'"),
@@ -6714,14 +6746,17 @@ function registerKnowledgeTools(server, state) {
6714
6746
 
6715
6747
  // src/index.ts
6716
6748
  async function main() {
6717
- const sidecar = isSidecarMode();
6718
- if (sidecar) {
6749
+ const captureOnly = process.argv.includes("--capture-only");
6750
+ const sidecar = !captureOnly && isSidecarMode();
6751
+ if (captureOnly) {
6752
+ console.error("[genart-mcp] Starting in capture-only mode");
6753
+ } else if (sidecar) {
6719
6754
  console.error("[genart-mcp] Starting in sidecar mode");
6720
6755
  } else {
6721
6756
  console.error("[genart-mcp] Starting in stdio mode");
6722
6757
  }
6723
6758
  const state = new EditorState();
6724
- const server = createServer(state);
6759
+ const server = createServer(state, { captureOnly });
6725
6760
  const transport = new StdioServerTransport();
6726
6761
  await server.connect(transport);
6727
6762
  console.error("[genart-mcp] Server connected and ready");