@artyfacts/mcp-server 1.0.1 → 1.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.
- package/dist/chunk-OZZ4SOPK.js +536 -0
- package/dist/chunk-VCIOVYRM.js +556 -0
- package/dist/index.cjs +31 -10
- package/dist/index.js +1 -1
- package/dist/server.cjs +31 -10
- package/dist/server.js +1 -1
- package/package.json +1 -1
- package/src/server.ts +33 -10
|
@@ -0,0 +1,536 @@
|
|
|
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",
|
|
72
|
+
inputSchema: {
|
|
73
|
+
type: "object",
|
|
74
|
+
properties: {
|
|
75
|
+
title: { type: "string", description: "Artifact title" },
|
|
76
|
+
type: { type: "string", description: "Type: goal, spec, research, report, experiment, decision" },
|
|
77
|
+
content: { type: "string", description: "Markdown content" },
|
|
78
|
+
project_id: { type: "string", description: "Project ID" },
|
|
79
|
+
parent_id: { type: "string", description: "Parent artifact ID" },
|
|
80
|
+
tags: { type: "array", items: { type: "string" }, description: "Tags" }
|
|
81
|
+
},
|
|
82
|
+
required: ["title"]
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
name: "update_artifact",
|
|
87
|
+
description: "Update an existing artifact",
|
|
88
|
+
inputSchema: {
|
|
89
|
+
type: "object",
|
|
90
|
+
properties: {
|
|
91
|
+
artifact_id: { type: "string", description: "Artifact ID" },
|
|
92
|
+
title: { type: "string", description: "New title" },
|
|
93
|
+
content: { type: "string", description: "New content" },
|
|
94
|
+
status: { type: "string", description: "New status" }
|
|
95
|
+
},
|
|
96
|
+
required: ["artifact_id"]
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
// Section tools
|
|
100
|
+
{
|
|
101
|
+
name: "list_sections",
|
|
102
|
+
description: "List sections of an artifact",
|
|
103
|
+
inputSchema: {
|
|
104
|
+
type: "object",
|
|
105
|
+
properties: {
|
|
106
|
+
artifact_id: { type: "string", description: "Artifact ID" }
|
|
107
|
+
},
|
|
108
|
+
required: ["artifact_id"]
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
name: "get_section",
|
|
113
|
+
description: "Get a specific section",
|
|
114
|
+
inputSchema: {
|
|
115
|
+
type: "object",
|
|
116
|
+
properties: {
|
|
117
|
+
artifact_id: { type: "string", description: "Artifact ID" },
|
|
118
|
+
section_id: { type: "string", description: "Section ID" }
|
|
119
|
+
},
|
|
120
|
+
required: ["artifact_id", "section_id"]
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
name: "create_section",
|
|
125
|
+
description: "Create a new section on an artifact",
|
|
126
|
+
inputSchema: {
|
|
127
|
+
type: "object",
|
|
128
|
+
properties: {
|
|
129
|
+
artifact_id: { type: "string", description: "Artifact ID" },
|
|
130
|
+
section_id: { type: "string", description: "Section identifier (slug)" },
|
|
131
|
+
heading: { type: "string", description: "Section heading" },
|
|
132
|
+
content: { type: "string", description: "Markdown content" },
|
|
133
|
+
type: { type: "string", description: "Type: content, task, decision, blocker" },
|
|
134
|
+
position: { type: "number", description: "Order position" }
|
|
135
|
+
},
|
|
136
|
+
required: ["artifact_id", "section_id", "heading"]
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
name: "update_section",
|
|
141
|
+
description: "Update an existing section",
|
|
142
|
+
inputSchema: {
|
|
143
|
+
type: "object",
|
|
144
|
+
properties: {
|
|
145
|
+
artifact_id: { type: "string", description: "Artifact ID" },
|
|
146
|
+
section_id: { type: "string", description: "Section ID" },
|
|
147
|
+
heading: { type: "string", description: "New heading" },
|
|
148
|
+
content: { type: "string", description: "New content" },
|
|
149
|
+
task_status: { type: "string", description: "Task status if type=task" }
|
|
150
|
+
},
|
|
151
|
+
required: ["artifact_id", "section_id"]
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
name: "delete_section",
|
|
156
|
+
description: "Delete a section",
|
|
157
|
+
inputSchema: {
|
|
158
|
+
type: "object",
|
|
159
|
+
properties: {
|
|
160
|
+
artifact_id: { type: "string", description: "Artifact ID" },
|
|
161
|
+
section_id: { type: "string", description: "Section ID" }
|
|
162
|
+
},
|
|
163
|
+
required: ["artifact_id", "section_id"]
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
// Task tools
|
|
167
|
+
{
|
|
168
|
+
name: "list_tasks",
|
|
169
|
+
description: "List tasks (sections with type=task)",
|
|
170
|
+
inputSchema: {
|
|
171
|
+
type: "object",
|
|
172
|
+
properties: {
|
|
173
|
+
artifact_id: { type: "string", description: "Filter by artifact" },
|
|
174
|
+
status: { type: "string", description: "Filter by status: pending, in_progress, done, blocked" },
|
|
175
|
+
assignee: { type: "string", description: "Filter by assignee agent" }
|
|
176
|
+
},
|
|
177
|
+
required: []
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
name: "claim_task",
|
|
182
|
+
description: "Claim a task for the current agent",
|
|
183
|
+
inputSchema: {
|
|
184
|
+
type: "object",
|
|
185
|
+
properties: {
|
|
186
|
+
task_id: { type: "string", description: "Task ID (section UUID)" }
|
|
187
|
+
},
|
|
188
|
+
required: ["task_id"]
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
name: "complete_task",
|
|
193
|
+
description: "Mark a task as complete",
|
|
194
|
+
inputSchema: {
|
|
195
|
+
type: "object",
|
|
196
|
+
properties: {
|
|
197
|
+
task_id: { type: "string", description: "Task ID" },
|
|
198
|
+
output_url: { type: "string", description: "URL to deliverable (PR, doc, etc.)" },
|
|
199
|
+
summary: { type: "string", description: "Completion summary" }
|
|
200
|
+
},
|
|
201
|
+
required: ["task_id"]
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
name: "block_task",
|
|
206
|
+
description: "Mark a task as blocked",
|
|
207
|
+
inputSchema: {
|
|
208
|
+
type: "object",
|
|
209
|
+
properties: {
|
|
210
|
+
task_id: { type: "string", description: "Task ID" },
|
|
211
|
+
reason: { type: "string", description: "Why it is blocked" },
|
|
212
|
+
blocker_type: { type: "string", description: "Type: decision, dependency, resource, external" }
|
|
213
|
+
},
|
|
214
|
+
required: ["task_id", "reason"]
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
// Agent tools
|
|
218
|
+
{
|
|
219
|
+
name: "list_agents",
|
|
220
|
+
description: "List all agents in the organization",
|
|
221
|
+
inputSchema: {
|
|
222
|
+
type: "object",
|
|
223
|
+
properties: {
|
|
224
|
+
status: { type: "string", description: "Filter by status: active, inactive" }
|
|
225
|
+
},
|
|
226
|
+
required: []
|
|
227
|
+
}
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
name: "get_agent",
|
|
231
|
+
description: "Get details about an agent",
|
|
232
|
+
inputSchema: {
|
|
233
|
+
type: "object",
|
|
234
|
+
properties: {
|
|
235
|
+
agent_id: { type: "string", description: "Agent ID" }
|
|
236
|
+
},
|
|
237
|
+
required: ["agent_id"]
|
|
238
|
+
}
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
name: "create_agent",
|
|
242
|
+
description: "Register a new agent",
|
|
243
|
+
inputSchema: {
|
|
244
|
+
type: "object",
|
|
245
|
+
properties: {
|
|
246
|
+
agentId: { type: "string", description: 'Unique agent ID (e.g., "engineering-agent", "qa-agent")' },
|
|
247
|
+
name: { type: "string", description: "Agent display name" },
|
|
248
|
+
type: { type: "string", description: "Type: pm, engineering, qa, research, content, design" },
|
|
249
|
+
description: { type: "string", description: "What this agent does" },
|
|
250
|
+
capabilities: { type: "array", items: { type: "string" }, description: "Agent capabilities" },
|
|
251
|
+
config: { type: "object", description: "Agent configuration" }
|
|
252
|
+
},
|
|
253
|
+
required: ["agentId", "name", "type"]
|
|
254
|
+
}
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
name: "update_agent",
|
|
258
|
+
description: "Update an agent",
|
|
259
|
+
inputSchema: {
|
|
260
|
+
type: "object",
|
|
261
|
+
properties: {
|
|
262
|
+
agent_id: { type: "string", description: "Agent ID" },
|
|
263
|
+
name: { type: "string", description: "New name" },
|
|
264
|
+
status: { type: "string", description: "New status" },
|
|
265
|
+
config: { type: "object", description: "Updated config" }
|
|
266
|
+
},
|
|
267
|
+
required: ["agent_id"]
|
|
268
|
+
}
|
|
269
|
+
},
|
|
270
|
+
// Blocker tools
|
|
271
|
+
{
|
|
272
|
+
name: "list_blockers",
|
|
273
|
+
description: "List blockers (decisions, dependencies needing resolution)",
|
|
274
|
+
inputSchema: {
|
|
275
|
+
type: "object",
|
|
276
|
+
properties: {
|
|
277
|
+
artifact_id: { type: "string", description: "Filter by artifact" },
|
|
278
|
+
status: { type: "string", description: "Filter by status: open, resolved" }
|
|
279
|
+
},
|
|
280
|
+
required: []
|
|
281
|
+
}
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
name: "create_blocker",
|
|
285
|
+
description: "Create a blocker (decision request, dependency, etc.)",
|
|
286
|
+
inputSchema: {
|
|
287
|
+
type: "object",
|
|
288
|
+
properties: {
|
|
289
|
+
artifact_id: { type: "string", description: "Artifact ID" },
|
|
290
|
+
kind: { type: "string", description: "Kind: decision, dependency, resource, external" },
|
|
291
|
+
title: { type: "string", description: "Blocker title" },
|
|
292
|
+
description: { type: "string", description: "Details" },
|
|
293
|
+
options: { type: "array", description: "Options for decisions" },
|
|
294
|
+
blocked_tasks: { type: "array", items: { type: "string" }, description: "Task IDs blocked by this" }
|
|
295
|
+
},
|
|
296
|
+
required: ["artifact_id", "kind", "title"]
|
|
297
|
+
}
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
name: "resolve_blocker",
|
|
301
|
+
description: "Resolve a blocker",
|
|
302
|
+
inputSchema: {
|
|
303
|
+
type: "object",
|
|
304
|
+
properties: {
|
|
305
|
+
blocker_id: { type: "string", description: "Blocker ID" },
|
|
306
|
+
resolution: { type: "string", description: "How it was resolved" },
|
|
307
|
+
selected_option: { type: "string", description: "Selected option (for decisions)" }
|
|
308
|
+
},
|
|
309
|
+
required: ["blocker_id", "resolution"]
|
|
310
|
+
}
|
|
311
|
+
},
|
|
312
|
+
// Search tools
|
|
313
|
+
{
|
|
314
|
+
name: "search_artifacts",
|
|
315
|
+
description: "Search artifacts by text query",
|
|
316
|
+
inputSchema: {
|
|
317
|
+
type: "object",
|
|
318
|
+
properties: {
|
|
319
|
+
query: { type: "string", description: "Search query" },
|
|
320
|
+
type: { type: "string", description: "Filter by type" },
|
|
321
|
+
limit: { type: "number", description: "Max results" }
|
|
322
|
+
},
|
|
323
|
+
required: ["query"]
|
|
324
|
+
}
|
|
325
|
+
},
|
|
326
|
+
// Context tools
|
|
327
|
+
{
|
|
328
|
+
name: "get_task_context",
|
|
329
|
+
description: "Get full context for a task (org, project, artifact, related sections)",
|
|
330
|
+
inputSchema: {
|
|
331
|
+
type: "object",
|
|
332
|
+
properties: {
|
|
333
|
+
task_id: { type: "string", description: "Task ID" }
|
|
334
|
+
},
|
|
335
|
+
required: ["task_id"]
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
];
|
|
339
|
+
var ArtyfactsApiClient = class {
|
|
340
|
+
constructor(baseUrl, apiKey) {
|
|
341
|
+
this.baseUrl = baseUrl;
|
|
342
|
+
this.apiKey = apiKey;
|
|
343
|
+
}
|
|
344
|
+
async request(method, path, body) {
|
|
345
|
+
const url = `${this.baseUrl}${path}`;
|
|
346
|
+
const response = await fetch(url, {
|
|
347
|
+
method,
|
|
348
|
+
headers: {
|
|
349
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
350
|
+
"Content-Type": "application/json"
|
|
351
|
+
},
|
|
352
|
+
body: body ? JSON.stringify(body) : void 0
|
|
353
|
+
});
|
|
354
|
+
if (!response.ok) {
|
|
355
|
+
const error = await response.json().catch(() => ({ error: "Request failed" }));
|
|
356
|
+
throw new Error(error.error || `HTTP ${response.status}: ${response.statusText}`);
|
|
357
|
+
}
|
|
358
|
+
return response.json();
|
|
359
|
+
}
|
|
360
|
+
get(path) {
|
|
361
|
+
return this.request("GET", path);
|
|
362
|
+
}
|
|
363
|
+
post(path, body) {
|
|
364
|
+
return this.request("POST", path, body);
|
|
365
|
+
}
|
|
366
|
+
patch(path, body) {
|
|
367
|
+
return this.request("PATCH", path, body);
|
|
368
|
+
}
|
|
369
|
+
delete(path) {
|
|
370
|
+
return this.request("DELETE", path);
|
|
371
|
+
}
|
|
372
|
+
};
|
|
373
|
+
var toolHandlers = {
|
|
374
|
+
// Organization
|
|
375
|
+
get_organization: (client) => client.get("/org"),
|
|
376
|
+
// Projects
|
|
377
|
+
list_projects: (client, args) => {
|
|
378
|
+
const params = new URLSearchParams();
|
|
379
|
+
if (args.limit) params.set("limit", String(args.limit));
|
|
380
|
+
if (args.offset) params.set("offset", String(args.offset));
|
|
381
|
+
return client.get(`/projects?${params}`);
|
|
382
|
+
},
|
|
383
|
+
get_project: (client, args) => client.get(`/projects/${args.project_id}`),
|
|
384
|
+
// Artifacts
|
|
385
|
+
list_artifacts: (client, args) => {
|
|
386
|
+
const params = new URLSearchParams();
|
|
387
|
+
if (args.project_id) params.set("project_id", String(args.project_id));
|
|
388
|
+
if (args.type) params.set("type", String(args.type));
|
|
389
|
+
if (args.status) params.set("status", String(args.status));
|
|
390
|
+
if (args.limit) params.set("limit", String(args.limit));
|
|
391
|
+
return client.get(`/artifacts?${params}`);
|
|
392
|
+
},
|
|
393
|
+
get_artifact: (client, args) => client.get(`/artifacts/${args.artifact_id}`),
|
|
394
|
+
create_artifact: (client, args) => client.post("/artifacts", args),
|
|
395
|
+
update_artifact: (client, args) => {
|
|
396
|
+
const { artifact_id, ...body } = args;
|
|
397
|
+
return client.patch(`/artifacts/${artifact_id}`, body);
|
|
398
|
+
},
|
|
399
|
+
// Sections
|
|
400
|
+
list_sections: (client, args) => client.get(`/artifacts/${args.artifact_id}/sections`),
|
|
401
|
+
get_section: (client, args) => client.get(`/artifacts/${args.artifact_id}/sections/${args.section_id}`),
|
|
402
|
+
create_section: (client, args) => {
|
|
403
|
+
const { artifact_id, ...body } = args;
|
|
404
|
+
return client.post(`/artifacts/${artifact_id}/sections`, body);
|
|
405
|
+
},
|
|
406
|
+
update_section: (client, args) => {
|
|
407
|
+
const { artifact_id, section_id, ...body } = args;
|
|
408
|
+
return client.patch(`/artifacts/${artifact_id}/sections/${section_id}`, body);
|
|
409
|
+
},
|
|
410
|
+
delete_section: (client, args) => client.delete(`/artifacts/${args.artifact_id}/sections/${args.section_id}`),
|
|
411
|
+
// Tasks
|
|
412
|
+
list_tasks: (client, args) => {
|
|
413
|
+
const params = new URLSearchParams();
|
|
414
|
+
if (args.artifact_id) params.set("artifact_id", String(args.artifact_id));
|
|
415
|
+
if (args.status) params.set("status", String(args.status));
|
|
416
|
+
if (args.assignee) params.set("assignee", String(args.assignee));
|
|
417
|
+
return client.get(`/tasks?${params}`);
|
|
418
|
+
},
|
|
419
|
+
claim_task: (client, args) => client.post(`/tasks/${args.task_id}/claim`),
|
|
420
|
+
complete_task: (client, args) => {
|
|
421
|
+
const { task_id, ...body } = args;
|
|
422
|
+
return client.post(`/tasks/${task_id}/complete`, body);
|
|
423
|
+
},
|
|
424
|
+
block_task: (client, args) => {
|
|
425
|
+
const { task_id, ...body } = args;
|
|
426
|
+
return client.post(`/tasks/${task_id}/block`, body);
|
|
427
|
+
},
|
|
428
|
+
// Agents
|
|
429
|
+
list_agents: (client, args) => {
|
|
430
|
+
const params = new URLSearchParams();
|
|
431
|
+
if (args.status) params.set("status", String(args.status));
|
|
432
|
+
return client.get(`/agents?${params}`);
|
|
433
|
+
},
|
|
434
|
+
get_agent: (client, args) => client.get(`/agents/${args.agent_id}`),
|
|
435
|
+
create_agent: (client, args) => client.post("/agents", args),
|
|
436
|
+
update_agent: (client, args) => {
|
|
437
|
+
const { agent_id, ...body } = args;
|
|
438
|
+
return client.patch(`/agents/${agent_id}`, body);
|
|
439
|
+
},
|
|
440
|
+
// Blockers
|
|
441
|
+
list_blockers: (client, args) => {
|
|
442
|
+
const params = new URLSearchParams();
|
|
443
|
+
if (args.artifact_id) params.set("artifact_id", String(args.artifact_id));
|
|
444
|
+
if (args.status) params.set("status", String(args.status));
|
|
445
|
+
return client.get(`/blockers?${params}`);
|
|
446
|
+
},
|
|
447
|
+
create_blocker: (client, args) => {
|
|
448
|
+
const { artifact_id, ...body } = args;
|
|
449
|
+
return client.post(`/artifacts/${artifact_id}/blockers`, body);
|
|
450
|
+
},
|
|
451
|
+
resolve_blocker: (client, args) => {
|
|
452
|
+
const { blocker_id, ...body } = args;
|
|
453
|
+
return client.post(`/blockers/${blocker_id}/resolve`, body);
|
|
454
|
+
},
|
|
455
|
+
// Search
|
|
456
|
+
search_artifacts: (client, args) => {
|
|
457
|
+
const params = new URLSearchParams();
|
|
458
|
+
params.set("q", String(args.query));
|
|
459
|
+
if (args.type) params.set("type", String(args.type));
|
|
460
|
+
if (args.limit) params.set("limit", String(args.limit));
|
|
461
|
+
return client.get(`/search?${params}`);
|
|
462
|
+
},
|
|
463
|
+
// Context
|
|
464
|
+
get_task_context: (client, args) => client.get(`/tasks/${args.task_id}/context`)
|
|
465
|
+
};
|
|
466
|
+
var ArtyfactsMcpServer = class {
|
|
467
|
+
server;
|
|
468
|
+
client;
|
|
469
|
+
config;
|
|
470
|
+
constructor(config) {
|
|
471
|
+
this.config = config;
|
|
472
|
+
this.client = new ArtyfactsApiClient(
|
|
473
|
+
config.baseUrl || "https://artyfacts.dev/api/v1",
|
|
474
|
+
config.apiKey
|
|
475
|
+
);
|
|
476
|
+
this.server = new Server(
|
|
477
|
+
{
|
|
478
|
+
name: config.name || "artyfacts-mcp",
|
|
479
|
+
version: config.version || "1.0.0"
|
|
480
|
+
},
|
|
481
|
+
{
|
|
482
|
+
capabilities: {
|
|
483
|
+
tools: {}
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
);
|
|
487
|
+
this.setupHandlers();
|
|
488
|
+
}
|
|
489
|
+
setupHandlers() {
|
|
490
|
+
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
491
|
+
return { tools: ARTYFACTS_TOOLS };
|
|
492
|
+
});
|
|
493
|
+
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
494
|
+
const { name, arguments: args } = request.params;
|
|
495
|
+
const handler = toolHandlers[name];
|
|
496
|
+
if (!handler) {
|
|
497
|
+
return {
|
|
498
|
+
content: [{ type: "text", text: `Unknown tool: ${name}` }],
|
|
499
|
+
isError: true
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
try {
|
|
503
|
+
const result = await handler(this.client, args || {});
|
|
504
|
+
return {
|
|
505
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
506
|
+
};
|
|
507
|
+
} catch (error) {
|
|
508
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
509
|
+
return {
|
|
510
|
+
content: [{ type: "text", text: `Error: ${message}` }],
|
|
511
|
+
isError: true
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
async start() {
|
|
517
|
+
const transport = new StdioServerTransport();
|
|
518
|
+
await this.server.connect(transport);
|
|
519
|
+
console.error(`Artyfacts MCP server running (${ARTYFACTS_TOOLS.length} tools)`);
|
|
520
|
+
}
|
|
521
|
+
getServer() {
|
|
522
|
+
return this.server;
|
|
523
|
+
}
|
|
524
|
+
};
|
|
525
|
+
function createMcpServer(config) {
|
|
526
|
+
return new ArtyfactsMcpServer(config);
|
|
527
|
+
}
|
|
528
|
+
async function startServer(server) {
|
|
529
|
+
await server.start();
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
export {
|
|
533
|
+
ArtyfactsMcpServer,
|
|
534
|
+
createMcpServer,
|
|
535
|
+
startServer
|
|
536
|
+
};
|
|
@@ -0,0 +1,556 @@
|
|
|
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
|
+
// Agent tools
|
|
217
|
+
{
|
|
218
|
+
name: "list_agents",
|
|
219
|
+
description: "List all agents in the organization",
|
|
220
|
+
inputSchema: {
|
|
221
|
+
type: "object",
|
|
222
|
+
properties: {
|
|
223
|
+
status: { type: "string", description: "Filter by status: active, inactive" }
|
|
224
|
+
},
|
|
225
|
+
required: []
|
|
226
|
+
}
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
name: "get_agent",
|
|
230
|
+
description: "Get details about an agent",
|
|
231
|
+
inputSchema: {
|
|
232
|
+
type: "object",
|
|
233
|
+
properties: {
|
|
234
|
+
agent_id: { type: "string", description: "Agent ID" }
|
|
235
|
+
},
|
|
236
|
+
required: ["agent_id"]
|
|
237
|
+
}
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
name: "create_agent",
|
|
241
|
+
description: "Register a new agent",
|
|
242
|
+
inputSchema: {
|
|
243
|
+
type: "object",
|
|
244
|
+
properties: {
|
|
245
|
+
agentId: { type: "string", description: 'Unique agent ID (e.g., "engineering-agent", "qa-agent")' },
|
|
246
|
+
name: { type: "string", description: "Agent display name" },
|
|
247
|
+
type: { type: "string", description: "Type: pm, engineering, qa, research, content, design" },
|
|
248
|
+
description: { type: "string", description: "What this agent does" },
|
|
249
|
+
capabilities: { type: "array", items: { type: "string" }, description: "Agent capabilities" },
|
|
250
|
+
config: { type: "object", description: "Agent configuration" }
|
|
251
|
+
},
|
|
252
|
+
required: ["agentId", "name", "type"]
|
|
253
|
+
}
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
name: "update_agent",
|
|
257
|
+
description: "Update an agent",
|
|
258
|
+
inputSchema: {
|
|
259
|
+
type: "object",
|
|
260
|
+
properties: {
|
|
261
|
+
agent_id: { type: "string", description: "Agent ID" },
|
|
262
|
+
name: { type: "string", description: "New name" },
|
|
263
|
+
status: { type: "string", description: "New status" },
|
|
264
|
+
config: { type: "object", description: "Updated config" }
|
|
265
|
+
},
|
|
266
|
+
required: ["agent_id"]
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
// Blocker tools
|
|
270
|
+
{
|
|
271
|
+
name: "list_blockers",
|
|
272
|
+
description: "List blockers (decisions, dependencies needing resolution)",
|
|
273
|
+
inputSchema: {
|
|
274
|
+
type: "object",
|
|
275
|
+
properties: {
|
|
276
|
+
artifact_id: { type: "string", description: "Filter by artifact" },
|
|
277
|
+
status: { type: "string", description: "Filter by status: open, resolved" }
|
|
278
|
+
},
|
|
279
|
+
required: []
|
|
280
|
+
}
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
name: "create_blocker",
|
|
284
|
+
description: "Create a blocker (decision request, dependency, etc.)",
|
|
285
|
+
inputSchema: {
|
|
286
|
+
type: "object",
|
|
287
|
+
properties: {
|
|
288
|
+
artifact_id: { type: "string", description: "Artifact ID" },
|
|
289
|
+
kind: { type: "string", description: "Kind: decision, dependency, resource, external" },
|
|
290
|
+
title: { type: "string", description: "Blocker title" },
|
|
291
|
+
description: { type: "string", description: "Details" },
|
|
292
|
+
options: { type: "array", description: "Options for decisions" },
|
|
293
|
+
blocked_tasks: { type: "array", items: { type: "string" }, description: "Task IDs blocked by this" }
|
|
294
|
+
},
|
|
295
|
+
required: ["artifact_id", "kind", "title"]
|
|
296
|
+
}
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
name: "resolve_blocker",
|
|
300
|
+
description: "Resolve a blocker",
|
|
301
|
+
inputSchema: {
|
|
302
|
+
type: "object",
|
|
303
|
+
properties: {
|
|
304
|
+
blocker_id: { type: "string", description: "Blocker ID" },
|
|
305
|
+
resolution: { type: "string", description: "How it was resolved" },
|
|
306
|
+
selected_option: { type: "string", description: "Selected option (for decisions)" }
|
|
307
|
+
},
|
|
308
|
+
required: ["blocker_id", "resolution"]
|
|
309
|
+
}
|
|
310
|
+
},
|
|
311
|
+
// Search tools
|
|
312
|
+
{
|
|
313
|
+
name: "search_artifacts",
|
|
314
|
+
description: "Search artifacts by text query",
|
|
315
|
+
inputSchema: {
|
|
316
|
+
type: "object",
|
|
317
|
+
properties: {
|
|
318
|
+
query: { type: "string", description: "Search query" },
|
|
319
|
+
type: { type: "string", description: "Filter by type" },
|
|
320
|
+
limit: { type: "number", description: "Max results" }
|
|
321
|
+
},
|
|
322
|
+
required: ["query"]
|
|
323
|
+
}
|
|
324
|
+
},
|
|
325
|
+
// Context tools
|
|
326
|
+
{
|
|
327
|
+
name: "get_task_context",
|
|
328
|
+
description: "Get full context for a task (org, project, artifact, related sections)",
|
|
329
|
+
inputSchema: {
|
|
330
|
+
type: "object",
|
|
331
|
+
properties: {
|
|
332
|
+
task_id: { type: "string", description: "Task ID" }
|
|
333
|
+
},
|
|
334
|
+
required: ["task_id"]
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
];
|
|
338
|
+
var ArtyfactsApiClient = class {
|
|
339
|
+
constructor(baseUrl, apiKey) {
|
|
340
|
+
this.baseUrl = baseUrl;
|
|
341
|
+
this.apiKey = apiKey;
|
|
342
|
+
}
|
|
343
|
+
async request(method, path, body) {
|
|
344
|
+
const url = `${this.baseUrl}${path}`;
|
|
345
|
+
const response = await fetch(url, {
|
|
346
|
+
method,
|
|
347
|
+
headers: {
|
|
348
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
349
|
+
"Content-Type": "application/json"
|
|
350
|
+
},
|
|
351
|
+
body: body ? JSON.stringify(body) : void 0
|
|
352
|
+
});
|
|
353
|
+
if (!response.ok) {
|
|
354
|
+
const error = await response.json().catch(() => ({ error: "Request failed" }));
|
|
355
|
+
throw new Error(error.error || `HTTP ${response.status}: ${response.statusText}`);
|
|
356
|
+
}
|
|
357
|
+
return response.json();
|
|
358
|
+
}
|
|
359
|
+
get(path) {
|
|
360
|
+
return this.request("GET", path);
|
|
361
|
+
}
|
|
362
|
+
post(path, body) {
|
|
363
|
+
return this.request("POST", path, body);
|
|
364
|
+
}
|
|
365
|
+
patch(path, body) {
|
|
366
|
+
return this.request("PATCH", path, body);
|
|
367
|
+
}
|
|
368
|
+
delete(path) {
|
|
369
|
+
return this.request("DELETE", path);
|
|
370
|
+
}
|
|
371
|
+
};
|
|
372
|
+
var toolHandlers = {
|
|
373
|
+
// Organization
|
|
374
|
+
get_organization: (client) => client.get("/org"),
|
|
375
|
+
// Projects
|
|
376
|
+
list_projects: (client, args) => {
|
|
377
|
+
const params = new URLSearchParams();
|
|
378
|
+
if (args.limit) params.set("limit", String(args.limit));
|
|
379
|
+
if (args.offset) params.set("offset", String(args.offset));
|
|
380
|
+
return client.get(`/projects?${params}`);
|
|
381
|
+
},
|
|
382
|
+
get_project: (client, args) => client.get(`/projects/${args.project_id}`),
|
|
383
|
+
// Artifacts
|
|
384
|
+
list_artifacts: (client, args) => {
|
|
385
|
+
const params = new URLSearchParams();
|
|
386
|
+
if (args.project_id) params.set("project_id", String(args.project_id));
|
|
387
|
+
if (args.type) params.set("type", String(args.type));
|
|
388
|
+
if (args.status) params.set("status", String(args.status));
|
|
389
|
+
if (args.limit) params.set("limit", String(args.limit));
|
|
390
|
+
return client.get(`/artifacts?${params}`);
|
|
391
|
+
},
|
|
392
|
+
get_artifact: (client, args) => client.get(`/artifacts/${args.artifact_id}`),
|
|
393
|
+
create_artifact: (client, args) => {
|
|
394
|
+
const envelope = {
|
|
395
|
+
aah_version: "0.3",
|
|
396
|
+
artifact: {
|
|
397
|
+
id: args.id || `artifact-${Date.now()}`,
|
|
398
|
+
title: args.title,
|
|
399
|
+
type: args.type || "document/sectioned",
|
|
400
|
+
artifact_type: args.artifact_type || args.type || "doc",
|
|
401
|
+
parent_id: args.parent_id,
|
|
402
|
+
tags: args.tags
|
|
403
|
+
},
|
|
404
|
+
content: args.content ? {
|
|
405
|
+
media_type: "text/markdown",
|
|
406
|
+
body: args.content
|
|
407
|
+
} : void 0,
|
|
408
|
+
source: {
|
|
409
|
+
agent_id: "mcp-agent"
|
|
410
|
+
}
|
|
411
|
+
};
|
|
412
|
+
return client.post("/artifacts", envelope);
|
|
413
|
+
},
|
|
414
|
+
update_artifact: (client, args) => {
|
|
415
|
+
const { artifact_id, ...body } = args;
|
|
416
|
+
return client.patch(`/artifacts/${artifact_id}`, body);
|
|
417
|
+
},
|
|
418
|
+
// Sections
|
|
419
|
+
list_sections: (client, args) => client.get(`/artifacts/${args.artifact_id}/sections`),
|
|
420
|
+
get_section: (client, args) => client.get(`/artifacts/${args.artifact_id}/sections/${args.section_id}`),
|
|
421
|
+
create_section: (client, args) => {
|
|
422
|
+
const { artifact_id, section_id, ...rest } = args;
|
|
423
|
+
const body = { id: section_id, ...rest };
|
|
424
|
+
return client.post(`/artifacts/${artifact_id}/sections`, body);
|
|
425
|
+
},
|
|
426
|
+
update_section: (client, args) => {
|
|
427
|
+
const { artifact_id, section_id, ...body } = args;
|
|
428
|
+
return client.patch(`/artifacts/${artifact_id}/sections/${section_id}`, body);
|
|
429
|
+
},
|
|
430
|
+
delete_section: (client, args) => client.delete(`/artifacts/${args.artifact_id}/sections/${args.section_id}`),
|
|
431
|
+
// Tasks
|
|
432
|
+
list_tasks: (client, args) => {
|
|
433
|
+
const params = new URLSearchParams();
|
|
434
|
+
if (args.artifact_id) params.set("artifact_id", String(args.artifact_id));
|
|
435
|
+
if (args.status) params.set("status", String(args.status));
|
|
436
|
+
if (args.assignee) params.set("assignee", String(args.assignee));
|
|
437
|
+
return client.get(`/tasks?${params}`);
|
|
438
|
+
},
|
|
439
|
+
claim_task: (client, args) => client.post(`/tasks/${args.task_id}/claim`),
|
|
440
|
+
complete_task: (client, args) => {
|
|
441
|
+
const { task_id, ...body } = args;
|
|
442
|
+
return client.post(`/tasks/${task_id}/complete`, body);
|
|
443
|
+
},
|
|
444
|
+
block_task: (client, args) => {
|
|
445
|
+
const { task_id, ...body } = args;
|
|
446
|
+
return client.post(`/tasks/${task_id}/block`, body);
|
|
447
|
+
},
|
|
448
|
+
// Agents
|
|
449
|
+
list_agents: (client, args) => {
|
|
450
|
+
const params = new URLSearchParams();
|
|
451
|
+
if (args.status) params.set("status", String(args.status));
|
|
452
|
+
return client.get(`/agents?${params}`);
|
|
453
|
+
},
|
|
454
|
+
get_agent: (client, args) => client.get(`/agents/${args.agent_id}`),
|
|
455
|
+
create_agent: (client, args) => client.post("/agents", args),
|
|
456
|
+
update_agent: (client, args) => {
|
|
457
|
+
const { agent_id, ...body } = args;
|
|
458
|
+
return client.patch(`/agents/${agent_id}`, body);
|
|
459
|
+
},
|
|
460
|
+
// Blockers
|
|
461
|
+
list_blockers: (client, args) => {
|
|
462
|
+
const params = new URLSearchParams();
|
|
463
|
+
if (args.artifact_id) params.set("artifact_id", String(args.artifact_id));
|
|
464
|
+
if (args.status) params.set("status", String(args.status));
|
|
465
|
+
return client.get(`/blockers?${params}`);
|
|
466
|
+
},
|
|
467
|
+
create_blocker: (client, args) => {
|
|
468
|
+
const { artifact_id, ...body } = args;
|
|
469
|
+
return client.post(`/artifacts/${artifact_id}/blockers`, body);
|
|
470
|
+
},
|
|
471
|
+
resolve_blocker: (client, args) => {
|
|
472
|
+
const { blocker_id, ...body } = args;
|
|
473
|
+
return client.post(`/blockers/${blocker_id}/resolve`, body);
|
|
474
|
+
},
|
|
475
|
+
// Search
|
|
476
|
+
search_artifacts: (client, args) => {
|
|
477
|
+
const params = new URLSearchParams();
|
|
478
|
+
params.set("q", String(args.query));
|
|
479
|
+
if (args.type) params.set("type", String(args.type));
|
|
480
|
+
if (args.limit) params.set("limit", String(args.limit));
|
|
481
|
+
return client.get(`/search?${params}`);
|
|
482
|
+
},
|
|
483
|
+
// Context
|
|
484
|
+
get_task_context: (client, args) => client.get(`/tasks/${args.task_id}/context`)
|
|
485
|
+
};
|
|
486
|
+
var ArtyfactsMcpServer = class {
|
|
487
|
+
server;
|
|
488
|
+
client;
|
|
489
|
+
config;
|
|
490
|
+
constructor(config) {
|
|
491
|
+
this.config = config;
|
|
492
|
+
this.client = new ArtyfactsApiClient(
|
|
493
|
+
config.baseUrl || "https://artyfacts.dev/api/v1",
|
|
494
|
+
config.apiKey
|
|
495
|
+
);
|
|
496
|
+
this.server = new Server(
|
|
497
|
+
{
|
|
498
|
+
name: config.name || "artyfacts-mcp",
|
|
499
|
+
version: config.version || "1.0.0"
|
|
500
|
+
},
|
|
501
|
+
{
|
|
502
|
+
capabilities: {
|
|
503
|
+
tools: {}
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
);
|
|
507
|
+
this.setupHandlers();
|
|
508
|
+
}
|
|
509
|
+
setupHandlers() {
|
|
510
|
+
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
511
|
+
return { tools: ARTYFACTS_TOOLS };
|
|
512
|
+
});
|
|
513
|
+
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
514
|
+
const { name, arguments: args } = request.params;
|
|
515
|
+
const handler = toolHandlers[name];
|
|
516
|
+
if (!handler) {
|
|
517
|
+
return {
|
|
518
|
+
content: [{ type: "text", text: `Unknown tool: ${name}` }],
|
|
519
|
+
isError: true
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
try {
|
|
523
|
+
const result = await handler(this.client, args || {});
|
|
524
|
+
return {
|
|
525
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
526
|
+
};
|
|
527
|
+
} catch (error) {
|
|
528
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
529
|
+
return {
|
|
530
|
+
content: [{ type: "text", text: `Error: ${message}` }],
|
|
531
|
+
isError: true
|
|
532
|
+
};
|
|
533
|
+
}
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
async start() {
|
|
537
|
+
const transport = new StdioServerTransport();
|
|
538
|
+
await this.server.connect(transport);
|
|
539
|
+
console.error(`Artyfacts MCP server running (${ARTYFACTS_TOOLS.length} tools)`);
|
|
540
|
+
}
|
|
541
|
+
getServer() {
|
|
542
|
+
return this.server;
|
|
543
|
+
}
|
|
544
|
+
};
|
|
545
|
+
function createMcpServer(config) {
|
|
546
|
+
return new ArtyfactsMcpServer(config);
|
|
547
|
+
}
|
|
548
|
+
async function startServer(server) {
|
|
549
|
+
await server.start();
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
export {
|
|
553
|
+
ArtyfactsMcpServer,
|
|
554
|
+
createMcpServer,
|
|
555
|
+
startServer
|
|
556
|
+
};
|
package/dist/index.cjs
CHANGED
|
@@ -93,18 +93,17 @@ var ARTYFACTS_TOOLS = [
|
|
|
93
93
|
},
|
|
94
94
|
{
|
|
95
95
|
name: "create_artifact",
|
|
96
|
-
description: "Create a new artifact",
|
|
96
|
+
description: "Create a new artifact (document, goal, spec, etc.)",
|
|
97
97
|
inputSchema: {
|
|
98
98
|
type: "object",
|
|
99
99
|
properties: {
|
|
100
100
|
title: { type: "string", description: "Artifact title" },
|
|
101
|
-
type: { type: "string", description: "
|
|
101
|
+
type: { type: "string", description: "Artifact type: goal, spec, research, report, experiment, decision, doc" },
|
|
102
102
|
content: { type: "string", description: "Markdown content" },
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
tags: { type: "array", items: { type: "string" }, description: "Tags" }
|
|
103
|
+
parent_id: { type: "string", description: "Parent artifact ID for nested artifacts" },
|
|
104
|
+
tags: { type: "array", items: { type: "string" }, description: "Tags for categorization" }
|
|
106
105
|
},
|
|
107
|
-
required: ["title"]
|
|
106
|
+
required: ["title", "type"]
|
|
108
107
|
}
|
|
109
108
|
},
|
|
110
109
|
{
|
|
@@ -158,7 +157,7 @@ var ARTYFACTS_TOOLS = [
|
|
|
158
157
|
type: { type: "string", description: "Type: content, task, decision, blocker" },
|
|
159
158
|
position: { type: "number", description: "Order position" }
|
|
160
159
|
},
|
|
161
|
-
required: ["artifact_id", "section_id", "heading"]
|
|
160
|
+
required: ["artifact_id", "section_id", "heading", "content"]
|
|
162
161
|
}
|
|
163
162
|
},
|
|
164
163
|
{
|
|
@@ -268,13 +267,14 @@ var ARTYFACTS_TOOLS = [
|
|
|
268
267
|
inputSchema: {
|
|
269
268
|
type: "object",
|
|
270
269
|
properties: {
|
|
270
|
+
agentId: { type: "string", description: 'Unique agent ID (e.g., "engineering-agent", "qa-agent")' },
|
|
271
271
|
name: { type: "string", description: "Agent display name" },
|
|
272
272
|
type: { type: "string", description: "Type: pm, engineering, qa, research, content, design" },
|
|
273
273
|
description: { type: "string", description: "What this agent does" },
|
|
274
274
|
capabilities: { type: "array", items: { type: "string" }, description: "Agent capabilities" },
|
|
275
275
|
config: { type: "object", description: "Agent configuration" }
|
|
276
276
|
},
|
|
277
|
-
required: ["name", "type"]
|
|
277
|
+
required: ["agentId", "name", "type"]
|
|
278
278
|
}
|
|
279
279
|
},
|
|
280
280
|
{
|
|
@@ -415,7 +415,27 @@ var toolHandlers = {
|
|
|
415
415
|
return client.get(`/artifacts?${params}`);
|
|
416
416
|
},
|
|
417
417
|
get_artifact: (client, args) => client.get(`/artifacts/${args.artifact_id}`),
|
|
418
|
-
create_artifact: (client, args) =>
|
|
418
|
+
create_artifact: (client, args) => {
|
|
419
|
+
const envelope = {
|
|
420
|
+
aah_version: "0.3",
|
|
421
|
+
artifact: {
|
|
422
|
+
id: args.id || `artifact-${Date.now()}`,
|
|
423
|
+
title: args.title,
|
|
424
|
+
type: args.type || "document/sectioned",
|
|
425
|
+
artifact_type: args.artifact_type || args.type || "doc",
|
|
426
|
+
parent_id: args.parent_id,
|
|
427
|
+
tags: args.tags
|
|
428
|
+
},
|
|
429
|
+
content: args.content ? {
|
|
430
|
+
media_type: "text/markdown",
|
|
431
|
+
body: args.content
|
|
432
|
+
} : void 0,
|
|
433
|
+
source: {
|
|
434
|
+
agent_id: "mcp-agent"
|
|
435
|
+
}
|
|
436
|
+
};
|
|
437
|
+
return client.post("/artifacts", envelope);
|
|
438
|
+
},
|
|
419
439
|
update_artifact: (client, args) => {
|
|
420
440
|
const { artifact_id, ...body } = args;
|
|
421
441
|
return client.patch(`/artifacts/${artifact_id}`, body);
|
|
@@ -424,7 +444,8 @@ var toolHandlers = {
|
|
|
424
444
|
list_sections: (client, args) => client.get(`/artifacts/${args.artifact_id}/sections`),
|
|
425
445
|
get_section: (client, args) => client.get(`/artifacts/${args.artifact_id}/sections/${args.section_id}`),
|
|
426
446
|
create_section: (client, args) => {
|
|
427
|
-
const { artifact_id, ...
|
|
447
|
+
const { artifact_id, section_id, ...rest } = args;
|
|
448
|
+
const body = { id: section_id, ...rest };
|
|
428
449
|
return client.post(`/artifacts/${artifact_id}/sections`, body);
|
|
429
450
|
},
|
|
430
451
|
update_section: (client, args) => {
|
package/dist/index.js
CHANGED
package/dist/server.cjs
CHANGED
|
@@ -91,18 +91,17 @@ var ARTYFACTS_TOOLS = [
|
|
|
91
91
|
},
|
|
92
92
|
{
|
|
93
93
|
name: "create_artifact",
|
|
94
|
-
description: "Create a new artifact",
|
|
94
|
+
description: "Create a new artifact (document, goal, spec, etc.)",
|
|
95
95
|
inputSchema: {
|
|
96
96
|
type: "object",
|
|
97
97
|
properties: {
|
|
98
98
|
title: { type: "string", description: "Artifact title" },
|
|
99
|
-
type: { type: "string", description: "
|
|
99
|
+
type: { type: "string", description: "Artifact type: goal, spec, research, report, experiment, decision, doc" },
|
|
100
100
|
content: { type: "string", description: "Markdown content" },
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
tags: { type: "array", items: { type: "string" }, description: "Tags" }
|
|
101
|
+
parent_id: { type: "string", description: "Parent artifact ID for nested artifacts" },
|
|
102
|
+
tags: { type: "array", items: { type: "string" }, description: "Tags for categorization" }
|
|
104
103
|
},
|
|
105
|
-
required: ["title"]
|
|
104
|
+
required: ["title", "type"]
|
|
106
105
|
}
|
|
107
106
|
},
|
|
108
107
|
{
|
|
@@ -156,7 +155,7 @@ var ARTYFACTS_TOOLS = [
|
|
|
156
155
|
type: { type: "string", description: "Type: content, task, decision, blocker" },
|
|
157
156
|
position: { type: "number", description: "Order position" }
|
|
158
157
|
},
|
|
159
|
-
required: ["artifact_id", "section_id", "heading"]
|
|
158
|
+
required: ["artifact_id", "section_id", "heading", "content"]
|
|
160
159
|
}
|
|
161
160
|
},
|
|
162
161
|
{
|
|
@@ -266,13 +265,14 @@ var ARTYFACTS_TOOLS = [
|
|
|
266
265
|
inputSchema: {
|
|
267
266
|
type: "object",
|
|
268
267
|
properties: {
|
|
268
|
+
agentId: { type: "string", description: 'Unique agent ID (e.g., "engineering-agent", "qa-agent")' },
|
|
269
269
|
name: { type: "string", description: "Agent display name" },
|
|
270
270
|
type: { type: "string", description: "Type: pm, engineering, qa, research, content, design" },
|
|
271
271
|
description: { type: "string", description: "What this agent does" },
|
|
272
272
|
capabilities: { type: "array", items: { type: "string" }, description: "Agent capabilities" },
|
|
273
273
|
config: { type: "object", description: "Agent configuration" }
|
|
274
274
|
},
|
|
275
|
-
required: ["name", "type"]
|
|
275
|
+
required: ["agentId", "name", "type"]
|
|
276
276
|
}
|
|
277
277
|
},
|
|
278
278
|
{
|
|
@@ -413,7 +413,27 @@ var toolHandlers = {
|
|
|
413
413
|
return client.get(`/artifacts?${params}`);
|
|
414
414
|
},
|
|
415
415
|
get_artifact: (client, args) => client.get(`/artifacts/${args.artifact_id}`),
|
|
416
|
-
create_artifact: (client, args) =>
|
|
416
|
+
create_artifact: (client, args) => {
|
|
417
|
+
const envelope = {
|
|
418
|
+
aah_version: "0.3",
|
|
419
|
+
artifact: {
|
|
420
|
+
id: args.id || `artifact-${Date.now()}`,
|
|
421
|
+
title: args.title,
|
|
422
|
+
type: args.type || "document/sectioned",
|
|
423
|
+
artifact_type: args.artifact_type || args.type || "doc",
|
|
424
|
+
parent_id: args.parent_id,
|
|
425
|
+
tags: args.tags
|
|
426
|
+
},
|
|
427
|
+
content: args.content ? {
|
|
428
|
+
media_type: "text/markdown",
|
|
429
|
+
body: args.content
|
|
430
|
+
} : void 0,
|
|
431
|
+
source: {
|
|
432
|
+
agent_id: "mcp-agent"
|
|
433
|
+
}
|
|
434
|
+
};
|
|
435
|
+
return client.post("/artifacts", envelope);
|
|
436
|
+
},
|
|
417
437
|
update_artifact: (client, args) => {
|
|
418
438
|
const { artifact_id, ...body } = args;
|
|
419
439
|
return client.patch(`/artifacts/${artifact_id}`, body);
|
|
@@ -422,7 +442,8 @@ var toolHandlers = {
|
|
|
422
442
|
list_sections: (client, args) => client.get(`/artifacts/${args.artifact_id}/sections`),
|
|
423
443
|
get_section: (client, args) => client.get(`/artifacts/${args.artifact_id}/sections/${args.section_id}`),
|
|
424
444
|
create_section: (client, args) => {
|
|
425
|
-
const { artifact_id, ...
|
|
445
|
+
const { artifact_id, section_id, ...rest } = args;
|
|
446
|
+
const body = { id: section_id, ...rest };
|
|
426
447
|
return client.post(`/artifacts/${artifact_id}/sections`, body);
|
|
427
448
|
},
|
|
428
449
|
update_section: (client, args) => {
|
package/dist/server.js
CHANGED
package/package.json
CHANGED
package/src/server.ts
CHANGED
|
@@ -97,18 +97,17 @@ const ARTYFACTS_TOOLS: Tool[] = [
|
|
|
97
97
|
},
|
|
98
98
|
{
|
|
99
99
|
name: 'create_artifact',
|
|
100
|
-
description: 'Create a new artifact',
|
|
100
|
+
description: 'Create a new artifact (document, goal, spec, etc.)',
|
|
101
101
|
inputSchema: {
|
|
102
102
|
type: 'object',
|
|
103
103
|
properties: {
|
|
104
104
|
title: { type: 'string', description: 'Artifact title' },
|
|
105
|
-
type: { type: 'string', description: '
|
|
105
|
+
type: { type: 'string', description: 'Artifact type: goal, spec, research, report, experiment, decision, doc' },
|
|
106
106
|
content: { type: 'string', description: 'Markdown content' },
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
tags: { type: 'array', items: { type: 'string' }, description: 'Tags' },
|
|
107
|
+
parent_id: { type: 'string', description: 'Parent artifact ID for nested artifacts' },
|
|
108
|
+
tags: { type: 'array', items: { type: 'string' }, description: 'Tags for categorization' },
|
|
110
109
|
},
|
|
111
|
-
required: ['title'],
|
|
110
|
+
required: ['title', 'type'],
|
|
112
111
|
},
|
|
113
112
|
},
|
|
114
113
|
{
|
|
@@ -163,7 +162,7 @@ const ARTYFACTS_TOOLS: Tool[] = [
|
|
|
163
162
|
type: { type: 'string', description: 'Type: content, task, decision, blocker' },
|
|
164
163
|
position: { type: 'number', description: 'Order position' },
|
|
165
164
|
},
|
|
166
|
-
required: ['artifact_id', 'section_id', 'heading'],
|
|
165
|
+
required: ['artifact_id', 'section_id', 'heading', 'content'],
|
|
167
166
|
},
|
|
168
167
|
},
|
|
169
168
|
{
|
|
@@ -275,13 +274,14 @@ const ARTYFACTS_TOOLS: Tool[] = [
|
|
|
275
274
|
inputSchema: {
|
|
276
275
|
type: 'object',
|
|
277
276
|
properties: {
|
|
277
|
+
agentId: { type: 'string', description: 'Unique agent ID (e.g., "engineering-agent", "qa-agent")' },
|
|
278
278
|
name: { type: 'string', description: 'Agent display name' },
|
|
279
279
|
type: { type: 'string', description: 'Type: pm, engineering, qa, research, content, design' },
|
|
280
280
|
description: { type: 'string', description: 'What this agent does' },
|
|
281
281
|
capabilities: { type: 'array', items: { type: 'string' }, description: 'Agent capabilities' },
|
|
282
282
|
config: { type: 'object', description: 'Agent configuration' },
|
|
283
283
|
},
|
|
284
|
-
required: ['name', 'type'],
|
|
284
|
+
required: ['agentId', 'name', 'type'],
|
|
285
285
|
},
|
|
286
286
|
},
|
|
287
287
|
{
|
|
@@ -436,7 +436,28 @@ const toolHandlers: Record<string, ToolHandler> = {
|
|
|
436
436
|
return client.get(`/artifacts?${params}`);
|
|
437
437
|
},
|
|
438
438
|
get_artifact: (client, args) => client.get(`/artifacts/${args.artifact_id}`),
|
|
439
|
-
create_artifact: (client, args) =>
|
|
439
|
+
create_artifact: (client, args) => {
|
|
440
|
+
// API expects AAH envelope format
|
|
441
|
+
const envelope = {
|
|
442
|
+
aah_version: '0.3',
|
|
443
|
+
artifact: {
|
|
444
|
+
id: args.id || `artifact-${Date.now()}`,
|
|
445
|
+
title: args.title,
|
|
446
|
+
type: args.type || 'document/sectioned',
|
|
447
|
+
artifact_type: args.artifact_type || args.type || 'doc',
|
|
448
|
+
parent_id: args.parent_id,
|
|
449
|
+
tags: args.tags,
|
|
450
|
+
},
|
|
451
|
+
content: args.content ? {
|
|
452
|
+
media_type: 'text/markdown',
|
|
453
|
+
body: args.content,
|
|
454
|
+
} : undefined,
|
|
455
|
+
source: {
|
|
456
|
+
agent_id: 'mcp-agent',
|
|
457
|
+
},
|
|
458
|
+
};
|
|
459
|
+
return client.post('/artifacts', envelope);
|
|
460
|
+
},
|
|
440
461
|
update_artifact: (client, args) => {
|
|
441
462
|
const { artifact_id, ...body } = args;
|
|
442
463
|
return client.patch(`/artifacts/${artifact_id}`, body);
|
|
@@ -446,7 +467,9 @@ const toolHandlers: Record<string, ToolHandler> = {
|
|
|
446
467
|
list_sections: (client, args) => client.get(`/artifacts/${args.artifact_id}/sections`),
|
|
447
468
|
get_section: (client, args) => client.get(`/artifacts/${args.artifact_id}/sections/${args.section_id}`),
|
|
448
469
|
create_section: (client, args) => {
|
|
449
|
-
const { artifact_id, ...
|
|
470
|
+
const { artifact_id, section_id, ...rest } = args;
|
|
471
|
+
// API expects 'id' not 'section_id'
|
|
472
|
+
const body = { id: section_id, ...rest };
|
|
450
473
|
return client.post(`/artifacts/${artifact_id}/sections`, body);
|
|
451
474
|
},
|
|
452
475
|
update_section: (client, args) => {
|