viewgate-mcp 1.0.40 → 1.0.42

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.
Files changed (2) hide show
  1. package/dist/index.js +84 -5
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -366,6 +366,70 @@ function createMcpServer(apiKey, personalKey) {
366
366
  const text = `${safeTitle}${list ? ' — ' + list : ''}`;
367
367
  return `<?xml version="1.0" encoding="UTF-8"?>\n<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="420">\n <defs>\n <linearGradient id="g" x1="0" y1="0" x2="1" y2="1">\n <stop offset="0" stop-color="#0f172a"/>\n <stop offset="1" stop-color="#111827"/>\n </linearGradient>\n </defs>\n <rect width="1200" height="420" rx="32" fill="url(#g)"/>\n <rect x="40" y="40" width="1120" height="340" rx="28" fill="#0b1220" stroke="rgba(255,255,255,0.08)"/>\n <text x="80" y="150" font-family="Inter,ui-sans-serif,system-ui" font-size="46" font-weight="800" fill="#e2e8f0">${safeTitle}</text>\n <text x="80" y="220" font-family="ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace" font-size="22" font-weight="700" fill="#94a3b8">Preview (fast)</text>\n <text x="80" y="280" font-family="Inter,ui-sans-serif,system-ui" font-size="18" font-weight="600" fill="#64748b">${text}</text>\n</svg>`;
368
368
  };
369
+ const buildDefaultProps = (propNames) => {
370
+ const defaults = {};
371
+ for (const p of propNames || []) {
372
+ if (!p)
373
+ continue;
374
+ const name = String(p);
375
+ if (name === 'disabled' || name === 'loading' || name === 'fullWidth') {
376
+ defaults[name] = false;
377
+ continue;
378
+ }
379
+ if (name === 'variant') {
380
+ defaults[name] = 'primary';
381
+ continue;
382
+ }
383
+ if (name === 'size') {
384
+ defaults[name] = 'md';
385
+ continue;
386
+ }
387
+ if (name === 'type') {
388
+ defaults[name] = 'button';
389
+ continue;
390
+ }
391
+ if (name === 'href') {
392
+ defaults[name] = '#';
393
+ continue;
394
+ }
395
+ if (name.toLowerCase().startsWith('on')) {
396
+ defaults[name] = null;
397
+ continue;
398
+ }
399
+ if (name === 'iconLeft' || name === 'iconRight') {
400
+ defaults[name] = null;
401
+ continue;
402
+ }
403
+ // Fallback
404
+ defaults[name] = '';
405
+ }
406
+ return defaults;
407
+ };
408
+ const buildComponentCode = (componentType, requiredProps) => {
409
+ const safeName = toPascalCase(componentType) || 'Component';
410
+ const props = (requiredProps || []).filter(Boolean);
411
+ const destructure = props.length > 0 ? `{ ${props.join(', ')} }` : 'props';
412
+ // IMPORTANT: This code is executed inside a browser ESM module where React is already imported.
413
+ // Avoid JSX to keep it runnable without a build step.
414
+ const lines = [];
415
+ lines.push(`const ${safeName} = (${destructure}) => {`);
416
+ lines.push(` return React.createElement(`);
417
+ lines.push(` "div",`);
418
+ lines.push(` { style: { fontFamily: 'ui-sans-serif, system-ui', padding: 12 } },`);
419
+ lines.push(` React.createElement(`);
420
+ lines.push(` "div",`);
421
+ lines.push(` { style: { fontSize: 14, fontWeight: 700, marginBottom: 8 } },`);
422
+ lines.push(` ${JSON.stringify(safeName)}
423
+ ),`);
424
+ lines.push(` React.createElement(`);
425
+ lines.push(` "pre",`);
426
+ lines.push(` { style: { fontSize: 12, opacity: 0.8, whiteSpace: 'pre-wrap' } },`);
427
+ lines.push(` JSON.stringify({ ${props.join(', ')} }, null, 2)
428
+ )`);
429
+ lines.push(` );`);
430
+ lines.push(`};`);
431
+ return { exportName: safeName, code: lines.join('\n') };
432
+ };
369
433
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
370
434
  const toolName = request.params.name;
371
435
  console.error(`[MCP] Handling tool call: ${toolName}`);
@@ -394,6 +458,7 @@ function createMcpServer(apiKey, personalKey) {
394
458
  case "generate_ui_components": {
395
459
  const args = request.params.arguments;
396
460
  const limit = Math.min(args.limit || 1, 10);
461
+ const targetComponentsDir = await resolveComponentsDir();
397
462
  const fetchUrl = new URL(`${BACKEND_URL}/api/mcp/components`);
398
463
  fetchUrl.searchParams.append("limit", limit.toString());
399
464
  fetchUrl.searchParams.append("status", "pending");
@@ -417,8 +482,8 @@ function createMcpServer(apiKey, personalKey) {
417
482
  const componentType = item.componentType;
418
483
  const requiredProps = (item.requiredProps || []);
419
484
  const commonProps = (item.commonProps || []);
420
- const model = buildPropModel(commonProps, requiredProps);
421
- const fileInfo = await writeComponentFile(componentType, model);
485
+ const defaults = buildDefaultProps(requiredProps);
486
+ const built = buildComponentCode(componentType, requiredProps);
422
487
  // Fast preview generation (SVG placeholder) + upload
423
488
  const svg = makePreviewSvg(componentType, requiredProps);
424
489
  const svg64 = Buffer.from(svg, 'utf8').toString('base64');
@@ -445,7 +510,7 @@ function createMcpServer(apiKey, personalKey) {
445
510
  'x-api-key': apiKey,
446
511
  ...(personalKey ? { 'x-personal-key': personalKey } : {})
447
512
  },
448
- body: JSON.stringify({ previewImage: previewUrl })
513
+ body: JSON.stringify({ previewImage: previewUrl, code: built.code, props: defaults })
449
514
  });
450
515
  if (!markResp.ok) {
451
516
  const errorBody = await markResp.text();
@@ -456,12 +521,26 @@ function createMcpServer(apiKey, personalKey) {
456
521
  componentType,
457
522
  figmaUrl: item.figmaUrl,
458
523
  requiredProps,
459
- written: fileInfo,
524
+ target: {
525
+ componentsDir: targetComponentsDir,
526
+ suggestedFileName: `${toPascalCase(componentType) || 'Component'}.jsx`
527
+ },
460
528
  previewImage: previewUrl,
461
529
  db: marked?.data?._id || item._id
462
530
  });
463
531
  }
464
- return { content: [{ type: "text", text: JSON.stringify({ ok: true, generated: results.length, results }, null, 2) }] };
532
+ return {
533
+ content: [{
534
+ type: "text",
535
+ text: JSON.stringify({
536
+ ok: true,
537
+ generated: results.length,
538
+ instruction: `IMPORTANTE: Generar/guardar el componente React real dentro del proyecto frontend detectado. Ruta objetivo sugerida: ${targetComponentsDir}. No escribir en rutas globales del editor.`,
539
+ targetComponentsDir,
540
+ results
541
+ }, null, 2)
542
+ }]
543
+ };
465
544
  }
466
545
  case "get_annotations": {
467
546
  const args = request.params.arguments;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "viewgate-mcp",
3
- "version": "1.0.40",
3
+ "version": "1.0.42",
4
4
  "main": "dist/index.js",
5
5
  "bin": {
6
6
  "viewgate-mcp": "./dist/index.js"