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.
Files changed (2) hide show
  1. package/dist/index.js +357 -0
  2. 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
+ }