viewgate-mcp 1.0.25 → 1.0.27

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
@@ -48,20 +48,22 @@ function createMcpServer(apiKey, personalKey) {
48
48
  tools: [
49
49
  {
50
50
  name: "get_annotations",
51
- description: "Retrieves all feedback annotations. Use 'status' to filter (e.g. 'pending,bug_fixing'). WORKFLOW: 1. Read these annotations, 2. Open the source files and apply SURGICAL fixes. 3. Call 'mark_annotation_ready' for EACH ticket. IMPORTANT: Uses 'id' for marking, but 'key' for readability.",
51
+ description: "Retrieves all feedback annotations. Use 'status' to filter (e.g. 'pending,bug_fixing'). WORKFLOW: 1. Read these annotations, 2. Open the source files and apply SURGICAL fixes. 3. Call 'mark_annotation_ready' for EACH ticket. IMPORTANT: Tickets already resolved by the AI in the current sprint are automatically filtered out to prevent redundant work.",
52
52
  inputSchema: {
53
53
  type: "object",
54
54
  properties: {
55
55
  limit: { type: "number", description: "Maximum number of annotations to retrieve (default: 3)", default: 3 },
56
56
  status: { type: "string", description: "Comma-separated list (e.g. 'pending,bug_fixing'). Use 'all' for any state.", default: "pending,bug_fixing" },
57
57
  search: { type: "string", description: "Search term to filter by message or file." },
58
- key: { type: "string", description: "Human key (e.g. VG-XXXX) to find a specific annotation." }
58
+ key: { type: "string", description: "Human key (e.g. VG-XXXX) or comma-separated keys to find specific annotations." },
59
+ keys: { type: "array", items: { type: "string" }, description: "List of human keys to find specific annotations." },
60
+ ids: { type: "string", description: "Comma-separated internal IDs to find specific annotations." }
59
61
  },
60
62
  },
61
63
  },
62
64
  {
63
65
  name: "mark_annotation_ready",
64
- description: "CRITICAL: Call this tool AFTER applying code fixes. REQUIREMENT: Use the internal database ID (e.g. 675ba...), NOT the human key (VG-XXXX).",
66
+ description: "CRITICAL: Call this tool AFTER applying code fixes. This also registers the tickets as resolved by the AI for the current sprint to avoid re-fetching them. REQUIREMENT: Use the internal database ID (e.g. 675ba...), NOT the human key (VG-XXXX).",
65
67
  inputSchema: {
66
68
  type: "object",
67
69
  properties: {
@@ -152,6 +154,11 @@ function createMcpServer(apiKey, personalKey) {
152
154
  },
153
155
  required: ["id"]
154
156
  },
157
+ },
158
+ {
159
+ name: "get_ai_resolved_tickets",
160
+ description: "Retrieves the list of ticket IDs that have already been resolved by the AI in the current sprint.",
161
+ inputSchema: { type: "object", properties: {} },
155
162
  }
156
163
  ],
157
164
  };
@@ -166,7 +173,14 @@ function createMcpServer(apiKey, personalKey) {
166
173
  const limit = args.limit || 3;
167
174
  const statuses = args.status || 'pending,bug_fixing';
168
175
  const search = args.search || '';
169
- const key = args.key || '';
176
+ // Normalize keys and ids
177
+ let keysToFetch = [];
178
+ if (args.key)
179
+ keysToFetch = keysToFetch.concat(args.key.split(',').map(s => s.trim()));
180
+ if (args.keys)
181
+ keysToFetch = keysToFetch.concat(args.keys);
182
+ const combinedKey = keysToFetch.filter(k => k).join(',');
183
+ const idsToFetch = args.ids || '';
170
184
  let fetchUrl = `${BACKEND_URL}/api/mcp/annotations?lock=true`;
171
185
  if (statuses && statuses !== 'all')
172
186
  fetchUrl += `&status=${statuses}`;
@@ -174,8 +188,10 @@ function createMcpServer(apiKey, personalKey) {
174
188
  fetchUrl += `&limit=${limit}`;
175
189
  if (search)
176
190
  fetchUrl += `&search=${encodeURIComponent(search)}`;
177
- if (key)
178
- fetchUrl += `&key=${encodeURIComponent(key)}`;
191
+ if (combinedKey)
192
+ fetchUrl += `&key=${encodeURIComponent(combinedKey)}`;
193
+ if (idsToFetch)
194
+ fetchUrl += `&ids=${encodeURIComponent(idsToFetch)}`;
179
195
  const response = await fetch(fetchUrl, {
180
196
  headers: {
181
197
  'x-api-key': apiKey,
@@ -196,8 +212,13 @@ function createMcpServer(apiKey, personalKey) {
196
212
  (ann.reference?.source && ann.reference.source.toLowerCase().includes(lowSearch)) ||
197
213
  (ann.key && ann.key.toLowerCase().includes(lowSearch)));
198
214
  }
199
- if (key) {
200
- rawAnnotations = rawAnnotations.filter((ann) => ann.key === key || ann._id === key);
215
+ if (combinedKey) {
216
+ const keyList = combinedKey.split(',').map(k => k.trim());
217
+ rawAnnotations = rawAnnotations.filter((ann) => keyList.includes(ann.key) || keyList.includes(ann._id));
218
+ }
219
+ if (idsToFetch) {
220
+ const idList = idsToFetch.split(',').map(i => i.trim());
221
+ rawAnnotations = rawAnnotations.filter((ann) => idList.includes(ann._id));
201
222
  }
202
223
  const priorityMap = { 'urgente': 4, 'urgent': 4, 'alta': 3, 'high': 3, 'media': 2, 'medium': 2, 'baja': 1, 'low': 1 };
203
224
  const sortedAnnotations = rawAnnotations.sort((a, b) => {
@@ -227,16 +248,16 @@ function createMcpServer(apiKey, personalKey) {
227
248
  line: ann.line || (line ? parseInt(line) : undefined),
228
249
  vgId: ann.reference?.vgId,
229
250
  outerHtml: ann.reference?.outerHtml,
230
- _ia_fix_instruction: `### 🎯 DESIGN CONTEXT (Figma)
231
- ${ann.figmaReference ? `A design reference is available: ${ann.figmaReference}` : 'No explicit design linked.'}
232
-
233
- ${pendingCorrection ? `### ⚠️ PENDING CORRECTION\nUser feedback: "${pendingCorrection.text}"` : ''}
234
-
235
- ### 🔬 FIX PROTOCOL
236
- 1. **Target**: \`data-vg-id="${ann.reference?.vgId}"\` in \`${file}\`.
237
- 2. **Context**: \`${ann.reference?.parentContext?.slice(0, 50)}...\`
238
-
239
- IMPORTANT: Respond in ${rawData.preferredLanguage === 'es' ? 'SPANISH' : 'ENGLISH'}.
251
+ _ia_fix_instruction: `### 🎯 DESIGN CONTEXT (Figma)
252
+ ${ann.figmaReference ? `A design reference is available: ${ann.figmaReference}` : 'No explicit design linked.'}
253
+
254
+ ${pendingCorrection ? `### ⚠️ PENDING CORRECTION\nUser feedback: "${pendingCorrection.text}"` : ''}
255
+
256
+ ### 🔬 FIX PROTOCOL
257
+ 1. **Target**: \`data-vg-id="${ann.reference?.vgId}"\` in \`${file}\`.
258
+ 2. **Context**: \`${ann.reference?.parentContext?.slice(0, 50)}...\`
259
+
260
+ IMPORTANT: Respond in ${rawData.preferredLanguage === 'es' ? 'SPANISH' : 'ENGLISH'}.
240
261
  Instruction: ${ann.message}`
241
262
  };
242
263
  });
@@ -307,9 +328,16 @@ Instruction: ${ann.message}`
307
328
  method: 'PATCH',
308
329
  headers: { 'x-api-key': apiKey, ...(personalKey ? { 'x-personal-key': personalKey } : {}) }
309
330
  });
331
+ return { content: [{ type: "text", text: "Optimization marked as applied." }] };
332
+ }
333
+ case "get_ai_resolved_tickets": {
334
+ const response = await fetch(`${BACKEND_URL}/api/mcp/resolved-tickets`, {
335
+ headers: { 'x-api-key': apiKey, ...(personalKey ? { 'x-personal-key': personalKey } : {}) }
336
+ });
310
337
  if (!response.ok)
311
338
  throw new Error(`Backend responded with ${response.status}`);
312
- return { content: [{ type: "text", text: "Optimization marked as applied." }] };
339
+ const data = await response.json();
340
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
313
341
  }
314
342
  default:
315
343
  throw new Error("Unknown tool");
@@ -0,0 +1,59 @@
1
+ import fetch from "node-fetch";
2
+ async function test() {
3
+ console.log("1. Connecting to http://localhost:3333/sse...");
4
+ const response = await fetch("http://localhost:3333/sse?apiKey=2af5628c9442f10b93cfe6970897d4de26578d958ba43a4e3bcb684fe0f92668");
5
+ if (!response.ok) {
6
+ console.error("Failed to connect to SSE:", response.status, await response.text());
7
+ return;
8
+ }
9
+ console.log("SSE connected. Reading stream for sessionId...");
10
+ const body = response.body;
11
+ let sessionId = null;
12
+ body.on("data", async (chunk) => {
13
+ const text = chunk.toString();
14
+ console.log("SSE Data:", text);
15
+ // Example event:
16
+ // event: endpoint
17
+ // data: /message?sessionId=...
18
+ const match = text.match(/sessionId=([a-f0-9-]+)/);
19
+ if (match && !sessionId) {
20
+ sessionId = match[1];
21
+ console.log("FOUND SESSION ID:", sessionId);
22
+ // 2. Test POST to /message
23
+ console.log(`2. Testing POST to /message?sessionId=${sessionId}...`);
24
+ const postResponse = await fetch(`http://localhost:3333/message?sessionId=${sessionId}`, {
25
+ method: 'POST',
26
+ headers: {
27
+ 'Content-Type': 'application/json'
28
+ },
29
+ body: JSON.stringify({
30
+ jsonrpc: "2.0",
31
+ id: 1,
32
+ method: "initialize",
33
+ params: {
34
+ clientInfo: { name: "test-client", version: "1.0.0" },
35
+ protocolVersion: "2024-11-05",
36
+ capabilities: {}
37
+ }
38
+ })
39
+ });
40
+ console.log("POST Response Status:", postResponse.status);
41
+ const responseText = await postResponse.text();
42
+ console.log("POST Response Body:", responseText);
43
+ if (postResponse.status === 200 || postResponse.status === 202) {
44
+ console.log("SUCCESS: Stream was readable and message was accepted.");
45
+ }
46
+ else {
47
+ console.error("FAILURE: Server returned error status.");
48
+ }
49
+ process.exit(0);
50
+ }
51
+ });
52
+ setTimeout(() => {
53
+ if (!sessionId) {
54
+ console.error("TIMEOUT: Did not receive sessionId from SSE.");
55
+ process.exit(1);
56
+ }
57
+ }, 10000);
58
+ }
59
+ test();
@@ -0,0 +1,23 @@
1
+ import fetch from "node-fetch";
2
+ async function test() {
3
+ console.log("Connecting to http://localhost:3333/sse...");
4
+ const response = await fetch("http://localhost:3333/sse?apiKey=test-key");
5
+ if (!response.ok) {
6
+ console.error("Failed to connect:", response.status, await response.text());
7
+ return;
8
+ }
9
+ console.log("Headers:", response.headers.raw());
10
+ const body = response.body;
11
+ body.on("data", (chunk) => {
12
+ console.log("Chunk received:", chunk.toString());
13
+ if (chunk.toString().includes("event: endpoint")) {
14
+ console.log("FOUND ENDPOINT EVENT!");
15
+ }
16
+ });
17
+ body.on("end", () => console.log("Connection closed"));
18
+ setTimeout(() => {
19
+ console.log("Closing test...");
20
+ process.exit(0);
21
+ }, 5000);
22
+ }
23
+ test();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "viewgate-mcp",
3
- "version": "1.0.25",
3
+ "version": "1.0.27",
4
4
  "main": "dist/index.js",
5
5
  "bin": {
6
6
  "viewgate-mcp": "./dist/index.js"