viewgate-mcp 1.0.47 → 1.0.49
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 +77 -63
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -53,6 +53,7 @@ function createMcpServer(apiKey, personalKey) {
|
|
|
53
53
|
step: 0,
|
|
54
54
|
startedAt: Date.now(),
|
|
55
55
|
lastActivityAt: Date.now(),
|
|
56
|
+
lockTokens: {},
|
|
56
57
|
};
|
|
57
58
|
function resetGuard() {
|
|
58
59
|
guard.flow = "idle";
|
|
@@ -60,6 +61,8 @@ function createMcpServer(apiKey, personalKey) {
|
|
|
60
61
|
guard.lastTool = undefined;
|
|
61
62
|
guard.startedAt = Date.now();
|
|
62
63
|
guard.lastActivityAt = Date.now();
|
|
64
|
+
guard.lockTokens = {};
|
|
65
|
+
guard.backlogVersion = undefined;
|
|
63
66
|
}
|
|
64
67
|
function getToolFlow(toolName) {
|
|
65
68
|
switch (toolName) {
|
|
@@ -68,7 +71,6 @@ function createMcpServer(apiKey, personalKey) {
|
|
|
68
71
|
case "mark_ui_component_generated":
|
|
69
72
|
return "ui_components";
|
|
70
73
|
case "get_annotations":
|
|
71
|
-
case "mark_annotation_ready":
|
|
72
74
|
case "mark_annotations_as_live":
|
|
73
75
|
return "annotations";
|
|
74
76
|
case "get_ui_improvements":
|
|
@@ -124,10 +126,13 @@ function createMcpServer(apiKey, personalKey) {
|
|
|
124
126
|
break;
|
|
125
127
|
default:
|
|
126
128
|
if (guard.flow === "idle") {
|
|
127
|
-
throw new Error(
|
|
129
|
+
throw new Error(`TOOL_CALL_BLOCKED: tool '${toolName}' not allowed in idle. Please start a workflow with 'get_annotations', 'get_ui_components', or 'get_ui_improvements'.`);
|
|
128
130
|
}
|
|
129
131
|
else {
|
|
130
|
-
|
|
132
|
+
const nextTool = guard.flow === "annotations" ? "mark_annotations_as_live" :
|
|
133
|
+
guard.flow === "ui_components" ? "mark_ui_component_generated" :
|
|
134
|
+
guard.flow === "ui_improvements" ? "mark_annotations_as_live" : "the next workflow step";
|
|
135
|
+
throw new Error(`TOOL_CALL_BLOCKED: tool '${toolName}' not allowed while in '${guard.flow}' workflow. You must call '${nextTool}' to complete the current task before starting another.`);
|
|
131
136
|
}
|
|
132
137
|
}
|
|
133
138
|
guard.startedAt = now;
|
|
@@ -160,16 +165,12 @@ function createMcpServer(apiKey, personalKey) {
|
|
|
160
165
|
// Allow re-fetching at any time during the flow
|
|
161
166
|
guard.step = 1;
|
|
162
167
|
}
|
|
163
|
-
else if (toolName === "
|
|
168
|
+
else if (toolName === "mark_annotations_as_live") {
|
|
164
169
|
if (guard.step !== 1)
|
|
165
170
|
throw new Error("TOOL_CALL_BLOCKED: unexpected step");
|
|
166
171
|
// Stop here and reset flow as per USER_REQUEST (MCP only reaches 'applied')
|
|
167
172
|
resetGuard();
|
|
168
173
|
}
|
|
169
|
-
else if (toolName === "mark_annotations_as_live") {
|
|
170
|
-
// Optional step if the model decides to use it, but no longer part of the required chain
|
|
171
|
-
resetGuard();
|
|
172
|
-
}
|
|
173
174
|
else {
|
|
174
175
|
throw new Error("TOOL_CALL_BLOCKED: tool not allowed in active flow");
|
|
175
176
|
}
|
|
@@ -178,14 +179,11 @@ function createMcpServer(apiKey, personalKey) {
|
|
|
178
179
|
if (toolName === "get_ui_improvements") {
|
|
179
180
|
guard.step = 1;
|
|
180
181
|
}
|
|
181
|
-
else if (toolName === "
|
|
182
|
+
else if (toolName === "mark_annotations_as_live") {
|
|
182
183
|
if (guard.step !== 1)
|
|
183
184
|
throw new Error("TOOL_CALL_BLOCKED: unexpected step");
|
|
184
185
|
resetGuard();
|
|
185
186
|
}
|
|
186
|
-
else if (toolName === "mark_annotations_as_live") {
|
|
187
|
-
resetGuard();
|
|
188
|
-
}
|
|
189
187
|
else {
|
|
190
188
|
throw new Error("TOOL_CALL_BLOCKED: tool not allowed in active flow");
|
|
191
189
|
}
|
|
@@ -290,8 +288,8 @@ function createMcpServer(apiKey, personalKey) {
|
|
|
290
288
|
},
|
|
291
289
|
},
|
|
292
290
|
{
|
|
293
|
-
name: "
|
|
294
|
-
description: "Mark as
|
|
291
|
+
name: "mark_annotations_as_live",
|
|
292
|
+
description: "Mark tickets (functional or UI/UX) as applied. Use this tool after fixing the code to submit your changes. IMPORTANT: appliedChanges must be in the project's preferredLanguage (e.g. SPANISH).",
|
|
295
293
|
inputSchema: {
|
|
296
294
|
type: "object",
|
|
297
295
|
properties: {
|
|
@@ -310,21 +308,6 @@ function createMcpServer(apiKey, personalKey) {
|
|
|
310
308
|
required: ["results"]
|
|
311
309
|
},
|
|
312
310
|
},
|
|
313
|
-
{
|
|
314
|
-
name: "mark_annotations_as_live",
|
|
315
|
-
description: "Mark as live (ready_for_review). IDs required.",
|
|
316
|
-
inputSchema: {
|
|
317
|
-
type: "object",
|
|
318
|
-
properties: {
|
|
319
|
-
ids: {
|
|
320
|
-
type: "array",
|
|
321
|
-
items: { type: "string" },
|
|
322
|
-
description: "Internal IDs."
|
|
323
|
-
}
|
|
324
|
-
},
|
|
325
|
-
required: ["ids"]
|
|
326
|
-
},
|
|
327
|
-
},
|
|
328
311
|
{
|
|
329
312
|
name: "planning",
|
|
330
313
|
description: "Planning tool for backlog tickets. Fetch tickets or submit analysis. IMPORTANT: aiAnalysis must be in the project's preferredLanguage (e.g. SPANISH).",
|
|
@@ -553,7 +536,13 @@ function createMcpServer(apiKey, personalKey) {
|
|
|
553
536
|
if (!Array.isArray(rawAnnotations)) {
|
|
554
537
|
return { content: [{ type: "text", text: "Error: Invalid format from backend" }], isError: true };
|
|
555
538
|
}
|
|
556
|
-
|
|
539
|
+
// Point: Lease Collection | Store lockTokens in the session guard
|
|
540
|
+
rawAnnotations.forEach((ann) => {
|
|
541
|
+
if (ann._id && ann.lockToken) {
|
|
542
|
+
guard.lockTokens[ann._id] = ann.lockToken;
|
|
543
|
+
}
|
|
544
|
+
});
|
|
545
|
+
console.error(`[MCP] Received ${rawAnnotations.length} annotations. Tokens stored: ${Object.keys(guard.lockTokens).length}`);
|
|
557
546
|
// Local filtering fallback (for older backend versions or additional client-side safety)
|
|
558
547
|
if (search) {
|
|
559
548
|
const lowSearch = search.toLowerCase();
|
|
@@ -608,6 +597,12 @@ Endpoints: ${ann.backendEndpoints?.length ? ann.backendEndpoints.join(', ') : 'N
|
|
|
608
597
|
Feedback previo: ${ann.corrections && Array.isArray(ann.corrections) && ann.corrections.length > 0 ? ann.corrections[ann.corrections.length - 1].text : 'Ninguno'}
|
|
609
598
|
Tarea: ${ann.message}
|
|
610
599
|
Lang: ${rawData.preferredLanguage === 'es' ? 'ES' : 'EN'}
|
|
600
|
+
|
|
601
|
+
### FLUJO DE TRABAJO OBLIGATORIO ###
|
|
602
|
+
1. Analiza el código y el problema.
|
|
603
|
+
2. Aplica la solución técnica necesaria.
|
|
604
|
+
3. AL TERMINAR, DEBES LLAMAR A 'mark_annotations_as_live' con el id '${ann._id}' y un resumen de tus cambios en 'appliedChanges' (en ESPAÑOL).
|
|
605
|
+
4. El estado final del ticket será 'applied'. NO intentes usar otros estados o herramientas hasta completar este paso.
|
|
611
606
|
(RECUERDA: Toda tu respuesta, comentarios y análisis DEBEN estar en ESPAÑOL)`
|
|
612
607
|
};
|
|
613
608
|
});
|
|
@@ -618,10 +613,10 @@ Lang: ${rawData.preferredLanguage === 'es' ? 'ES' : 'EN'}
|
|
|
618
613
|
content: [{ type: "text", text: langHint + JSON.stringify({ preferredLanguage: rawData.preferredLanguage || 'en', annotations: annotationsWithTips }, null, 2) }],
|
|
619
614
|
};
|
|
620
615
|
}
|
|
621
|
-
case "
|
|
616
|
+
case "mark_annotations_as_live": {
|
|
622
617
|
const args = argsAny;
|
|
623
618
|
const results = args.results;
|
|
624
|
-
console.error(`[
|
|
619
|
+
console.error(`[mark_annotations_as_live] Submitting results for ${results?.length} items as applied`);
|
|
625
620
|
const response = await fetch(`${BACKEND_URL}/api/mcp/annotations/batch-ready`, {
|
|
626
621
|
method: 'PATCH',
|
|
627
622
|
headers: {
|
|
@@ -631,7 +626,11 @@ Lang: ${rawData.preferredLanguage === 'es' ? 'ES' : 'EN'}
|
|
|
631
626
|
'x-personal-key': personalKey || ''
|
|
632
627
|
},
|
|
633
628
|
body: JSON.stringify({
|
|
634
|
-
results: results.map((r) => ({
|
|
629
|
+
results: results.map((r) => ({
|
|
630
|
+
...r,
|
|
631
|
+
status: 'applied',
|
|
632
|
+
lockToken: guard.lockTokens[r.id] // Attach the session-locked token
|
|
633
|
+
}))
|
|
635
634
|
})
|
|
636
635
|
});
|
|
637
636
|
if (!response.ok)
|
|
@@ -641,27 +640,6 @@ Lang: ${rawData.preferredLanguage === 'es' ? 'ES' : 'EN'}
|
|
|
641
640
|
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
642
641
|
};
|
|
643
642
|
}
|
|
644
|
-
case "mark_annotations_as_live": {
|
|
645
|
-
const args = argsAny;
|
|
646
|
-
const ids = args.ids;
|
|
647
|
-
console.error(`[mark_annotations_as_live] Marking ${ids?.length} items as live`);
|
|
648
|
-
const response = await fetch(`${BACKEND_URL}/api/mcp/annotations/mark-as-live`, {
|
|
649
|
-
method: 'POST',
|
|
650
|
-
headers: {
|
|
651
|
-
'Content-Type': 'application/json',
|
|
652
|
-
'x-api-key': apiKey,
|
|
653
|
-
'x-mcp-tool-name': toolName,
|
|
654
|
-
'x-personal-key': personalKey || ''
|
|
655
|
-
},
|
|
656
|
-
body: JSON.stringify({ ids })
|
|
657
|
-
});
|
|
658
|
-
if (!response.ok)
|
|
659
|
-
throw new Error(`Backend responded with ${response.status}`);
|
|
660
|
-
const data = (await response.json());
|
|
661
|
-
return {
|
|
662
|
-
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
663
|
-
};
|
|
664
|
-
}
|
|
665
643
|
case "planning": {
|
|
666
644
|
const args = argsAny;
|
|
667
645
|
const url = args.results ? `${BACKEND_URL}/api/mcp/annotations/batch-planning` : `${BACKEND_URL}/api/mcp/backlog`;
|
|
@@ -669,11 +647,18 @@ Lang: ${rawData.preferredLanguage === 'es' ? 'ES' : 'EN'}
|
|
|
669
647
|
const response = await fetch(url, {
|
|
670
648
|
method,
|
|
671
649
|
headers: { 'Content-Type': 'application/json', 'x-api-key': apiKey, 'x-mcp-tool-name': toolName, ...(personalKey ? { 'x-personal-key': personalKey } : {}) },
|
|
672
|
-
body: args.results ? JSON.stringify({
|
|
650
|
+
body: args.results ? JSON.stringify({
|
|
651
|
+
results: args.results,
|
|
652
|
+
force: args.force,
|
|
653
|
+
backlogVersion: guard.backlogVersion
|
|
654
|
+
}) : undefined
|
|
673
655
|
});
|
|
674
656
|
if (!response.ok)
|
|
675
657
|
throw new Error(`Backend responded with ${response.status}`);
|
|
676
658
|
const data = (await response.json());
|
|
659
|
+
// Point: Version Storing
|
|
660
|
+
if (data.backlogVersion)
|
|
661
|
+
guard.backlogVersion = data.backlogVersion;
|
|
677
662
|
const langHint = data.preferredLanguage === 'es'
|
|
678
663
|
? "\n*** [INSTRUCTION: Project is in SPANISH. Provide all comments, appliedChanges, and aiAnalysis in SPANISH ONLY.] ***\n\n\n\n"
|
|
679
664
|
: (data.preferredLanguage === 'en' ? "\n*** [INSTRUCTION: Provide all comments and analysis in English.] ***\n\n\n\n" : "");
|
|
@@ -681,6 +666,7 @@ Lang: ${rawData.preferredLanguage === 'es' ? 'ES' : 'EN'}
|
|
|
681
666
|
}
|
|
682
667
|
case "get_ui_improvements": {
|
|
683
668
|
const args = argsAny;
|
|
669
|
+
const agentId = personalKey || 'mcp-agent-ui-' + (apiKey?.slice(-6) || 'generic');
|
|
684
670
|
const fetchUrl = new URL(`${BACKEND_URL}/api/mcp/ui-improvements`);
|
|
685
671
|
if (args.limit)
|
|
686
672
|
fetchUrl.searchParams.append("limit", args.limit.toString());
|
|
@@ -690,6 +676,10 @@ Lang: ${rawData.preferredLanguage === 'es' ? 'ES' : 'EN'}
|
|
|
690
676
|
fetchUrl.searchParams.append("key", args.key);
|
|
691
677
|
if (args.ids)
|
|
692
678
|
fetchUrl.searchParams.append("ids", args.ids);
|
|
679
|
+
// Add lock and agentId parameters to enable blocking flow
|
|
680
|
+
fetchUrl.searchParams.append("lock", "true");
|
|
681
|
+
fetchUrl.searchParams.append("agentId", agentId);
|
|
682
|
+
console.error(`[get_ui_improvements] Fetching with lock: ${fetchUrl.toString()}`);
|
|
693
683
|
const response = await fetch(fetchUrl, {
|
|
694
684
|
headers: {
|
|
695
685
|
'x-api-key': apiKey,
|
|
@@ -697,15 +687,39 @@ Lang: ${rawData.preferredLanguage === 'es' ? 'ES' : 'EN'}
|
|
|
697
687
|
...(personalKey ? { 'x-personal-key': personalKey } : {})
|
|
698
688
|
}
|
|
699
689
|
});
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
690
|
+
const rawData = (await response.json());
|
|
691
|
+
let rawImprovements = Array.isArray(rawData) ? rawData : (rawData?.data || rawData?.improvements || []);
|
|
692
|
+
if (!Array.isArray(rawImprovements)) {
|
|
693
|
+
return { content: [{ type: "text", text: "Error: Invalid format from backend" }], isError: true };
|
|
703
694
|
}
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
695
|
+
// Point: Lease Collection UI | Store lockTokens for UI tickets
|
|
696
|
+
rawImprovements.forEach((ann) => {
|
|
697
|
+
if (ann._id && ann.lockToken) {
|
|
698
|
+
guard.lockTokens[ann._id] = ann.lockToken;
|
|
699
|
+
}
|
|
700
|
+
});
|
|
701
|
+
const improvementsWithTips = rawImprovements.map((ann) => {
|
|
702
|
+
return {
|
|
703
|
+
...ann,
|
|
704
|
+
_ia_fix_instruction: `### INSTRUCCIONES PARA LA IA (MEJORA UI - IMPORTANTE) ###
|
|
705
|
+
A continuación se presenta un ticket de MEJORA VISUAL/UX que requiere tu atención.
|
|
706
|
+
DEBES RESPONDER EN ESPAÑOL.
|
|
707
|
+
Proyecto: ${rawData.name || 'ViewGate'}
|
|
708
|
+
Tarea: ${ann.message}
|
|
709
|
+
Lang: ${rawData.preferredLanguage === 'es' ? 'ES' : 'EN'}
|
|
710
|
+
|
|
711
|
+
### FLUJO DE TRABAJO OBLIGATORIO ###
|
|
712
|
+
1. Analiza el diseño y los estilos CSS actuales.
|
|
713
|
+
2. Aplica los cambios visuales solicitados (STRICTLY LIMITED TO VISUAL/CSS CHANGES).
|
|
714
|
+
3. AL TERMINAR, DEBES LLAMAR A 'mark_annotations_as_live' con el id '${ann._id}' y un resumen de tus cambios en 'appliedChanges' (en ESPAÑOL).
|
|
715
|
+
4. El estado final del ticket será 'applied'. NO intentes usar otros estados o herramientas hasta completar este paso.
|
|
716
|
+
(RECUERDA: Toda tu respuesta, comentarios y análisis DEBEN estar en ESPAÑOL)`
|
|
717
|
+
};
|
|
718
|
+
});
|
|
719
|
+
const langHint = rawData.preferredLanguage === 'es'
|
|
720
|
+
? "\n*** [INSTRUCTION: Project is in SPANISH. Provide all comments and changes in SPANISH ONLY.] ***\n\n"
|
|
721
|
+
: (rawData.preferredLanguage === 'en' ? "\n*** [INSTRUCTION: Provide all comments and analysis in English.] ***\n\n" : "");
|
|
722
|
+
return { content: [{ type: "text", text: langHint + JSON.stringify({ preferredLanguage: rawData.preferredLanguage || 'en', improvements: improvementsWithTips }, null, 2) }] };
|
|
709
723
|
}
|
|
710
724
|
case "sync_endpoints": {
|
|
711
725
|
const args = argsAny;
|