@artyfacts/mcp-server 1.0.5 → 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.
@@ -0,0 +1,605 @@
1
+ // src/server.ts
2
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import {
5
+ CallToolRequestSchema,
6
+ ListToolsRequestSchema
7
+ } from "@modelcontextprotocol/sdk/types.js";
8
+ var ARTYFACTS_TOOLS = [
9
+ // Organization tools
10
+ {
11
+ name: "get_organization",
12
+ description: "Get details about the current organization",
13
+ inputSchema: {
14
+ type: "object",
15
+ properties: {},
16
+ required: []
17
+ }
18
+ },
19
+ // Project tools
20
+ {
21
+ name: "list_projects",
22
+ description: "List all projects in the organization",
23
+ inputSchema: {
24
+ type: "object",
25
+ properties: {
26
+ limit: { type: "number", description: "Max results (default 50)" },
27
+ offset: { type: "number", description: "Pagination offset" }
28
+ },
29
+ required: []
30
+ }
31
+ },
32
+ {
33
+ name: "get_project",
34
+ description: "Get details about a specific project",
35
+ inputSchema: {
36
+ type: "object",
37
+ properties: {
38
+ project_id: { type: "string", description: "Project ID" }
39
+ },
40
+ required: ["project_id"]
41
+ }
42
+ },
43
+ // Artifact tools
44
+ {
45
+ name: "list_artifacts",
46
+ description: "List artifacts, optionally filtered by project",
47
+ inputSchema: {
48
+ type: "object",
49
+ properties: {
50
+ project_id: { type: "string", description: "Filter by project" },
51
+ type: { type: "string", description: "Filter by type (goal, spec, research, etc.)" },
52
+ status: { type: "string", description: "Filter by status" },
53
+ limit: { type: "number", description: "Max results" }
54
+ },
55
+ required: []
56
+ }
57
+ },
58
+ {
59
+ name: "get_artifact",
60
+ description: "Get a specific artifact by ID",
61
+ inputSchema: {
62
+ type: "object",
63
+ properties: {
64
+ artifact_id: { type: "string", description: "Artifact ID" }
65
+ },
66
+ required: ["artifact_id"]
67
+ }
68
+ },
69
+ {
70
+ name: "create_artifact",
71
+ description: "Create a new artifact (document, goal, spec, etc.)",
72
+ inputSchema: {
73
+ type: "object",
74
+ properties: {
75
+ title: { type: "string", description: "Artifact title" },
76
+ type: { type: "string", description: "Artifact type: goal, spec, research, report, experiment, decision, doc" },
77
+ content: { type: "string", description: "Markdown content" },
78
+ parent_id: { type: "string", description: "Parent artifact ID for nested artifacts" },
79
+ tags: { type: "array", items: { type: "string" }, description: "Tags for categorization" }
80
+ },
81
+ required: ["title", "type"]
82
+ }
83
+ },
84
+ {
85
+ name: "update_artifact",
86
+ description: "Update an existing artifact",
87
+ inputSchema: {
88
+ type: "object",
89
+ properties: {
90
+ artifact_id: { type: "string", description: "Artifact ID" },
91
+ title: { type: "string", description: "New title" },
92
+ content: { type: "string", description: "New content" },
93
+ status: { type: "string", description: "New status" }
94
+ },
95
+ required: ["artifact_id"]
96
+ }
97
+ },
98
+ // Section tools
99
+ {
100
+ name: "list_sections",
101
+ description: "List sections of an artifact",
102
+ inputSchema: {
103
+ type: "object",
104
+ properties: {
105
+ artifact_id: { type: "string", description: "Artifact ID" }
106
+ },
107
+ required: ["artifact_id"]
108
+ }
109
+ },
110
+ {
111
+ name: "get_section",
112
+ description: "Get a specific section",
113
+ inputSchema: {
114
+ type: "object",
115
+ properties: {
116
+ artifact_id: { type: "string", description: "Artifact ID" },
117
+ section_id: { type: "string", description: "Section ID" }
118
+ },
119
+ required: ["artifact_id", "section_id"]
120
+ }
121
+ },
122
+ {
123
+ name: "create_section",
124
+ description: "Create a new section on an artifact",
125
+ inputSchema: {
126
+ type: "object",
127
+ properties: {
128
+ artifact_id: { type: "string", description: "Artifact ID" },
129
+ section_id: { type: "string", description: "Section identifier (slug)" },
130
+ heading: { type: "string", description: "Section heading" },
131
+ content: { type: "string", description: "Markdown content" },
132
+ type: { type: "string", description: "Type: content, task, decision, blocker" },
133
+ position: { type: "number", description: "Order position" }
134
+ },
135
+ required: ["artifact_id", "section_id", "heading", "content"]
136
+ }
137
+ },
138
+ {
139
+ name: "update_section",
140
+ description: "Update an existing section",
141
+ inputSchema: {
142
+ type: "object",
143
+ properties: {
144
+ artifact_id: { type: "string", description: "Artifact ID" },
145
+ section_id: { type: "string", description: "Section ID" },
146
+ heading: { type: "string", description: "New heading" },
147
+ content: { type: "string", description: "New content" },
148
+ task_status: { type: "string", description: "Task status if type=task" }
149
+ },
150
+ required: ["artifact_id", "section_id"]
151
+ }
152
+ },
153
+ {
154
+ name: "delete_section",
155
+ description: "Delete a section",
156
+ inputSchema: {
157
+ type: "object",
158
+ properties: {
159
+ artifact_id: { type: "string", description: "Artifact ID" },
160
+ section_id: { type: "string", description: "Section ID" }
161
+ },
162
+ required: ["artifact_id", "section_id"]
163
+ }
164
+ },
165
+ // Task tools
166
+ {
167
+ name: "list_tasks",
168
+ description: "List tasks (sections with type=task)",
169
+ inputSchema: {
170
+ type: "object",
171
+ properties: {
172
+ artifact_id: { type: "string", description: "Filter by artifact" },
173
+ status: { type: "string", description: "Filter by status: pending, in_progress, done, blocked" },
174
+ assignee: { type: "string", description: "Filter by assignee agent" }
175
+ },
176
+ required: []
177
+ }
178
+ },
179
+ {
180
+ name: "claim_task",
181
+ description: "Claim a task for the current agent",
182
+ inputSchema: {
183
+ type: "object",
184
+ properties: {
185
+ task_id: { type: "string", description: "Task ID (section UUID)" }
186
+ },
187
+ required: ["task_id"]
188
+ }
189
+ },
190
+ {
191
+ name: "complete_task",
192
+ description: "Mark a task as complete",
193
+ inputSchema: {
194
+ type: "object",
195
+ properties: {
196
+ task_id: { type: "string", description: "Task ID" },
197
+ output_url: { type: "string", description: "URL to deliverable (PR, doc, etc.)" },
198
+ summary: { type: "string", description: "Completion summary" }
199
+ },
200
+ required: ["task_id"]
201
+ }
202
+ },
203
+ {
204
+ name: "block_task",
205
+ description: "Mark a task as blocked",
206
+ inputSchema: {
207
+ type: "object",
208
+ properties: {
209
+ task_id: { type: "string", description: "Task ID" },
210
+ reason: { type: "string", description: "Why it is blocked" },
211
+ blocker_type: { type: "string", description: "Type: decision, dependency, resource, external" }
212
+ },
213
+ required: ["task_id", "reason"]
214
+ }
215
+ },
216
+ {
217
+ name: "create_task",
218
+ description: "Create a new task under a goal. Use this to create actionable tasks \u2014 NOT create_artifact or create_section.",
219
+ inputSchema: {
220
+ type: "object",
221
+ properties: {
222
+ goal_id: { type: "string", description: "The goal UUID this task belongs to (required)" },
223
+ title: { type: "string", description: "Task title" },
224
+ description: { type: "string", description: "Task description / what needs to be done" },
225
+ priority: { type: "string", description: "Priority: low, medium, high, urgent" },
226
+ assigned_to: { type: "string", description: "Agent UUID to assign the task to" },
227
+ depends_on: { type: "array", items: { type: "string" }, description: "List of task UUIDs this task depends on" },
228
+ estimated_minutes: { type: "number", description: "Estimated time in minutes" }
229
+ },
230
+ required: ["goal_id", "title"]
231
+ }
232
+ },
233
+ // Agent tools
234
+ {
235
+ name: "list_agents",
236
+ description: "List all agents in the organization",
237
+ inputSchema: {
238
+ type: "object",
239
+ properties: {
240
+ status: { type: "string", description: "Filter by status: active, inactive" }
241
+ },
242
+ required: []
243
+ }
244
+ },
245
+ {
246
+ name: "get_agent",
247
+ description: "Get details about an agent",
248
+ inputSchema: {
249
+ type: "object",
250
+ properties: {
251
+ agent_id: { type: "string", description: "Agent ID" }
252
+ },
253
+ required: ["agent_id"]
254
+ }
255
+ },
256
+ {
257
+ name: "create_agent",
258
+ description: "Register a new AI agent with role, capabilities, and permissions",
259
+ inputSchema: {
260
+ type: "object",
261
+ properties: {
262
+ agentId: { type: "string", description: 'Unique agent ID (e.g., "engineering-agent", "qa-agent")' },
263
+ name: { type: "string", description: "Agent display name" },
264
+ role: { type: "string", description: "Role: pm, engineering, qa, research, content, design" },
265
+ description: { type: "string", description: "What this agent does - detailed description" },
266
+ capabilities: { type: "array", items: { type: "string" }, description: 'List of capabilities (e.g., ["code-review", "testing", "debugging"])' },
267
+ permissions: {
268
+ type: "object",
269
+ description: "Permission settings",
270
+ properties: {
271
+ write: { type: "boolean", description: "Can create/edit artifacts" },
272
+ delete: { type: "boolean", description: "Can delete artifacts" },
273
+ delegate_tasks: { type: "boolean", description: "Can assign tasks to other agents" }
274
+ }
275
+ },
276
+ systemPrompt: { type: "string", description: "System prompt for the agent" }
277
+ },
278
+ required: ["agentId", "name", "role", "description"]
279
+ }
280
+ },
281
+ {
282
+ name: "update_agent",
283
+ description: "Update an agent",
284
+ inputSchema: {
285
+ type: "object",
286
+ properties: {
287
+ agent_id: { type: "string", description: "Agent ID" },
288
+ name: { type: "string", description: "New name" },
289
+ status: { type: "string", description: "New status" },
290
+ config: { type: "object", description: "Updated config" }
291
+ },
292
+ required: ["agent_id"]
293
+ }
294
+ },
295
+ // Inbox tools (human-in-the-loop)
296
+ {
297
+ name: "create_inbox_item",
298
+ description: "Request human approval, a decision, or an answer before proceeding. Automatically blocks the task. Use for agent creation, risky actions, or anything requiring human sign-off.",
299
+ inputSchema: {
300
+ type: "object",
301
+ properties: {
302
+ task_id: { type: "string", description: "UUID of the task being blocked (required)" },
303
+ type: { type: "string", description: "Type: approval, decision, question" },
304
+ title: { type: "string", description: "Short summary shown to the human in the inbox" },
305
+ content: { type: "string", description: "Full context and details for the human" },
306
+ action: { type: "string", description: "Action to auto-execute if approved (e.g. agent.create)" },
307
+ action_payload: { type: "object", description: "Data for the action (e.g. full agent spec for agent.create)" },
308
+ options: { type: "array", description: "Options for decision type: [{id, label, description}]" }
309
+ },
310
+ required: ["task_id", "type", "title"]
311
+ }
312
+ },
313
+ {
314
+ name: "list_inbox",
315
+ description: "List pending inbox items (approvals, decisions, questions) waiting for human resolution.",
316
+ inputSchema: {
317
+ type: "object",
318
+ properties: {
319
+ status: { type: "string", description: "Filter by status: pending (default), resolved" },
320
+ type: { type: "string", description: "Filter by type: approval, decision, question" },
321
+ limit: { type: "number", description: "Max results (default 50)" }
322
+ },
323
+ required: []
324
+ }
325
+ },
326
+ {
327
+ name: "resolve_inbox",
328
+ description: "Resolve an inbox item from the agent side. Humans resolve via the UI \u2014 only use this for automated resolution.",
329
+ inputSchema: {
330
+ type: "object",
331
+ properties: {
332
+ item_id: { type: "string", description: "Inbox item UUID" },
333
+ approved: { type: "boolean", description: "For approvals: true to approve, false to deny" },
334
+ chosen_option: { type: "string", description: "For decisions: the selected option ID" },
335
+ answer: { type: "string", description: "For questions: the answer text" },
336
+ notes: { type: "string", description: "Optional notes" }
337
+ },
338
+ required: ["item_id"]
339
+ }
340
+ },
341
+ // Search tools
342
+ {
343
+ name: "search_artifacts",
344
+ description: "Search artifacts by text query",
345
+ inputSchema: {
346
+ type: "object",
347
+ properties: {
348
+ query: { type: "string", description: "Search query" },
349
+ type: { type: "string", description: "Filter by type" },
350
+ limit: { type: "number", description: "Max results" }
351
+ },
352
+ required: ["query"]
353
+ }
354
+ },
355
+ // Context tools
356
+ {
357
+ name: "get_task_context",
358
+ description: "Get full context for a task (org, project, artifact, related sections)",
359
+ inputSchema: {
360
+ type: "object",
361
+ properties: {
362
+ task_id: { type: "string", description: "Task ID" }
363
+ },
364
+ required: ["task_id"]
365
+ }
366
+ }
367
+ ];
368
+ var ArtyfactsApiClient = class {
369
+ constructor(baseUrl, apiKey) {
370
+ this.baseUrl = baseUrl;
371
+ this.apiKey = apiKey;
372
+ }
373
+ async request(method, path, body) {
374
+ const url = `${this.baseUrl}${path}`;
375
+ const response = await fetch(url, {
376
+ method,
377
+ headers: {
378
+ "Authorization": `Bearer ${this.apiKey}`,
379
+ "Content-Type": "application/json"
380
+ },
381
+ body: body ? JSON.stringify(body) : void 0
382
+ });
383
+ if (!response.ok) {
384
+ const error = await response.json().catch(() => ({ error: "Request failed" }));
385
+ throw new Error(error.error || `HTTP ${response.status}: ${response.statusText}`);
386
+ }
387
+ return response.json();
388
+ }
389
+ get(path) {
390
+ return this.request("GET", path);
391
+ }
392
+ post(path, body) {
393
+ return this.request("POST", path, body);
394
+ }
395
+ patch(path, body) {
396
+ return this.request("PATCH", path, body);
397
+ }
398
+ delete(path) {
399
+ return this.request("DELETE", path);
400
+ }
401
+ };
402
+ var toolHandlers = {
403
+ // Organization
404
+ get_organization: (client) => client.get("/org"),
405
+ // Projects
406
+ list_projects: (client, args) => {
407
+ const params = new URLSearchParams();
408
+ if (args.limit) params.set("limit", String(args.limit));
409
+ if (args.offset) params.set("offset", String(args.offset));
410
+ return client.get(`/projects?${params}`);
411
+ },
412
+ get_project: (client, args) => client.get(`/projects/${args.project_id}`),
413
+ // Artifacts
414
+ list_artifacts: (client, args) => {
415
+ const params = new URLSearchParams();
416
+ if (args.project_id) params.set("project_id", String(args.project_id));
417
+ if (args.type) params.set("type", String(args.type));
418
+ if (args.status) params.set("status", String(args.status));
419
+ if (args.limit) params.set("limit", String(args.limit));
420
+ return client.get(`/artifacts?${params}`);
421
+ },
422
+ get_artifact: (client, args) => client.get(`/artifacts/${args.artifact_id}`),
423
+ create_artifact: (client, args) => {
424
+ const envelope = {
425
+ aah_version: "0.3",
426
+ artifact: {
427
+ id: args.id || `artifact-${Date.now()}`,
428
+ title: args.title,
429
+ type: args.type || "document/sectioned",
430
+ artifact_type: args.artifact_type || args.type || "doc",
431
+ parent_id: args.parent_id,
432
+ tags: args.tags
433
+ },
434
+ content: args.content ? {
435
+ media_type: "text/markdown",
436
+ body: args.content
437
+ } : void 0,
438
+ source: {
439
+ agent_id: "mcp-agent"
440
+ }
441
+ };
442
+ return client.post("/artifacts", envelope);
443
+ },
444
+ update_artifact: (client, args) => {
445
+ const { artifact_id, ...body } = args;
446
+ return client.patch(`/artifacts/${artifact_id}`, body);
447
+ },
448
+ // Sections
449
+ list_sections: (client, args) => client.get(`/artifacts/${args.artifact_id}/sections`),
450
+ get_section: (client, args) => client.get(`/artifacts/${args.artifact_id}/sections/${args.section_id}`),
451
+ create_section: (client, args) => {
452
+ const { artifact_id, section_id, ...rest } = args;
453
+ const body = { id: section_id, ...rest };
454
+ return client.post(`/artifacts/${artifact_id}/sections`, body);
455
+ },
456
+ update_section: (client, args) => {
457
+ const { artifact_id, section_id, ...body } = args;
458
+ return client.patch(`/artifacts/${artifact_id}/sections/${section_id}`, body);
459
+ },
460
+ delete_section: (client, args) => client.delete(`/artifacts/${args.artifact_id}/sections/${args.section_id}`),
461
+ // Tasks
462
+ list_tasks: (client, args) => {
463
+ const params = new URLSearchParams();
464
+ if (args.artifact_id) params.set("artifact_id", String(args.artifact_id));
465
+ if (args.status) params.set("status", String(args.status));
466
+ if (args.assignee) params.set("assignee", String(args.assignee));
467
+ return client.get(`/tasks?${params}`);
468
+ },
469
+ claim_task: (client, args) => client.post(`/tasks/${args.task_id}/claim`),
470
+ complete_task: (client, args) => {
471
+ const { task_id, ...body } = args;
472
+ return client.post(`/tasks/${task_id}/complete`, body);
473
+ },
474
+ block_task: (client, args) => {
475
+ const { task_id, ...body } = args;
476
+ return client.post(`/tasks/${task_id}/block`, body);
477
+ },
478
+ create_task: (client, args) => {
479
+ const { goal_id, title, description, priority, assigned_to, depends_on, estimated_minutes } = args;
480
+ return client.post("/tasks", { goal_id, title, description, priority, assigned_to, depends_on, estimated_minutes });
481
+ },
482
+ // Agents
483
+ list_agents: (client, args) => {
484
+ const params = new URLSearchParams();
485
+ if (args.status) params.set("status", String(args.status));
486
+ return client.get(`/agents?${params}`);
487
+ },
488
+ get_agent: (client, args) => client.get(`/agents/${args.agent_id}`),
489
+ create_agent: (client, args) => {
490
+ const body = {
491
+ agentId: args.agentId,
492
+ name: args.name,
493
+ role: args.role,
494
+ description: args.description,
495
+ permissions: args.permissions || { write: true, delete: false, delegate_tasks: false },
496
+ metadata: {
497
+ capabilities: args.capabilities || [],
498
+ systemPrompt: args.systemPrompt,
499
+ createdVia: "mcp"
500
+ }
501
+ };
502
+ return client.post("/agents", body);
503
+ },
504
+ update_agent: (client, args) => {
505
+ const { agent_id, ...body } = args;
506
+ return client.patch(`/agents/${agent_id}`, body);
507
+ },
508
+ // Inbox (human-in-the-loop)
509
+ create_inbox_item: (client, args) => {
510
+ const { task_id, type, title, content, action, action_payload, options } = args;
511
+ return client.post("/inbox", { task_id, type, title, content, action, action_payload, options });
512
+ },
513
+ list_inbox: (client, args) => {
514
+ const params = new URLSearchParams();
515
+ if (args.status) params.set("status", String(args.status));
516
+ if (args.type) params.set("type", String(args.type));
517
+ if (args.limit) params.set("limit", String(args.limit));
518
+ return client.get(`/inbox?${params}`);
519
+ },
520
+ resolve_inbox: (client, args) => {
521
+ const { item_id, ...body } = args;
522
+ return client.post(`/inbox/${item_id}/resolve`, body);
523
+ },
524
+ // Search
525
+ search_artifacts: (client, args) => {
526
+ const params = new URLSearchParams();
527
+ params.set("q", String(args.query));
528
+ if (args.type) params.set("type", String(args.type));
529
+ if (args.limit) params.set("limit", String(args.limit));
530
+ return client.get(`/search?${params}`);
531
+ },
532
+ // Context
533
+ get_task_context: (client, args) => client.get(`/tasks/${args.task_id}/context`)
534
+ };
535
+ var ArtyfactsMcpServer = class {
536
+ server;
537
+ client;
538
+ config;
539
+ constructor(config) {
540
+ this.config = config;
541
+ this.client = new ArtyfactsApiClient(
542
+ config.baseUrl || "https://artyfacts.dev/api/v1",
543
+ config.apiKey
544
+ );
545
+ this.server = new Server(
546
+ {
547
+ name: config.name || "artyfacts-mcp",
548
+ version: config.version || "1.0.0"
549
+ },
550
+ {
551
+ capabilities: {
552
+ tools: {}
553
+ }
554
+ }
555
+ );
556
+ this.setupHandlers();
557
+ }
558
+ setupHandlers() {
559
+ this.server.setRequestHandler(ListToolsRequestSchema, async () => {
560
+ return { tools: ARTYFACTS_TOOLS };
561
+ });
562
+ this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
563
+ const { name, arguments: args } = request.params;
564
+ const handler = toolHandlers[name];
565
+ if (!handler) {
566
+ return {
567
+ content: [{ type: "text", text: `Unknown tool: ${name}` }],
568
+ isError: true
569
+ };
570
+ }
571
+ try {
572
+ const result = await handler(this.client, args || {});
573
+ return {
574
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
575
+ };
576
+ } catch (error) {
577
+ const message = error instanceof Error ? error.message : String(error);
578
+ return {
579
+ content: [{ type: "text", text: `Error: ${message}` }],
580
+ isError: true
581
+ };
582
+ }
583
+ });
584
+ }
585
+ async start() {
586
+ const transport = new StdioServerTransport();
587
+ await this.server.connect(transport);
588
+ console.error(`Artyfacts MCP server running (${ARTYFACTS_TOOLS.length} tools)`);
589
+ }
590
+ getServer() {
591
+ return this.server;
592
+ }
593
+ };
594
+ function createMcpServer(config) {
595
+ return new ArtyfactsMcpServer(config);
596
+ }
597
+ async function startServer(server) {
598
+ await server.start();
599
+ }
600
+
601
+ export {
602
+ ArtyfactsMcpServer,
603
+ createMcpServer,
604
+ startServer
605
+ };
package/dist/index.cjs CHANGED
@@ -317,46 +317,50 @@ var ARTYFACTS_TOOLS = [
317
317
  required: ["agent_id"]
318
318
  }
