super-feedback-mcp 0.2.2 → 0.2.6

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/README.md CHANGED
@@ -1,6 +1,6 @@
1
- # Super Feedback MCP Server
1
+ # SuperFeedback MCP Server
2
2
 
3
- An MCP (Model Context Protocol) server that enables AI agents in Cursor to query and resolve client feedback from Super Feedback projects.
3
+ An MCP (Model Context Protocol) server that enables AI agents in Cursor to query and resolve client feedback from SuperFeedback projects.
4
4
 
5
5
  ## Installation
6
6
 
@@ -57,7 +57,7 @@ Or if published to npm:
57
57
  *At least one of `ACCESS_CODE` or `ADMIN_CODE` is required. For full functionality (read + resolve), provide both.
58
58
 
59
59
  **Where to find these codes:**
60
- - Go to your Super Feedback dashboard
60
+ - Go to your SuperFeedback dashboard
61
61
  - Select your project
62
62
  - Click "Settings" or the gear icon
63
63
  - Copy the "Access Code" and "Admin Code"
@@ -121,7 +121,7 @@ The agent will:
121
121
 
122
122
  ## How It Works
123
123
 
124
- The MCP server connects to your Super Feedback project via the Convex API using your access code. It transforms the raw feedback data into AI-friendly format with:
124
+ The MCP server connects to your SuperFeedback project via the Convex API using your access code. It transforms the raw feedback data into AI-friendly format with:
125
125
 
126
126
  - **Element identification**: Multiple selector strategies (ID, test ID, CSS path, XPath)
127
127
  - **Route mapping**: Extracts page path and suggests likely source files
@@ -150,7 +150,7 @@ Make sure you've set the `SUPER_FEEDBACK_ACCESS_CODE` in your MCP config's `env`
150
150
 
151
151
  ### "API error: 401"
152
152
 
153
- Your access code is invalid or expired. Check your project settings in Super Feedback.
153
+ Your access code is invalid or expired. Check your project settings in SuperFeedback.
154
154
 
155
155
  ### "API error: 404"
156
156
 
package/dist/index.js CHANGED
@@ -39,7 +39,7 @@ async function callConvexAPI(endpoint, options) {
39
39
  // Create MCP server
40
40
  const server = new McpServer({
41
41
  name: "super-feedback",
42
- version: "0.2.2",
42
+ version: "0.2.6",
43
43
  });
44
44
  // Tool 1: Get feedback summary (lightweight overview)
45
45
  server.registerTool("get_feedback_summary", {
@@ -137,8 +137,10 @@ Returns everything needed to work on the feedback:
137
137
  - All replies/thread history
138
138
  - Design suggestions (if any)
139
139
  - Cross-element references (if any)
140
+ - Image attachment count (if any)
140
141
 
141
- Use this after get_feedback_summary to dive into a specific comment.`,
142
+ Use this after get_feedback_summary to dive into a specific comment.
143
+ If the comment has attached images, use get_comment_images to fetch and view them.`,
142
144
  inputSchema: {
143
145
  commentId: z.string().describe("The comment ID to get full details for"),
144
146
  },
@@ -207,6 +209,10 @@ Use this after get_feedback_summary to dive into a specific comment.`,
207
209
  text += `\n ${change.property}: ${change.oldValue} → ${change.newValue}`;
208
210
  });
209
211
  }
212
+ // Note if there are images attached (use get_comment_images to fetch them)
213
+ if (c.imageUrls && c.imageUrls.length > 0) {
214
+ text += `\n\nšŸ–¼ļø Attached Images: ${c.imageUrls.length} image(s) - use get_comment_images("${c.id}") to view`;
215
+ }
210
216
  return {
211
217
  content: [{ type: "text", text }],
212
218
  structuredContent: { found: true, comment: c },
@@ -221,7 +227,82 @@ Use this after get_feedback_summary to dive into a specific comment.`,
221
227
  };
222
228
  }
223
229
  });
