agenthub-multiagent-mcp 1.1.5 → 1.3.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.
@@ -0,0 +1,66 @@
1
+ /**
2
+ * WebSocket client for real-time push notifications from AgentHub server.
3
+ *
4
+ * Receives pushed tasks and messages and stores them in a queue
5
+ * for inclusion in tool responses.
6
+ */
7
+ import type { Message, PendingTask } from "./client.js";
8
+ export interface WSMessage {
9
+ type: "task" | "message" | "ping" | "pong" | "ack";
10
+ timestamp: string;
11
+ task?: PendingTask;
12
+ message?: Message;
13
+ data?: unknown;
14
+ }
15
+ export interface PushedItems {
16
+ tasks: PendingTask[];
17
+ messages: Message[];
18
+ }
19
+ export declare class WebSocketClient {
20
+ private ws;
21
+ private baseUrl;
22
+ private apiKey;
23
+ private agentId;
24
+ private reconnectAttempts;
25
+ private maxReconnectAttempts;
26
+ private reconnectDelay;
27
+ private reconnectTimer;
28
+ private isConnecting;
29
+ private isClosing;
30
+ private pushedTasks;
31
+ private pushedMessages;
32
+ constructor(baseUrl: string, apiKey: string);
33
+ /**
34
+ * Connect to WebSocket for a specific agent
35
+ */
36
+ connect(agentId: string): void;
37
+ /**
38
+ * Handle incoming WebSocket message
39
+ */
40
+ private handleMessage;
41
+ /**
42
+ * Send acknowledgment for received item
43
+ */
44
+ private sendAck;
45
+ /**
46
+ * Send a message over WebSocket
47
+ */
48
+ private send;
49
+ /**
50
+ * Schedule reconnection with exponential backoff
51
+ */
52
+ private scheduleReconnect;
53
+ /**
54
+ * Get and clear pushed items
55
+ */
56
+ getPushedItems(): PushedItems;
57
+ /**
58
+ * Check if connected
59
+ */
60
+ isConnected(): boolean;
61
+ /**
62
+ * Close the WebSocket connection
63
+ */
64
+ close(): void;
65
+ }
66
+ //# sourceMappingURL=websocket.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"websocket.d.ts","sourceRoot":"","sources":["../src/websocket.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAExD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;IACnD,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAAuB;IACtC,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,oBAAoB,CAAK;IACjC,OAAO,CAAC,cAAc,CAAQ;IAC9B,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,SAAS,CAAS;IAG1B,OAAO,CAAC,WAAW,CAAqB;IACxC,OAAO,CAAC,cAAc,CAAiB;gBAE3B,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAS3C;;OAEG;IACH,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAiD9B;;OAEG;IACH,OAAO,CAAC,aAAa;IA+BrB;;OAEG;IACH,OAAO,CAAC,OAAO;IAQf;;OAEG;IACH,OAAO,CAAC,IAAI;IAUZ;;OAEG;IACH,OAAO,CAAC,iBAAiB;IA0BzB;;OAEG;IACH,cAAc,IAAI,WAAW;IAa7B;;OAEG;IACH,WAAW,IAAI,OAAO;IAItB;;OAEG;IACH,KAAK,IAAI,IAAI;CAuBd"}
@@ -0,0 +1,196 @@
1
+ /**
2
+ * WebSocket client for real-time push notifications from AgentHub server.
3
+ *
4
+ * Receives pushed tasks and messages and stores them in a queue
5
+ * for inclusion in tool responses.
6
+ */
7
+ import WebSocket from "ws";
8
+ export class WebSocketClient {
9
+ ws = null;
10
+ baseUrl;
11
+ apiKey;
12
+ agentId = null;
13
+ reconnectAttempts = 0;
14
+ maxReconnectAttempts = 5;
15
+ reconnectDelay = 1000; // Start with 1 second
16
+ reconnectTimer = null;
17
+ isConnecting = false;
18
+ isClosing = false;
19
+ // Queue for pushed items
20
+ pushedTasks = [];
21
+ pushedMessages = [];
22
+ constructor(baseUrl, apiKey) {
23
+ // Convert HTTP URL to WebSocket URL
24
+ this.baseUrl = baseUrl
25
+ .replace(/^https:/, "wss:")
26
+ .replace(/^http:/, "ws:")
27
+ .replace(/\/$/, "");
28
+ this.apiKey = apiKey;
29
+ }
30
+ /**
31
+ * Connect to WebSocket for a specific agent
32
+ */
33
+ connect(agentId) {
34
+ if (this.isConnecting || (this.ws && this.ws.readyState === WebSocket.OPEN)) {
35
+ return;
36
+ }
37
+ this.agentId = agentId;
38
+ this.isConnecting = true;
39
+ this.isClosing = false;
40
+ const url = `${this.baseUrl}/ws/agents/${agentId}?api_key=${encodeURIComponent(this.apiKey)}`;
41
+ try {
42
+ this.ws = new WebSocket(url);
43
+ this.ws.on("open", () => {
44
+ this.isConnecting = false;
45
+ this.reconnectAttempts = 0;
46
+ this.reconnectDelay = 1000;
47
+ console.error(`[AgentHub] WebSocket connected for agent: ${agentId}`);
48
+ });
49
+ this.ws.on("message", (data) => {
50
+ try {
51
+ const msg = JSON.parse(data.toString());
52
+ this.handleMessage(msg);
53
+ }
54
+ catch (error) {
55
+ console.error("[AgentHub] Failed to parse WebSocket message:", error);
56
+ }
57
+ });
58
+ this.ws.on("close", () => {
59
+ this.isConnecting = false;
60
+ if (!this.isClosing) {
61
+ console.error("[AgentHub] WebSocket disconnected, will reconnect...");
62
+ this.scheduleReconnect();
63
+ }
64
+ });
65
+ this.ws.on("error", (error) => {
66
+ this.isConnecting = false;
67
+ console.error("[AgentHub] WebSocket error:", error.message);
68
+ });
69
+ }
70
+ catch (error) {
71
+ this.isConnecting = false;
72
+ console.error("[AgentHub] Failed to create WebSocket:", error);
73
+ this.scheduleReconnect();
74
+ }
75
+ }
76
+ /**
77
+ * Handle incoming WebSocket message
78
+ */
79
+ handleMessage(msg) {
80
+ switch (msg.type) {
81
+ case "task":
82
+ if (msg.task) {
83
+ console.error(`[AgentHub] Received pushed task: ${msg.task.id}`);
84
+ this.pushedTasks.push(msg.task);
85
+ // Send ack
86
+ this.sendAck(msg.task.id);
87
+ }
88
+ break;
89
+ case "message":
90
+ if (msg.message) {
91
+ console.error(`[AgentHub] Received pushed message: ${msg.message.id}`);
92
+ this.pushedMessages.push(msg.message);
93
+ // Send ack
94
+ this.sendAck(msg.message.id);
95
+ }
96
+ break;
97
+ case "ping":
98
+ // Respond with pong
99
+ this.send({ type: "pong", timestamp: new Date().toISOString() });
100
+ break;
101
+ default:
102
+ // Ignore other message types
103
+ break;
104
+ }
105
+ }
106
+ /**
107
+ * Send acknowledgment for received item
108
+ */
109
+ sendAck(itemId) {
110
+ this.send({
111
+ type: "ack",
112
+ timestamp: new Date().toISOString(),
113
+ data: { id: itemId },
114
+ });
115
+ }
116
+ /**
117
+ * Send a message over WebSocket
118
+ */
119
+ send(msg) {
120
+ if (this.ws && this.ws.readyState === WebSocket.OPEN) {
121
+ try {
122
+ this.ws.send(JSON.stringify(msg));
123
+ }
124
+ catch (error) {
125
+ console.error("[AgentHub] Failed to send WebSocket message:", error);
126
+ }
127
+ }
128
+ }
129
+ /**
130
+ * Schedule reconnection with exponential backoff
131
+ */
132
+ scheduleReconnect() {
133
+ if (this.isClosing || !this.agentId) {
134
+ return;
135
+ }
136
+ if (this.reconnectAttempts >= this.maxReconnectAttempts) {
137
+ console.error("[AgentHub] Max reconnect attempts reached, giving up");
138
+ return;
139
+ }
140
+ if (this.reconnectTimer) {
141
+ clearTimeout(this.reconnectTimer);
142
+ }
143
+ this.reconnectTimer = setTimeout(() => {
144
+ this.reconnectAttempts++;
145
+ console.error(`[AgentHub] Reconnect attempt ${this.reconnectAttempts}/${this.maxReconnectAttempts}`);
146
+ if (this.agentId) {
147
+ this.connect(this.agentId);
148
+ }
149
+ }, this.reconnectDelay);
150
+ // Exponential backoff with max of 30 seconds
151
+ this.reconnectDelay = Math.min(this.reconnectDelay * 2, 30000);
152
+ }
153
+ /**
154
+ * Get and clear pushed items
155
+ */
156
+ getPushedItems() {
157
+ const items = {
158
+ tasks: [...this.pushedTasks],
159
+ messages: [...this.pushedMessages],
160
+ };
161
+ // Clear the queues
162
+ this.pushedTasks = [];
163
+ this.pushedMessages = [];
164
+ return items;
165
+ }
166
+ /**
167
+ * Check if connected
168
+ */
169
+ isConnected() {
170
+ return this.ws !== null && this.ws.readyState === WebSocket.OPEN;
171
+ }
172
+ /**
173
+ * Close the WebSocket connection
174
+ */
175
+ close() {
176
+ this.isClosing = true;
177
+ if (this.reconnectTimer) {
178
+ clearTimeout(this.reconnectTimer);
179
+ this.reconnectTimer = null;
180
+ }
181
+ if (this.ws) {
182
+ try {
183
+ this.ws.close();
184
+ }
185
+ catch (error) {
186
+ // Ignore close errors
187
+ }
188
+ this.ws = null;
189
+ }
190
+ this.agentId = null;
191
+ this.pushedTasks = [];
192
+ this.pushedMessages = [];
193
+ console.error("[AgentHub] WebSocket closed");
194
+ }
195
+ }
196
+ //# sourceMappingURL=websocket.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"websocket.js","sourceRoot":"","sources":["../src/websocket.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agenthub-multiagent-mcp",
3
- "version": "1.1.5",
3
+ "version": "1.3.0",
4
4
  "description": "MCP server for AgentHub multi-agent communication",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -39,10 +39,13 @@
