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.
- package/dist/index.js +84 -5
- 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
|
|
421
|
-
const
|
|
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
|
-
|
|
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 {
|
|
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;
|