224
- // Tool 3: Mark feedback as resolved
230
+ // Tool 3: Get images attached to a comment
231
+ server.registerTool("get_comment_images", {
232
+ title: "Get Comment Images",
233
+ description: `Fetches and returns the images attached to a feedback comment.
234
+
235
+ Use this when:
236
+ - get_comment_details indicates a comment has attached images
237
+ - You need to see visual context for the feedback (screenshots, mockups, etc.)
238
+ - The user's feedback references something visual
239
+
240
+ Returns the images as viewable content. Call this after get_comment_details
241
+ if you need to see the attached images.`,
242
+ inputSchema: {
243
+ commentId: z.string().describe("The comment ID to fetch images for"),
244
+ },
245
+ outputSchema: {
246
+ found: z.boolean(),
247
+ imageCount: z.number(),
248
+ },
249
+ }, async ({ commentId }) => {
250
+ try {
251
+ const params = getAuthParams();
252
+ params.set("commentId", commentId);
253
+ const response = await callConvexAPI(`/api/feedback/ai/comment?${params.toString()}`);
254
+ if (!response.found || !response.comment) {
255
+ return {
256
+ content: [{ type: "text", text: `Comment ${commentId} not found` }],
257
+ structuredContent: { found: false, imageCount: 0 },
258
+ };
259
+ }
260
+ const c = response.comment;
261
+ if (!c.imageUrls || c.imageUrls.length === 0) {
262
+ return {
263
+ content: [{ type: "text", text: `No images attached to comment ${commentId}` }],
264
+ structuredContent: { found: true, imageCount: 0 },
265
+ };
266
+ }
267
+ // Fetch images and convert to base64 for MCP ImageContent
268
+ const imageContents = [];
269
+ const failedUrls = [];
270
+ for (const url of c.imageUrls) {
271
+ try {
272
+ const imgResponse = await fetch(url);
273
+ if (imgResponse.ok) {
274
+ const buffer = await imgResponse.arrayBuffer();
275
+ const base64 = Buffer.from(buffer).toString("base64");
276
+ const mimeType = imgResponse.headers.get("content-type") || "image/png";
277
+ imageContents.push({ type: "image", data: base64, mimeType });
278
+ }
279
+ else {
280
+ failedUrls.push(url);
281
+ }
282
+ }
283
+ catch {
284
+ failedUrls.push(url);
285
+ }
286
+ }
287
+ const summary = `šŸ–¼ļø Images for comment ${commentId}: ${imageContents.length} of ${c.imageUrls.length} loaded successfully${failedUrls.length > 0 ? ` (${failedUrls.length} failed)` : ""}`;
288
+ return {
289
+ content: [
290
+ { type: "text", text: summary },
291
+ ...imageContents,
292
+ ],
293
+ structuredContent: { found: true, imageCount: imageContents.length },
294
+ };
295
+ }
296
+ catch (error) {
297
+ const message = error instanceof Error ? error.message : "Unknown error";
298
+ return {
299
+ content: [{ type: "text", text: `Error fetching images: ${message}` }],
300
+ structuredContent: { found: false, imageCount: 0 },
301
+ isError: true,
302
+ };
303
+ }
304
+ });
305
+ // Tool 4: Mark feedback as resolved
225
306
  server.registerTool("mark_feedback_resolved", {
226
307
  title: "Mark Feedback Resolved",
227
308
  description: `Marks a feedback comment as resolved after you've fixed the issue.
@@ -277,7 +358,7 @@ async function main() {
277
358
  const transport = new StdioServerTransport();
278
359
  await server.connect(transport);
279
360
  // Log to stderr so it doesn't interfere with MCP protocol on stdout
280
- console.error("Super Feedback MCP server running...");
361
+ console.error("SuperFeedback MCP server running...");
281
362
  }
282
363
  main().catch((error) => {
283
364
  console.error("Fatal error:", error);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "super-feedback-mcp",
3
- "version": "0.2.2",
4
- "description": "MCP server for Super Feedback - enables AI agents to query and resolve client feedback",
3
+ "version": "0.2.6",
4
+ "description": "MCP server for SuperFeedback - enables AI agents to query and resolve client feedback",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "bin": {
package/src/index.ts CHANGED
@@ -72,6 +72,7 @@ interface FullCommentDetails {
72
72
  elementText: string;
73
73
  label?: string;
74
74
  }>;
75
+ imageUrls?: string[];
75
76
  }
76
77
 
77
78
  // Configuration from environment
@@ -115,7 +116,7 @@ async function callConvexAPI<T>(endpoint: string, options?: RequestInit): Promis
115
116
  // Create MCP server
116
117
  const server = new McpServer({
117
118
  name: "super-feedback",
118
- version: "0.2.2",
119
+ version: "0.2.6",
119
120
  });
120
121
 
121
122
  // Tool 1: Get feedback summary (lightweight overview)
@@ -225,8 +226,10 @@ Returns everything needed to work on the feedback:
225
226
  - All replies/thread history
226
227
  - Design suggestions (if any)
227
228
  - Cross-element references (if any)
229
+ - Image attachment count (if any)
228
230
 
229
- Use this after get_feedback_summary to dive into a specific comment.`,
231
+ Use this after get_feedback_summary to dive into a specific comment.
232
+ If the comment has attached images, use get_comment_images to fetch and view them.`,
230
233
  inputSchema: {
231
234
  commentId: z.string().describe("The comment ID to get full details for"),
232
235
  },
@@ -309,6 +312,11 @@ Use this after get_feedback_summary to dive into a specific comment.`,
309
312
  });
