@defai.digital/mcp-server 13.0.3

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.
Files changed (178) hide show
  1. package/LICENSE +214 -0
  2. package/dist/bin.d.ts +3 -0
  3. package/dist/bin.d.ts.map +1 -0
  4. package/dist/bin.js +7 -0
  5. package/dist/bin.js.map +1 -0
  6. package/dist/bootstrap.d.ts +89 -0
  7. package/dist/bootstrap.d.ts.map +1 -0
  8. package/dist/bootstrap.js +161 -0
  9. package/dist/bootstrap.js.map +1 -0
  10. package/dist/index.d.ts +10 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +17 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/middleware/rate-limiter.d.ts +136 -0
  15. package/dist/middleware/rate-limiter.d.ts.map +1 -0
  16. package/dist/middleware/rate-limiter.js +262 -0
  17. package/dist/middleware/rate-limiter.js.map +1 -0
  18. package/dist/prompts/agent-guide.d.ts +16 -0
  19. package/dist/prompts/agent-guide.d.ts.map +1 -0
  20. package/dist/prompts/agent-guide.js +391 -0
  21. package/dist/prompts/agent-guide.js.map +1 -0
  22. package/dist/prompts/explain-workflow.d.ts +15 -0
  23. package/dist/prompts/explain-workflow.d.ts.map +1 -0
  24. package/dist/prompts/explain-workflow.js +157 -0
  25. package/dist/prompts/explain-workflow.js.map +1 -0
  26. package/dist/prompts/index.d.ts +39 -0
  27. package/dist/prompts/index.d.ts.map +1 -0
  28. package/dist/prompts/index.js +83 -0
  29. package/dist/prompts/index.js.map +1 -0
  30. package/dist/prompts/review-changes.d.ts +15 -0
  31. package/dist/prompts/review-changes.d.ts.map +1 -0
  32. package/dist/prompts/review-changes.js +102 -0
  33. package/dist/prompts/review-changes.js.map +1 -0
  34. package/dist/prompts/troubleshoot-session.d.ts +15 -0
  35. package/dist/prompts/troubleshoot-session.d.ts.map +1 -0
  36. package/dist/prompts/troubleshoot-session.js +156 -0
  37. package/dist/prompts/troubleshoot-session.js.map +1 -0
  38. package/dist/registry-accessor.d.ts +83 -0
  39. package/dist/registry-accessor.d.ts.map +1 -0
  40. package/dist/registry-accessor.js +153 -0
  41. package/dist/registry-accessor.js.map +1 -0
  42. package/dist/resources/agents.d.ts +40 -0
  43. package/dist/resources/agents.d.ts.map +1 -0
  44. package/dist/resources/agents.js +123 -0
  45. package/dist/resources/agents.js.map +1 -0
  46. package/dist/resources/config.d.ts +57 -0
  47. package/dist/resources/config.d.ts.map +1 -0
  48. package/dist/resources/config.js +222 -0
  49. package/dist/resources/config.js.map +1 -0
  50. package/dist/resources/index.d.ts +38 -0
  51. package/dist/resources/index.d.ts.map +1 -0
  52. package/dist/resources/index.js +132 -0
  53. package/dist/resources/index.js.map +1 -0
  54. package/dist/resources/policies.d.ts +40 -0
  55. package/dist/resources/policies.d.ts.map +1 -0
  56. package/dist/resources/policies.js +122 -0
  57. package/dist/resources/policies.js.map +1 -0
  58. package/dist/resources/sessions.d.ts +30 -0
  59. package/dist/resources/sessions.d.ts.map +1 -0
  60. package/dist/resources/sessions.js +64 -0
  61. package/dist/resources/sessions.js.map +1 -0
  62. package/dist/resources/workflows.d.ts +40 -0
  63. package/dist/resources/workflows.d.ts.map +1 -0
  64. package/dist/resources/workflows.js +143 -0
  65. package/dist/resources/workflows.js.map +1 -0
  66. package/dist/schema-registry.d.ts +23 -0
  67. package/dist/schema-registry.d.ts.map +1 -0
  68. package/dist/schema-registry.js +225 -0
  69. package/dist/schema-registry.js.map +1 -0
  70. package/dist/server.d.ts +63 -0
  71. package/dist/server.d.ts.map +1 -0
  72. package/dist/server.js +393 -0
  73. package/dist/server.js.map +1 -0
  74. package/dist/session-accessor.d.ts +23 -0
  75. package/dist/session-accessor.d.ts.map +1 -0
  76. package/dist/session-accessor.js +39 -0
  77. package/dist/session-accessor.js.map +1 -0
  78. package/dist/shared-registry.d.ts +23 -0
  79. package/dist/shared-registry.d.ts.map +1 -0
  80. package/dist/shared-registry.js +235 -0
  81. package/dist/shared-registry.js.map +1 -0
  82. package/dist/stdio.d.ts +6 -0
  83. package/dist/stdio.d.ts.map +1 -0
  84. package/dist/stdio.js +152 -0
  85. package/dist/stdio.js.map +1 -0
  86. package/dist/tool-namespacing.d.ts +28 -0
  87. package/dist/tool-namespacing.d.ts.map +1 -0
  88. package/dist/tool-namespacing.js +80 -0
  89. package/dist/tool-namespacing.js.map +1 -0
  90. package/dist/tools/ability.d.ts +55 -0
  91. package/dist/tools/ability.d.ts.map +1 -0
  92. package/dist/tools/ability.js +560 -0
  93. package/dist/tools/ability.js.map +1 -0
  94. package/dist/tools/agent.d.ts +73 -0
  95. package/dist/tools/agent.d.ts.map +1 -0
  96. package/dist/tools/agent.js +895 -0
  97. package/dist/tools/agent.js.map +1 -0
  98. package/dist/tools/config.d.ts +36 -0
  99. package/dist/tools/config.d.ts.map +1 -0
  100. package/dist/tools/config.js +265 -0
  101. package/dist/tools/config.js.map +1 -0
  102. package/dist/tools/design.d.ts +42 -0
  103. package/dist/tools/design.d.ts.map +1 -0
  104. package/dist/tools/design.js +736 -0
  105. package/dist/tools/design.js.map +1 -0
  106. package/dist/tools/discuss.d.ts +40 -0
  107. package/dist/tools/discuss.d.ts.map +1 -0
  108. package/dist/tools/discuss.js +331 -0
  109. package/dist/tools/discuss.js.map +1 -0
  110. package/dist/tools/file-system.d.ts +63 -0
  111. package/dist/tools/file-system.d.ts.map +1 -0
  112. package/dist/tools/file-system.js +513 -0
  113. package/dist/tools/file-system.js.map +1 -0
  114. package/dist/tools/guard.d.ts +29 -0
  115. package/dist/tools/guard.d.ts.map +1 -0
  116. package/dist/tools/guard.js +311 -0
  117. package/dist/tools/guard.js.map +1 -0
  118. package/dist/tools/index.d.ts +35 -0
  119. package/dist/tools/index.d.ts.map +1 -0
  120. package/dist/tools/index.js +178 -0
  121. package/dist/tools/index.js.map +1 -0
  122. package/dist/tools/memory.d.ts +101 -0
  123. package/dist/tools/memory.d.ts.map +1 -0
  124. package/dist/tools/memory.js +704 -0
  125. package/dist/tools/memory.js.map +1 -0
  126. package/dist/tools/orchestration.d.ts +58 -0
  127. package/dist/tools/orchestration.d.ts.map +1 -0
  128. package/dist/tools/orchestration.js +714 -0
  129. package/dist/tools/orchestration.js.map +1 -0
  130. package/dist/tools/review.d.ts +40 -0
  131. package/dist/tools/review.d.ts.map +1 -0
  132. package/dist/tools/review.js +319 -0
  133. package/dist/tools/review.js.map +1 -0
  134. package/dist/tools/scaffold.d.ts +27 -0
  135. package/dist/tools/scaffold.d.ts.map +1 -0
  136. package/dist/tools/scaffold.js +495 -0
  137. package/dist/tools/scaffold.js.map +1 -0
  138. package/dist/tools/session.d.ts +75 -0
  139. package/dist/tools/session.d.ts.map +1 -0
  140. package/dist/tools/session.js +749 -0
  141. package/dist/tools/session.js.map +1 -0
  142. package/dist/tools/telemetry.d.ts +58 -0
  143. package/dist/tools/telemetry.d.ts.map +1 -0
  144. package/dist/tools/telemetry.js +638 -0
  145. package/dist/tools/telemetry.js.map +1 -0
  146. package/dist/tools/trace.d.ts +29 -0
  147. package/dist/tools/trace.d.ts.map +1 -0
  148. package/dist/tools/trace.js +191 -0
  149. package/dist/tools/trace.js.map +1 -0
  150. package/dist/tools/workflow.d.ts +26 -0
  151. package/dist/tools/workflow.d.ts.map +1 -0
  152. package/dist/tools/workflow.js +269 -0
  153. package/dist/tools/workflow.js.map +1 -0
  154. package/dist/trace-wrapper.d.ts +79 -0
  155. package/dist/trace-wrapper.d.ts.map +1 -0
  156. package/dist/trace-wrapper.js +151 -0
  157. package/dist/trace-wrapper.js.map +1 -0
  158. package/dist/types.d.ts +185 -0
  159. package/dist/types.d.ts.map +1 -0
  160. package/dist/types.js +11 -0
  161. package/dist/types.js.map +1 -0
  162. package/dist/utils/artifact-store.d.ts +49 -0
  163. package/dist/utils/artifact-store.d.ts.map +1 -0
  164. package/dist/utils/artifact-store.js +102 -0
  165. package/dist/utils/artifact-store.js.map +1 -0
  166. package/dist/utils/index.d.ts +6 -0
  167. package/dist/utils/index.d.ts.map +1 -0
  168. package/dist/utils/index.js +10 -0
  169. package/dist/utils/index.js.map +1 -0
  170. package/dist/utils/response.d.ts +139 -0
  171. package/dist/utils/response.d.ts.map +1 -0
  172. package/dist/utils/response.js +293 -0
  173. package/dist/utils/response.js.map +1 -0
  174. package/dist/validation.d.ts +223 -0
  175. package/dist/validation.d.ts.map +1 -0
  176. package/dist/validation.js +372 -0
  177. package/dist/validation.js.map +1 -0
  178. package/package.json +67 -0