319
319
  },
320
- // Blocker tools
320
+ // Inbox tools (human-in-the-loop)
321
321
  {
322
- name: "list_blockers",
323
- description: "List blockers (decisions, dependencies needing resolution)",
322
+ name: "create_inbox_item",
323
+ description: "Request human approval, a decision, or an answer before proceeding. Automatically blocks the task. Use for agent creation, risky actions, or anything requiring human sign-off.",
324
324
  inputSchema: {
325
325
  type: "object",
326
326
  properties: {
327
- artifact_id: { type: "string", description: "Filter by artifact" },
328
- status: { type: "string", description: "Filter by status: open, resolved" }
327
+ task_id: { type: "string", description: "UUID of the task being blocked (required)" },
328
+ type: { type: "string", description: "Type: approval, decision, question" },
329
+ title: { type: "string", description: "Short summary shown to the human in the inbox" },
330
+ content: { type: "string", description: "Full context and details for the human" },
331
+ action: { type: "string", description: "Action to auto-execute if approved (e.g. agent.create)" },
332
+ action_payload: { type: "object", description: "Data for the action (e.g. full agent spec for agent.create)" },
333
+ options: { type: "array", description: "Options for decision type: [{id, label, description}]" }
329
334
  },
330
- required: []
335
+ required: ["task_id", "type", "title"]
331
336
  }
332
337
  },
