@artyfacts/mcp-server 1.1.2 → 1.1.4

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.
@@ -5,6 +5,7 @@ import { createMcpServer, startServer } from '../dist/index.js';
5
5
  // Get config from environment or args
6
6
  const apiKey = process.env.ARTYFACTS_API_KEY;
7
7
  const baseUrl = process.env.ARTYFACTS_BASE_URL || 'https://artyfacts.dev/api/v1';
8
+ const agentId = process.env.ARTYFACTS_AGENT_ID;
8
9
 
9
10
  if (!apiKey) {
10
11
  console.error('Error: ARTYFACTS_API_KEY environment variable is required');
@@ -20,6 +21,7 @@ if (!apiKey) {
20
21
  const server = createMcpServer({
21
22
  apiKey,
22
23
  baseUrl,
24
+ agentId,
23
25
  });
24
26
 
25
27
  startServer(server).catch((error) => {
@@ -0,0 +1,631 @@
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. Always pass output_artifact_id if you created an artifact. Always pass output_references listing every entity you created or touched.",
193
+ inputSchema: {
194
+ type: "object",
195
+ properties: {
196
+ task_id: { type: "string", description: "Task ID" },
197
+ output_text: { type: "string", description: "Completion summary / what was done" },
198
+ output_url: { type: "string", description: "URL to deliverable (PR, doc, etc.)" },
199
+ output_artifact_id: { type: "string", description: "UUID of the primary artifact produced by this task" },
200
+ output_references: {
201
+ type: "array",
202
+ description: "All entities created or interacted with: artifacts, tasks, agents, goals",
203
+ items: {
204
+ type: "object",
205
+ properties: {
206
+ type: { type: "string", description: "artifact | task | agent | goal" },
207
+ id: { type: "string", description: "Entity UUID" },
208
+ title: { type: "string", description: "Display name for the reference card" },
209
+ subtitle: { type: "string", description: "Optional: type label, status, role, etc." }
210
+ },
211
+ required: ["type", "id", "title"]
212
+ }
213
+ }
214
+ },
215
+ required: ["task_id"]
216
+ }
217
+ },
218
+ {
219
+ name: "block_task",
220
+ description: "Mark a task as blocked",
221
+ inputSchema: {
222
+ type: "object",
223
+ properties: {
224
+ task_id: { type: "string", description: "Task ID" },
225
+ reason: { type: "string", description: "Why it is blocked" },
226
+ blocker_type: { type: "string", description: "Type: decision, dependency, resource, external" }
227
+ },
228
+ required: ["task_id", "reason"]
229
+ }
230
+ },
231
+ {
232
+ name: "create_task",
233
+ description: "Create a new task under a goal. Use this to create actionable tasks \u2014 NOT create_artifact or create_section.",
234
+ inputSchema: {
235
+ type: "object",
236
+ properties: {
237
+ goal_id: { type: "string", description: "The goal UUID this task belongs to (required)" },
238
+ title: { type: "string", description: "Task title" },
239
+ description: { type: "string", description: "Task description / what needs to be done" },
240
+ priority: { type: "string", description: "Priority: low, medium, high, urgent" },
241
+ assigned_to: { type: "string", description: "Agent UUID to assign the task to" },
242
+ depends_on: { type: "array", items: { type: "string" }, description: "List of task UUIDs this task depends on" },
243
+ estimated_minutes: { type: "number", description: "Estimated time in minutes" }
244
+ },
245
+ required: ["goal_id", "title"]
246
+ }
247
+ },
248
+ // Agent tools
249
+ {
250
+ name: "list_agents",
251
+ description: "List all agents in the organization",
252
+ inputSchema: {
253
+ type: "object",
254
+ properties: {
255
+ status: { type: "string", description: "Filter by status: active, inactive" }
256
+ },
257
+ required: []
258
+ }
259
+ },
260
+ {
261
+ name: "get_agent",
262
+ description: "Get details about an agent",
263
+ inputSchema: {
264
+ type: "object",
265
+ properties: {
266
+ agent_id: { type: "string", description: "Agent ID" }
267
+ },
268
+ required: ["agent_id"]
269
+ }
270
+ },
271
+ {
272
+ name: "create_agent",
273
+ description: "Register a new AI agent with role, capabilities, and permissions",
274
+ inputSchema: {
275
+ type: "object",
276
+ properties: {
277
+ agentId: { type: "string", description: 'Unique agent ID (e.g., "engineering-agent", "qa-agent")' },
278
+ name: { type: "string", description: "Agent display name" },
279
+ role: { type: "string", description: "Role: pm, engineering, qa, research, content, design" },
280
+ description: { type: "string", description: "What this agent does - detailed description" },
281
+ capabilities: { type: "array", items: { type: "string" }, description: 'List of capabilities (e.g., ["code-review", "testing", "debugging"])' },
282
+ permissions: {
283
+ type: "object",
284
+ description: "Permission settings",
285
+ properties: {
286
+ write: { type: "boolean", description: "Can create/edit artifacts" },
287
+ delete: { type: "boolean", description: "Can delete artifacts" },
288
+ delegate_tasks: { type: "boolean", description: "Can assign tasks to other agents" }
289
+ }
290
+ },
291
+ systemPrompt: { type: "string", description: "System prompt for the agent" },
292
+ reportsToAgentId: { type: "string", description: 'Agent ID or UUID of the parent agent this agent reports to. Use agent slugs like "chief-of-staff" for readability.' }
293
+ },
294
+ required: ["agentId", "name", "role", "description"]
295
+ }
296
+ },
297
+ {
298
+ name: "update_agent",
299
+ description: "Update an agent",
300
+ inputSchema: {
301
+ type: "object",
302
+ properties: {
303
+ agent_id: { type: "string", description: "Agent ID" },
304
+ name: { type: "string", description: "New name" },
305
+ status: { type: "string", description: "New status" },
306
+ config: { type: "object", description: "Updated config" }
307
+ },
308
+ required: ["agent_id"]
309
+ }
310
+ },
311
+ // Inbox tools (human-in-the-loop)
312
+ {
313
+ name: "create_inbox_item",
314
+ 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.",
315
+ inputSchema: {
316
+ type: "object",
317
+ properties: {
318
+ task_id: { type: "string", description: "UUID of the task being blocked (required)" },
319
+ type: { type: "string", description: "Type: approval, decision, question" },
320
+ title: { type: "string", description: "Short summary shown to the human in the inbox" },
321
+ content: { type: "string", description: "Full context and details for the human" },
322
+ action: { type: "string", description: "Action to auto-execute if approved (e.g. agent.create)" },
323
+ action_payload: { type: "object", description: "Data for the action (e.g. full agent spec for agent.create)" },
324
+ options: { type: "array", description: "Options for decision type: [{id, label, description}]" }
325
+ },
326
+ required: ["task_id", "type", "title"]
327
+ }
328
+ },
329
+ {
330
+ name: "list_inbox",
331
+ description: "List pending inbox items (approvals, decisions, questions) waiting for human resolution.",
332
+ inputSchema: {
333
+ type: "object",
334
+ properties: {
335
+ status: { type: "string", description: "Filter by status: pending (default), resolved" },
336
+ type: { type: "string", description: "Filter by type: approval, decision, question" },
337
+ limit: { type: "number", description: "Max results (default 50)" }
338
+ },
339
+ required: []
340
+ }
341
+ },
342
+ {
343
+ name: "resolve_inbox",
344
+ description: "Resolve an inbox item from the agent side. Humans resolve via the UI \u2014 only use this for automated resolution.",
345
+ inputSchema: {
346
+ type: "object",
347
+ properties: {
348
+ item_id: { type: "string", description: "Inbox item UUID" },
349
+ approved: { type: "boolean", description: "For approvals: true to approve, false to deny" },
350
+ chosen_option: { type: "string", description: "For decisions: the selected option ID" },
351
+ answer: { type: "string", description: "For questions: the answer text" },
352
+ notes: { type: "string", description: "Optional notes" }
353
+ },
354
+ required: ["item_id"]
355
+ }
356
+ },
357
+ // Search tools
358
+ {
359
+ name: "search_artifacts",
360
+ description: "Search artifacts by text query",
361
+ inputSchema: {
362
+ type: "object",
363
+ properties: {
364
+ query: { type: "string", description: "Search query" },
365
+ type: { type: "string", description: "Filter by type" },
366
+ limit: { type: "number", description: "Max results" }
367
+ },
368
+ required: ["query"]
369
+ }
370
+ },
371
+ // Context tools
372
+ {
373
+ name: "get_task_context",
374
+ description: "Get full context for a task (org, project, artifact, related sections)",
375
+ inputSchema: {
376
+ type: "object",
377
+ properties: {
378
+ task_id: { type: "string", description: "Task ID" }
379
+ },
380
+ required: ["task_id"]
381
+ }
382
+ }
383
+ ];
384
+ var ArtyfactsApiClient = class {
385
+ constructor(baseUrl, apiKey, agentId) {
386
+ this.baseUrl = baseUrl;
387
+ this.apiKey = apiKey;
388
+ this.agentId = agentId;
389
+ }
390
+ async request(method, path, body) {
391
+ const url = `${this.baseUrl}${path}`;
392
+ const headers = {
393
+ "Authorization": `Bearer ${this.apiKey}`,
394
+ "Content-Type": "application/json"
395
+ };
396
+ if (this.agentId) {
397
+ headers["X-Agent-Id"] = this.agentId;
398
+ }
399
+ const response = await fetch(url, {
400
+ method,
401
+ headers,
402
+ body: body ? JSON.stringify(body) : void 0
403
+ });
404
+ if (!response.ok) {
405
+ const error = await response.json().catch(() => ({ error: "Request failed" }));
406
+ throw new Error(error.error || `HTTP ${response.status}: ${response.statusText}`);
407
+ }
408
+ return response.json();
409
+ }
410
+ get(path) {
411
+ return this.request("GET", path);
412
+ }
413
+ getAgentId() {
414
+ return this.agentId;
415
+ }
416
+ post(path, body) {
417
+ return this.request("POST", path, body);
418
+ }
419
+ patch(path, body) {
420
+ return this.request("PATCH", path, body);
421
+ }
422
+ delete(path) {
423
+ return this.request("DELETE", path);
424
+ }
425
+ };
426
+ var toolHandlers = {
427
+ // Organization
428
+ get_organization: (client) => client.get("/org"),
429
+ // Projects
430
+ list_projects: (client, args) => {
431
+ const params = new URLSearchParams();
432
+ if (args.limit) params.set("limit", String(args.limit));
433
+ if (args.offset) params.set("offset", String(args.offset));
434
+ return client.get(`/projects?${params}`);
435
+ },
436
+ get_project: (client, args) => client.get(`/projects/${args.project_id}`),
437
+ // Artifacts
438
+ list_artifacts: (client, args) => {
439
+ const params = new URLSearchParams();
440
+ if (args.project_id) params.set("project_id", String(args.project_id));
441
+ if (args.type) params.set("type", String(args.type));
442
+ if (args.status) params.set("status", String(args.status));
443
+ if (args.limit) params.set("limit", String(args.limit));
444
+ return client.get(`/artifacts?${params}`);
445
+ },
446
+ get_artifact: (client, args) => client.get(`/artifacts/${args.artifact_id}`),
447
+ create_artifact: (client, args) => {
448
+ const envelope = {
449
+ aah_version: "0.3",
450
+ artifact: {
451
+ id: args.id || `artifact-${Date.now()}`,
452
+ title: args.title,
453
+ type: args.type || "document/sectioned",
454
+ artifact_type: args.artifact_type || args.type || "doc",
455
+ parent_id: args.parent_id,
456
+ tags: args.tags
457
+ },
458
+ content: args.content ? {
459
+ media_type: "text/markdown",
460
+ body: args.content
461
+ } : void 0,
462
+ source: {
463
+ agent_id: client.getAgentId() || "mcp-agent"
464
+ }
465
+ };
466
+ return client.post("/artifacts", envelope);
467
+ },
468
+ update_artifact: (client, args) => {
469
+ const { artifact_id, ...body } = args;
470
+ return client.patch(`/artifacts/${artifact_id}`, body);
471
+ },
472
+ // Sections
473
+ list_sections: (client, args) => client.get(`/artifacts/${args.artifact_id}/sections`),
474
+ get_section: (client, args) => client.get(`/artifacts/${args.artifact_id}/sections/${args.section_id}`),
475
+ create_section: (client, args) => {
476
+ const { artifact_id, section_id, ...rest } = args;
477
+ const body = { id: section_id, ...rest };
478
+ return client.post(`/artifacts/${artifact_id}/sections`, body);
479
+ },
480
+ update_section: (client, args) => {
481
+ const { artifact_id, section_id, ...body } = args;
482
+ return client.patch(`/artifacts/${artifact_id}/sections/${section_id}`, body);
483
+ },
484
+ delete_section: (client, args) => client.delete(`/artifacts/${args.artifact_id}/sections/${args.section_id}`),
485
+ // Tasks
486
+ list_tasks: (client, args) => {
487
+ const params = new URLSearchParams();
488
+ if (args.artifact_id) params.set("artifact_id", String(args.artifact_id));
489
+ if (args.status) params.set("status", String(args.status));
490
+ if (args.assignee) params.set("assignee", String(args.assignee));
491
+ return client.get(`/tasks?${params}`);
492
+ },
493
+ claim_task: (client, args) => client.post(`/tasks/${args.task_id}/claim`),
494
+ complete_task: (client, args) => {
495
+ const { task_id, ...body } = args;
496
+ return client.post(`/tasks/${task_id}/complete`, body);
497
+ },
498
+ block_task: (client, args) => {
499
+ const { task_id, ...body } = args;
500
+ return client.post(`/tasks/${task_id}/block`, body);
501
+ },
502
+ create_task: (client, args) => {
503
+ const { goal_id, title, description, priority, assigned_to, depends_on, estimated_minutes } = args;
504
+ return client.post("/tasks", { goal_id, title, description, priority, assigned_to, depends_on, estimated_minutes });
505
+ },
506
+ // Agents
507
+ list_agents: (client, args) => {
508
+ const params = new URLSearchParams();
509
+ if (args.status) params.set("status", String(args.status));
510
+ return client.get(`/agents?${params}`);
511
+ },
512
+ get_agent: (client, args) => client.get(`/agents/${args.agent_id}`),
513
+ create_agent: (client, args) => {
514
+ const body = {
515
+ agentId: args.agentId,
516
+ name: args.name,
517
+ role: args.role,
518
+ description: args.description,
519
+ reportsToAgentId: args.reportsToAgentId,
520
+ permissions: args.permissions || { write: true, delete: false, delegate_tasks: false },
521
+ metadata: {
522
+ capabilities: args.capabilities || [],
523
+ systemPrompt: args.systemPrompt,
524
+ createdVia: "mcp"
525
+ }
526
+ };
527
+ return client.post("/agents", body);
528
+ },
529
+ update_agent: (client, args) => {
530
+ const { agent_id, ...body } = args;
531
+ return client.patch(`/agents/${agent_id}`, body);
532
+ },
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) => {
539
+ const params = new URLSearchParams();
540
+ if (args.status) params.set("status", String(args.status));
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}`);
544
+ },
545
+ resolve_inbox: (client, args) => {
546
+ const { item_id, ...body } = args;
547
+ return client.post(`/inbox/${item_id}/resolve`, body);
548
+ },
549
+ // Search
550
+ search_artifacts: (client, args) => {
551
+ const params = new URLSearchParams();
552
+ params.set("q", String(args.query));
553
+ if (args.type) params.set("type", String(args.type));
554
+ if (args.limit) params.set("limit", String(args.limit));
555
+ return client.get(`/search?${params}`);
556
+ },
557
+ // Context
558
+ get_task_context: (client, args) => client.get(`/tasks/${args.task_id}/context`)
559
+ };
560
+ var ArtyfactsMcpServer = class {
561
+ server;
562
+ client;
563
+ config;
564
+ constructor(config) {
565
+ this.config = config;
566
+ this.client = new ArtyfactsApiClient(
567
+ config.baseUrl || "https://artyfacts.dev/api/v1",
568
+ config.apiKey,
569
+ config.agentId
570
+ );
571
+ this.server = new Server(
572
+ {
573
+ name: config.name || "artyfacts-mcp",
574
+ version: config.version || "1.0.0"
575
+ },
576
+ {
577
+ capabilities: {
578
+ tools: {}
579
+ }
580
+ }
581
+ );
582
+ this.setupHandlers();
583
+ }
584
+ setupHandlers() {
585
+ this.server.setRequestHandler(ListToolsRequestSchema, async () => {
586
+ return { tools: ARTYFACTS_TOOLS };
587
+ });
588
+ this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
589
+ const { name, arguments: args } = request.params;
590
+ const handler = toolHandlers[name];
591
+ if (!handler) {
592
+ return {
593
+ content: [{ type: "text", text: `Unknown tool: ${name}` }],
594
+ isError: true
595
+ };
596
+ }
597
+ try {
598
+ const result = await handler(this.client, args || {});
599
+ return {
600
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
601
+ };
602
+ } catch (error) {
603
+ const message = error instanceof Error ? error.message : String(error);
604
+ return {
605
+ content: [{ type: "text", text: `Error: ${message}` }],
606
+ isError: true
607
+ };
608
+ }
609
+ });
610
+ }
611
+ async start() {
612
+ const transport = new StdioServerTransport();
613
+ await this.server.connect(transport);
614
+ console.error(`Artyfacts MCP server running (${ARTYFACTS_TOOLS.length} tools)`);
615
+ }
616
+ getServer() {
617
+ return this.server;
618
+ }
619
+ };
620
+ function createMcpServer(config) {
621
+ return new ArtyfactsMcpServer(config);
622
+ }
623
+ async function startServer(server) {
624
+ await server.start();
625
+ }
626
+
627
+ export {
628
+ ArtyfactsMcpServer,
629
+ createMcpServer,
630
+ startServer
631
+ };
package/dist/index.cjs CHANGED
@@ -313,7 +313,8 @@ var ARTYFACTS_TOOLS = [
313
313
  delegate_tasks: { type: "boolean", description: "Can assign tasks to other agents" }
314
314
  }
315
315
  },
316
- systemPrompt: { type: "string", description: "System prompt for the agent" }
316
+ systemPrompt: { type: "string", description: "System prompt for the agent" },
317
+ reportsToAgentId: { type: "string", description: 'Agent ID or UUID of the parent agent this agent reports to. Use agent slugs like "chief-of-staff" for readability.' }
317
318
  },
318
319
  required: ["agentId", "name", "role", "description"]
319
320
  }
@@ -406,18 +407,23 @@ var ARTYFACTS_TOOLS = [
406
407
  }
407
408
  ];
408
409
  var ArtyfactsApiClient = class {
409
- constructor(baseUrl, apiKey) {
410
+ constructor(baseUrl, apiKey, agentId) {
410
411
  this.baseUrl = baseUrl;
411
412
  this.apiKey = apiKey;
413
+ this.agentId = agentId;
412
414
  }
413
415
  async request(method, path, body) {
414
416
  const url = `${this.baseUrl}${path}`;
417
+ const headers = {
418
+ "Authorization": `Bearer ${this.apiKey}`,
419
+ "Content-Type": "application/json"
420
+ };
421
+ if (this.agentId) {
422
+ headers["X-Agent-Id"] = this.agentId;
423
+ }
415
424
  const response = await fetch(url, {
416
425
  method,
417
- headers: {
418
- "Authorization": `Bearer ${this.apiKey}`,
419
- "Content-Type": "application/json"
420
- },
426
+ headers,
421
427
  body: body ? JSON.stringify(body) : void 0
422
428
  });
423
429
  if (!response.ok) {
@@ -429,6 +435,9 @@ var ArtyfactsApiClient = class {
429
435
  get(path) {
430
436
  return this.request("GET", path);
431
437
  }
438
+ getAgentId() {
439
+ return this.agentId;
440
+ }
432
441
  post(path, body) {
433
442
  return this.request("POST", path, body);
434
443
  }
@@ -476,7 +485,7 @@ var toolHandlers = {
476
485
  body: args.content
477
486
  } : void 0,
478
487
  source: {
479
- agent_id: "mcp-agent"
488
+ agent_id: client.getAgentId() || "mcp-agent"
480
489
  }
481
490
  };
482
491
  return client.post("/artifacts", envelope);
@@ -532,6 +541,7 @@ var toolHandlers = {
532
541
  name: args.name,
533
542
  role: args.role,
534
543
  description: args.description,
544
+ reportsToAgentId: args.reportsToAgentId,
535
545
  permissions: args.permissions || { write: true, delete: false, delegate_tasks: false },
536
546
  metadata: {
537
547
  capabilities: args.capabilities || [],
@@ -580,7 +590,8 @@ var ArtyfactsMcpServer = class {
580
590
  this.config = config;
581
591
  this.client = new ArtyfactsApiClient(
582
592
  config.baseUrl || "https://artyfacts.dev/api/v1",
583
- config.apiKey
593
+ config.apiKey,
594
+ config.agentId
584
595
  );
585
596
  this.server = new import_server.Server(
586
597
  {
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  ArtyfactsMcpServer,
3
3
  createMcpServer,
4
4
  startServer
5
- } from "./chunk-324EM5A4.js";
5
+ } from "./chunk-GOOQPNGV.js";
6
6
  export {
7
7
  ArtyfactsMcpServer,
8
8
  createMcpServer,
package/dist/server.cjs CHANGED
@@ -311,7 +311,8 @@ var ARTYFACTS_TOOLS = [
311
311
  delegate_tasks: { type: "boolean", description: "Can assign tasks to other agents" }
312
312
  }
313
313
  },
314
- systemPrompt: { type: "string", description: "System prompt for the agent" }
314
+ systemPrompt: { type: "string", description: "System prompt for the agent" },
315
+ reportsToAgentId: { type: "string", description: 'Agent ID or UUID of the parent agent this agent reports to. Use agent slugs like "chief-of-staff" for readability.' }
315
316
  },
316
317
  required: ["agentId", "name", "role", "description"]
317
318
  }
@@ -404,18 +405,23 @@ var ARTYFACTS_TOOLS = [
404
405
  }
405
406
  ];
406
407
  var ArtyfactsApiClient = class {
407
- constructor(baseUrl, apiKey) {
408
+ constructor(baseUrl, apiKey, agentId) {
408
409
  this.baseUrl = baseUrl;
409
410
  this.apiKey = apiKey;
411
+ this.agentId = agentId;
410
412
  }
411
413
  async request(method, path, body) {
412
414
  const url = `${this.baseUrl}${path}`;
415
+ const headers = {
416
+ "Authorization": `Bearer ${this.apiKey}`,
417
+ "Content-Type": "application/json"
418
+ };
419
+ if (this.agentId) {
420
+ headers["X-Agent-Id"] = this.agentId;
421
+ }
413
422
  const response = await fetch(url, {
414
423
  method,
415
- headers: {
416
- "Authorization": `Bearer ${this.apiKey}`,
417
- "Content-Type": "application/json"
418
- },
424
+ headers,
419
425
  body: body ? JSON.stringify(body) : void 0
420
426
  });
421
427
  if (!response.ok) {
@@ -427,6 +433,9 @@ var ArtyfactsApiClient = class {
427
433
  get(path) {
428
434
  return this.request("GET", path);
429
435
  }
436
+ getAgentId() {
437
+ return this.agentId;
438
+ }
430
439
  post(path, body) {
431
440
  return this.request("POST", path, body);
432
441
  }
@@ -474,7 +483,7 @@ var toolHandlers = {
474
483
  body: args.content
475
484
  } : void 0,
476
485
  source: {
477
- agent_id: "mcp-agent"
486
+ agent_id: client.getAgentId() || "mcp-agent"
478
487
  }
479
488
  };
480
489
  return client.post("/artifacts", envelope);
@@ -530,6 +539,7 @@ var toolHandlers = {
530
539
  name: args.name,
531
540
  role: args.role,
532
541
  description: args.description,
542
+ reportsToAgentId: args.reportsToAgentId,
533
543
  permissions: args.permissions || { write: true, delete: false, delegate_tasks: false },
534
544
  metadata: {
535
545
  capabilities: args.capabilities || [],
@@ -578,7 +588,8 @@ var ArtyfactsMcpServer = class {
578
588
  this.config = config;
579
589
  this.client = new ArtyfactsApiClient(
580
590
  config.baseUrl || "https://artyfacts.dev/api/v1",
581
- config.apiKey
591
+ config.apiKey,
592
+ config.agentId
582
593
  );
583
594
  this.server = new import_server.Server(
584
595
  {
package/dist/server.d.cts CHANGED
@@ -12,6 +12,8 @@ interface McpServerConfig {
12
12
  apiKey: string;
13
13
  /** Artyfacts API base URL */
14
14
  baseUrl?: string;
15
+ /** Agent slug (e.g. 'chief-of-staff') — used to attribute writes to the correct agent */
16
+ agentId?: string;
15
17
  /** Server name */
16
18
  name?: string;
17
19
  /** Server version */
package/dist/server.d.ts CHANGED
@@ -12,6 +12,8 @@ interface McpServerConfig {
12
12
  apiKey: string;
13
13
  /** Artyfacts API base URL */
14
14
  baseUrl?: string;
15
+ /** Agent slug (e.g. 'chief-of-staff') — used to attribute writes to the correct agent */
16
+ agentId?: string;
15
17
  /** Server name */
16
18
  name?: string;
17
19
  /** Server version */
package/dist/server.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  ArtyfactsMcpServer,
3
3
  createMcpServer,
4
4
  startServer
5
- } from "./chunk-324EM5A4.js";
5
+ } from "./chunk-GOOQPNGV.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.1.2",
3
+ "version": "1.1.4",
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
@@ -22,6 +22,8 @@ export interface McpServerConfig {
22
22
  apiKey: string;
23
23
  /** Artyfacts API base URL */
24
24
  baseUrl?: string;
25
+ /** Agent slug (e.g. 'chief-of-staff') — used to attribute writes to the correct agent */
26
+ agentId?: string;
25
27
  /** Server name */
26
28
  name?: string;
27
29
  /** Server version */
@@ -321,6 +323,7 @@ const ARTYFACTS_TOOLS: Tool[] = [
321
323
  }
322
324
  },
323
325
  systemPrompt: { type: 'string', description: 'System prompt for the agent' },
326
+ reportsToAgentId: { type: 'string', description: 'Agent ID or UUID of the parent agent this agent reports to. Use agent slugs like "chief-of-staff" for readability.' },
324
327
  },
325
328
  required: ['agentId', 'name', 'role', 'description'],
326
329
  },
@@ -423,18 +426,24 @@ const ARTYFACTS_TOOLS: Tool[] = [
423
426
  class ArtyfactsApiClient {
424
427
  constructor(
425
428
  private baseUrl: string,
426
- private apiKey: string
429
+ private apiKey: string,
430
+ private agentId?: string
427
431
  ) {}
428
432
 
429
433
  async request(method: string, path: string, body?: unknown): Promise<unknown> {
430
434
  const url = `${this.baseUrl}${path}`;
431
-
435
+
436
+ const headers: Record<string, string> = {
437
+ 'Authorization': `Bearer ${this.apiKey}`,
438
+ 'Content-Type': 'application/json',
439
+ };
440
+ if (this.agentId) {
441
+ headers['X-Agent-Id'] = this.agentId;
442
+ }
443
+
432
444
  const response = await fetch(url, {
433
445
  method,
434
- headers: {
435
- 'Authorization': `Bearer ${this.apiKey}`,
436
- 'Content-Type': 'application/json',
437
- },
446
+ headers,
438
447
  body: body ? JSON.stringify(body) : undefined,
439
448
  });
440
449
 
@@ -447,6 +456,7 @@ class ArtyfactsApiClient {
447
456
  }
448
457
 
449
458
  get(path: string) { return this.request('GET', path); }
459
+ getAgentId() { return this.agentId; }
450
460
  post(path: string, body?: unknown) { return this.request('POST', path, body); }
451
461
  patch(path: string, body?: unknown) { return this.request('PATCH', path, body); }
452
462
  delete(path: string) { return this.request('DELETE', path); }
@@ -498,7 +508,7 @@ const toolHandlers: Record<string, ToolHandler> = {
498
508
  body: args.content,
499
509
  } : undefined,
500
510
  source: {
501
- agent_id: 'mcp-agent',
511
+ agent_id: client.getAgentId() || 'mcp-agent',
502
512
  },
503
513
  };
504
514
  return client.post('/artifacts', envelope);
@@ -559,6 +569,7 @@ const toolHandlers: Record<string, ToolHandler> = {
559
569
  name: args.name,
560
570
  role: args.role,
561
571
  description: args.description,
572
+ reportsToAgentId: args.reportsToAgentId,
562
573
  permissions: args.permissions || { write: true, delete: false, delegate_tasks: false },
563
574
  metadata: {
564
575
  capabilities: args.capabilities || [],
@@ -616,7 +627,8 @@ export class ArtyfactsMcpServer {
616
627
  this.config = config;
617
628
  this.client = new ArtyfactsApiClient(
618
629
  config.baseUrl || 'https://artyfacts.dev/api/v1',
619
- config.apiKey
630
+ config.apiKey,
631
+ config.agentId
620
632
  );
621
633
 
622
634
  this.server = new Server(