@@ -0,0 +1,749 @@
1
+ import { createSessionStore, createSessionManager, DEFAULT_SESSION_DOMAIN_CONFIG, } from '@defai.digital/session-domain';
2
+ import { LIMIT_SESSIONS } from '@defai.digital/contracts';
3
+ // Create shared store and manager instances
4
+ const store = createSessionStore();
5
+ const manager = createSessionManager(store, DEFAULT_SESSION_DOMAIN_CONFIG);
6
+ /**
7
+ * Session create tool definition
8
+ * INV-MCP-004: Non-idempotent - creates new session each call
9
+ * INV-MCP-002: Side effects - creates session in store
10
+ */
11
+ export const sessionCreateTool = {
12
+ name: 'session_create',
13
+ description: 'Create a new collaboration session. SIDE EFFECTS: Creates new session in store with unique ID.',
14
+ inputSchema: {
15
+ type: 'object',
16
+ properties: {
17
+ initiator: {
18
+ type: 'string',
19
+ description: 'Identifier of the agent creating the session',
20
+ },
21
+ task: {
22
+ type: 'string',
23
+ description: 'Description of the session task/objective',
24
+ },
25
+ workspace: {
26
+ type: 'string',
27
+ description: 'Optional workspace path for the session',
28
+ },
29
+ metadata: {
30
+ type: 'object',
31
+ description: 'Optional metadata for the session',
32
+ },
33
+ },
34
+ required: ['initiator', 'task'],
35
+ },
36
+ outputSchema: {
37
+ type: 'object',
38
+ properties: {
39
+ sessionId: { type: 'string', description: 'Unique session identifier' },
40
+ initiator: { type: 'string', description: 'Session initiator' },
41
+ task: { type: 'string', description: 'Session task' },
42
+ status: { type: 'string', description: 'Session status' },
43
+ createdAt: { type: 'string', description: 'Creation timestamp' },
44
+ workspace: { type: 'string', description: 'Workspace path' },
45
+ },
46
+ required: ['sessionId', 'initiator', 'task', 'status', 'createdAt'],
47
+ },
48
+ idempotent: false,
49
+ };
50
+ /**
51
+ * Session status tool definition
52
+ * INV-MCP-004: Idempotent - read-only operation
53
+ */
54
+ export const sessionStatusTool = {
55
+ name: 'session_status',
56
+ description: 'Get the current status of a session. Read-only, no side effects.',
57
+ inputSchema: {
58
+ type: 'object',
59
+ properties: {
60
+ sessionId: {
61
+ type: 'string',
62
+ description: 'The ID of the session to check',
63
+ },
64
+ },
65
+ required: ['sessionId'],
66
+ },
67
+ outputSchema: {
68
+ type: 'object',
69
+ properties: {
70
+ sessionId: { type: 'string' },
71
+ status: { type: 'string', enum: ['active', 'completed', 'failed'] },
72
+ initiator: { type: 'string' },
73
+ task: { type: 'string' },
74
+ participants: {
75
+ type: 'array',
76
+ items: {
77
+ type: 'object',
78
+ properties: {
79
+ agentId: { type: 'string' },
80
+ role: { type: 'string' },
81
+ joinedAt: { type: 'string' },
82
+ taskCount: { type: 'number' },
83
+ },
84
+ },
85
+ },
86
+ createdAt: { type: 'string' },
87
+ updatedAt: { type: 'string' },
88
+ completedAt: { type: 'string' },
89
+ },
90
+ required: ['sessionId', 'status', 'initiator', 'task', 'participants', 'createdAt'],
91
+ },
92
+ idempotent: true,
93
+ };
94
+ /**
95
+ * Session complete tool definition
96
+ * INV-MCP-004: Idempotent - completing already completed session is safe
97
+ * INV-MCP-002: Side effects - updates session status to completed
98
+ */
99
+ export const sessionCompleteTool = {
100
+ name: 'session_complete',
101
+ description: 'Complete a session. SIDE EFFECTS: Updates session status to completed. Idempotent for already-completed sessions.',
102
+ inputSchema: {
103
+ type: 'object',
104
+ properties: {
105
+ sessionId: {
106
+ type: 'string',
107
+ description: 'The ID of the session to complete',
108
+ },
109
+ summary: {
110
+ type: 'string',
111
+ description: 'Optional summary of what was accomplished',
112
+ },
113
+ },
114
+ required: ['sessionId'],
115
+ },
116
+ outputSchema: {
117
+ type: 'object',
118
+ properties: {
119
+ sessionId: { type: 'string' },
120
+ status: { type: 'string' },
121
+ completedAt: { type: 'string' },
122
+ summary: { type: 'string' },
123
+ },
124
+ required: ['sessionId', 'status', 'completedAt'],
125
+ },
126
+ idempotent: true,
127
+ };
128
+ /**
129
+ * Session list tool definition
130
+ * INV-MCP-004: Idempotent - read-only operation
131
+ */
132
+ export const sessionListTool = {
133
+ name: 'session_list',
134
+ description: 'List sessions with optional filtering. Read-only, no side effects.',
135
+ inputSchema: {
136
+ type: 'object',
137
+ properties: {
138
+ status: {
139
+ type: 'string',
140
+ description: 'Filter by session status',
141
+ enum: ['active', 'completed', 'failed'],
142
+ },
143
+ initiator: {
144
+ type: 'string',
145
+ description: 'Filter by initiator',
146
+ },
147
+ limit: {
148
+ type: 'number',
149
+ description: 'Maximum number of sessions to return',
150
+ default: LIMIT_SESSIONS,
151
+ },
152
+ },
153
+ },
154
+ outputSchema: {
155
+ type: 'object',
156
+ properties: {
157
+ sessions: {
158
+ type: 'array',
159
+ items: {
160
+ type: 'object',
161
+ properties: {
162
+ sessionId: { type: 'string' },
163
+ initiator: { type: 'string' },
164
+ task: { type: 'string' },
165
+ status: { type: 'string' },
166
+ participantCount: { type: 'number' },
167
+ createdAt: { type: 'string' },
168
+ },
169
+ },
170
+ },
171
+ total: { type: 'number' },
172
+ },
173
+ required: ['sessions', 'total'],
174
+ },
175
+ idempotent: true,
176
+ };
177
+ /**
178
+ * Session join tool definition
179
+ * INV-MCP-004: Idempotent - joining twice returns existing participation
180
+ * INV-MCP-002: Side effects - adds participant to session
181
+ */
182
+ export const sessionJoinTool = {
183
+ name: 'session_join',
184
+ description: 'Join an existing session as a participant. SIDE EFFECTS: Adds agent to session participants. Idempotent - joining twice returns existing participation.',
185
+ inputSchema: {
186
+ type: 'object',
187
+ properties: {
188
+ sessionId: {
189
+ type: 'string',
190
+ description: 'The ID of the session to join',
191
+ },
192
+ agentId: {
193
+ type: 'string',
194
+ description: 'The ID of the agent joining',
195
+ },
196
+ role: {
197
+ type: 'string',
198
+ description: 'Role in the session',
199
+ enum: ['collaborator', 'delegate'],
200
+ default: 'collaborator',
201
+ },
202
+ },
203
+ required: ['sessionId', 'agentId'],
204
+ },
205
+ outputSchema: {
206
+ type: 'object',
207
+ properties: {
208
+ sessionId: { type: 'string' },
209
+ agentId: { type: 'string' },
210
+ role: { type: 'string' },
211
+ joinedAt: { type: 'string' },
212
+ participantCount: { type: 'number' },
213
+ },
214
+ required: ['sessionId', 'agentId', 'role', 'joinedAt', 'participantCount'],
215
+ },
216
+ idempotent: true,
217
+ };
218
+ /**
219
+ * Session leave tool definition
220
+ * INV-MCP-004: Non-idempotent - fails if not a participant
221
+ * INV-MCP-002: Side effects - removes participant from session
222
+ */
223
+ export const sessionLeaveTool = {
224
+ name: 'session_leave',
225
+ description: 'Leave a session. SIDE EFFECTS: Removes agent from session participants. Fails if not currently a participant.',
226
+ inputSchema: {
227
+ type: 'object',
228
+ properties: {
229
+ sessionId: {
230
+ type: 'string',
231
+ description: 'The ID of the session to leave',
232
+ },
233
+ agentId: {
234
+ type: 'string',
235
+ description: 'The ID of the agent leaving',
236
+ },
237
+ },
238
+ required: ['sessionId', 'agentId'],
239
+ },
240
+ outputSchema: {
241
+ type: 'object',
242
+ properties: {
243
+ sessionId: { type: 'string' },
244
+ agentId: { type: 'string' },
245
+ leftAt: { type: 'string' },
246
+ remainingParticipants: { type: 'number' },
247
+ },
248
+ required: ['sessionId', 'agentId', 'leftAt', 'remainingParticipants'],
249
+ },
250
+ idempotent: false,
251
+ };
252
+ /**
253
+ * Session fail tool definition
254
+ * INV-MCP-004: Non-idempotent - only active sessions can be failed
255
+ * INV-MCP-002: Side effects - updates session status to failed
256
+ */
257
+ export const sessionFailTool = {
258
+ name: 'session_fail',
259
+ description: 'Mark a session as failed with error details. SIDE EFFECTS: Updates session status to failed. Only active sessions can be failed.',
260
+ inputSchema: {
261
+ type: 'object',
262
+ properties: {
263
+ sessionId: {
264
+ type: 'string',
265
+ description: 'The ID of the session to mark as failed',
266
+ },
267
+ error: {
268
+ type: 'object',
269
+ description: 'Error details object with code and message properties',
270
+ },
271
+ },
272
+ required: ['sessionId', 'error'],
273
+ },
274
+ outputSchema: {
275
+ type: 'object',
276
+ properties: {
277
+ sessionId: { type: 'string' },
278
+ status: { type: 'string' },
279
+ failedAt: { type: 'string' },
280
+ error: {
281
+ type: 'object',
282
+ properties: {
283
+ code: { type: 'string' },
284
+ message: { type: 'string' },
285
+ },
286
+ },
287
+ },
288
+ required: ['sessionId', 'status', 'failedAt', 'error'],
289
+ },
290
+ idempotent: false,
291
+ };
292
+ /**
293
+ * Handler for session_create tool
294
+ */
295
+ export const handleSessionCreate = async (args) => {
296
+ const initiator = args.initiator;
297
+ const task = args.task;
298
+ const workspace = args.workspace;
299
+ const metadata = args.metadata;
300
+ try {
301
+ const session = await manager.createSession({
302
+ initiator,
303
+ task,
304
+ workspace,
305
+ metadata,
306
+ });
307
+ return {
308
+ content: [
309
+ {
310
+ type: 'text',
311
+ text: JSON.stringify({
312
+ sessionId: session.sessionId,
313
+ initiator: session.initiator,
314
+ task: session.task,
315
+ status: session.status,
316
+ createdAt: session.createdAt,
317
+ workspace: session.workspace,
318
+ }, null, 2),
319
+ },
320
+ ],
321
+ };
322
+ }
323
+ catch (error) {
324
+ const message = error instanceof Error ? error.message : 'Unknown error';
325
+ return {
326
+ content: [
327
+ {
328
+ type: 'text',
329
+ text: JSON.stringify({
330
+ error: 'SESSION_CREATE_FAILED',
331
+ message,
332
+ }),
333
+ },
334
+ ],
335
+ isError: true,
336
+ };
337
+ }
338
+ };
339
+ /**
340
+ * Handler for session_status tool
341
+ */
342
+ export const handleSessionStatus = async (args) => {
343
+ const sessionId = args.sessionId;
344
+ try {
345
+ const session = await manager.getSession(sessionId);
346
+ if (session === undefined) {
347
+ return {
348
+ content: [
349
+ {
350
+ type: 'text',
351
+ text: JSON.stringify({
352
+ error: 'SESSION_NOT_FOUND',
353
+ message: `Session "${sessionId}" not found`,
354
+ }),
355
+ },
356
+ ],
357
+ isError: true,
358
+ };
359
+ }
360
+ // Build participant summaries
361
+ const participants = session.participants.map((p) => ({
362
+ agentId: p.agentId,
363
+ role: p.role,
364
+ joinedAt: p.joinedAt,
365
+ taskCount: p.tasks.length,
366
+ }));
367
+ return {
368
+ content: [
369
+ {
370
+ type: 'text',
371
+ text: JSON.stringify({
372
+ sessionId: session.sessionId,
373
+ status: session.status,
374
+ initiator: session.initiator,
375
+ task: session.task,
376
+ participants,
377
+ createdAt: session.createdAt,
378
+ updatedAt: session.updatedAt,
379
+ completedAt: session.completedAt,
380
+ }, null, 2),
381
+ },
382
+ ],
383
+ };
384
+ }
385
+ catch (error) {
386
+ const message = error instanceof Error ? error.message : 'Unknown error';
387
+ return {
388
+ content: [
389
+ {
390
+ type: 'text',
391
+ text: JSON.stringify({
392
+ error: 'SESSION_STATUS_FAILED',
393
+ message,
394
+ }),
395
+ },
396
+ ],
397
+ isError: true,
398
+ };
399
+ }
400
+ };
401
+ /**
402
+ * Handler for session_complete tool
403
+ */
404
+ export const handleSessionComplete = async (args) => {
405
+ const sessionId = args.sessionId;
406
+ const summary = args.summary;
407
+ try {
408
+ const session = await manager.completeSession(sessionId, summary);
409
+ return {
410
+ content: [
411
+ {
412
+ type: 'text',
413
+ text: JSON.stringify({
414
+ sessionId: session.sessionId,
415
+ status: session.status,
416
+ completedAt: session.completedAt,
417
+ summary,
418
+ }, null, 2),
419
+ },
420
+ ],
421
+ };
422
+ }
423
+ catch (error) {
424
+ const message = error instanceof Error ? error.message : 'Unknown error';
425
+ const code = error.code ?? 'SESSION_COMPLETE_FAILED';
426
+ return {
427
+ content: [
428
+ {
429
+ type: 'text',
430
+ text: JSON.stringify({
431
+ error: code,
432
+ message,
433
+ }),
434
+ },
435
+ ],
436
+ isError: true,
437
+ };
438
+ }
439
+ };
440
+ /**
441
+ * Handler for session_list tool
442
+ */
443
+ export const handleSessionList = async (args) => {
444
+ const status = args.status;
445
+ const initiator = args.initiator;
446
+ const limit = args.limit ?? 20;
447
+ try {
448
+ // Build filter only with defined properties
449
+ const filter = {};
450
+ if (status !== undefined) {
451
+ filter.status = status;
452
+ }
453
+ if (initiator !== undefined) {
454
+ filter.initiator = initiator;
455
+ }
456
+ const sessions = await manager.listSessions(Object.keys(filter).length > 0 ? filter : undefined);
457
+ const sessionSummaries = sessions.slice(0, limit).map((s) => ({
458
+ sessionId: s.sessionId,
459
+ initiator: s.initiator,
460
+ task: s.task,
461
+ status: s.status,
462
+ participantCount: s.participants.length,
463
+ createdAt: s.createdAt,
464
+ }));
465
+ return {
466
+ content: [
467
+ {
468
+ type: 'text',
469
+ text: JSON.stringify({
470
+ sessions: sessionSummaries,
471
+ total: sessions.length,
472
+ }, null, 2),
473
+ },
474
+ ],
475
+ };
476
+ }
477
+ catch (error) {
478
+ const message = error instanceof Error ? error.message : 'Unknown error';
479
+ return {
480
+ content: [
481
+ {
482
+ type: 'text',
483
+ text: JSON.stringify({
484
+ error: 'SESSION_LIST_FAILED',
485
+ message,
486
+ }),
487
+ },
488
+ ],
489
+ isError: true,
490
+ };
491
+ }
492
+ };
493
+ /**
494
+ * Handler for session_join tool
495
+ * INV-MCP-SES-001: Cannot join completed/failed session
496
+ * INV-MCP-SES-002: Joining twice returns existing participation (idempotent)
497
+ * INV-MCP-SES-003: Max participants enforced (default: 10)
498
+ */
499
+ export const handleSessionJoin = async (args) => {
500
+ const sessionId = args.sessionId;
501
+ const agentId = args.agentId;
502
+ const role = args.role ?? 'collaborator';
503
+ try {
504
+ const session = await manager.getSession(sessionId);
505
+ if (session === undefined) {
506
+ return {
507
+ content: [
508
+ {
509
+ type: 'text',
510
+ text: JSON.stringify({
511
+ error: 'SESSION_NOT_FOUND',
512
+ message: `Session "${sessionId}" not found`,
513
+ }),
514
+ },
515
+ ],
516
+ isError: true,
517
+ };
518
+ }
519
+ // INV-MCP-SES-001: Cannot join completed/failed session
520
+ if (session.status !== 'active') {
521
+ return {
522
+ content: [
523
+ {
524
+ type: 'text',
525
+ text: JSON.stringify({
526
+ error: 'SESSION_INVALID_TRANSITION',
527
+ message: `Cannot join session with status "${session.status}"`,
528
+ }),
529
+ },
530
+ ],
531
+ isError: true,
532
+ };
533
+ }
534
+ // INV-MCP-SES-003: Max participants check
535
+ const MAX_PARTICIPANTS = 10;
536
+ if (session.participants.length >= MAX_PARTICIPANTS) {
537
+ // Check if already a participant (INV-MCP-SES-002)
538
+ const existing = session.participants.find((p) => p.agentId === agentId);
539
+ if (existing === undefined) {
540
+ return {
541
+ content: [
542
+ {
543
+ type: 'text',
544
+ text: JSON.stringify({
545
+ error: 'SESSION_MAX_PARTICIPANTS',
546
+ message: `Session has reached maximum participants (${MAX_PARTICIPANTS})`,
547
+ }),
548
+ },
549
+ ],
550
+ isError: true,
551
+ };
552
+ }
553
+ }
554
+ // Join the session (joinSession handles idempotency - INV-MCP-SES-002)
555
+ const updatedSession = await manager.joinSession({ sessionId, agentId, role });
556
+ const participant = updatedSession.participants.find((p) => p.agentId === agentId);
557
+ return {
558
+ content: [
559
+ {
560
+ type: 'text',
561
+ text: JSON.stringify({
562
+ sessionId: updatedSession.sessionId,
563
+ agentId,
564
+ role: participant?.role ?? role,
565
+ joinedAt: participant?.joinedAt ?? new Date().toISOString(),
566
+ participantCount: updatedSession.participants.length,
567
+ }, null, 2),
568
+ },
569
+ ],
570
+ };
571
+ }
572
+ catch (error) {
573
+ const message = error instanceof Error ? error.message : 'Unknown error';
574
+ const code = error.code ?? 'SESSION_JOIN_FAILED';
575
+ return {
576
+ content: [
577
+ {
578
+ type: 'text',
579
+ text: JSON.stringify({
580
+ error: code,
581
+ message,
582
+ }),
583
+ },
584
+ ],
585
+ isError: true,
586
+ };
587
+ }
588
+ };
589
+ /**
590
+ * Handler for session_leave tool
591
+ * INV-MCP-SES-004: Cannot leave if not a participant
592
+ * INV-MCP-SES-005: Initiator cannot leave active session
593
+ */
594
+ export const handleSessionLeave = async (args) => {
595
+ const sessionId = args.sessionId;
596
+ const agentId = args.agentId;
597
+ try {
598
+ const session = await manager.getSession(sessionId);
599
+ if (session === undefined) {
600
+ return {
601
+ content: [
602
+ {
603
+ type: 'text',
604
+ text: JSON.stringify({
605
+ error: 'SESSION_NOT_FOUND',
606
+ message: `Session "${sessionId}" not found`,
607
+ }),
608
+ },
609
+ ],
610
+ isError: true,
611
+ };
612
+ }
613
+ // INV-MCP-SES-004: Cannot leave if not a participant
614
+ const isParticipant = session.participants.some((p) => p.agentId === agentId);
615
+ if (!isParticipant) {
616
+ return {
617
+ content: [
618
+ {
619
+ type: 'text',
620
+ text: JSON.stringify({
621
+ error: 'SESSION_AGENT_NOT_PARTICIPANT',
622
+ message: `Agent "${agentId}" is not a participant in this session`,
623
+ }),
624
+ },
625
+ ],
626
+ isError: true,
627
+ };
628
+ }
629
+ // INV-MCP-SES-005: Initiator cannot leave active session
630
+ if (session.initiator === agentId && session.status === 'active') {
631
+ return {
632
+ content: [
633
+ {
634
+ type: 'text',
635
+ text: JSON.stringify({
636
+ error: 'SESSION_INITIATOR_CANNOT_LEAVE',
637
+ message: 'Session initiator cannot leave an active session. Complete or fail the session first.',
638
+ }),
639
+ },
640
+ ],
641
+ isError: true,
642
+ };
643
+ }
644
+ // Leave the session
645
+ const updatedSession = await manager.leaveSession(sessionId, agentId);
646
+ return {
647
+ content: [
648
+ {
649
+ type: 'text',
650
+ text: JSON.stringify({
651
+ sessionId: updatedSession.sessionId,
652
+ agentId,
653
+ leftAt: new Date().toISOString(),
654
+ remainingParticipants: updatedSession.participants.length,
655
+ }, null, 2),
656
+ },
657
+ ],
658
+ };
659
+ }
660
+ catch (error) {
661
+ const message = error instanceof Error ? error.message : 'Unknown error';
662
+ const code = error.code ?? 'SESSION_LEAVE_FAILED';
663
+ return {
664
+ content: [
665
+ {
666
+ type: 'text',
667
+ text: JSON.stringify({
668
+ error: code,
669
+ message,
670
+ }),
671
+ },
672
+ ],
673
+ isError: true,
674
+ };
675
+ }
676
+ };
677
+ /**
678
+ * Handler for session_fail tool
679
+ */
680
+ export const handleSessionFail = async (args) => {
681
+ const sessionId = args.sessionId;
682
+ const error = args.error;
683
+ try {
684
+ const session = await manager.getSession(sessionId);
685
+ if (session === undefined) {
686
+ return {
687
+ content: [
688
+ {
689
+ type: 'text',
690
+ text: JSON.stringify({
691
+ error: 'SESSION_NOT_FOUND',
692
+ message: `Session "${sessionId}" not found`,
693
+ }),
694
+ },
695
+ ],
696
+ isError: true,
697
+ };
698
+ }
699
+ if (session.status !== 'active') {
700
+ return {
701
+ content: [
702
+ {
703
+ type: 'text',
704
+ text: JSON.stringify({
705
+ error: 'SESSION_INVALID_TRANSITION',
706
+ message: `Cannot fail session with status "${session.status}"`,
707
+ }),
708
+ },
709
+ ],
710
+ isError: true,
711
+ };
712
+ }
713
+ // Fail the session
714
+ const updatedSession = await manager.failSession(sessionId, error);
715
+ return {
716
+ content: [
717
+ {
718
+ type: 'text',
719
+ text: JSON.stringify({
720
+ sessionId: updatedSession.sessionId,
721
+ status: 'failed',
722
+ failedAt: updatedSession.completedAt ?? new Date().toISOString(),
723
+ error: {
724
+ code: error.code,
725
+ message: error.message,
726
+ },
727
+ }, null, 2),
728
+ },
729
+ ],
730
+ };
731
+ }
732
+ catch (err) {
733
+ const message = err instanceof Error ? err.message : 'Unknown error';
734
+ const code = err.code ?? 'SESSION_FAIL_FAILED';
735
+ return {
736
+ content: [
737
+ {
738
+ type: 'text',
739
+ text: JSON.stringify({
740
+ error: code,
741
+ message,
742
+ }),
743
+ },
744
+ ],
745
+ isError: true,
746
+ };
747
+ }
748
+ };
749
+ //# sourceMappingURL=session.js.map