super-feedback-mcp 0.1.0

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 ADDED
@@ -0,0 +1,145 @@
1
+ # Super Feedback MCP Server
2
+
3
+ An MCP (Model Context Protocol) server that enables AI agents in Cursor to query and resolve client feedback from Super Feedback projects.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ cd mcp-server
9
+ npm install
10
+ npm run build
11
+ ```
12
+
13
+ ## Configuration
14
+
15
+ Add to your Cursor MCP settings (`~/.cursor/mcp.json` or workspace settings):
16
+
17
+ ```json
18
+ {
19
+ "mcpServers": {
20
+ "super-feedback": {
21
+ "command": "node",
22
+ "args": ["/path/to/super-feedback/mcp-server/dist/index.js"],
23
+ "env": {
24
+ "SUPER_FEEDBACK_ACCESS_CODE": "your-project-access-code",
25
+ "SUPER_FEEDBACK_ADMIN_CODE": "your-project-admin-code"
26
+ }
27
+ }
28
+ }
29
+ }
30
+ ```
31
+
32
+ Or if published to npm:
33
+
34
+ ```json
35
+ {
36
+ "mcpServers": {
37
+ "super-feedback": {
38
+ "command": "npx",
39
+ "args": ["super-feedback-mcp"],
40
+ "env": {
41
+ "SUPER_FEEDBACK_ACCESS_CODE": "your-project-access-code",
42
+ "SUPER_FEEDBACK_ADMIN_CODE": "your-project-admin-code"
43
+ }
44
+ }
45
+ }
46
+ }
47
+ ```
48
+
49
+ ### Environment Variables
50
+
51
+ | Variable | Required | Description |
52
+ |----------|----------|-------------|
53
+ | `SUPER_FEEDBACK_ACCESS_CODE` | Yes* | Your project's access code (for reading feedback) |
54
+ | `SUPER_FEEDBACK_ADMIN_CODE` | Yes* | Your project's admin code (required for marking resolved) |
55
+ | `CONVEX_URL` | No | Custom Convex HTTP URL (defaults to production). Use `.convex.site` domain, not `.convex.cloud` |
56
+
57
+ *At least one of `ACCESS_CODE` or `ADMIN_CODE` is required. For full functionality (read + resolve), provide both.
58
+
59
+ **Where to find these codes:**
60
+ - Go to your Super Feedback dashboard
61
+ - Select your project
62
+ - Click "Settings" or the gear icon
63
+ - Copy the "Access Code" and "Admin Code"
64
+
65
+ ## Available Tools
66
+
67
+ ### 1. `get_open_feedback`
68
+
69
+ Retrieves all open (unresolved) feedback comments for your project.
70
+
71
+ **Parameters:**
72
+ - `includeResolved` (boolean, optional): Include resolved comments too
73
+ - `pageFilter` (string, optional): Filter to a specific page path (e.g., `/pricing`)
74
+
75
+ **Returns:**
76
+ - Project name
77
+ - Total count of matching feedback
78
+ - Array of feedback items with:
79
+ - Feedback text
80
+ - Element context (tag, text, test IDs, CSS classes)
81
+ - Page URL and extracted route path
82
+ - Hints for locating code (possible file paths, search terms)
83
+
84
+ ### 2. `mark_feedback_resolved`
85
+
86
+ Marks a feedback comment as resolved after you've fixed the issue.
87
+
88
+ **Parameters:**
89
+ - `commentId` (string): The comment ID to mark as resolved
90
+
91
+ ### 3. `get_feedback_details`
92
+
93
+ Gets full details for a specific feedback comment.
94
+
95
+ **Parameters:**
96
+ - `commentId` (string): The comment ID to get details for
97
+
98
+ ## Usage Example
99
+
100
+ In Cursor, you can ask the AI agent:
101
+
102
+ > "Get all open feedback for my project and fix them"
103
+
104
+ The agent will:
105
+ 1. Call `get_open_feedback` to retrieve all open comments
106
+ 2. For each comment, use the hints to search your codebase
107
+ 3. Make the necessary code changes
108
+ 4. Call `mark_feedback_resolved` to update the status
109
+
110
+ ## How It Works
111
+
112
+ 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:
113
+
114
+ - **Element identification**: Multiple selector strategies (ID, test ID, CSS path, XPath)
115
+ - **Route mapping**: Extracts page path and suggests likely source files
116
+ - **Search hints**: Generates terms to grep for in your codebase
117
+
118
+ ## Development
119
+
120
+ ```bash
121
+ # Watch mode
122
+ npm run dev
123
+
124
+ # Build
125
+ npm run build
126
+
127
+ # Test locally
128
+ SUPER_FEEDBACK_ACCESS_CODE=your-access-code \
129
+ SUPER_FEEDBACK_ADMIN_CODE=your-admin-code \
130
+ node dist/index.js
131
+ ```
132
+
133
+ ## Troubleshooting
134
+
135
+ ### "ACCESS_CODE environment variable is required"
136
+
137
+ Make sure you've set the `SUPER_FEEDBACK_ACCESS_CODE` in your MCP config's `env` section.
138
+
139
+ ### "API error: 401"
140
+
141
+ Your access code is invalid or expired. Check your project settings in Super Feedback.
142
+
143
+ ### "API error: 404"
144
+
145
+ The project may have been deleted or the Convex deployment URL is incorrect.
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,221 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import * as z from "zod";
5
+ // Configuration from environment
6
+ // Note: HTTP endpoints use .convex.site, not .convex.cloud
7
+ const CONVEX_URL = process.env.CONVEX_URL || "https://energized-eel-335.convex.site";
8
+ const ACCESS_CODE = process.env.SUPER_FEEDBACK_ACCESS_CODE;
9
+ const ADMIN_CODE = process.env.SUPER_FEEDBACK_ADMIN_CODE;
10
+ if (!ACCESS_CODE && !ADMIN_CODE) {
11
+ console.error("Error: Either SUPER_FEEDBACK_ACCESS_CODE or SUPER_FEEDBACK_ADMIN_CODE environment variable is required");
12
+ process.exit(1);
13
+ }
14
+ // API call helper
15
+ async function callConvexAPI(endpoint, options) {
16
+ const url = `${CONVEX_URL}${endpoint}`;
17
+ const response = await fetch(url, {
18
+ ...options,
19
+ headers: {
20
+ "Content-Type": "application/json",
21
+ ...options?.headers,
22
+ },
23
+ });
24
+ if (!response.ok) {
25
+ const error = await response.text();
26
+ throw new Error(`API error: ${response.status} - ${error}`);
27
+ }
28
+ return response.json();
29
+ }
30
+ // Create MCP server
31
+ const server = new McpServer({
32
+ name: "super-feedback",
33
+ version: "0.1.0",
34
+ });
35
+ // Tool 1: Get open feedback
36
+ server.registerTool("get_open_feedback", {
37
+ title: "Get Open Feedback",
38
+ description: `Retrieves all open (unresolved) feedback comments for the configured Super Feedback project.
39
+
40
+ Returns feedback formatted for AI consumption with:
41
+ - The actual feedback/comment text
42
+ - Element context (tag, text content, CSS classes, test IDs)
43
+ - Page URL and likely file paths
44
+ - Search hints to help locate the code
45
+
46
+ Use this to understand what changes clients have requested.`,
47
+ inputSchema: {
48
+ includeResolved: z.boolean().optional().describe("Include resolved comments too (default: false)"),
49
+ pageFilter: z.string().optional().describe("Filter to specific page path (e.g., '/pricing')"),
50
+ },
51
+ outputSchema: {
52
+ projectName: z.string(),
53
+ totalCount: z.number(),
54
+ comments: z.array(z.object({
55
+ id: z.string(),
56
+ index: z.number(),
57
+ feedback: z.string(),
58
+ author: z.string(),
59
+ status: z.string(),
60
+ createdAt: z.string(),
61
+ element: z.any().nullable(),
62
+ page: z.object({
63
+ url: z.string(),
64
+ path: z.string(),
65
+ }),
66
+ hints: z.object({
67
+ possibleFiles: z.array(z.string()),
68
+ searchTerms: z.array(z.string()),
69
+ }),
70
+ })),
71
+ },
72
+ }, async ({ includeResolved = false, pageFilter }) => {
73
+ try {
74
+ // Build query params
75
+ const params = new URLSearchParams();
76
+ if (ACCESS_CODE)
77
+ params.set("accessCode", ACCESS_CODE);
78
+ if (ADMIN_CODE)
79
+ params.set("adminCode", ADMIN_CODE);
80
+ if (!includeResolved)
81
+ params.set("status", "open");
82
+ if (pageFilter)
83
+ params.set("page", pageFilter);
84
+ // Use the AI-optimized endpoint
85
+ const response = await callConvexAPI(`/api/feedback/ai?${params.toString()}`);
86
+ const output = {
87
+ projectName: response.project?.name || "Unknown Project",
88
+ totalCount: response.totalCount,
89
+ comments: response.comments,
90
+ };
91
+ // Create human-readable summary
92
+ const summary = response.comments.map(c => `#${c.index} [${c.status}] "${c.feedback}" on <${c.element?.tag || "element"}> "${c.element?.text || ""}" (${c.page.path})`).join("\n");
93
+ return {
94
+ content: [{
95
+ type: "text",
96
+ text: `Found ${response.totalCount} feedback item(s):\n\n${summary}\n\nFull data available in structuredContent.`,
97
+ }],
98
+ structuredContent: output,
99
+ };
100
+ }
101
+ catch (error) {
102
+ const message = error instanceof Error ? error.message : "Unknown error";
103
+ return {
104
+ content: [{ type: "text", text: `Error fetching feedback: ${message}` }],
105
+ isError: true,
106
+ };
107
+ }
108
+ });
109
+ // Tool 2: Mark feedback as resolved
110
+ server.registerTool("mark_feedback_resolved", {
111
+ title: "Mark Feedback Resolved",
112
+ description: `Marks a feedback comment as resolved after you've fixed the issue.
113
+
114
+ Call this after making the code changes to update the feedback status.
115
+ The comment ID can be obtained from get_open_feedback.
116
+
117
+ Note: Requires SUPER_FEEDBACK_ADMIN_CODE to be configured.`,
118
+ inputSchema: {
119
+ commentId: z.string().describe("The comment ID to mark as resolved"),
120
+ },
121
+ outputSchema: {
122
+ success: z.boolean(),
123
+ message: z.string(),
124
+ },
125
+ }, async ({ commentId }) => {
126
+ if (!ADMIN_CODE) {
127
+ return {
128
+ content: [{ type: "text", text: "Error: SUPER_FEEDBACK_ADMIN_CODE is required to update feedback status" }],
129
+ structuredContent: { success: false, message: "Admin code not configured" },
130
+ isError: true,
131
+ };
132
+ }
133
+ try {
134
+ await callConvexAPI(`/api/feedback/ai/status`, {
135
+ method: "POST",
136
+ body: JSON.stringify({
137
+ adminCode: ADMIN_CODE,
138
+ commentId,
139
+ status: "resolved",
140
+ }),
141
+ });
142
+ const output = {
143
+ success: true,
144
+ message: `Comment ${commentId} marked as resolved`,
145
+ };
146
+ return {
147
+ content: [{ type: "text", text: output.message }],
148
+ structuredContent: output,
149
+ };
150
+ }
151
+ catch (error) {
152
+ const message = error instanceof Error ? error.message : "Unknown error";
153
+ return {
154
+ content: [{ type: "text", text: `Error: ${message}` }],
155
+ structuredContent: { success: false, message },
156
+ isError: true,
157
+ };
158
+ }
159
+ });
160
+ // Tool 3: Get feedback details
161
+ server.registerTool("get_feedback_details", {
162
+ title: "Get Feedback Details",
163
+ description: `Gets full details for a specific feedback comment, including all element data and metadata.
164
+
165
+ Use this when you need more context about a specific piece of feedback.`,
166
+ inputSchema: {
167
+ commentId: z.string().describe("The comment ID to get details for"),
168
+ },
169
+ outputSchema: {
170
+ found: z.boolean(),
171
+ comment: z.any().nullable(),
172
+ },
173
+ }, async ({ commentId }) => {
174
+ try {
175
+ // Build query params - get all comments and find the specific one
176
+ const params = new URLSearchParams();
177
+ if (ACCESS_CODE)
178
+ params.set("accessCode", ACCESS_CODE);
179
+ if (ADMIN_CODE)
180
+ params.set("adminCode", ADMIN_CODE);
181
+ params.set("status", "all"); // Get all statuses
182
+ const response = await callConvexAPI(`/api/feedback/ai?${params.toString()}`);
183
+ const comment = response.comments?.find(c => c.id === commentId);
184
+ if (!comment) {
185
+ return {
186
+ content: [{ type: "text", text: `Comment ${commentId} not found` }],
187
+ structuredContent: { found: false, comment: null },
188
+ };
189
+ }
190
+ const output = {
191
+ found: true,
192
+ comment: comment,
193
+ };
194
+ return {
195
+ content: [{
196
+ type: "text",
197
+ text: `Feedback: "${comment.feedback}"\nElement: <${comment.element?.tag || "unknown"}> "${comment.element?.text || ""}"\nPage: ${comment.page.path}\nSearch terms: ${comment.hints.searchTerms.join(", ")}`,
198
+ }],
199
+ structuredContent: output,
200
+ };
201
+ }
202
+ catch (error) {
203
+ const message = error instanceof Error ? error.message : "Unknown error";
204
+ return {
205
+ content: [{ type: "text", text: `Error: ${message}` }],
206
+ structuredContent: { found: false, comment: null },
207
+ isError: true,
208
+ };
209
+ }
210
+ });
211
+ // Start the server
212
+ async function main() {
213
+ const transport = new StdioServerTransport();
214
+ await server.connect(transport);
215
+ // Log to stderr so it doesn't interfere with MCP protocol on stdout
216
+ console.error("Super Feedback MCP server running...");
217
+ }
218
+ main().catch((error) => {
219
+ console.error("Fatal error:", error);
220
+ process.exit(1);
221
+ });
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "super-feedback-mcp",
3
+ "version": "0.1.0",
4
+ "description": "MCP server for Super Feedback - enables AI agents to query and resolve client feedback",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "super-feedback-mcp": "dist/index.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "dev": "tsc --watch",
13
+ "start": "node dist/index.js",
14
+ "prepare": "npm run build"
15
+ },
16
+ "keywords": [
17
+ "mcp",
18
+ "feedback",
19
+ "cursor",
20
+ "ai-agent"
21
+ ],
22
+ "license": "MIT",
23
+ "dependencies": {
24
+ "@modelcontextprotocol/sdk": "^1.0.0",
25
+ "zod": "^3.24.0"
26
+ },
27
+ "devDependencies": {
28
+ "@types/node": "^22.10.0",
29
+ "typescript": "^5.7.2"
30
+ },
31
+ "engines": {
32
+ "node": ">=18"
33
+ }
34
+ }
package/src/index.ts ADDED
@@ -0,0 +1,284 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import * as z from "zod";
5
+
6
+ // Types for API responses
7
+ interface FeedbackComment {
8
+ id: string;
9
+ index: number;
10
+ feedback: string;
11
+ author: string;
12
+ status: string;
13
+ createdAt: string;
14
+ element: {
15
+ tag?: string;
16
+ text?: string;
17
+ testId?: string;
18
+ id?: string;
19
+ cssPath?: string;
20
+ section?: string;
21
+ nearbyText?: string;
22
+ selector?: string;
23
+ } | null;
24
+ page: { url: string; path: string };
25
+ hints: { possibleFiles: string[]; searchTerms: string[] };
26
+ raw?: { elementSelector?: string; elementXPath?: string };
27
+ }
28
+
29
+ interface FeedbackResponse {
30
+ project: { id: string; name: string; url: string };
31
+ isAdmin?: boolean;
32
+ totalCount: number;
33
+ comments: FeedbackComment[];
34
+ }
35
+
36
+ // Configuration from environment
37
+ // Note: HTTP endpoints use .convex.site, not .convex.cloud
38
+ const CONVEX_URL = process.env.CONVEX_URL || "https://energized-eel-335.convex.site";
39
+ const ACCESS_CODE = process.env.SUPER_FEEDBACK_ACCESS_CODE;
40
+ const ADMIN_CODE = process.env.SUPER_FEEDBACK_ADMIN_CODE;
41
+
42
+ if (!ACCESS_CODE && !ADMIN_CODE) {
43
+ console.error("Error: Either SUPER_FEEDBACK_ACCESS_CODE or SUPER_FEEDBACK_ADMIN_CODE environment variable is required");
44
+ process.exit(1);
45
+ }
46
+
47
+ // API call helper
48
+ async function callConvexAPI<T>(endpoint: string, options?: RequestInit): Promise<T> {
49
+ const url = `${CONVEX_URL}${endpoint}`;
50
+ const response = await fetch(url, {
51
+ ...options,
52
+ headers: {
53
+ "Content-Type": "application/json",
54
+ ...options?.headers,
55
+ },
56
+ });
57
+
58
+ if (!response.ok) {
59
+ const error = await response.text();
60
+ throw new Error(`API error: ${response.status} - ${error}`);
61
+ }
62
+
63
+ return response.json();
64
+ }
65
+
66
+ // Create MCP server
67
+ const server = new McpServer({
68
+ name: "super-feedback",
69
+ version: "0.1.0",
70
+ });
71
+
72
+ // Tool 1: Get open feedback
73
+ server.registerTool(
74
+ "get_open_feedback",
75
+ {
76
+ title: "Get Open Feedback",
77
+ description: `Retrieves all open (unresolved) feedback comments for the configured Super Feedback project.
78
+
79
+ Returns feedback formatted for AI consumption with:
80
+ - The actual feedback/comment text
81
+ - Element context (tag, text content, CSS classes, test IDs)
82
+ - Page URL and likely file paths
83
+ - Search hints to help locate the code
84
+
85
+ Use this to understand what changes clients have requested.`,
86
+ inputSchema: {
87
+ includeResolved: z.boolean().optional().describe("Include resolved comments too (default: false)"),
88
+ pageFilter: z.string().optional().describe("Filter to specific page path (e.g., '/pricing')"),
89
+ },
90
+ outputSchema: {
91
+ projectName: z.string(),
92
+ totalCount: z.number(),
93
+ comments: z.array(z.object({
94
+ id: z.string(),
95
+ index: z.number(),
96
+ feedback: z.string(),
97
+ author: z.string(),
98
+ status: z.string(),
99
+ createdAt: z.string(),
100
+ element: z.any().nullable(),
101
+ page: z.object({
102
+ url: z.string(),
103
+ path: z.string(),
104
+ }),
105
+ hints: z.object({
106
+ possibleFiles: z.array(z.string()),
107
+ searchTerms: z.array(z.string()),
108
+ }),
109
+ })),
110
+ },
111
+ },
112
+ async ({ includeResolved = false, pageFilter }) => {
113
+ try {
114
+ // Build query params
115
+ const params = new URLSearchParams();
116
+ if (ACCESS_CODE) params.set("accessCode", ACCESS_CODE);
117
+ if (ADMIN_CODE) params.set("adminCode", ADMIN_CODE);
118
+ if (!includeResolved) params.set("status", "open");
119
+ if (pageFilter) params.set("page", pageFilter);
120
+
121
+ // Use the AI-optimized endpoint
122
+ const response = await callConvexAPI<FeedbackResponse>(
123
+ `/api/feedback/ai?${params.toString()}`
124
+ );
125
+
126
+ const output = {
127
+ projectName: response.project?.name || "Unknown Project",
128
+ totalCount: response.totalCount,
129
+ comments: response.comments,
130
+ };
131
+
132
+ // Create human-readable summary
133
+ const summary = response.comments.map(c =>
134
+ `#${c.index} [${c.status}] "${c.feedback}" on <${c.element?.tag || "element"}> "${c.element?.text || ""}" (${c.page.path})`
135
+ ).join("\n");
136
+
137
+ return {
138
+ content: [{
139
+ type: "text",
140
+ text: `Found ${response.totalCount} feedback item(s):\n\n${summary}\n\nFull data available in structuredContent.`,
141
+ }],
142
+ structuredContent: output,
143
+ };
144
+ } catch (error) {
145
+ const message = error instanceof Error ? error.message : "Unknown error";
146
+ return {
147
+ content: [{ type: "text", text: `Error fetching feedback: ${message}` }],
148
+ isError: true,
149
+ };
150
+ }
151
+ }
152
+ );
153
+
154
+ // Tool 2: Mark feedback as resolved
155
+ server.registerTool(
156
+ "mark_feedback_resolved",
157
+ {
158
+ title: "Mark Feedback Resolved",
159
+ description: `Marks a feedback comment as resolved after you've fixed the issue.
160
+
161
+ Call this after making the code changes to update the feedback status.
162
+ The comment ID can be obtained from get_open_feedback.
163
+
164
+ Note: Requires SUPER_FEEDBACK_ADMIN_CODE to be configured.`,
165
+ inputSchema: {
166
+ commentId: z.string().describe("The comment ID to mark as resolved"),
167
+ },
168
+ outputSchema: {
169
+ success: z.boolean(),
170
+ message: z.string(),
171
+ },
172
+ },
173
+ async ({ commentId }) => {
174
+ if (!ADMIN_CODE) {
175
+ return {
176
+ content: [{ type: "text", text: "Error: SUPER_FEEDBACK_ADMIN_CODE is required to update feedback status" }],
177
+ structuredContent: { success: false, message: "Admin code not configured" },
178
+ isError: true,
179
+ };
180
+ }
181
+
182
+ try {
183
+ await callConvexAPI(`/api/feedback/ai/status`, {
184
+ method: "POST",
185
+ body: JSON.stringify({
186
+ adminCode: ADMIN_CODE,
187
+ commentId,
188
+ status: "resolved",
189
+ }),
190
+ });
191
+
192
+ const output = {
193
+ success: true,
194
+ message: `Comment ${commentId} marked as resolved`,
195
+ };
196
+
197
+ return {
198
+ content: [{ type: "text", text: output.message }],
199
+ structuredContent: output,
200
+ };
201
+ } catch (error) {
202
+ const message = error instanceof Error ? error.message : "Unknown error";
203
+ return {
204
+ content: [{ type: "text", text: `Error: ${message}` }],
205
+ structuredContent: { success: false, message },
206
+ isError: true,
207
+ };
208
+ }
209
+ }
210
+ );
211
+
212
+ // Tool 3: Get feedback details
213
+ server.registerTool(
214
+ "get_feedback_details",
215
+ {
216
+ title: "Get Feedback Details",
217
+ description: `Gets full details for a specific feedback comment, including all element data and metadata.
218
+
219
+ Use this when you need more context about a specific piece of feedback.`,
220
+ inputSchema: {
221
+ commentId: z.string().describe("The comment ID to get details for"),
222
+ },
223
+ outputSchema: {
224
+ found: z.boolean(),
225
+ comment: z.any().nullable(),
226
+ },
227
+ },
228
+ async ({ commentId }) => {
229
+ try {
230
+ // Build query params - get all comments and find the specific one
231
+ const params = new URLSearchParams();
232
+ if (ACCESS_CODE) params.set("accessCode", ACCESS_CODE);
233
+ if (ADMIN_CODE) params.set("adminCode", ADMIN_CODE);
234
+ params.set("status", "all"); // Get all statuses
235
+
236
+ const response = await callConvexAPI<FeedbackResponse>(
237
+ `/api/feedback/ai?${params.toString()}`
238
+ );
239
+
240
+ const comment = response.comments?.find(c => c.id === commentId);
241
+
242
+ if (!comment) {
243
+ return {
244
+ content: [{ type: "text", text: `Comment ${commentId} not found` }],
245
+ structuredContent: { found: false, comment: null },
246
+ };
247
+ }
248
+
249
+ const output = {
250
+ found: true,
251
+ comment: comment,
252
+ };
253
+
254
+ return {
255
+ content: [{
256
+ type: "text",
257
+ text: `Feedback: "${comment.feedback}"\nElement: <${comment.element?.tag || "unknown"}> "${comment.element?.text || ""}"\nPage: ${comment.page.path}\nSearch terms: ${comment.hints.searchTerms.join(", ")}`,
258
+ }],
259
+ structuredContent: output,
260
+ };
261
+ } catch (error) {
262
+ const message = error instanceof Error ? error.message : "Unknown error";
263
+ return {
264
+ content: [{ type: "text", text: `Error: ${message}` }],
265
+ structuredContent: { found: false, comment: null },
266
+ isError: true,
267
+ };
268
+ }
269
+ }
270
+ );
271
+
272
+ // Start the server
273
+ async function main() {
274
+ const transport = new StdioServerTransport();
275
+ await server.connect(transport);
276
+
277
+ // Log to stderr so it doesn't interfere with MCP protocol on stdout
278
+ console.error("Super Feedback MCP server running...");
279
+ }
280
+
281
+ main().catch((error) => {
282
+ console.error("Fatal error:", error);
283
+ process.exit(1);
284
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "esModuleInterop": true,
7
+ "strict": true,
8
+ "skipLibCheck": true,
9
+ "outDir": "dist",
10
+ "rootDir": "src",
11
+ "declaration": true,
12
+ "resolveJsonModule": true
13
+ },
14
+ "include": ["src/**/*"],
15
+ "exclude": ["node_modules", "dist"]
16
+ }