agent-desk-mcp 1.0.4 → 1.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/dist/index.js +80 -32
- package/package.json +1 -1
- package/src/index.ts +85 -33
package/dist/index.js
CHANGED
|
@@ -2,6 +2,7 @@ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
|
2
2
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
3
|
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
4
4
|
import axios from "axios";
|
|
5
|
+
import { WebSocket } from "ws";
|
|
5
6
|
class APIClient {
|
|
6
7
|
client;
|
|
7
8
|
constructor(baseUrl) {
|
|
@@ -44,6 +45,8 @@ class AgentDeskServer {
|
|
|
44
45
|
server;
|
|
45
46
|
apiClient = null;
|
|
46
47
|
apiUrl;
|
|
48
|
+
ws = null;
|
|
49
|
+
pendingRequests = new Map();
|
|
47
50
|
constructor(apiUrl) {
|
|
48
51
|
this.apiUrl = apiUrl;
|
|
49
52
|
this.server = new Server({
|
|
@@ -157,41 +160,84 @@ Returns: User's answers concatenated with newlines, or timeout message.`,
|
|
|
157
160
|
id: q.id || `Q${i + 1}`,
|
|
158
161
|
}));
|
|
159
162
|
await this.apiClient.addAgent(sessionId, agent_summary, context, processedQuestions, timeout_seconds);
|
|
160
|
-
//
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
163
|
+
// Wait for answer via WebSocket push
|
|
164
|
+
const answerPromise = new Promise((resolve) => {
|
|
165
|
+
this.pendingRequests.set(sessionId, resolve);
|
|
166
|
+
});
|
|
167
|
+
// Set up timeout if specified
|
|
168
|
+
let timeoutHandle = null;
|
|
169
|
+
if (timeout_seconds) {
|
|
170
|
+
timeoutHandle = setTimeout(() => {
|
|
171
|
+
this.pendingRequests.delete(sessionId);
|
|
166
172
|
console.error(`[${new Date().toISOString()}] TIMEOUT handleAskUser: ${sessionId}`);
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
173
|
+
}, timeout_seconds * 1000);
|
|
174
|
+
}
|
|
175
|
+
try {
|
|
176
|
+
const answer = await answerPromise;
|
|
177
|
+
if (timeoutHandle)
|
|
178
|
+
clearTimeout(timeoutHandle);
|
|
179
|
+
console.error(`[${new Date().toISOString()}] ANSWERED handleAskUser: ${sessionId}`);
|
|
180
|
+
return {
|
|
181
|
+
content: [
|
|
182
|
+
{
|
|
183
|
+
type: "text",
|
|
184
|
+
text: answer,
|
|
185
|
+
},
|
|
186
|
+
],
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
catch (error) {
|
|
190
|
+
if (timeoutHandle)
|
|
191
|
+
clearTimeout(timeoutHandle);
|
|
192
|
+
return {
|
|
193
|
+
content: [
|
|
194
|
+
{
|
|
195
|
+
type: "text",
|
|
196
|
+
text: "User did not respond within the timeout period.",
|
|
197
|
+
},
|
|
198
|
+
],
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
setupWebSocket() {
|
|
203
|
+
const wsUrl = this.apiUrl.replace(/^http/, "ws") + "/ws";
|
|
204
|
+
console.error(`Connecting to WebSocket: ${wsUrl}`);
|
|
205
|
+
this.ws = new WebSocket(wsUrl);
|
|
206
|
+
this.ws.on("open", () => {
|
|
207
|
+
console.error("WebSocket connected");
|
|
208
|
+
});
|
|
209
|
+
this.ws.on("message", (data) => {
|
|
210
|
+
try {
|
|
211
|
+
const message = JSON.parse(data.toString());
|
|
212
|
+
console.error(`WebSocket message received: ${JSON.stringify(message)}`);
|
|
213
|
+
if (message.type === "agent_answered") {
|
|
214
|
+
const sessionId = message.session_id;
|
|
215
|
+
const resolver = this.pendingRequests.get(sessionId);
|
|
216
|
+
if (resolver) {
|
|
217
|
+
// Fetch the full answer from API
|
|
218
|
+
this.apiClient.getAgent(sessionId).then((agent) => {
|
|
219
|
+
if (agent && agent.status === "answered") {
|
|
220
|
+
const answers = agent.questions
|
|
221
|
+
.filter((q) => q.answer)
|
|
222
|
+
.map((q) => `${q.id}: ${q.answer}`);
|
|
223
|
+
resolver(answers.join("\n"));
|
|
224
|
+
this.pendingRequests.delete(sessionId);
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
}
|
|
175
229
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
if (agent && agent.status === "answered") {
|
|
179
|
-
console.error(`[${new Date().toISOString()}] ANSWERED handleAskUser: ${sessionId}`);
|
|
180
|
-
const answers = agent.questions
|
|
181
|
-
.filter((q) => q.answer)
|
|
182
|
-
.map((q) => `${q.id}: ${q.answer}`);
|
|
183
|
-
return {
|
|
184
|
-
content: [
|
|
185
|
-
{
|
|
186
|
-
type: "text",
|
|
187
|
-
text: answers.join("\n"),
|
|
188
|
-
},
|
|
189
|
-
],
|
|
190
|
-
};
|
|
230
|
+
catch (error) {
|
|
231
|
+
console.error("Error processing WebSocket message:", error);
|
|
191
232
|
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
233
|
+
});
|
|
234
|
+
this.ws.on("error", (error) => {
|
|
235
|
+
console.error("WebSocket error:", error);
|
|
236
|
+
});
|
|
237
|
+
this.ws.on("close", () => {
|
|
238
|
+
console.error("WebSocket closed, reconnecting in 5s...");
|
|
239
|
+
setTimeout(() => this.setupWebSocket(), 5000);
|
|
240
|
+
});
|
|
195
241
|
}
|
|
196
242
|
async run() {
|
|
197
243
|
this.apiClient = new APIClient(this.apiUrl);
|
|
@@ -202,6 +248,8 @@ Returns: User's answers concatenated with newlines, or timeout message.`,
|
|
|
202
248
|
console.error("Please ensure the API Server is running.");
|
|
203
249
|
process.exit(1);
|
|
204
250
|
}
|
|
251
|
+
// Setup WebSocket connection
|
|
252
|
+
this.setupWebSocket();
|
|
205
253
|
const transport = new StdioServerTransport();
|
|
206
254
|
await this.server.connect(transport);
|
|
207
255
|
console.error("Agent Desk MCP Server started");
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
ServerCapabilities,
|
|
7
7
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
8
8
|
import axios, { AxiosInstance } from "axios";
|
|
9
|
+
import { WebSocket } from "ws";
|
|
9
10
|
|
|
10
11
|
interface Question {
|
|
11
12
|
id: string;
|
|
@@ -73,6 +74,8 @@ class AgentDeskServer {
|
|
|
73
74
|
private server: Server;
|
|
74
75
|
private apiClient: APIClient | null = null;
|
|
75
76
|
private apiUrl: string;
|
|
77
|
+
private ws: WebSocket | null = null;
|
|
78
|
+
private pendingRequests: Map<string, (answer: string) => void> = new Map();
|
|
76
79
|
|
|
77
80
|
constructor(apiUrl: string) {
|
|
78
81
|
this.apiUrl = apiUrl;
|
|
@@ -215,44 +218,90 @@ Returns: User's answers concatenated with newlines, or timeout message.`,
|
|
|
215
218
|
timeout_seconds
|
|
216
219
|
);
|
|
217
220
|
|
|
218
|
-
//
|
|
219
|
-
const
|
|
220
|
-
|
|
221
|
+
// Wait for answer via WebSocket push
|
|
222
|
+
const answerPromise = new Promise<string>((resolve) => {
|
|
223
|
+
this.pendingRequests.set(sessionId, resolve);
|
|
224
|
+
});
|
|
221
225
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
226
|
+
// Set up timeout if specified
|
|
227
|
+
let timeoutHandle: NodeJS.Timeout | null = null;
|
|
228
|
+
if (timeout_seconds) {
|
|
229
|
+
timeoutHandle = setTimeout(() => {
|
|
230
|
+
this.pendingRequests.delete(sessionId);
|
|
225
231
|
console.error(`[${new Date().toISOString()}] TIMEOUT handleAskUser: ${sessionId}`);
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
{
|
|
229
|
-
type: "text",
|
|
230
|
-
text: "User did not respond within the timeout period.",
|
|
231
|
-
},
|
|
232
|
-
],
|
|
233
|
-
};
|
|
234
|
-
}
|
|
232
|
+
}, timeout_seconds * 1000);
|
|
233
|
+
}
|
|
235
234
|
|
|
236
|
-
|
|
237
|
-
const
|
|
238
|
-
if (
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
235
|
+
try {
|
|
236
|
+
const answer = await answerPromise;
|
|
237
|
+
if (timeoutHandle) clearTimeout(timeoutHandle);
|
|
238
|
+
console.error(`[${new Date().toISOString()}] ANSWERED handleAskUser: ${sessionId}`);
|
|
239
|
+
return {
|
|
240
|
+
content: [
|
|
241
|
+
{
|
|
242
|
+
type: "text",
|
|
243
|
+
text: answer,
|
|
244
|
+
},
|
|
245
|
+
],
|
|
246
|
+
};
|
|
247
|
+
} catch (error) {
|
|
248
|
+
if (timeoutHandle) clearTimeout(timeoutHandle);
|
|
249
|
+
return {
|
|
250
|
+
content: [
|
|
251
|
+
{
|
|
252
|
+
type: "text",
|
|
253
|
+
text: "User did not respond within the timeout period.",
|
|
254
|
+
},
|
|
255
|
+
],
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
private setupWebSocket(): void {
|
|
261
|
+
const wsUrl = this.apiUrl.replace(/^http/, "ws") + "/ws";
|
|
262
|
+
console.error(`Connecting to WebSocket: ${wsUrl}`);
|
|
263
|
+
|
|
264
|
+
this.ws = new WebSocket(wsUrl);
|
|
265
|
+
|
|
266
|
+
this.ws.on("open", () => {
|
|
267
|
+
console.error("WebSocket connected");
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
this.ws.on("message", (data: Buffer) => {
|
|
271
|
+
try {
|
|
272
|
+
const message = JSON.parse(data.toString());
|
|
273
|
+
console.error(`WebSocket message received: ${JSON.stringify(message)}`);
|
|
274
|
+
|
|
275
|
+
if (message.type === "agent_answered") {
|
|
276
|
+
const sessionId = message.session_id;
|
|
277
|
+
const resolver = this.pendingRequests.get(sessionId);
|
|
278
|
+
|
|
279
|
+
if (resolver) {
|
|
280
|
+
// Fetch the full answer from API
|
|
281
|
+
this.apiClient!.getAgent(sessionId).then((agent) => {
|
|
282
|
+
if (agent && agent.status === "answered") {
|
|
283
|
+
const answers = agent.questions
|
|
284
|
+
.filter((q) => q.answer)
|
|
285
|
+
.map((q) => `${q.id}: ${q.answer}`);
|
|
286
|
+
resolver(answers.join("\n"));
|
|
287
|
+
this.pendingRequests.delete(sessionId);
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
} catch (error) {
|
|
293
|
+
console.error("Error processing WebSocket message:", error);
|
|
251
294
|
}
|
|
295
|
+
});
|
|
252
296
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
}
|
|
297
|
+
this.ws.on("error", (error) => {
|
|
298
|
+
console.error("WebSocket error:", error);
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
this.ws.on("close", () => {
|
|
302
|
+
console.error("WebSocket closed, reconnecting in 5s...");
|
|
303
|
+
setTimeout(() => this.setupWebSocket(), 5000);
|
|
304
|
+
});
|
|
256
305
|
}
|
|
257
306
|
|
|
258
307
|
async run(): Promise<void> {
|
|
@@ -266,6 +315,9 @@ Returns: User's answers concatenated with newlines, or timeout message.`,
|
|
|
266
315
|
process.exit(1);
|
|
267
316
|
}
|
|
268
317
|
|
|
318
|
+
// Setup WebSocket connection
|
|
319
|
+
this.setupWebSocket();
|
|
320
|
+
|
|
269
321
|
const transport = new StdioServerTransport();
|
|
270
322
|
await this.server.connect(transport);
|
|
271
323
|
|