project-tree-mindev188-mcp 0.0.1
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/index.js +357 -0
- package/package.json +32 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
// src/index.ts
|
|
5
|
+
var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
6
|
+
|
|
7
|
+
// src/server.ts
|
|
8
|
+
var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
9
|
+
var import_zod = require("zod");
|
|
10
|
+
var import_db = require("@project-tree/db");
|
|
11
|
+
function createMcpServer() {
|
|
12
|
+
const server = new import_mcp.McpServer({
|
|
13
|
+
name: "project-tree",
|
|
14
|
+
version: "0.0.1"
|
|
15
|
+
});
|
|
16
|
+
server.tool(
|
|
17
|
+
"get_next_tasks",
|
|
18
|
+
"Get the next tasks to work on, filtered by project, assignee, or status",
|
|
19
|
+
{
|
|
20
|
+
project_id: import_zod.z.string().uuid().optional().describe("Filter by project ID"),
|
|
21
|
+
assignee: import_zod.z.string().optional().describe("Filter by assignee ID"),
|
|
22
|
+
status: import_zod.z.array(import_zod.z.enum(["backlog", "todo", "in_progress", "review", "done"])).optional().describe("Filter by status(es)"),
|
|
23
|
+
limit: import_zod.z.number().int().min(1).max(100).optional().describe("Max results (default 10)")
|
|
24
|
+
},
|
|
25
|
+
async ({ project_id, assignee, status, limit }) => {
|
|
26
|
+
const tasks = await (0, import_db.listTasks)({
|
|
27
|
+
projectId: project_id,
|
|
28
|
+
assigneeId: assignee,
|
|
29
|
+
status,
|
|
30
|
+
limit: limit ?? 10
|
|
31
|
+
});
|
|
32
|
+
return {
|
|
33
|
+
content: [
|
|
34
|
+
{
|
|
35
|
+
type: "text",
|
|
36
|
+
text: JSON.stringify(tasks, null, 2)
|
|
37
|
+
}
|
|
38
|
+
]
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
);
|
|
42
|
+
server.tool(
|
|
43
|
+
"update_progress",
|
|
44
|
+
"Update the progress of a task (status, notes, completion percentage)",
|
|
45
|
+
{
|
|
46
|
+
task_id: import_zod.z.string().uuid().describe("Task ID to update"),
|
|
47
|
+
status: import_zod.z.enum(["backlog", "todo", "in_progress", "review", "done"]).optional().describe("New status"),
|
|
48
|
+
note: import_zod.z.string().optional().describe("Progress note"),
|
|
49
|
+
progress_pct: import_zod.z.number().min(0).max(100).optional().describe("Completion percentage")
|
|
50
|
+
},
|
|
51
|
+
async ({ task_id, status, note, progress_pct }) => {
|
|
52
|
+
const updated = await (0, import_db.updateTask)(task_id, {
|
|
53
|
+
status,
|
|
54
|
+
note,
|
|
55
|
+
progressPct: progress_pct
|
|
56
|
+
});
|
|
57
|
+
if (!updated) {
|
|
58
|
+
return {
|
|
59
|
+
content: [{ type: "text", text: `Task ${task_id} not found` }],
|
|
60
|
+
isError: true
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
await (0, import_db.createActivity)({
|
|
64
|
+
projectId: updated.projectId,
|
|
65
|
+
action: "update_progress",
|
|
66
|
+
entityType: "task",
|
|
67
|
+
entityId: task_id,
|
|
68
|
+
metadata: { status, note, progress_pct },
|
|
69
|
+
source: "mcp"
|
|
70
|
+
});
|
|
71
|
+
return {
|
|
72
|
+
content: [
|
|
73
|
+
{
|
|
74
|
+
type: "text",
|
|
75
|
+
text: JSON.stringify(updated, null, 2)
|
|
76
|
+
}
|
|
77
|
+
]
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
);
|
|
81
|
+
server.tool(
|
|
82
|
+
"add_item",
|
|
83
|
+
"Add a new task, note, or document to a project",
|
|
84
|
+
{
|
|
85
|
+
type: import_zod.z.enum(["task", "note", "document"]).describe("Item type to create"),
|
|
86
|
+
project_id: import_zod.z.string().uuid().describe("Project ID"),
|
|
87
|
+
title: import_zod.z.string().describe("Item title"),
|
|
88
|
+
content: import_zod.z.string().optional().describe("Item content/description"),
|
|
89
|
+
priority: import_zod.z.number().int().min(1).max(5).optional().describe("Priority (tasks only, 1-5)"),
|
|
90
|
+
labels: import_zod.z.array(import_zod.z.string()).optional().describe("Labels (tasks only)"),
|
|
91
|
+
tags: import_zod.z.array(import_zod.z.string()).optional().describe("Tags (documents only)"),
|
|
92
|
+
doc_type: import_zod.z.enum(["note", "doc", "spec", "adr"]).optional().describe("Document type")
|
|
93
|
+
},
|
|
94
|
+
async ({ type, project_id, title, content, priority, labels, tags, doc_type }) => {
|
|
95
|
+
let result;
|
|
96
|
+
if (type === "task") {
|
|
97
|
+
result = await (0, import_db.createTask)({
|
|
98
|
+
projectId: project_id,
|
|
99
|
+
title,
|
|
100
|
+
description: content,
|
|
101
|
+
priority: priority ?? 3,
|
|
102
|
+
labels: labels ?? []
|
|
103
|
+
});
|
|
104
|
+
await (0, import_db.createActivity)({
|
|
105
|
+
projectId: project_id,
|
|
106
|
+
action: "create",
|
|
107
|
+
entityType: "task",
|
|
108
|
+
entityId: result.id,
|
|
109
|
+
metadata: { title, priority },
|
|
110
|
+
source: "mcp"
|
|
111
|
+
});
|
|
112
|
+
} else {
|
|
113
|
+
result = await (0, import_db.createDocument)({
|
|
114
|
+
projectId: project_id,
|
|
115
|
+
title,
|
|
116
|
+
content: content ?? "",
|
|
117
|
+
type: doc_type ?? (type === "note" ? "note" : "doc"),
|
|
118
|
+
tags: tags ?? []
|
|
119
|
+
});
|
|
120
|
+
await (0, import_db.createActivity)({
|
|
121
|
+
projectId: project_id,
|
|
122
|
+
action: "create",
|
|
123
|
+
entityType: "document",
|
|
124
|
+
entityId: result.id,
|
|
125
|
+
metadata: { title, type: doc_type ?? type },
|
|
126
|
+
source: "mcp"
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
return {
|
|
130
|
+
content: [
|
|
131
|
+
{
|
|
132
|
+
type: "text",
|
|
133
|
+
text: JSON.stringify(result, null, 2)
|
|
134
|
+
}
|
|
135
|
+
]
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
);
|
|
139
|
+
server.tool(
|
|
140
|
+
"get_project_overview",
|
|
141
|
+
"Get a comprehensive overview of a project including repos, task summary, and recent activity",
|
|
142
|
+
{
|
|
143
|
+
project_id: import_zod.z.string().uuid().describe("Project ID")
|
|
144
|
+
},
|
|
145
|
+
async ({ project_id }) => {
|
|
146
|
+
const project = await (0, import_db.getProject)(project_id);
|
|
147
|
+
if (!project) {
|
|
148
|
+
return {
|
|
149
|
+
content: [{ type: "text", text: `Project ${project_id} not found` }],
|
|
150
|
+
isError: true
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
const [repos, allTasks, activities] = await Promise.all([
|
|
154
|
+
(0, import_db.listRepositories)(project_id),
|
|
155
|
+
(0, import_db.listTasks)({ projectId: project_id, limit: 1e3 }),
|
|
156
|
+
(0, import_db.listActivities)(project_id, 10)
|
|
157
|
+
]);
|
|
158
|
+
const taskSummary = {
|
|
159
|
+
total: allTasks.length,
|
|
160
|
+
byStatus: {
|
|
161
|
+
backlog: allTasks.filter((t) => t.status === "backlog").length,
|
|
162
|
+
todo: allTasks.filter((t) => t.status === "todo").length,
|
|
163
|
+
in_progress: allTasks.filter((t) => t.status === "in_progress").length,
|
|
164
|
+
review: allTasks.filter((t) => t.status === "review").length,
|
|
165
|
+
done: allTasks.filter((t) => t.status === "done").length
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
const overview = {
|
|
169
|
+
project,
|
|
170
|
+
repositories: repos,
|
|
171
|
+
taskSummary,
|
|
172
|
+
recentActivity: activities
|
|
173
|
+
};
|
|
174
|
+
return {
|
|
175
|
+
content: [
|
|
176
|
+
{
|
|
177
|
+
type: "text",
|
|
178
|
+
text: JSON.stringify(overview, null, 2)
|
|
179
|
+
}
|
|
180
|
+
]
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
);
|
|
184
|
+
server.tool(
|
|
185
|
+
"search_docs",
|
|
186
|
+
"Search documents by content with optional filters",
|
|
187
|
+
{
|
|
188
|
+
query: import_zod.z.string().describe("Search query"),
|
|
189
|
+
project_id: import_zod.z.string().uuid().optional().describe("Filter by project"),
|
|
190
|
+
type: import_zod.z.enum(["note", "doc", "spec", "adr"]).optional().describe("Filter by document type"),
|
|
191
|
+
limit: import_zod.z.number().int().min(1).max(50).optional().describe("Max results")
|
|
192
|
+
},
|
|
193
|
+
async ({ query, project_id, type, limit }) => {
|
|
194
|
+
const results = await (0, import_db.searchDocuments)({
|
|
195
|
+
query,
|
|
196
|
+
projectId: project_id,
|
|
197
|
+
type,
|
|
198
|
+
limit
|
|
199
|
+
});
|
|
200
|
+
return {
|
|
201
|
+
content: [
|
|
202
|
+
{
|
|
203
|
+
type: "text",
|
|
204
|
+
text: JSON.stringify(results, null, 2)
|
|
205
|
+
}
|
|
206
|
+
]
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
);
|
|
210
|
+
server.tool(
|
|
211
|
+
"delete_task",
|
|
212
|
+
"Delete a task by ID",
|
|
213
|
+
{
|
|
214
|
+
task_id: import_zod.z.string().uuid().describe("Task ID to delete")
|
|
215
|
+
},
|
|
216
|
+
async ({ task_id }) => {
|
|
217
|
+
const existing = await (0, import_db.listTasks)({ limit: 1e3 });
|
|
218
|
+
const task = existing.find((t) => t.id === task_id);
|
|
219
|
+
if (!task) {
|
|
220
|
+
return {
|
|
221
|
+
content: [{ type: "text", text: `Task ${task_id} not found` }],
|
|
222
|
+
isError: true
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
await (0, import_db.deleteTask)(task_id);
|
|
226
|
+
await (0, import_db.createActivity)({
|
|
227
|
+
projectId: task.projectId,
|
|
228
|
+
action: "delete",
|
|
229
|
+
entityType: "task",
|
|
230
|
+
entityId: task_id,
|
|
231
|
+
metadata: { title: task.title },
|
|
232
|
+
source: "mcp"
|
|
233
|
+
});
|
|
234
|
+
return {
|
|
235
|
+
content: [{ type: "text", text: `Task ${task_id} deleted` }]
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
);
|
|
239
|
+
server.tool(
|
|
240
|
+
"update_document",
|
|
241
|
+
"Update a document's title, content, type, or tags",
|
|
242
|
+
{
|
|
243
|
+
doc_id: import_zod.z.string().uuid().describe("Document ID to update"),
|
|
244
|
+
title: import_zod.z.string().optional().describe("New title"),
|
|
245
|
+
content: import_zod.z.string().optional().describe("New content"),
|
|
246
|
+
type: import_zod.z.enum(["note", "doc", "spec", "adr"]).optional().describe("New document type"),
|
|
247
|
+
tags: import_zod.z.array(import_zod.z.string()).optional().describe("New tags (replaces existing)")
|
|
248
|
+
},
|
|
249
|
+
async ({ doc_id, title, content, type, tags }) => {
|
|
250
|
+
const updated = await (0, import_db.updateDocument)(doc_id, { title, content, type, tags });
|
|
251
|
+
if (!updated) {
|
|
252
|
+
return {
|
|
253
|
+
content: [{ type: "text", text: `Document ${doc_id} not found` }],
|
|
254
|
+
isError: true
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
await (0, import_db.createActivity)({
|
|
258
|
+
projectId: updated.projectId,
|
|
259
|
+
action: "update",
|
|
260
|
+
entityType: "document",
|
|
261
|
+
entityId: doc_id,
|
|
262
|
+
metadata: { title, type },
|
|
263
|
+
source: "mcp"
|
|
264
|
+
});
|
|
265
|
+
return {
|
|
266
|
+
content: [{ type: "text", text: JSON.stringify(updated, null, 2) }]
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
);
|
|
270
|
+
server.tool(
|
|
271
|
+
"delete_document",
|
|
272
|
+
"Delete a document by ID",
|
|
273
|
+
{
|
|
274
|
+
doc_id: import_zod.z.string().uuid().describe("Document ID to delete")
|
|
275
|
+
},
|
|
276
|
+
async ({ doc_id }) => {
|
|
277
|
+
const existing = await (0, import_db.getDocument)(doc_id);
|
|
278
|
+
if (!existing) {
|
|
279
|
+
return {
|
|
280
|
+
content: [{ type: "text", text: `Document ${doc_id} not found` }],
|
|
281
|
+
isError: true
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
await (0, import_db.deleteDocument)(doc_id);
|
|
285
|
+
await (0, import_db.createActivity)({
|
|
286
|
+
projectId: existing.projectId,
|
|
287
|
+
action: "delete",
|
|
288
|
+
entityType: "document",
|
|
289
|
+
entityId: doc_id,
|
|
290
|
+
metadata: { title: existing.title },
|
|
291
|
+
source: "mcp"
|
|
292
|
+
});
|
|
293
|
+
return {
|
|
294
|
+
content: [{ type: "text", text: `Document ${doc_id} deleted` }]
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
);
|
|
298
|
+
server.tool(
|
|
299
|
+
"list_projects",
|
|
300
|
+
"List all projects",
|
|
301
|
+
{},
|
|
302
|
+
async () => {
|
|
303
|
+
const projects = await (0, import_db.listProjects)();
|
|
304
|
+
return {
|
|
305
|
+
content: [{ type: "text", text: JSON.stringify(projects, null, 2) }]
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
);
|
|
309
|
+
server.tool(
|
|
310
|
+
"get_document",
|
|
311
|
+
"Get full content of a document by ID",
|
|
312
|
+
{
|
|
313
|
+
doc_id: import_zod.z.string().uuid().describe("Document ID")
|
|
314
|
+
},
|
|
315
|
+
async ({ doc_id }) => {
|
|
316
|
+
const doc = await (0, import_db.getDocument)(doc_id);
|
|
317
|
+
if (!doc) {
|
|
318
|
+
return {
|
|
319
|
+
content: [{ type: "text", text: `Document ${doc_id} not found` }],
|
|
320
|
+
isError: true
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
return {
|
|
324
|
+
content: [{ type: "text", text: JSON.stringify(doc, null, 2) }]
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
);
|
|
328
|
+
server.tool(
|
|
329
|
+
"list_documents",
|
|
330
|
+
"List documents with optional filters by project or type",
|
|
331
|
+
{
|
|
332
|
+
project_id: import_zod.z.string().uuid().optional().describe("Filter by project ID"),
|
|
333
|
+
type: import_zod.z.enum(["note", "doc", "spec", "adr"]).optional().describe("Filter by document type")
|
|
334
|
+
},
|
|
335
|
+
async ({ project_id, type }) => {
|
|
336
|
+
const docs = await (0, import_db.listDocuments)({ projectId: project_id, type });
|
|
337
|
+
return {
|
|
338
|
+
content: [{ type: "text", text: JSON.stringify(docs, null, 2) }]
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
);
|
|
342
|
+
return server;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// src/index.ts
|
|
346
|
+
var import_db2 = require("@project-tree/db");
|
|
347
|
+
async function main() {
|
|
348
|
+
(0, import_db2.runMigrations)();
|
|
349
|
+
const server = createMcpServer();
|
|
350
|
+
const transport = new import_stdio.StdioServerTransport();
|
|
351
|
+
await server.connect(transport);
|
|
352
|
+
console.error("ProjectTree MCP server running on stdio");
|
|
353
|
+
}
|
|
354
|
+
main().catch((err) => {
|
|
355
|
+
console.error("Fatal error:", err);
|
|
356
|
+
process.exit(1);
|
|
357
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "project-tree-mindev188-mcp",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"bin": {
|
|
6
|
+
"project-tree-mcp": "dist/index.js"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"publishConfig": {
|
|
12
|
+
"access": "public"
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsup",
|
|
16
|
+
"dev": "tsx watch src/index.ts",
|
|
17
|
+
"start": "tsx src/index.ts",
|
|
18
|
+
"clean": "rm -rf dist"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
22
|
+
"@project-tree/db": "workspace:*",
|
|
23
|
+
"@project-tree/shared": "workspace:*",
|
|
24
|
+
"simple-git": "^3.27.0",
|
|
25
|
+
"zod": "^3.24.0"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"tsup": "^8.5.1",
|
|
29
|
+
"tsx": "^4.19.0",
|
|
30
|
+
"typescript": "^5.7.0"
|
|
31
|
+
}
|
|
32
|
+
}
|