mcp-feedback-enhanced 0.1.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/README.md +113 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +361 -0
- package/package.json +50 -0
package/README.md
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# MCP Feedback Enhanced Server
|
|
2
|
+
|
|
3
|
+
**Version: 0.1.44**
|
|
4
|
+
|
|
5
|
+
MCP Server component that connects to the VSCode Extension's WebSocket server to collect user feedback.
|
|
6
|
+
|
|
7
|
+
## Architecture
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
┌─────────────────┐ ┌─────────────────┐
|
|
11
|
+
│ Cursor/AI │ stdio │ MCP Server │
|
|
12
|
+
│ (AI Client) │ ←────→ │ (This) │
|
|
13
|
+
└─────────────────┘ └────────┬────────┘
|
|
14
|
+
│ WebSocket
|
|
15
|
+
▼
|
|
16
|
+
┌─────────────────┐
|
|
17
|
+
│ VSCode Extension│
|
|
18
|
+
│ (WS Server) │
|
|
19
|
+
└────────┬────────┘
|
|
20
|
+
│
|
|
21
|
+
▼
|
|
22
|
+
┌─────────────────┐
|
|
23
|
+
│ Feedback Panel │
|
|
24
|
+
│ (Webview) │
|
|
25
|
+
└─────────────────┘
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## How It Works
|
|
29
|
+
|
|
30
|
+
1. **Extension starts** → Creates WebSocket server → Writes `~/.config/mcp-feedback-enhanced/servers/<pid>.json`
|
|
31
|
+
2. **MCP Server starts** → Waits for `interactive_feedback` call
|
|
32
|
+
3. **AI calls tool** → MCP Server reads server files → Finds matching Extension by workspace path → Connects
|
|
33
|
+
4. **User submits** → Feedback flows back to AI
|
|
34
|
+
|
|
35
|
+
## Server Discovery
|
|
36
|
+
|
|
37
|
+
MCP Server finds the correct Extension using multi-strategy matching:
|
|
38
|
+
|
|
39
|
+
1. **Exact workspace match** - `project_directory` in server's `workspaces` array
|
|
40
|
+
2. **Prefix match** - Project is inside a workspace directory
|
|
41
|
+
3. **parentPid match** - Same parent process (backward compatibility)
|
|
42
|
+
4. **Single server** - Only one server running
|
|
43
|
+
5. **Most recent** - Last registered server
|
|
44
|
+
|
|
45
|
+
## Tools
|
|
46
|
+
|
|
47
|
+
### interactive_feedback
|
|
48
|
+
|
|
49
|
+
Collect feedback from user through the VSCode sidebar panel.
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
{
|
|
53
|
+
project_directory: string; // Project path for context & server matching
|
|
54
|
+
summary: string; // AI summary for user review
|
|
55
|
+
timeout?: number; // Timeout in seconds (default: 600)
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### get_system_info
|
|
60
|
+
|
|
61
|
+
Returns system environment information.
|
|
62
|
+
|
|
63
|
+
## Configuration
|
|
64
|
+
|
|
65
|
+
Add to `~/.cursor/mcp.json`:
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
{
|
|
69
|
+
"mcpServers": {
|
|
70
|
+
"mcp-feedback-enhanced": {
|
|
71
|
+
"command": "node",
|
|
72
|
+
"args": ["/path/to/mcp-server/dist/index.js"],
|
|
73
|
+
"env": {
|
|
74
|
+
"MCP_FEEDBACK_DEBUG": "true"
|
|
75
|
+
},
|
|
76
|
+
"timeout": 89400,
|
|
77
|
+
"autoApprove": ["interactive_feedback"]
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Environment Variables
|
|
84
|
+
|
|
85
|
+
| Variable | Default | Description |
|
|
86
|
+
|----------|---------|-------------|
|
|
87
|
+
| `MCP_FEEDBACK_DEBUG` | `false` | Enable debug logging to stderr |
|
|
88
|
+
|
|
89
|
+
## Debug Mode
|
|
90
|
+
|
|
91
|
+
Set `MCP_FEEDBACK_DEBUG=true` to see:
|
|
92
|
+
- Server discovery process
|
|
93
|
+
- WebSocket connection status
|
|
94
|
+
- Message flow between components
|
|
95
|
+
|
|
96
|
+
## Troubleshooting
|
|
97
|
+
|
|
98
|
+
### "No MCP Feedback Extension found for project"
|
|
99
|
+
|
|
100
|
+
1. Ensure VSCode extension is installed and activated
|
|
101
|
+
2. Open the MCP Feedback panel (click sidebar icon)
|
|
102
|
+
3. Check `~/.config/mcp-feedback-enhanced/servers/` for server files
|
|
103
|
+
4. Verify your project path is in the `workspaces` array
|
|
104
|
+
|
|
105
|
+
### Connection timeout
|
|
106
|
+
|
|
107
|
+
1. Check if Extension's WebSocket server is running (port in server file)
|
|
108
|
+
2. Verify no firewall blocking localhost connections
|
|
109
|
+
3. Try reloading the Cursor window
|
|
110
|
+
|
|
111
|
+
## License
|
|
112
|
+
|
|
113
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* MCP Feedback Server - TypeScript Implementation
|
|
4
|
+
*
|
|
5
|
+
* This server provides the interactive_feedback tool that collects
|
|
6
|
+
* user feedback through a VSCode extension sidebar panel.
|
|
7
|
+
*
|
|
8
|
+
* NEW ARCHITECTURE: MCP Server connects to Extension's WebSocket Server
|
|
9
|
+
* (instead of running its own WebSocket Server)
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* MCP Feedback Server - TypeScript Implementation
|
|
4
|
+
*
|
|
5
|
+
* This server provides the interactive_feedback tool that collects
|
|
6
|
+
* user feedback through a VSCode extension sidebar panel.
|
|
7
|
+
*
|
|
8
|
+
* NEW ARCHITECTURE: MCP Server connects to Extension's WebSocket Server
|
|
9
|
+
* (instead of running its own WebSocket Server)
|
|
10
|
+
*/
|
|
11
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
12
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
13
|
+
import WebSocket from 'ws';
|
|
14
|
+
import * as z from 'zod';
|
|
15
|
+
import * as os from 'os';
|
|
16
|
+
import * as fs from 'fs';
|
|
17
|
+
import * as path from 'path';
|
|
18
|
+
import { createRequire } from 'module';
|
|
19
|
+
// Read version from package.json (ES module compatible)
|
|
20
|
+
const require = createRequire(import.meta.url);
|
|
21
|
+
const packageJson = require('../package.json');
|
|
22
|
+
const VERSION = packageJson.version || '0.0.0';
|
|
23
|
+
// Configuration
|
|
24
|
+
const DEBUG = process.env.MCP_FEEDBACK_DEBUG === 'true';
|
|
25
|
+
const CONFIG_DIR = path.join(os.homedir(), '.config', 'mcp-feedback-enhanced');
|
|
26
|
+
const SERVERS_DIR = path.join(CONFIG_DIR, 'servers');
|
|
27
|
+
const CONNECTION_TIMEOUT_MS = 5000; // 5 seconds to connect
|
|
28
|
+
const HEARTBEAT_INTERVAL_MS = 30000; // 30 seconds heartbeat
|
|
29
|
+
// Debug logging
|
|
30
|
+
function debug(message) {
|
|
31
|
+
if (DEBUG) {
|
|
32
|
+
console.error(`[MCP Feedback] ${message}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// State
|
|
36
|
+
let ws = null;
|
|
37
|
+
let isConnected = false;
|
|
38
|
+
let pendingFeedbackResolvers = new Map();
|
|
39
|
+
/**
|
|
40
|
+
* Get all live Extension servers
|
|
41
|
+
*/
|
|
42
|
+
function getLiveServers() {
|
|
43
|
+
try {
|
|
44
|
+
if (!fs.existsSync(SERVERS_DIR)) {
|
|
45
|
+
debug('Servers directory not found');
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
48
|
+
const files = fs.readdirSync(SERVERS_DIR);
|
|
49
|
+
const servers = [];
|
|
50
|
+
for (const file of files) {
|
|
51
|
+
if (!file.endsWith('.json'))
|
|
52
|
+
continue;
|
|
53
|
+
try {
|
|
54
|
+
const data = JSON.parse(fs.readFileSync(path.join(SERVERS_DIR, file), 'utf-8'));
|
|
55
|
+
// Verify process is still alive
|
|
56
|
+
try {
|
|
57
|
+
process.kill(data.pid, 0);
|
|
58
|
+
servers.push({
|
|
59
|
+
...data,
|
|
60
|
+
workspaces: data.workspaces || [] // Handle old format
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
// Process dead, skip
|
|
65
|
+
debug(`Skipping dead server: pid=${data.pid}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// Skip invalid files
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return servers;
|
|
73
|
+
}
|
|
74
|
+
catch (e) {
|
|
75
|
+
debug(`Error reading servers: ${e}`);
|
|
76
|
+
return [];
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Find the best Extension server for a given project path
|
|
81
|
+
* Uses workspace matching as primary strategy
|
|
82
|
+
*/
|
|
83
|
+
function findExtensionForProject(projectPath) {
|
|
84
|
+
const servers = getLiveServers();
|
|
85
|
+
debug(`Looking for Extension for project: ${projectPath}`);
|
|
86
|
+
debug(`Found ${servers.length} live Extension server(s)`);
|
|
87
|
+
if (servers.length === 0) {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
// Strategy 1: Exact workspace match
|
|
91
|
+
for (const server of servers) {
|
|
92
|
+
if (server.workspaces?.includes(projectPath)) {
|
|
93
|
+
debug(`✓ Exact workspace match: port=${server.port}`);
|
|
94
|
+
return server;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// Strategy 2: Prefix match (project is inside a workspace)
|
|
98
|
+
for (const server of servers) {
|
|
99
|
+
for (const ws of server.workspaces || []) {
|
|
100
|
+
if (projectPath.startsWith(ws + path.sep) || ws.startsWith(projectPath + path.sep)) {
|
|
101
|
+
debug(`✓ Prefix workspace match: port=${server.port}, workspace=${ws}`);
|
|
102
|
+
return server;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Strategy 3: parentPid match (backward compatibility)
|
|
107
|
+
const myParentPid = process.ppid;
|
|
108
|
+
const parentMatch = servers.find(s => s.parentPid === myParentPid);
|
|
109
|
+
if (parentMatch) {
|
|
110
|
+
debug(`✓ parentPid match: port=${parentMatch.port}`);
|
|
111
|
+
return parentMatch;
|
|
112
|
+
}
|
|
113
|
+
// Strategy 4: Single server fallback
|
|
114
|
+
if (servers.length === 1) {
|
|
115
|
+
debug(`✓ Single server fallback: port=${servers[0].port}`);
|
|
116
|
+
return servers[0];
|
|
117
|
+
}
|
|
118
|
+
// Strategy 5: Most recent server
|
|
119
|
+
const sorted = servers.sort((a, b) => b.timestamp - a.timestamp);
|
|
120
|
+
debug(`✓ Using most recent server: port=${sorted[0].port}`);
|
|
121
|
+
debug(` Available servers:`);
|
|
122
|
+
sorted.forEach(s => {
|
|
123
|
+
debug(` - pid=${s.pid}, port=${s.port}, workspaces=${s.workspaces?.join(', ')}`);
|
|
124
|
+
});
|
|
125
|
+
return sorted[0];
|
|
126
|
+
}
|
|
127
|
+
// Track which server we're connected to
|
|
128
|
+
let connectedPort = null;
|
|
129
|
+
/**
|
|
130
|
+
* Connect to Extension's WebSocket Server for a specific project
|
|
131
|
+
*/
|
|
132
|
+
function connectToExtension(projectPath) {
|
|
133
|
+
return new Promise((resolve, reject) => {
|
|
134
|
+
const server = findExtensionForProject(projectPath);
|
|
135
|
+
if (!server) {
|
|
136
|
+
reject(new Error(`No MCP Feedback Extension found for project: ${projectPath}. Please ensure the extension is installed and a Cursor window is open with this project.`));
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const url = `ws://127.0.0.1:${server.port}/ws`;
|
|
140
|
+
debug(`Connecting to Extension at ${url} for project ${projectPath}`);
|
|
141
|
+
ws = new WebSocket(url);
|
|
142
|
+
ws.on('open', () => {
|
|
143
|
+
debug('Connected to Extension WebSocket Server');
|
|
144
|
+
isConnected = true;
|
|
145
|
+
connectedPort = server.port;
|
|
146
|
+
// Register as MCP Server
|
|
147
|
+
ws?.send(JSON.stringify({
|
|
148
|
+
type: 'register',
|
|
149
|
+
clientType: 'mcp-server',
|
|
150
|
+
pid: process.pid,
|
|
151
|
+
parentPid: process.ppid
|
|
152
|
+
}));
|
|
153
|
+
resolve();
|
|
154
|
+
});
|
|
155
|
+
ws.on('message', (data) => {
|
|
156
|
+
try {
|
|
157
|
+
const message = JSON.parse(data.toString());
|
|
158
|
+
handleMessage(message);
|
|
159
|
+
}
|
|
160
|
+
catch (e) {
|
|
161
|
+
debug(`Parse error: ${e}`);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
ws.on('close', () => {
|
|
165
|
+
debug('Disconnected from Extension');
|
|
166
|
+
isConnected = false;
|
|
167
|
+
connectedPort = null;
|
|
168
|
+
ws = null;
|
|
169
|
+
// Reject all pending feedback requests
|
|
170
|
+
pendingFeedbackResolvers.forEach((resolver, sessionId) => {
|
|
171
|
+
clearTimeout(resolver.timeout);
|
|
172
|
+
resolver.reject(new Error('Connection to Extension lost'));
|
|
173
|
+
});
|
|
174
|
+
pendingFeedbackResolvers.clear();
|
|
175
|
+
});
|
|
176
|
+
ws.on('error', (err) => {
|
|
177
|
+
debug(`WebSocket error: ${err.message}`);
|
|
178
|
+
if (!isConnected) {
|
|
179
|
+
reject(err);
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
// Timeout for initial connection
|
|
183
|
+
setTimeout(() => {
|
|
184
|
+
if (!isConnected) {
|
|
185
|
+
ws?.close();
|
|
186
|
+
reject(new Error(`Connection timeout to ${url}`));
|
|
187
|
+
}
|
|
188
|
+
}, CONNECTION_TIMEOUT_MS);
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Ensure connected to the right Extension for this project
|
|
193
|
+
*/
|
|
194
|
+
async function ensureConnectedForProject(projectPath) {
|
|
195
|
+
// Check if we need to reconnect (different project might need different Extension)
|
|
196
|
+
const server = findExtensionForProject(projectPath);
|
|
197
|
+
if (!server) {
|
|
198
|
+
throw new Error(`No MCP Feedback Extension found for project: ${projectPath}. Please open the project in Cursor with the MCP Feedback extension installed.`);
|
|
199
|
+
}
|
|
200
|
+
// If already connected to the right server, reuse connection
|
|
201
|
+
if (isConnected && ws?.readyState === WebSocket.OPEN && connectedPort === server.port) {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
// Close existing connection if any
|
|
205
|
+
if (ws) {
|
|
206
|
+
ws.close();
|
|
207
|
+
ws = null;
|
|
208
|
+
isConnected = false;
|
|
209
|
+
connectedPort = null;
|
|
210
|
+
}
|
|
211
|
+
// Connect to the right server
|
|
212
|
+
await connectToExtension(projectPath);
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Handle messages from Extension
|
|
216
|
+
*/
|
|
217
|
+
function handleMessage(message) {
|
|
218
|
+
debug(`Received: ${message.type}`);
|
|
219
|
+
switch (message.type) {
|
|
220
|
+
case 'connection_established':
|
|
221
|
+
debug(`Connected to Extension v${message.version}`);
|
|
222
|
+
break;
|
|
223
|
+
case 'feedback_result':
|
|
224
|
+
// User submitted feedback
|
|
225
|
+
const resolver = pendingFeedbackResolvers.get(message.session_id);
|
|
226
|
+
if (resolver) {
|
|
227
|
+
clearTimeout(resolver.timeout);
|
|
228
|
+
resolver.resolve({
|
|
229
|
+
feedback: message.feedback,
|
|
230
|
+
images: message.images || []
|
|
231
|
+
});
|
|
232
|
+
pendingFeedbackResolvers.delete(message.session_id);
|
|
233
|
+
}
|
|
234
|
+
break;
|
|
235
|
+
case 'feedback_error':
|
|
236
|
+
// Error getting feedback
|
|
237
|
+
const errorResolver = pendingFeedbackResolvers.get(message.session_id);
|
|
238
|
+
if (errorResolver) {
|
|
239
|
+
clearTimeout(errorResolver.timeout);
|
|
240
|
+
errorResolver.reject(new Error(message.error));
|
|
241
|
+
pendingFeedbackResolvers.delete(message.session_id);
|
|
242
|
+
}
|
|
243
|
+
break;
|
|
244
|
+
case 'pong':
|
|
245
|
+
// Heartbeat response
|
|
246
|
+
break;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Request feedback from user via Extension
|
|
251
|
+
*/
|
|
252
|
+
async function requestFeedback(projectDirectory, summary, timeout) {
|
|
253
|
+
await ensureConnectedForProject(projectDirectory);
|
|
254
|
+
const sessionId = `session_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
|
|
255
|
+
return new Promise((resolve, reject) => {
|
|
256
|
+
// Set timeout
|
|
257
|
+
const timeoutHandle = setTimeout(() => {
|
|
258
|
+
pendingFeedbackResolvers.delete(sessionId);
|
|
259
|
+
reject(new Error(`Feedback timeout after ${timeout} seconds`));
|
|
260
|
+
}, timeout * 1000);
|
|
261
|
+
// Store resolver
|
|
262
|
+
pendingFeedbackResolvers.set(sessionId, {
|
|
263
|
+
resolve,
|
|
264
|
+
reject,
|
|
265
|
+
timeout: timeoutHandle
|
|
266
|
+
});
|
|
267
|
+
// Send request to Extension
|
|
268
|
+
ws?.send(JSON.stringify({
|
|
269
|
+
type: 'feedback_request',
|
|
270
|
+
session_id: sessionId,
|
|
271
|
+
project_directory: projectDirectory,
|
|
272
|
+
summary,
|
|
273
|
+
timeout
|
|
274
|
+
}));
|
|
275
|
+
debug(`Feedback request sent: session=${sessionId}`);
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
// ============================================================================
|
|
279
|
+
// MCP Server Setup
|
|
280
|
+
// ============================================================================
|
|
281
|
+
const server = new McpServer({
|
|
282
|
+
name: 'mcp-feedback-enhanced',
|
|
283
|
+
version: VERSION
|
|
284
|
+
});
|
|
285
|
+
// Register the interactive_feedback tool
|
|
286
|
+
server.tool('interactive_feedback', 'Collect feedback from user through VSCode extension panel. The feedback panel will display the AI summary and wait for user input.', {
|
|
287
|
+
project_directory: z.string().describe('The project directory path for context'),
|
|
288
|
+
summary: z.string().describe('Summary of AI work completed for user review'),
|
|
289
|
+
timeout: z.number().optional().default(600).describe('Timeout in seconds (default: 600)')
|
|
290
|
+
}, async ({ project_directory, summary, timeout }) => {
|
|
291
|
+
debug(`interactive_feedback called: project=${project_directory}`);
|
|
292
|
+
try {
|
|
293
|
+
const result = await requestFeedback(project_directory, summary, timeout || 600);
|
|
294
|
+
// Format response
|
|
295
|
+
let response = `User Feedback:\n${result.feedback}`;
|
|
296
|
+
if (result.images && result.images.length > 0) {
|
|
297
|
+
response += `\n\n[${result.images.length} image(s) attached]`;
|
|
298
|
+
}
|
|
299
|
+
return {
|
|
300
|
+
content: [{ type: 'text', text: response }]
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
catch (error) {
|
|
304
|
+
debug(`Feedback error: ${error.message}`);
|
|
305
|
+
return {
|
|
306
|
+
content: [{ type: 'text', text: `Error: ${error.message}` }],
|
|
307
|
+
isError: true
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
// Register get_system_info tool
|
|
312
|
+
server.tool('get_system_info', 'Get system environment information', {}, async () => {
|
|
313
|
+
const info = {
|
|
314
|
+
platform: os.platform(),
|
|
315
|
+
hostname: os.hostname(),
|
|
316
|
+
user: os.userInfo().username,
|
|
317
|
+
homeDir: os.homedir(),
|
|
318
|
+
nodeVersion: process.version,
|
|
319
|
+
pid: process.pid,
|
|
320
|
+
parentPid: process.ppid,
|
|
321
|
+
extensionConnected: isConnected
|
|
322
|
+
};
|
|
323
|
+
return {
|
|
324
|
+
content: [{ type: 'text', text: JSON.stringify(info, null, 2) }]
|
|
325
|
+
};
|
|
326
|
+
});
|
|
327
|
+
// ============================================================================
|
|
328
|
+
// Main Entry Point
|
|
329
|
+
// ============================================================================
|
|
330
|
+
async function main() {
|
|
331
|
+
debug('MCP Feedback Server starting...');
|
|
332
|
+
debug(`PID: ${process.pid}, Parent PID: ${process.ppid}`);
|
|
333
|
+
debug(`Version: ${VERSION}`);
|
|
334
|
+
// Log environment for debugging
|
|
335
|
+
if (DEBUG) {
|
|
336
|
+
console.error('[MCP Feedback] Environment:');
|
|
337
|
+
Object.keys(process.env).filter(k => k.includes('CURSOR') || k.includes('VSCODE') || k.includes('MCP')).forEach(k => console.error(` ${k}=${process.env[k]}`));
|
|
338
|
+
// Show available servers
|
|
339
|
+
const servers = getLiveServers();
|
|
340
|
+
console.error(`[MCP Feedback] Available servers: ${servers.length}`);
|
|
341
|
+
servers.forEach(s => {
|
|
342
|
+
console.error(` - port=${s.port}, workspaces=${s.workspaces?.join(', ')}`);
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
// Don't connect at startup - we'll connect on demand when interactive_feedback is called
|
|
346
|
+
// This allows us to use project_directory for server matching
|
|
347
|
+
// Start MCP server on stdio
|
|
348
|
+
const transport = new StdioServerTransport();
|
|
349
|
+
await server.connect(transport);
|
|
350
|
+
debug('MCP Server running on stdio, will connect to Extension on first feedback request');
|
|
351
|
+
// Heartbeat to keep connection alive
|
|
352
|
+
setInterval(() => {
|
|
353
|
+
if (ws?.readyState === WebSocket.OPEN) {
|
|
354
|
+
ws.send(JSON.stringify({ type: 'ping' }));
|
|
355
|
+
}
|
|
356
|
+
}, HEARTBEAT_INTERVAL_MS);
|
|
357
|
+
}
|
|
358
|
+
main().catch((error) => {
|
|
359
|
+
console.error('Fatal error:', error);
|
|
360
|
+
process.exit(1);
|
|
361
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "mcp-feedback-enhanced",
|
|
3
|
+
"version": "0.1.45",
|
|
4
|
+
"description": "MCP Feedback Enhanced Server - Interactive feedback collection for AI assistants",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"mcp-feedback-enhanced": "dist/index.js",
|
|
9
|
+
"mcp-feedback-server": "dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [
|
|
12
|
+
"mcp",
|
|
13
|
+
"model-context-protocol",
|
|
14
|
+
"ai",
|
|
15
|
+
"feedback",
|
|
16
|
+
"cursor",
|
|
17
|
+
"vscode",
|
|
18
|
+
"claude"
|
|
19
|
+
],
|
|
20
|
+
"author": "Minidoracat",
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "https://github.com/Minidoracat/mcp-feedback-enhanced"
|
|
25
|
+
},
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "tsc",
|
|
28
|
+
"start": "node dist/index.js",
|
|
29
|
+
"dev": "tsx src/index.ts",
|
|
30
|
+
"prepublishOnly": "npm run build"
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
"dist",
|
|
34
|
+
"README.md"
|
|
35
|
+
],
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
38
|
+
"ws": "^8.18.0",
|
|
39
|
+
"zod": "^3.23.0"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/node": "^20.0.0",
|
|
43
|
+
"@types/ws": "^8.5.0",
|
|
44
|
+
"tsx": "^4.0.0",
|
|
45
|
+
"typescript": "^5.0.0"
|
|
46
|
+
},
|
|
47
|
+
"engines": {
|
|
48
|
+
"node": ">=18.0.0"
|
|
49
|
+
}
|
|
50
|
+
}
|