333
338
  {
334
- name: "create_blocker",
335
- description: "Create a blocker (decision request, dependency, etc.)",
339
+ name: "list_inbox",
340
+ description: "List pending inbox items (approvals, decisions, questions) waiting for human resolution.",
336
341
  inputSchema: {
337
342
  type: "object",
338
343
  properties: {
339
- artifact_id: { type: "string", description: "Artifact ID" },
340
- kind: { type: "string", description: "Kind: decision, dependency, resource, external" },
341
- title: { type: "string", description: "Blocker title" },
342
- description: { type: "string", description: "Details" },
343
- options: { type: "array", description: "Options for decisions" },
344
- blocked_tasks: { type: "array", items: { type: "string" }, description: "Task IDs blocked by this" }
344
+ status: { type: "string", description: "Filter by status: pending (default), resolved" },
345
+ type: { type: "string", description: "Filter by type: approval, decision, question" },
346
+ limit: { type: "number", description: "Max results (default 50)" }
345
347
  },
346
- required: ["artifact_id", "kind", "title"]
348
+ required: []
347
349
  }
348
350
  },
349
351
  {
350
- name: "resolve_blocker",
351
- description: "Resolve a blocker",
352
+ name: "resolve_inbox",
353
+ description: "Resolve an inbox item from the agent side. Humans resolve via the UI \u2014 only use this for automated resolution.",
352
354
  inputSchema: {
353
355
  type: "object",
354
356
  properties: {
355
- blocker_id: { type: "string", description: "Blocker ID" },
356
- resolution: { type: "string", description: "How it was resolved" },
357
- selected_option: { type: "string", description: "Selected option (for decisions)" }
357
+ item_id: { type: "string", description: "Inbox item UUID" },
358
+ approved: { type: "boolean", description: "For approvals: true to approve, false to deny" },
359
+ chosen_option: { type: "string", description: "For decisions: the selected option ID" },
360
+ answer: { type: "string", description: "For questions: the answer text" },
361
+ notes: { type: "string", description: "Optional notes" }
358
362
  },
359
- required: ["blocker_id", "resolution"]
363
+ required: ["item_id"]
360
364
  }
361
365
  },