39
39
  },
40
40
  "dependencies": {
41
41
  "@modelcontextprotocol/sdk": "^1.0.0",
42
+ "open": "^11.0.0",
43
+ "ws": "^8.18.0",
42
44
  "zod": "^3.23.0"
43
45
  },
44
46
  "devDependencies": {
45
47
  "@types/node": "^20.0.0",
48
+ "@types/ws": "^8.5.13",
46
49
  "tsx": "^4.0.0",
47
50
  "typescript": "^5.0.0",
48
51
  "vitest": "^4.0.16"
package/src/client.ts CHANGED
@@ -28,6 +28,76 @@ export interface PendingTask {
28
28
  created_at: string;
29
29
  }
30
30
 
31
+ // Ticket system types
32
+ export interface TicketTask {
33
+ id: string;
34
+ org_id: string;
35
+ project_id: string;
36
+ epic_id?: string;
37
+ story_id?: string;
38
+ key: string;
39
+ type: string;
40
+ title: string;
41
+ description?: string;
42
+ status: string;
43
+ priority: string;
44
+ points?: number;
45
+ review_mode: string;
46
+ assignee_id?: string;
47
+ assigned_agent?: string;
48
+ claimed_by?: string;
49
+ labels?: string[];
50
+ sprint_id?: string;
51
+ due_date?: string;
52
+ created_by: string;
53
+ created_at: string;
54
+ updated_at: string;
55
+ }
56
+
57
+ export interface TicketTaskContext {
58
+ task: TicketTask;
59
+ story?: {
60
+ id: string;
61
+ title: string;
62
+ description?: string;
63
+ status: string;
64
+ };
65
+ epic?: {
66
+ id: string;
67
+ title: string;
68
+ description?: string;
69
+ status: string;
70
+ };
71
+ project?: {
72
+ id: string;
73
+ key: string;
74
+ name: string;
75
+ description?: string;
76
+ };
77
+ }
78
+
79
+ export interface TaskCheckpoint {
80
+ id: string;
81
+ task_id: string;
82
+ task_key: string;
83
+ agent_id: string;
84
+ description: string;
85
+ status: string;
86
+ reviewed_by?: string;
87
+ review_notes?: string;
88
+ reviewed_at?: string;
89
+ created_at: string;
90
+ }
91
+
92
+ export interface CheckpointResponse {
93
+ id: string;
94
+ task_id: string;
95
+ task_key: string;
96
+ status: string;
97
+ slack_posted: boolean;
98
+ created_at: string;
99
+ }
100
+
31
101
  export interface TaskCompletionResponse {
32
102
  task_id: string;
33
103
  elapsed_time: string;
@@ -150,11 +220,19 @@ export class ApiClient {
150
220
  async startWork(
151
221
  agentId: string,
152
222
  task: string,
153
- project?: string
154
- ): Promise<{ acknowledged: boolean; slack_posted: boolean }> {
223
+ project?: string,
224
+ taskId?: string
225
+ ): Promise<{
226
+ acknowledged: boolean;
227
+ slack_posted: boolean;
228
+ task_id?: string;
229
+ task_key?: string;
230
+ task_linked?: boolean;
231
+ }> {
155
232
  return this.request("POST", `/agents/${agentId}/start-work`, {
156
233
  task,
157
234
  project,
235
+ task_id: taskId,
158
236
  });
159
237
  }
160
238
 
@@ -294,4 +372,114 @@ export class ApiClient {
294
372
  reason,
295
373
  });
296
374
  }
375
+
376
+ // Ticket system methods (for agent integration)
377
+
378
+ async getAvailableTasks(params?: {
379
+ status?: string;
380
+ project_id?: string;
381
+ priority?: string;
382
+ }): Promise<{ tasks: TicketTask[]; total: number }> {
383
+ const query = new URLSearchParams();
384
+ if (params?.status) query.set("status", params.status);
385
+ if (params?.project_id) query.set("project_id", params.project_id);
386
+ if (params?.priority) query.set("priority", params.priority);
387
+ const queryStr = query.toString() ? `?${query}` : "";
388
+ return this.request("GET", `/agent-tickets/available${queryStr}`);
389
+ }
390
+
391
+ async getTicketTask(taskId: string): Promise<TicketTaskContext> {
392
+ return this.request("GET", `/agent-tickets/${taskId}`);
393
+ }
394
+
395
+ async claimTicketTask(
396
+ taskId: string,
397
+ agentId: string
398
+ ): Promise<{
399
+ success: boolean;
400
+ task: TicketTask;
401
+ task_id: string;
402
+ task_key: string;
403
+ }> {
404
+ return this.request("POST", `/agent-tickets/${taskId}/claim`, {
405
+ agent_id: agentId,
406
+ });
407
+ }
408
+
409
+ async createCheckpoint(
410
+ taskId: string,
411
+ agentId: string,
412
+ description: string
413
+ ): Promise<CheckpointResponse> {
414
+ return this.request("POST", `/agent-tickets/${taskId}/checkpoint`, {
415
+ agent_id: agentId,
416
+ description,
417
+ });
418
+ }
419
+
420
+ // Browser-based registration flow
421
+ async initRegistration(agentId?: string, agentName?: string): Promise<{
422
+ session_token: string;
423
+ dashboard_url: string;
424
+ expires_at: string;
425
+ }> {
426
+ return this.request("POST", "/agents/register-init", {
427
+ agent_id: agentId,
428
+ agent_name: agentName,
429
+ });
430
+ }
431
+
432
+ async pollRegistrationCallback(token: string): Promise<{
433
+ status: "pending" | "completed" | "expired";
434
+ agent_id?: string;
435
+ agent_name?: string;
436
+ agent_type?: string;
437
+ connect_token?: string;
438
+ expires_at?: string;
439
+ }> {
440
+ const url = `${this.baseUrl}/agents/register-callback/${token}`;
441
+ const response = await fetch(url, {
442
+ method: "GET",
443
+ headers: {
444
+ "Content-Type": "application/json",
445
+ "X-API-Key": this.apiKey,
446
+ },
447
+ });
448
+
449
+ if (response.status === 202) {
450
+ // Still pending
451
+ const data = await response.json() as { status: string; expires_at: string };
452
+ return { status: "pending", expires_at: data.expires_at };
453
+ }
454
+
455
+ if (response.status === 410) {
456
+ // Expired
457
+ return { status: "expired" };
458
+ }
459
+
460
+ if (!response.ok) {
461
+ const data = await response.json() as { message?: string };
462
+ throw new Error(data.message || `Request failed: ${response.status}`);
463
+ }
464
+
465
+ const data = await response.json() as {
466
+ status: string;
467
+ agent_id: string;
468
+ agent_name: string;
469
+ agent_type: string;
470
+ connect_token: string;
471
+ };
472
+
473
+ return {
474
+ status: "completed",
475
+ agent_id: data.agent_id,
476
+ agent_name: data.agent_name,
477
+ agent_type: data.agent_type,
478
+ connect_token: data.connect_token,
479
+ };
480
+ }
481
+
482
+ getBaseUrl(): string {
483
+ return this.baseUrl;
484
+ }
297
485
  }