viewgate-mcp 1.0.32 → 1.0.33

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 +77 -28
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -21,6 +21,7 @@ import fetch from "node-fetch";
21
21
  import cors from "cors";
22
22
  import dotenv from "dotenv";
23
23
  import path from "path";
24
+ import os from "os";
24
25
  import { fileURLToPath } from "url";
25
26
  const __filename = fileURLToPath(import.meta.url);
26
27
  const __dirname = path.dirname(__filename);
@@ -29,6 +30,8 @@ const port = process.env.PORT || 3000;
29
30
  const BACKEND_URL = process.env.BACKEND_URL || "https://view-gate.vercel.app";
30
31
  console.error(`[MCP Config] BACKEND_URL: ${BACKEND_URL}`);
31
32
  console.error(`[MCP Config] API_KEY Prefix: ${process.env.API_KEY?.substring(0, 5)}...`);
33
+ const agentId = `${os.hostname()}-${process.pid}`;
34
+ console.error(`[MCP Identity] Agent ID: ${agentId}`);
32
35
  // Store active sessions for SSE: sessionId -> { server, transport }
33
36
  const sessions = new Map();
34
37
  /**
@@ -82,6 +85,21 @@ function createMcpServer(apiKey, personalKey) {
82
85
  required: ["results"]
83
86
  },
84
87
  },
88
+ {
89
+ name: "mark_annotations_as_live",
90
+ description: "Transitions annotations from 'applied' (local fix) to 'ready_for_review' (live on server). Call this tool ONLY after you have successfully deployed/uploaded your code changes.",
91
+ inputSchema: {
92
+ type: "object",
93
+ properties: {
94
+ ids: {
95
+ type: "array",
96
+ items: { type: "string" },
97
+ description: "List of internal database IDs to mark as live."
98
+ }
99
+ },
100
+ required: ["ids"]
101
+ },
102
+ },
85
103
  {
86
104
  name: "planning",
87
105
  description: "Planning tool for backlog tickets. Fetch tickets or submit analysis.",
@@ -177,23 +195,27 @@ function createMcpServer(apiKey, personalKey) {
177
195
  let keysToFetch = [];
178
196
  if (args.key)
179
197
  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 || '';
198
+ const key = args.key;
199
+ const keys = args.keys;
200
+ const ids = args.ids;
184
201
  const agentId = personalKey || 'mcp-agent-' + (apiKey?.slice(-6) || 'generic');
185
- let fetchUrl = `${BACKEND_URL}/api/mcp/annotations?lock=true&agentId=${encodeURIComponent(agentId)}`;
186
- if (statuses && statuses !== 'all')
187
- fetchUrl += `&status=${statuses}`;
202
+ const fetchUrl = new URL(`${BACKEND_URL}/api/mcp/annotations`);
188
203
  if (limit)
189
- fetchUrl += `&limit=${limit}`;
204
+ fetchUrl.searchParams.append("limit", limit.toString());
205
+ if (statuses)
206
+ fetchUrl.searchParams.append("status", statuses);
190
207
  if (search)
191
- fetchUrl += `&search=${encodeURIComponent(search)}`;
192
- if (combinedKey)
193
- fetchUrl += `&key=${encodeURIComponent(combinedKey)}`;
194
- if (idsToFetch)
195
- fetchUrl += `&ids=${encodeURIComponent(idsToFetch)}`;
196
- console.error(`[MCP] Fetching: ${fetchUrl}`);
208
+ fetchUrl.searchParams.append("search", search);
209
+ if (key)
210
+ fetchUrl.searchParams.append("key", key);
211
+ if (ids)
212
+ fetchUrl.searchParams.append("ids", ids);
213
+ if (keys && keys.length > 0)
214
+ fetchUrl.searchParams.append("keys", keys.join(","));
215
+ // Add lock and agentId parameters
216
+ fetchUrl.searchParams.append("lock", "true");
217
+ fetchUrl.searchParams.append("agentId", agentId);
218
+ console.error(`[get_annotations] Fetching: ${fetchUrl.toString()}`);
197
219
  const response = await fetch(fetchUrl, {
198
220
  headers: {
199
221
  'x-api-key': apiKey,
@@ -217,10 +239,11 @@ function createMcpServer(apiKey, personalKey) {
217
239
  (ann.reference?.source && ann.reference.source.toLowerCase().includes(lowSearch)) ||
218
240
  (ann.key && ann.key.toLowerCase().includes(lowSearch)));
219
241
  }
242
+ const combinedKey = key || (keys && keys.join(','));
220
243
  if (combinedKey) {
221
244
  // Normalize keyList for case-insensitive matching and handle VG- prefix
222
- const keyList = combinedKey.split(',').map(k => k.trim().toUpperCase());
223
- const baseKeys = keyList.map(k => k.startsWith('VG-') ? k.substring(3) : k);
245
+ const keyList = combinedKey.split(',').map((k) => k.trim().toUpperCase());
246
+ const baseKeys = keyList.map((k) => k.startsWith('VG-') ? k.substring(3) : k);
224
247
  rawAnnotations = rawAnnotations.filter((ann) => {
225
248
  if (!ann.key)
226
249
  return keyList.includes(ann._id);
@@ -232,8 +255,8 @@ function createMcpServer(apiKey, personalKey) {
232
255
  });
233
256
  console.error(`[MCP] Filtered with keys. Remaining: ${rawAnnotations.length}`);
234
257
  }
235
- if (idsToFetch) {
236
- const idList = idsToFetch.split(',').map(i => i.trim());
258
+ if (ids) {
259
+ const idList = ids.split(',').map((i) => i.trim());
237
260
  rawAnnotations = rawAnnotations.filter((ann) => idList.includes(ann._id));
238
261
  console.error(`[MCP] Filtered with IDs. Remaining: ${rawAnnotations.length}`);
239
262
  }
@@ -293,19 +316,45 @@ Instruction: ${ann.message}`
293
316
  }
294
317
  case "mark_annotation_ready": {
295
318
  const args = request.params.arguments;
296
- console.error(`[MCP] Marking ${args.results.length} annotations as ready.`);
297
- console.error(`[MCP] Batch ready update: ${BACKEND_URL}/api/mcp/annotations/batch-ready`);
319
+ const results = args.results;
320
+ console.error(`[mark_annotation_ready] Submitting results for ${results?.length} items`);
298
321
  const response = await fetch(`${BACKEND_URL}/api/mcp/annotations/batch-ready`, {
299
322
  method: 'PATCH',
300
- headers: { 'Content-Type': 'application/json', 'x-api-key': apiKey, ...(personalKey ? { 'x-personal-key': personalKey } : {}) },
301
- body: JSON.stringify({ results: args.results })
323
+ headers: {
324
+ 'Content-Type': 'application/json',
325
+ 'x-api-key': apiKey,
326
+ 'x-personal-key': personalKey || ''
327
+ },
328
+ body: JSON.stringify({
329
+ results: results.map((r) => ({ ...r, status: 'applied' }))
330
+ })
302
331
  });
303
- if (!response.ok) {
304
- const errorBody = await response.text();
305
- throw new Error(`Backend responded with ${response.status}: ${errorBody}`);
306
- }
307
- const result = await response.json();
308
- return { content: [{ type: "text", text: `Processed: ${JSON.stringify(result, null, 2)}` }] };
332
+ if (!response.ok)
333
+ throw new Error(`Backend responded with ${response.status}`);
334
+ const data = await response.json();
335
+ return {
336
+ content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
337
+ };
338
+ }
339
+ case "mark_annotations_as_live": {
340
+ const args = request.params.arguments;
341
+ const ids = args.ids;
342
+ console.error(`[mark_annotations_as_live] Marking ${ids?.length} items as live`);
343
+ const response = await fetch(`${BACKEND_URL}/api/mcp/annotations/mark-as-live`, {
344
+ method: 'POST',
345
+ headers: {
346
+ 'Content-Type': 'application/json',
347
+ 'x-api-key': apiKey,
348
+ 'x-personal-key': personalKey || ''
349
+ },
350
+ body: JSON.stringify({ ids })
351
+ });
352
+ if (!response.ok)
353
+ throw new Error(`Backend responded with ${response.status}`);
354
+ const data = await response.json();
355
+ return {
356
+ content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
357
+ };
309
358
  }
310
359
  case "planning": {
311
360
  const args = request.params.arguments;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "viewgate-mcp",
3
- "version": "1.0.32",
3
+ "version": "1.0.33",
4
4
  "main": "dist/index.js",
5
5
  "bin": {
6
6
  "viewgate-mcp": "./dist/index.js"