viewgate-mcp 1.0.43 → 1.0.45
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 +247 -13
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -46,6 +46,187 @@ function createMcpServer(apiKey, personalKey) {
|
|
|
46
46
|
tools: {},
|
|
47
47
|
},
|
|
48
48
|
});
|
|
49
|
+
const FLOW_TTL_MS = 10 * 60 * 1000;
|
|
50
|
+
const guard = {
|
|
51
|
+
flow: "idle",
|
|
52
|
+
step: 0,
|
|
53
|
+
startedAt: Date.now(),
|
|
54
|
+
lastActivityAt: Date.now(),
|
|
55
|
+
};
|
|
56
|
+
function resetGuard() {
|
|
57
|
+
guard.flow = "idle";
|
|
58
|
+
guard.step = 0;
|
|
59
|
+
guard.lastTool = undefined;
|
|
60
|
+
guard.startedAt = Date.now();
|
|
61
|
+
guard.lastActivityAt = Date.now();
|
|
62
|
+
}
|
|
63
|
+
function getToolFlow(toolName) {
|
|
64
|
+
switch (toolName) {
|
|
65
|
+
case "get_ui_components":
|
|
66
|
+
case "generate_ui_components":
|
|
67
|
+
case "mark_ui_component_generated":
|
|
68
|
+
return "ui_components";
|
|
69
|
+
case "get_annotations":
|
|
70
|
+
case "mark_annotation_ready":
|
|
71
|
+
case "mark_annotations_as_live":
|
|
72
|
+
return "annotations";
|
|
73
|
+
case "get_ui_improvements":
|
|
74
|
+
return "ui_improvements";
|
|
75
|
+
case "planning":
|
|
76
|
+
return "planning";
|
|
77
|
+
case "sync_endpoints":
|
|
78
|
+
case "get_synced_endpoints":
|
|
79
|
+
return "sync";
|
|
80
|
+
case "get_ai_resolved_tickets":
|
|
81
|
+
return "idle";
|
|
82
|
+
default:
|
|
83
|
+
return "idle";
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function enforceWorkflow(toolName, args) {
|
|
87
|
+
const now = Date.now();
|
|
88
|
+
if (guard.flow !== "idle" && now - guard.lastActivityAt > FLOW_TTL_MS) {
|
|
89
|
+
resetGuard();
|
|
90
|
+
}
|
|
91
|
+
const desiredFlow = getToolFlow(toolName);
|
|
92
|
+
if (toolName === "get_ai_resolved_tickets") {
|
|
93
|
+
if (guard.flow !== "idle") {
|
|
94
|
+
throw new Error("TOOL_CALL_BLOCKED: tool not allowed in active flow");
|
|
95
|
+
}
|
|
96
|
+
guard.lastTool = toolName;
|
|
97
|
+
guard.lastActivityAt = now;
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (guard.flow === "idle") {
|
|
101
|
+
switch (toolName) {
|
|
102
|
+
case "get_ui_components":
|
|
103
|
+
guard.flow = "ui_components";
|
|
104
|
+
guard.step = 1;
|
|
105
|
+
break;
|
|
106
|
+
case "get_annotations":
|
|
107
|
+
guard.flow = "annotations";
|
|
108
|
+
guard.step = 1;
|
|
109
|
+
break;
|
|
110
|
+
case "get_ui_improvements":
|
|
111
|
+
guard.flow = "ui_improvements";
|
|
112
|
+
guard.step = 1;
|
|
113
|
+
break;
|
|
114
|
+
case "planning":
|
|
115
|
+
if (args?.results) {
|
|
116
|
+
throw new Error("TOOL_CALL_BLOCKED: planning submit requires prior fetch");
|
|
117
|
+
}
|
|
118
|
+
guard.flow = "planning";
|
|
119
|
+
guard.step = 1;
|
|
120
|
+
break;
|
|
121
|
+
case "sync_endpoints":
|
|
122
|
+
guard.flow = "sync";
|
|
123
|
+
guard.step = 1;
|
|
124
|
+
break;
|
|
125
|
+
default:
|
|
126
|
+
throw new Error("TOOL_CALL_BLOCKED: tool not allowed in idle");
|
|
127
|
+
}
|
|
128
|
+
guard.startedAt = now;
|
|
129
|
+
guard.lastTool = toolName;
|
|
130
|
+
guard.lastActivityAt = now;
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
if (desiredFlow !== guard.flow) {
|
|
134
|
+
throw new Error("TOOL_CALL_BLOCKED: tool not allowed in active flow");
|
|
135
|
+
}
|
|
136
|
+
if (guard.flow === "ui_components") {
|
|
137
|
+
if (toolName === "get_ui_components") {
|
|
138
|
+
if (guard.step > 2)
|
|
139
|
+
throw new Error("TOOL_CALL_BLOCKED: cannot restart flow at this step");
|
|
140
|
+
guard.step = 1;
|
|
141
|
+
}
|
|
142
|
+
else if (toolName === "generate_ui_components") {
|
|
143
|
+
if (guard.step !== 1)
|
|
144
|
+
throw new Error("TOOL_CALL_BLOCKED: unexpected step");
|
|
145
|
+
guard.step = 2;
|
|
146
|
+
}
|
|
147
|
+
else if (toolName === "mark_ui_component_generated") {
|
|
148
|
+
if (guard.step !== 2)
|
|
149
|
+
throw new Error("TOOL_CALL_BLOCKED: unexpected step");
|
|
150
|
+
resetGuard();
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
throw new Error("TOOL_CALL_BLOCKED: tool not allowed in active flow");
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
else if (guard.flow === "annotations") {
|
|
157
|
+
if (toolName === "get_annotations") {
|
|
158
|
+
if (guard.step > 2)
|
|
159
|
+
throw new Error("TOOL_CALL_BLOCKED: cannot restart flow at this step");
|
|
160
|
+
guard.step = 1;
|
|
161
|
+
}
|
|
162
|
+
else if (toolName === "mark_annotation_ready") {
|
|
163
|
+
if (guard.step !== 1)
|
|
164
|
+
throw new Error("TOOL_CALL_BLOCKED: unexpected step");
|
|
165
|
+
guard.step = 2;
|
|
166
|
+
}
|
|
167
|
+
else if (toolName === "mark_annotations_as_live") {
|
|
168
|
+
if (guard.step !== 2)
|
|
169
|
+
throw new Error("TOOL_CALL_BLOCKED: unexpected step");
|
|
170
|
+
resetGuard();
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
throw new Error("TOOL_CALL_BLOCKED: tool not allowed in active flow");
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
else if (guard.flow === "ui_improvements") {
|
|
177
|
+
if (toolName === "get_ui_improvements") {
|
|
178
|
+
if (guard.step > 2)
|
|
179
|
+
throw new Error("TOOL_CALL_BLOCKED: cannot restart flow at this step");
|
|
180
|
+
guard.step = 1;
|
|
181
|
+
}
|
|
182
|
+
else if (toolName === "mark_annotation_ready") {
|
|
183
|
+
if (guard.step !== 1)
|
|
184
|
+
throw new Error("TOOL_CALL_BLOCKED: unexpected step");
|
|
185
|
+
guard.step = 2;
|
|
186
|
+
}
|
|
187
|
+
else if (toolName === "mark_annotations_as_live") {
|
|
188
|
+
if (guard.step !== 2)
|
|
189
|
+
throw new Error("TOOL_CALL_BLOCKED: unexpected step");
|
|
190
|
+
resetGuard();
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
throw new Error("TOOL_CALL_BLOCKED: tool not allowed in active flow");
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
else if (guard.flow === "planning") {
|
|
197
|
+
if (toolName !== "planning") {
|
|
198
|
+
throw new Error("TOOL_CALL_BLOCKED: tool not allowed in active flow");
|
|
199
|
+
}
|
|
200
|
+
const isSubmit = Array.isArray(args?.results);
|
|
201
|
+
if (!isSubmit) {
|
|
202
|
+
if (guard.step !== 1)
|
|
203
|
+
throw new Error("TOOL_CALL_BLOCKED: unexpected step");
|
|
204
|
+
guard.step = 1;
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
if (guard.step !== 1)
|
|
208
|
+
throw new Error("TOOL_CALL_BLOCKED: unexpected step");
|
|
209
|
+
resetGuard();
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
else if (guard.flow === "sync") {
|
|
213
|
+
if (toolName === "sync_endpoints") {
|
|
214
|
+
if (guard.step !== 1)
|
|
215
|
+
throw new Error("TOOL_CALL_BLOCKED: unexpected step");
|
|
216
|
+
guard.step = 2;
|
|
217
|
+
}
|
|
218
|
+
else if (toolName === "get_synced_endpoints") {
|
|
219
|
+
if (guard.step !== 2)
|
|
220
|
+
throw new Error("TOOL_CALL_BLOCKED: unexpected step");
|
|
221
|
+
resetGuard();
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
throw new Error("TOOL_CALL_BLOCKED: tool not allowed in active flow");
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
guard.lastTool = toolName;
|
|
228
|
+
guard.lastActivityAt = now;
|
|
229
|
+
}
|
|
49
230
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
50
231
|
return {
|
|
51
232
|
tools: [
|
|
@@ -62,7 +243,7 @@ function createMcpServer(apiKey, personalKey) {
|
|
|
62
243
|
},
|
|
63
244
|
{
|
|
64
245
|
name: "generate_ui_components",
|
|
65
|
-
description: "
|
|
246
|
+
description: "Fetch pending UI component specs and return clear instructions for the LLM to implement a real, functional component. Does not write files, upload previews, or mark components as generated.",
|
|
66
247
|
inputSchema: {
|
|
67
248
|
type: "object",
|
|
68
249
|
properties: {
|
|
@@ -99,6 +280,19 @@ function createMcpServer(apiKey, personalKey) {
|
|
|
99
280
|
},
|
|
100
281
|
},
|
|
101
282
|
},
|
|
283
|
+
{
|
|
284
|
+
name: "get_ui_improvements",
|
|
285
|
+
description: "Fetch pending UI/UX improvement tickets. STRICTLY LIMITED TO VISUAL/CSS CHANGES. Do not add functional logic or modify backend integrations.",
|
|
286
|
+
inputSchema: {
|
|
287
|
+
type: "object",
|
|
288
|
+
properties: {
|
|
289
|
+
limit: { type: "number", description: "Max results.", default: 5 },
|
|
290
|
+
search: { type: "string", description: "Search message/file." },
|
|
291
|
+
key: { type: "string", description: "VG-XXXX key." },
|
|
292
|
+
ids: { type: "string", description: "Internal IDs." }
|
|
293
|
+
},
|
|
294
|
+
},
|
|
295
|
+
},
|
|
102
296
|
{
|
|
103
297
|
name: "mark_annotation_ready",
|
|
104
298
|
description: "Mark as ready/applied. Use internal IDs. IMPORTANT: appliedChanges must be in the project's preferredLanguage (e.g. SPANISH).",
|
|
@@ -203,10 +397,12 @@ function createMcpServer(apiKey, personalKey) {
|
|
|
203
397
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
204
398
|
const toolName = request.params.name;
|
|
205
399
|
console.error(`[MCP] Handling tool call: ${toolName}`);
|
|
400
|
+
const argsAny = request.params.arguments;
|
|
206
401
|
try {
|
|
402
|
+
enforceWorkflow(toolName, argsAny);
|
|
207
403
|
switch (toolName) {
|
|
208
404
|
case "get_ui_components": {
|
|
209
|
-
const args =
|
|
405
|
+
const args = argsAny;
|
|
210
406
|
const limit = args.limit || 1;
|
|
211
407
|
const status = args.status || 'pending';
|
|
212
408
|
const fetchUrl = new URL(`${BACKEND_URL}/api/mcp/components`);
|
|
@@ -215,6 +411,7 @@ function createMcpServer(apiKey, personalKey) {
|
|
|
215
411
|
const response = await fetch(fetchUrl, {
|
|
216
412
|
headers: {
|
|
217
413
|
'x-api-key': apiKey,
|
|
414
|
+
'x-mcp-tool-name': toolName,
|
|
218
415
|
...(personalKey ? { 'x-personal-key': personalKey } : {})
|
|
219
416
|
}
|
|
220
417
|
});
|
|
@@ -226,7 +423,7 @@ function createMcpServer(apiKey, personalKey) {
|
|
|
226
423
|
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
227
424
|
}
|
|
228
425
|
case "generate_ui_components": {
|
|
229
|
-
const args =
|
|
426
|
+
const args = argsAny;
|
|
230
427
|
const limit = Math.min(args.limit || 1, 10);
|
|
231
428
|
const fetchUrl = new URL(`${BACKEND_URL}/api/mcp/components`);
|
|
232
429
|
fetchUrl.searchParams.append("limit", limit.toString());
|
|
@@ -234,6 +431,7 @@ function createMcpServer(apiKey, personalKey) {
|
|
|
234
431
|
const response = await fetch(fetchUrl, {
|
|
235
432
|
headers: {
|
|
236
433
|
'x-api-key': apiKey,
|
|
434
|
+
'x-mcp-tool-name': toolName,
|
|
237
435
|
...(personalKey ? { 'x-personal-key': personalKey } : {})
|
|
238
436
|
}
|
|
239
437
|
});
|
|
@@ -256,11 +454,15 @@ function createMcpServer(apiKey, personalKey) {
|
|
|
256
454
|
requiredProps,
|
|
257
455
|
commonProps,
|
|
258
456
|
figmaUrl: item.figmaUrl,
|
|
457
|
+
htmlContent: item.htmlContent,
|
|
458
|
+
cssContent: item.cssContent,
|
|
459
|
+
sourceType: item.sourceType,
|
|
259
460
|
constraints: {
|
|
260
461
|
mustBeFunctional: true,
|
|
261
462
|
mustSupportRequiredProps: true,
|
|
262
463
|
mustSupportCommonProps: true,
|
|
263
464
|
avoidBreakingChanges: true,
|
|
465
|
+
useProvidedHtmlAndCssIfAvailable: true
|
|
264
466
|
}
|
|
265
467
|
};
|
|
266
468
|
results.push({
|
|
@@ -285,7 +487,7 @@ function createMcpServer(apiKey, personalKey) {
|
|
|
285
487
|
};
|
|
286
488
|
}
|
|
287
489
|
case "mark_ui_component_generated": {
|
|
288
|
-
const args =
|
|
490
|
+
const args = argsAny;
|
|
289
491
|
if (!args?.id || !args?.code) {
|
|
290
492
|
throw new Error("id and code are required");
|
|
291
493
|
}
|
|
@@ -294,6 +496,7 @@ function createMcpServer(apiKey, personalKey) {
|
|
|
294
496
|
headers: {
|
|
295
497
|
'Content-Type': 'application/json',
|
|
296
498
|
'x-api-key': apiKey,
|
|
499
|
+
'x-mcp-tool-name': toolName,
|
|
297
500
|
...(personalKey ? { 'x-personal-key': personalKey } : {})
|
|
298
501
|
},
|
|
299
502
|
body: JSON.stringify({ code: args.code, props: args.props })
|
|
@@ -306,7 +509,7 @@ function createMcpServer(apiKey, personalKey) {
|
|
|
306
509
|
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
307
510
|
}
|
|
308
511
|
case "get_annotations": {
|
|
309
|
-
const args =
|
|
512
|
+
const args = argsAny;
|
|
310
513
|
const limit = args.limit || 3;
|
|
311
514
|
// Strictly enforce allowed statuses: pending and bug_fixing
|
|
312
515
|
const allowedStatuses = ['pending', 'bug_fixing'];
|
|
@@ -341,6 +544,7 @@ function createMcpServer(apiKey, personalKey) {
|
|
|
341
544
|
const response = await fetch(fetchUrl, {
|
|
342
545
|
headers: {
|
|
343
546
|
'x-api-key': apiKey,
|
|
547
|
+
'x-mcp-tool-name': toolName,
|
|
344
548
|
...(personalKey ? { 'x-personal-key': personalKey } : {})
|
|
345
549
|
}
|
|
346
550
|
});
|
|
@@ -419,7 +623,7 @@ Lang: ${rawData.preferredLanguage === 'es' ? 'ES' : 'EN'}
|
|
|
419
623
|
};
|
|
420
624
|
}
|
|
421
625
|
case "mark_annotation_ready": {
|
|
422
|
-
const args =
|
|
626
|
+
const args = argsAny;
|
|
423
627
|
const results = args.results;
|
|
424
628
|
console.error(`[mark_annotation_ready] Submitting results for ${results?.length} items`);
|
|
425
629
|
const response = await fetch(`${BACKEND_URL}/api/mcp/annotations/batch-ready`, {
|
|
@@ -427,6 +631,7 @@ Lang: ${rawData.preferredLanguage === 'es' ? 'ES' : 'EN'}
|
|
|
427
631
|
headers: {
|
|
428
632
|
'Content-Type': 'application/json',
|
|
429
633
|
'x-api-key': apiKey,
|
|
634
|
+
'x-mcp-tool-name': toolName,
|
|
430
635
|
'x-personal-key': personalKey || ''
|
|
431
636
|
},
|
|
432
637
|
body: JSON.stringify({
|
|
@@ -441,7 +646,7 @@ Lang: ${rawData.preferredLanguage === 'es' ? 'ES' : 'EN'}
|
|
|
441
646
|
};
|
|
442
647
|
}
|
|
443
648
|
case "mark_annotations_as_live": {
|
|
444
|
-
const args =
|
|
649
|
+
const args = argsAny;
|
|
445
650
|
const ids = args.ids;
|
|
446
651
|
console.error(`[mark_annotations_as_live] Marking ${ids?.length} items as live`);
|
|
447
652
|
const response = await fetch(`${BACKEND_URL}/api/mcp/annotations/mark-as-live`, {
|
|
@@ -449,6 +654,7 @@ Lang: ${rawData.preferredLanguage === 'es' ? 'ES' : 'EN'}
|
|
|
449
654
|
headers: {
|
|
450
655
|
'Content-Type': 'application/json',
|
|
451
656
|
'x-api-key': apiKey,
|
|
657
|
+
'x-mcp-tool-name': toolName,
|
|
452
658
|
'x-personal-key': personalKey || ''
|
|
453
659
|
},
|
|
454
660
|
body: JSON.stringify({ ids })
|
|
@@ -461,12 +667,12 @@ Lang: ${rawData.preferredLanguage === 'es' ? 'ES' : 'EN'}
|
|
|
461
667
|
};
|
|
462
668
|
}
|
|
463
669
|
case "planning": {
|
|
464
|
-
const args =
|
|
670
|
+
const args = argsAny;
|
|
465
671
|
const url = args.results ? `${BACKEND_URL}/api/mcp/annotations/batch-planning` : `${BACKEND_URL}/api/mcp/backlog`;
|
|
466
672
|
const method = args.results ? 'PATCH' : 'GET';
|
|
467
673
|
const response = await fetch(url, {
|
|
468
674
|
method,
|
|
469
|
-
headers: { 'Content-Type': 'application/json', 'x-api-key': apiKey, ...(personalKey ? { 'x-personal-key': personalKey } : {}) },
|
|
675
|
+
headers: { 'Content-Type': 'application/json', 'x-api-key': apiKey, 'x-mcp-tool-name': toolName, ...(personalKey ? { 'x-personal-key': personalKey } : {}) },
|
|
470
676
|
body: args.results ? JSON.stringify({ results: args.results, force: args.force }) : undefined
|
|
471
677
|
});
|
|
472
678
|
if (!response.ok)
|
|
@@ -477,11 +683,39 @@ Lang: ${rawData.preferredLanguage === 'es' ? 'ES' : 'EN'}
|
|
|
477
683
|
: (data.preferredLanguage === 'en' ? "\n*** [INSTRUCTION: Provide all comments and analysis in English.] ***\n\n\n\n" : "");
|
|
478
684
|
return { content: [{ type: "text", text: langHint + JSON.stringify(data, null, 2) }] };
|
|
479
685
|
}
|
|
686
|
+
case "get_ui_improvements": {
|
|
687
|
+
const args = argsAny;
|
|
688
|
+
const fetchUrl = new URL(`${BACKEND_URL}/api/mcp/ui-improvements`);
|
|
689
|
+
if (args.limit)
|
|
690
|
+
fetchUrl.searchParams.append("limit", args.limit.toString());
|
|
691
|
+
if (args.search)
|
|
692
|
+
fetchUrl.searchParams.append("search", args.search);
|
|
693
|
+
if (args.key)
|
|
694
|
+
fetchUrl.searchParams.append("key", args.key);
|
|
695
|
+
if (args.ids)
|
|
696
|
+
fetchUrl.searchParams.append("ids", args.ids);
|
|
697
|
+
const response = await fetch(fetchUrl, {
|
|
698
|
+
headers: {
|
|
699
|
+
'x-api-key': apiKey,
|
|
700
|
+
'x-mcp-tool-name': toolName,
|
|
701
|
+
...(personalKey ? { 'x-personal-key': personalKey } : {})
|
|
702
|
+
}
|
|
703
|
+
});
|
|
704
|
+
if (!response.ok) {
|
|
705
|
+
const errorBody = await response.text();
|
|
706
|
+
throw new Error(`Backend responded with ${response.status}: ${errorBody}`);
|
|
707
|
+
}
|
|
708
|
+
const data = (await response.json());
|
|
709
|
+
const langHint = data.preferredLanguage === 'es'
|
|
710
|
+
? "\n*** [INSTRUCTION: Project is in SPANISH. Provide all CSS/Visual changes in SPANISH comments if requested.] ***\n\n\n\n"
|
|
711
|
+
: "";
|
|
712
|
+
return { content: [{ type: "text", text: langHint + JSON.stringify(data, null, 2) }] };
|
|
713
|
+
}
|
|
480
714
|
case "sync_endpoints": {
|
|
481
|
-
const args =
|
|
715
|
+
const args = argsAny;
|
|
482
716
|
const response = await fetch(`${BACKEND_URL}/api/mcp/sync-endpoints`, {
|
|
483
717
|
method: 'POST',
|
|
484
|
-
headers: { 'Content-Type': 'application/json', 'x-api-key': apiKey, ...(personalKey ? { 'x-personal-key': personalKey } : {}) },
|
|
718
|
+
headers: { 'Content-Type': 'application/json', 'x-api-key': apiKey, 'x-mcp-tool-name': toolName, ...(personalKey ? { 'x-personal-key': personalKey } : {}) },
|
|
485
719
|
body: JSON.stringify(args)
|
|
486
720
|
});
|
|
487
721
|
if (!response.ok)
|
|
@@ -491,7 +725,7 @@ Lang: ${rawData.preferredLanguage === 'es' ? 'ES' : 'EN'}
|
|
|
491
725
|
}
|
|
492
726
|
case "get_synced_endpoints": {
|
|
493
727
|
const response = await fetch(`${BACKEND_URL}/api/projects/endpoints`, {
|
|
494
|
-
headers: { 'x-api-key': apiKey, ...(personalKey ? { 'x-personal-key': personalKey } : {}) }
|
|
728
|
+
headers: { 'x-api-key': apiKey, 'x-mcp-tool-name': toolName, ...(personalKey ? { 'x-personal-key': personalKey } : {}) }
|
|
495
729
|
});
|
|
496
730
|
if (!response.ok)
|
|
497
731
|
throw new Error(`Backend responded with ${response.status}`);
|
|
@@ -500,7 +734,7 @@ Lang: ${rawData.preferredLanguage === 'es' ? 'ES' : 'EN'}
|
|
|
500
734
|
}
|
|
501
735
|
case "get_ai_resolved_tickets": {
|
|
502
736
|
const response = await fetch(`${BACKEND_URL}/api/mcp/resolved-tickets`, {
|
|
503
|
-
headers: { 'x-api-key': apiKey, ...(personalKey ? { 'x-personal-key': personalKey } : {}) }
|
|
737
|
+
headers: { 'x-api-key': apiKey, 'x-mcp-tool-name': toolName, ...(personalKey ? { 'x-personal-key': personalKey } : {}) }
|
|
504
738
|
});
|
|
505
739
|
if (!response.ok)
|
|
506
740
|
throw new Error(`Backend responded with ${response.status}`);
|