310
313
  }
311
314
 
315
+ // Note if there are images attached (use get_comment_images to fetch them)
316
+ if (c.imageUrls && c.imageUrls.length > 0) {
317
+ text += `\n\nšŸ–¼ļø Attached Images: ${c.imageUrls.length} image(s) - use get_comment_images("${c.id}") to view`;
318
+ }
319
+
312
320
  return {
313
321
  content: [{ type: "text", text }],
314
322
  structuredContent: { found: true, comment: c },
@@ -324,7 +332,94 @@ Use this after get_feedback_summary to dive into a specific comment.`,
324
332
  }
325
333
  );
326
334
 
327
- // Tool 3: Mark feedback as resolved
335
+ // Tool 3: Get images attached to a comment
336
+ server.registerTool(
337
+ "get_comment_images",
338
+ {
339
+ title: "Get Comment Images",
340
+ description: `Fetches and returns the images attached to a feedback comment.
341
+
342
+ Use this when:
343
+ - get_comment_details indicates a comment has attached images
344
+ - You need to see visual context for the feedback (screenshots, mockups, etc.)
345
+ - The user's feedback references something visual
346
+
347
+ Returns the images as viewable content. Call this after get_comment_details
348
+ if you need to see the attached images.`,
349
+ inputSchema: {
350
+ commentId: z.string().describe("The comment ID to fetch images for"),
351
+ },
352
+ outputSchema: {
353
+ found: z.boolean(),
354
+ imageCount: z.number(),
355
+ },
356
+ },
357
+ async ({ commentId }) => {
358
+ try {
359
+ const params = getAuthParams();
360
+ params.set("commentId", commentId);
361
+
362
+ const response = await callConvexAPI<{ found: boolean; comment: FullCommentDetails | null }>(
363
+ `/api/feedback/ai/comment?${params.toString()}`
364
+ );
365
+
366
+ if (!response.found || !response.comment) {
367
+ return {
368
+ content: [{ type: "text", text: `Comment ${commentId} not found` }],
369
+ structuredContent: { found: false, imageCount: 0 },
370
+ };
371
+ }
372
+
373
+ const c = response.comment;
374
+
375
+ if (!c.imageUrls || c.imageUrls.length === 0) {
376
+ return {
377
+ content: [{ type: "text", text: `No images attached to comment ${commentId}` }],
378
+ structuredContent: { found: true, imageCount: 0 },
379
+ };
380
+ }
381
+
382
+ // Fetch images and convert to base64 for MCP ImageContent
383
+ const imageContents: Array<{ type: "image"; data: string; mimeType: string }> = [];
384
+ const failedUrls: string[] = [];
385
+
386
+ for (const url of c.imageUrls) {
387
+ try {
388
+ const imgResponse = await fetch(url);
389
+ if (imgResponse.ok) {
390
+ const buffer = await imgResponse.arrayBuffer();
391
+ const base64 = Buffer.from(buffer).toString("base64");
392
+ const mimeType = imgResponse.headers.get("content-type") || "image/png";
393
+ imageContents.push({ type: "image", data: base64, mimeType });
394
+ } else {
395
+ failedUrls.push(url);
396
+ }
397
+ } catch {
398
+ failedUrls.push(url);
399
+ }
400
+ }
401
+
402
+ const summary = `šŸ–¼ļø Images for comment ${commentId}: ${imageContents.length} of ${c.imageUrls.length} loaded successfully${failedUrls.length > 0 ? ` (${failedUrls.length} failed)` : ""}`;
403
+
404
+ return {
405
+ content: [
406
+ { type: "text", text: summary },
407
+ ...imageContents,
408
+ ],
409
+ structuredContent: { found: true, imageCount: imageContents.length },
410
+ };
411
+ } catch (error) {
412
+ const message = error instanceof Error ? error.message : "Unknown error";
413
+ return {
414
+ content: [{ type: "text", text: `Error fetching images: ${message}` }],
415
+ structuredContent: { found: false, imageCount: 0 },
416
+ isError: true,
417
+ };
418
+ }
419
+ }
420
+ );
421
+
422
+ // Tool 4: Mark feedback as resolved
328
423
  server.registerTool(
329
424
  "mark_feedback_resolved",
330
425
  {
@@ -388,7 +483,7 @@ async function main() {
388
483
  await server.connect(transport);
389
484
 
390
485
  // Log to stderr so it doesn't interfere with MCP protocol on stdout
391
- console.error("Super Feedback MCP server running...");
486
+ console.error("SuperFeedback MCP server running...");
392
487
  }
393
488
 
394
489
  main().catch((error) => {