362
366
  // Search tools
@@ -526,20 +530,21 @@ var toolHandlers = {
526
530
  const { agent_id, ...body } = args;
527
531
  return client.patch(`/agents/${agent_id}`, body);
528
532
  },
529
- // Blockers
530
- list_blockers: (client, args) => {
533
+ // Inbox (human-in-the-loop)
534
+ create_inbox_item: (client, args) => {
535
+ const { task_id, type, title, content, action, action_payload, options } = args;
536
+ return client.post("/inbox", { task_id, type, title, content, action, action_payload, options });
537
+ },
538
+ list_inbox: (client, args) => {
531
539
  const params = new URLSearchParams();
532
- if (args.artifact_id) params.set("artifact_id", String(args.artifact_id));
533
540
  if (args.status) params.set("status", String(args.status));
534
- return client.get(`/blockers?${params}`);
535
- },
536
- create_blocker: (client, args) => {
537
- const { artifact_id, ...body } = args;
538
- return client.post(`/artifacts/${artifact_id}/blockers`, body);
541
+ if (args.type) params.set("type", String(args.type));
542
+ if (args.limit) params.set("limit", String(args.limit));
543
+ return client.get(`/inbox?${params}`);
539
544
  },
540
- resolve_blocker: (client, args) => {
541
- const { blocker_id, ...body } = args;
542
- return client.post(`/blockers/${blocker_id}/resolve`, body);
545
+ resolve_inbox: (client, args) => {
546
+ const { item_id, ...body } = args;
547
+ return client.post(`/inbox/${item_id}/resolve`, body);
543
548
  },
544
549
  // Search
545
550
  search_artifacts: (client, args) => {
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  ArtyfactsMcpServer,
3
3
  createMcpServer,
4
4
  startServer
5
- } from "./chunk-NUVCJMET.js";
5
+ } from "./chunk-XLUIPOCO.js";
6
6
  export {
7
7
  ArtyfactsMcpServer,
8
8
  createMcpServer,
package/dist/server.cjs CHANGED
@@ -315,46 +315,50 @@ var ARTYFACTS_TOOLS = [
315
315
  required: ["agent_id"]
316
316
  }
317
317
  },
318
- // Blocker tools
318
+ // Inbox tools (human-in-the-loop)
319
319
  {
320
- name: "list_blockers",
321
- description: "List blockers (decisions, dependencies needing resolution)",
320
+ name: "create_inbox_item",
321
+ description: "Request human approval, a decision, or an answer before proceeding. Automatically blocks the task. Use for agent creation, risky actions, or anything requiring human sign-off.",
322
322
  inputSchema: {
323
323
  type: "object",
324
324
  properties: {
325
- artifact_id: { type: "string", description: "Filter by artifact" },
326
- status: { type: "string", description: "Filter by status: open, resolved" }
325
+ task_id: { type: "string", description: "UUID of the task being blocked (required)" },
326
+ type: { type: "string", description: "Type: approval, decision, question" },
327
+ title: { type: "string", description: "Short summary shown to the human in the inbox" },
328
+ content: { type: "string", description: "Full context and details for the human" },
329
+ action: { type: "string", description: "Action to auto-execute if approved (e.g. agent.create)" },
330
+ action_payload: { type: "object", description: "Data for the action (e.g. full agent spec for agent.create)" },
331
+ options: { type: "array", description: "Options for decision type: [{id, label, description}]" }
327
332
  },
328
- required: []
333
+ required: ["task_id", "type", "title"]
329
334
  }
330
335
  },
331
336
  {
332
- name: "create_blocker",
333
- description: "Create a blocker (decision request, dependency, etc.)",
337
+ name: "list_inbox",
338
+ description: "List pending inbox items (approvals, decisions, questions) waiting for human resolution.",
334
339
  inputSchema: {
335
340
  type: "object",
336
341
  properties: {
337
- artifact_id: { type: "string", description: "Artifact ID" },
338
- kind: { type: "string", description: "Kind: decision, dependency, resource, external" },
339
- title: { type: "string", description: "Blocker title" },
340
- description: { type: "string", description: "Details" },
341
- options: { type: "array", description: "Options for decisions" },
342
- blocked_tasks: { type: "array", items: { type: "string" }, description: "Task IDs blocked by this" }
342
+ status: { type: "string", description: "Filter by status: pending (default), resolved" },
343
+ type: { type: "string", description: "Filter by type: approval, decision, question" },
344
+ limit: { type: "number", description: "Max results (default 50)" }
343
345
  },
344
- required: ["artifact_id", "kind", "title"]
346
+ required: []
345
347
  }
346
348
  },
347
349
  {
348
- name: "resolve_blocker",
349
- description: "Resolve a blocker",
350
+ name: "resolve_inbox",
351
+ description: "Resolve an inbox item from the agent side. Humans resolve via the UI \u2014 only use this for automated resolution.",
350
352
  inputSchema: {
351
353
  type: "object",
352
354
  properties: {
353
- blocker_id: { type: "string", description: "Blocker ID" },
354
- resolution: { type: "string", description: "How it was resolved" },
355
- selected_option: { type: "string", description: "Selected option (for decisions)" }
355
+ item_id: { type: "string", description: "Inbox item UUID" },
356
+ approved: { type: "boolean", description: "For approvals: true to approve, false to deny" },
357
+ chosen_option: { type: "string", description: "For decisions: the selected option ID" },
358
+ answer: { type: "string", description: "For questions: the answer text" },
359
+ notes: { type: "string", description: "Optional notes" }
356
360
  },
357
- required: ["blocker_id", "resolution"]
361
+ required: ["item_id"]
358
362
  }
359
363
  },
360
364
  // Search tools
@@ -524,20 +528,21 @@ var toolHandlers = {
524
528
  const { agent_id, ...body } = args;
525
529
  return client.patch(`/agents/${agent_id}`, body);
526
530
  },
527
- // Blockers
528
- list_blockers: (client, args) => {
531
+ // Inbox (human-in-the-loop)
532
+ create_inbox_item: (client, args) => {
533
+ const { task_id, type, title, content, action, action_payload, options } = args;
534
+ return client.post("/inbox", { task_id, type, title, content, action, action_payload, options });
535
+ },
536
+ list_inbox: (client, args) => {
529
537
  const params = new URLSearchParams();
530
- if (args.artifact_id) params.set("artifact_id", String(args.artifact_id));
531
538
  if (args.status) params.set("status", String(args.status));
532
- return client.get(`/blockers?${params}`);
533
- },
534
- create_blocker: (client, args) => {
535
- const { artifact_id, ...body } = args;
536
- return client.post(`/artifacts/${artifact_id}/blockers`, body);
539
+ if (args.type) params.set("type", String(args.type));
540
+ if (args.limit) params.set("limit", String(args.limit));
541
+ return client.get(`/inbox?${params}`);
537
542
  },
538
- resolve_blocker: (client, args) => {
539
- const { blocker_id, ...body } = args;
540
- return client.post(`/blockers/${blocker_id}/resolve`, body);
543
+ resolve_inbox: (client, args) => {
544
+ const { item_id, ...body } = args;
545
+ return client.post(`/inbox/${item_id}/resolve`, body);
541
546
  },
542
547
  // Search
543
548
  search_artifacts: (client, args) => {
package/dist/server.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  ArtyfactsMcpServer,
3
3
  createMcpServer,
4
4
  startServer
5
- } from "./chunk-NUVCJMET.js";
5
+ } from "./chunk-XLUIPOCO.js";
6
6
  export {
7
7
  ArtyfactsMcpServer,
8
8
  createMcpServer,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@artyfacts/mcp-server",
3
- "version": "1.0.5",
3
+ "version": "1.1.0",
4
4
  "description": "MCP server exposing Artyfacts tools for Claude Code",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/src/server.ts CHANGED
@@ -325,46 +325,50 @@ const ARTYFACTS_TOOLS: Tool[] = [
325
325
  },
326
326
  },
327
327
 
328
- // Blocker tools
328
+ // Inbox tools (human-in-the-loop)
329
329
  {
330
- name: 'list_blockers',
331
- description: 'List blockers (decisions, dependencies needing resolution)',
330
+ name: 'create_inbox_item',
331
+ description: 'Request human approval, a decision, or an answer before proceeding. Automatically blocks the task. Use for agent creation, risky actions, or anything requiring human sign-off.',
332
332
  inputSchema: {
333
333
  type: 'object',
334
334
  properties: {
335
- artifact_id: { type: 'string', description: 'Filter by artifact' },
336
- status: { type: 'string', description: 'Filter by status: open, resolved' },
335
+ task_id: { type: 'string', description: 'UUID of the task being blocked (required)' },
336
+ type: { type: 'string', description: 'Type: approval, decision, question' },
337
+ title: { type: 'string', description: 'Short summary shown to the human in the inbox' },
338
+ content: { type: 'string', description: 'Full context and details for the human' },
339
+ action: { type: 'string', description: 'Action to auto-execute if approved (e.g. agent.create)' },
340
+ action_payload: { type: 'object', description: 'Data for the action (e.g. full agent spec for agent.create)' },
341
+ options: { type: 'array', description: 'Options for decision type: [{id, label, description}]' },
337
342
  },
338
- required: [],
343
+ required: ['task_id', 'type', 'title'],
339
344
  },
340
345
  },
341
346
  {
342
- name: 'create_blocker',
343
- description: 'Create a blocker (decision request, dependency, etc.)',
347
+ name: 'list_inbox',
348
+ description: 'List pending inbox items (approvals, decisions, questions) waiting for human resolution.',
344
349
  inputSchema: {
345
350
  type: 'object',
346
351
  properties: {
347
- artifact_id: { type: 'string', description: 'Artifact ID' },
348
- kind: { type: 'string', description: 'Kind: decision, dependency, resource, external' },
349
- title: { type: 'string', description: 'Blocker title' },
350
- description: { type: 'string', description: 'Details' },
351
- options: { type: 'array', description: 'Options for decisions' },
352
- blocked_tasks: { type: 'array', items: { type: 'string' }, description: 'Task IDs blocked by this' },
352
+ status: { type: 'string', description: 'Filter by status: pending (default), resolved' },
353
+ type: { type: 'string', description: 'Filter by type: approval, decision, question' },
354
+ limit: { type: 'number', description: 'Max results (default 50)' },
353
355
  },
354
- required: ['artifact_id', 'kind', 'title'],
356
+ required: [],
355
357
  },
356
358
  },
357
359
  {
358
- name: 'resolve_blocker',
359
- description: 'Resolve a blocker',
360
+ name: 'resolve_inbox',
361
+ description: 'Resolve an inbox item from the agent side. Humans resolve via the UI — only use this for automated resolution.',
360
362
  inputSchema: {
361
363
  type: 'object',
362
364
  properties: {
363
- blocker_id: { type: 'string', description: 'Blocker ID' },
364
- resolution: { type: 'string', description: 'How it was resolved' },
365
- selected_option: { type: 'string', description: 'Selected option (for decisions)' },
365
+ item_id: { type: 'string', description: 'Inbox item UUID' },
366
+ approved: { type: 'boolean', description: 'For approvals: true to approve, false to deny' },
367
+ chosen_option: { type: 'string', description: 'For decisions: the selected option ID' },
368
+ answer: { type: 'string', description: 'For questions: the answer text' },
369
+ notes: { type: 'string', description: 'Optional notes' },
366
370
  },
367
- required: ['blocker_id', 'resolution'],
371
+ required: ['item_id'],
368
372
  },
369
373
  },
370
374
 
@@ -554,20 +558,21 @@ const toolHandlers: Record<string, ToolHandler> = {
554
558
  return client.patch(`/agents/${agent_id}`, body);
555
559
  },
556
560
 
557
- // Blockers
558
- list_blockers: (client, args) => {
561
+ // Inbox (human-in-the-loop)
562
+ create_inbox_item: (client, args) => {
563
+ const { task_id, type, title, content, action, action_payload, options } = args;
564
+ return client.post('/inbox', { task_id, type, title, content, action, action_payload, options });
565
+ },
566
+ list_inbox: (client, args) => {
559
567
  const params = new URLSearchParams();
560
- if (args.artifact_id) params.set('artifact_id', String(args.artifact_id));
561
568
  if (args.status) params.set('status', String(args.status));
562
- return client.get(`/blockers?${params}`);
563
- },
564
- create_blocker: (client, args) => {
565
- const { artifact_id, ...body } = args;
566
- return client.post(`/artifacts/${artifact_id}/blockers`, body);
569
+ if (args.type) params.set('type', String(args.type));
570
+ if (args.limit) params.set('limit', String(args.limit));
571
+ return client.get(`/inbox?${params}`);
567
572
  },
568
- resolve_blocker: (client, args) => {
569
- const { blocker_id, ...body } = args;
570
- return client.post(`/blockers/${blocker_id}/resolve`, body);
573
+ resolve_inbox: (client, args) => {
574
+ const { item_id, ...body } = args;
575
+ return client.post(`/inbox/${item_id}/resolve`, body);
571
576
  },
572
577
 
573
578
  // Search