@mtaap/mcp 0.2.3 → 0.2.5
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/README.md +20 -20
- package/dist/cli.js +215 -67
- package/dist/cli.js.map +1 -1
- package/dist/index.js +179 -31
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/cli.js
CHANGED
|
@@ -28,7 +28,7 @@ var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
|
28
28
|
var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
29
29
|
|
|
30
30
|
// src/version.ts
|
|
31
|
-
var VERSION = "0.2.
|
|
31
|
+
var VERSION = "0.2.5";
|
|
32
32
|
|
|
33
33
|
// src/index.ts
|
|
34
34
|
var import_zod3 = require("zod");
|
|
@@ -402,7 +402,8 @@ var ListProjectsInputSchema = import_zod2.z.object({
|
|
|
402
402
|
var ListTasksInputSchema = import_zod2.z.object({
|
|
403
403
|
projectId: import_zod2.z.string().optional(),
|
|
404
404
|
state: import_zod2.z.nativeEnum(TaskState).optional(),
|
|
405
|
-
assigneeId: import_zod2.z.string().optional()
|
|
405
|
+
assigneeId: import_zod2.z.string().optional(),
|
|
406
|
+
includeArchived: import_zod2.z.boolean().optional()
|
|
406
407
|
});
|
|
407
408
|
var cuidOrPrefixedId = import_zod2.z.string().regex(/^([a-z0-9]+|[a-z]+_[a-zA-Z0-9]+)$/);
|
|
408
409
|
var GetTaskInputSchema = import_zod2.z.object({
|
|
@@ -454,6 +455,14 @@ var ApproveTaskInputSchema = import_zod2.z.object({
|
|
|
454
455
|
taskId: cuidOrPrefixedId,
|
|
455
456
|
reviewComments: import_zod2.z.string().max(2e3).optional()
|
|
456
457
|
});
|
|
458
|
+
var ArchiveTaskInputSchema = import_zod2.z.object({
|
|
459
|
+
projectId: cuidOrPrefixedId,
|
|
460
|
+
taskId: cuidOrPrefixedId
|
|
461
|
+
});
|
|
462
|
+
var UnarchiveTaskInputSchema = import_zod2.z.object({
|
|
463
|
+
projectId: cuidOrPrefixedId,
|
|
464
|
+
taskId: cuidOrPrefixedId
|
|
465
|
+
});
|
|
457
466
|
var CreatePersonalProjectInputSchema = import_zod2.z.object({
|
|
458
467
|
name: import_zod2.z.string().min(1).max(100),
|
|
459
468
|
description: import_zod2.z.string().max(500).optional(),
|
|
@@ -495,7 +504,8 @@ var UpdateProjectInputSchema = import_zod2.z.object({
|
|
|
495
504
|
description: import_zod2.z.string().max(500).optional(),
|
|
496
505
|
repositoryUrl: import_zod2.z.string().url().optional(),
|
|
497
506
|
baseBranch: import_zod2.z.string().optional(),
|
|
498
|
-
tags: import_zod2.z.array(import_zod2.z.string()).optional()
|
|
507
|
+
tags: import_zod2.z.array(import_zod2.z.string()).optional(),
|
|
508
|
+
allowMemberArchive: import_zod2.z.boolean().optional()
|
|
499
509
|
});
|
|
500
510
|
var CreateEpicInputSchema = import_zod2.z.object({
|
|
501
511
|
projectId: cuidOrPrefixedId,
|
|
@@ -1021,6 +1031,7 @@ var MCPApiClient = class {
|
|
|
1021
1031
|
if (filters.projectId) params.set("projectId", filters.projectId);
|
|
1022
1032
|
if (filters.state) params.set("state", filters.state);
|
|
1023
1033
|
if (filters.assigneeId) params.set("assigneeId", filters.assigneeId);
|
|
1034
|
+
if (filters.includeArchived) params.set("includeArchived", "true");
|
|
1024
1035
|
const queryString = params.toString();
|
|
1025
1036
|
const path = queryString ? `/api/mcp/tasks?${queryString}` : "/api/mcp/tasks";
|
|
1026
1037
|
return this.request("GET", path);
|
|
@@ -1065,6 +1076,22 @@ var MCPApiClient = class {
|
|
|
1065
1076
|
deleteBranch
|
|
1066
1077
|
});
|
|
1067
1078
|
}
|
|
1079
|
+
/**
|
|
1080
|
+
* Archive a task (soft delete)
|
|
1081
|
+
*/
|
|
1082
|
+
async archiveTask(taskId, projectId) {
|
|
1083
|
+
return this.request("POST", `/api/mcp/tasks/${taskId}/archive`, {
|
|
1084
|
+
projectId
|
|
1085
|
+
});
|
|
1086
|
+
}
|
|
1087
|
+
/**
|
|
1088
|
+
* Unarchive a task (restore)
|
|
1089
|
+
*/
|
|
1090
|
+
async unarchiveTask(taskId, projectId) {
|
|
1091
|
+
return this.request("DELETE", `/api/mcp/tasks/${taskId}/archive`, {
|
|
1092
|
+
projectId
|
|
1093
|
+
});
|
|
1094
|
+
}
|
|
1068
1095
|
/**
|
|
1069
1096
|
* Report task error
|
|
1070
1097
|
*/
|
|
@@ -1109,18 +1136,18 @@ var MCPApiClient = class {
|
|
|
1109
1136
|
}
|
|
1110
1137
|
};
|
|
1111
1138
|
function createApiClientFromEnv() {
|
|
1112
|
-
const baseUrl = process.env.
|
|
1113
|
-
const apiKey = process.env.
|
|
1139
|
+
const baseUrl = process.env.COLLAB_BASE_URL;
|
|
1140
|
+
const apiKey = process.env.COLLAB_API_KEY;
|
|
1114
1141
|
if (!baseUrl) {
|
|
1115
|
-
throw new Error("
|
|
1142
|
+
throw new Error("COLLAB_BASE_URL environment variable is required");
|
|
1116
1143
|
}
|
|
1117
1144
|
if (!apiKey) {
|
|
1118
|
-
throw new Error("
|
|
1145
|
+
throw new Error("COLLAB_API_KEY environment variable is required");
|
|
1119
1146
|
}
|
|
1120
1147
|
return new MCPApiClient({
|
|
1121
1148
|
baseUrl,
|
|
1122
1149
|
apiKey,
|
|
1123
|
-
debug: process.env.
|
|
1150
|
+
debug: process.env.COLLAB_DEBUG === "true"
|
|
1124
1151
|
});
|
|
1125
1152
|
}
|
|
1126
1153
|
|
|
@@ -1150,11 +1177,62 @@ function assertApiKeyPermission(apiKey, required, toolName) {
|
|
|
1150
1177
|
}
|
|
1151
1178
|
|
|
1152
1179
|
// src/index.ts
|
|
1180
|
+
var COLLAB_SERVER_INSTRUCTIONS = `Collab - AI-assisted software development task management platform.
|
|
1181
|
+
|
|
1182
|
+
TOOL CATEGORIES:
|
|
1183
|
+
|
|
1184
|
+
1. Project Discovery (READ):
|
|
1185
|
+
- list_projects, get_project_context, get_version
|
|
1186
|
+
|
|
1187
|
+
2. Task Management (READ/WRITE):
|
|
1188
|
+
- list_tasks, get_task, create_task, archive_task, unarchive_task
|
|
1189
|
+
|
|
1190
|
+
3. Task Execution (WRITE):
|
|
1191
|
+
- assign_task, update_progress, add_note, complete_task, abandon_task, report_error
|
|
1192
|
+
|
|
1193
|
+
4. Code Review (WRITE):
|
|
1194
|
+
- request_changes, approve_task
|
|
1195
|
+
|
|
1196
|
+
5. Session Management (READ):
|
|
1197
|
+
- check_active_task
|
|
1198
|
+
|
|
1199
|
+
WORKFLOWS:
|
|
1200
|
+
|
|
1201
|
+
Standard Task Workflow:
|
|
1202
|
+
list_projects -> get_project_context -> list_tasks(state=READY) -> get_task -> assign_task -> [update_progress...] -> complete_task
|
|
1203
|
+
|
|
1204
|
+
Resume Workflow:
|
|
1205
|
+
check_active_task -> (if active) get_task -> update_progress -> complete_task
|
|
1206
|
+
|
|
1207
|
+
Review Workflow:
|
|
1208
|
+
list_tasks(state=REVIEW) -> get_task -> approve_task OR request_changes
|
|
1209
|
+
|
|
1210
|
+
Error Recovery:
|
|
1211
|
+
report_error -> abandon_task(deleteBranch=false) -> list_tasks -> assign_task (retry or pick different task)
|
|
1212
|
+
(abandon_task returns IN_PROGRESS tasks to READY state)
|
|
1213
|
+
|
|
1214
|
+
TASK STATE FLOW:
|
|
1215
|
+
BACKLOG -> READY -> IN_PROGRESS -> REVIEW -> DONE
|
|
1216
|
+
(request_changes: REVIEW -> IN_PROGRESS)
|
|
1217
|
+
(abandon_task: IN_PROGRESS -> READY)
|
|
1218
|
+
|
|
1219
|
+
CONSTRAINTS:
|
|
1220
|
+
- assign_task is atomic - fails if already claimed
|
|
1221
|
+
- Only READY tasks can be assigned
|
|
1222
|
+
- complete_task requires IN_PROGRESS state
|
|
1223
|
+
- request_changes/approve_task require REVIEW state
|
|
1224
|
+
- Always check_active_task before starting new work
|
|
1225
|
+
- Call update_progress frequently to checkpoint`;
|
|
1153
1226
|
async function createMCPServer() {
|
|
1154
|
-
const server = new import_mcp.McpServer(
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1227
|
+
const server = new import_mcp.McpServer(
|
|
1228
|
+
{
|
|
1229
|
+
name: "collab",
|
|
1230
|
+
version: VERSION
|
|
1231
|
+
},
|
|
1232
|
+
{
|
|
1233
|
+
instructions: COLLAB_SERVER_INSTRUCTIONS
|
|
1234
|
+
}
|
|
1235
|
+
);
|
|
1158
1236
|
const apiClient = createApiClientFromEnv();
|
|
1159
1237
|
let authContext;
|
|
1160
1238
|
try {
|
|
@@ -1171,7 +1249,7 @@ async function createMCPServer() {
|
|
|
1171
1249
|
server.registerTool(
|
|
1172
1250
|
"list_projects",
|
|
1173
1251
|
{
|
|
1174
|
-
description: "
|
|
1252
|
+
description: "Discover all accessible projects. Use first to find project IDs. Filter by TEAM, PERSONAL, or ALL workspaces.",
|
|
1175
1253
|
inputSchema: {
|
|
1176
1254
|
workspaceType: import_zod3.z.enum(["TEAM", "PERSONAL", "ALL"]).optional().describe("Filter by workspace type")
|
|
1177
1255
|
}
|
|
@@ -1201,11 +1279,12 @@ async function createMCPServer() {
|
|
|
1201
1279
|
server.registerTool(
|
|
1202
1280
|
"list_tasks",
|
|
1203
1281
|
{
|
|
1204
|
-
description: "
|
|
1282
|
+
description: "Query tasks with filters. Use state=READY for assignable tasks, state=REVIEW for pending reviews.",
|
|
1205
1283
|
inputSchema: {
|
|
1206
1284
|
projectId: import_zod3.z.string().optional().describe("Filter by project ID"),
|
|
1207
1285
|
state: import_zod3.z.nativeEnum(TaskState).optional().describe("Filter by task state"),
|
|
1208
|
-
assigneeId: import_zod3.z.string().optional().describe("Filter by assignee ID")
|
|
1286
|
+
assigneeId: import_zod3.z.string().optional().describe("Filter by assignee ID"),
|
|
1287
|
+
includeArchived: import_zod3.z.boolean().optional().describe("Include archived tasks (default: false)")
|
|
1209
1288
|
}
|
|
1210
1289
|
},
|
|
1211
1290
|
async (args) => {
|
|
@@ -1215,7 +1294,8 @@ async function createMCPServer() {
|
|
|
1215
1294
|
const tasks = await apiClient.listTasks({
|
|
1216
1295
|
projectId: validated.projectId,
|
|
1217
1296
|
state: validated.state,
|
|
1218
|
-
assigneeId: validated.assigneeId
|
|
1297
|
+
assigneeId: validated.assigneeId,
|
|
1298
|
+
includeArchived: validated.includeArchived
|
|
1219
1299
|
});
|
|
1220
1300
|
return {
|
|
1221
1301
|
content: [
|
|
@@ -1233,7 +1313,7 @@ async function createMCPServer() {
|
|
|
1233
1313
|
server.registerTool(
|
|
1234
1314
|
"get_task",
|
|
1235
1315
|
{
|
|
1236
|
-
description: "
|
|
1316
|
+
description: "Get complete task details with acceptance criteria and notes. Call before assign_task to understand requirements.",
|
|
1237
1317
|
inputSchema: {
|
|
1238
1318
|
taskId: import_zod3.z.string().describe("The task ID to retrieve")
|
|
1239
1319
|
}
|
|
@@ -1259,7 +1339,7 @@ async function createMCPServer() {
|
|
|
1259
1339
|
server.registerTool(
|
|
1260
1340
|
"assign_task",
|
|
1261
1341
|
{
|
|
1262
|
-
description: "
|
|
1342
|
+
description: "Atomically claim a task and create git branch. Race-safe - fails if already assigned. Task must be READY.",
|
|
1263
1343
|
inputSchema: {
|
|
1264
1344
|
projectId: import_zod3.z.string().describe("The project ID"),
|
|
1265
1345
|
taskId: import_zod3.z.string().describe("The task ID to assign"),
|
|
@@ -1295,7 +1375,7 @@ async function createMCPServer() {
|
|
|
1295
1375
|
server.registerTool(
|
|
1296
1376
|
"update_progress",
|
|
1297
1377
|
{
|
|
1298
|
-
description: "
|
|
1378
|
+
description: "Report progress and checkpoint work. Call frequently during execution. Marks acceptance criteria complete.",
|
|
1299
1379
|
inputSchema: {
|
|
1300
1380
|
taskId: import_zod3.z.string().describe("The task ID to update"),
|
|
1301
1381
|
statusMessage: import_zod3.z.string().optional().describe("Status message (max 1000 chars)"),
|
|
@@ -1332,7 +1412,7 @@ async function createMCPServer() {
|
|
|
1332
1412
|
server.registerTool(
|
|
1333
1413
|
"complete_task",
|
|
1334
1414
|
{
|
|
1335
|
-
description: "
|
|
1415
|
+
description: "Finish task and create pull request. Moves task to REVIEW. Requires IN_PROGRESS state.",
|
|
1336
1416
|
inputSchema: {
|
|
1337
1417
|
projectId: import_zod3.z.string().describe("The project ID"),
|
|
1338
1418
|
taskId: import_zod3.z.string().describe("The task ID to complete"),
|
|
@@ -1370,7 +1450,7 @@ async function createMCPServer() {
|
|
|
1370
1450
|
server.registerTool(
|
|
1371
1451
|
"check_active_task",
|
|
1372
1452
|
{
|
|
1373
|
-
description: "Check for resumable
|
|
1453
|
+
description: "Check for resumable work from previous session. Always call before starting new work."
|
|
1374
1454
|
},
|
|
1375
1455
|
async () => {
|
|
1376
1456
|
assertApiKeyPermission(
|
|
@@ -1392,7 +1472,7 @@ async function createMCPServer() {
|
|
|
1392
1472
|
server.registerTool(
|
|
1393
1473
|
"report_error",
|
|
1394
1474
|
{
|
|
1395
|
-
description: "Report unrecoverable
|
|
1475
|
+
description: "Report unrecoverable errors (BUILD_FAILURE, TEST_FAILURE, CONFLICT, AUTH_ERROR). Consider abandon_task after.",
|
|
1396
1476
|
inputSchema: {
|
|
1397
1477
|
taskId: import_zod3.z.string().describe("The task ID"),
|
|
1398
1478
|
errorType: import_zod3.z.nativeEnum(ErrorType).describe("Error type: BUILD_FAILURE, TEST_FAILURE, CONFLICT, AUTH_ERROR, OTHER"),
|
|
@@ -1430,7 +1510,7 @@ async function createMCPServer() {
|
|
|
1430
1510
|
server.registerTool(
|
|
1431
1511
|
"get_project_context",
|
|
1432
1512
|
{
|
|
1433
|
-
description: "
|
|
1513
|
+
description: "Load project README, tech stack, and coding conventions. Call after selecting project.",
|
|
1434
1514
|
inputSchema: {
|
|
1435
1515
|
projectId: import_zod3.z.string().describe("The project ID")
|
|
1436
1516
|
}
|
|
@@ -1460,7 +1540,7 @@ async function createMCPServer() {
|
|
|
1460
1540
|
server.registerTool(
|
|
1461
1541
|
"add_note",
|
|
1462
1542
|
{
|
|
1463
|
-
description: "
|
|
1543
|
+
description: "Document implementation decisions. Notes persist for future reference and handoff.",
|
|
1464
1544
|
inputSchema: {
|
|
1465
1545
|
taskId: import_zod3.z.string().describe("The task ID"),
|
|
1466
1546
|
content: import_zod3.z.string().describe("Note content (max 500 chars)")
|
|
@@ -1490,7 +1570,7 @@ async function createMCPServer() {
|
|
|
1490
1570
|
server.registerTool(
|
|
1491
1571
|
"abandon_task",
|
|
1492
1572
|
{
|
|
1493
|
-
description: "
|
|
1573
|
+
description: "Release task assignment and optionally clean up branch. Task returns to READY. Use after errors.",
|
|
1494
1574
|
inputSchema: {
|
|
1495
1575
|
projectId: import_zod3.z.string().describe("The project ID"),
|
|
1496
1576
|
taskId: import_zod3.z.string().describe("The task ID to abandon"),
|
|
@@ -1523,10 +1603,78 @@ async function createMCPServer() {
|
|
|
1523
1603
|
}
|
|
1524
1604
|
}
|
|
1525
1605
|
);
|
|
1606
|
+
server.registerTool(
|
|
1607
|
+
"archive_task",
|
|
1608
|
+
{
|
|
1609
|
+
description: "Soft-delete a task. Hidden but restorable via unarchive_task.",
|
|
1610
|
+
inputSchema: {
|
|
1611
|
+
projectId: import_zod3.z.string().describe("The project ID"),
|
|
1612
|
+
taskId: import_zod3.z.string().describe("The task ID to archive")
|
|
1613
|
+
}
|
|
1614
|
+
},
|
|
1615
|
+
async (args) => {
|
|
1616
|
+
assertApiKeyPermission(
|
|
1617
|
+
mockApiKey,
|
|
1618
|
+
ApiKeyPermission.WRITE,
|
|
1619
|
+
"archive_task"
|
|
1620
|
+
);
|
|
1621
|
+
const validated = ArchiveTaskInputSchema.parse(args);
|
|
1622
|
+
try {
|
|
1623
|
+
const result = await apiClient.archiveTask(
|
|
1624
|
+
validated.taskId,
|
|
1625
|
+
validated.projectId
|
|
1626
|
+
);
|
|
1627
|
+
return {
|
|
1628
|
+
content: [
|
|
1629
|
+
{
|
|
1630
|
+
type: "text",
|
|
1631
|
+
text: JSON.stringify(result, null, 2)
|
|
1632
|
+
}
|
|
1633
|
+
]
|
|
1634
|
+
};
|
|
1635
|
+
} catch (error) {
|
|
1636
|
+
return handleApiError(error);
|
|
1637
|
+
}
|
|
1638
|
+
}
|
|
1639
|
+
);
|
|
1640
|
+
server.registerTool(
|
|
1641
|
+
"unarchive_task",
|
|
1642
|
+
{
|
|
1643
|
+
description: "Restore previously archived task to original state.",
|
|
1644
|
+
inputSchema: {
|
|
1645
|
+
projectId: import_zod3.z.string().describe("The project ID"),
|
|
1646
|
+
taskId: import_zod3.z.string().describe("The task ID to restore")
|
|
1647
|
+
}
|
|
1648
|
+
},
|
|
1649
|
+
async (args) => {
|
|
1650
|
+
assertApiKeyPermission(
|
|
1651
|
+
mockApiKey,
|
|
1652
|
+
ApiKeyPermission.WRITE,
|
|
1653
|
+
"unarchive_task"
|
|
1654
|
+
);
|
|
1655
|
+
const validated = UnarchiveTaskInputSchema.parse(args);
|
|
1656
|
+
try {
|
|
1657
|
+
const result = await apiClient.unarchiveTask(
|
|
1658
|
+
validated.taskId,
|
|
1659
|
+
validated.projectId
|
|
1660
|
+
);
|
|
1661
|
+
return {
|
|
1662
|
+
content: [
|
|
1663
|
+
{
|
|
1664
|
+
type: "text",
|
|
1665
|
+
text: JSON.stringify(result, null, 2)
|
|
1666
|
+
}
|
|
1667
|
+
]
|
|
1668
|
+
};
|
|
1669
|
+
} catch (error) {
|
|
1670
|
+
return handleApiError(error);
|
|
1671
|
+
}
|
|
1672
|
+
}
|
|
1673
|
+
);
|
|
1526
1674
|
server.registerTool(
|
|
1527
1675
|
"create_personal_project",
|
|
1528
1676
|
{
|
|
1529
|
-
description: "Create project in
|
|
1677
|
+
description: "Create new project in personal workspace linked to GitHub repository.",
|
|
1530
1678
|
inputSchema: {
|
|
1531
1679
|
name: import_zod3.z.string().describe("Project name (max 100 chars)"),
|
|
1532
1680
|
description: import_zod3.z.string().optional().describe("Project description (max 500 chars)"),
|
|
@@ -1562,7 +1710,7 @@ async function createMCPServer() {
|
|
|
1562
1710
|
server.registerTool(
|
|
1563
1711
|
"create_task",
|
|
1564
1712
|
{
|
|
1565
|
-
description: "Create
|
|
1713
|
+
description: "Create task with title, description, acceptance criteria. Starts in BACKLOG. Priority: LOW/MEDIUM/HIGH/CRITICAL.",
|
|
1566
1714
|
inputSchema: {
|
|
1567
1715
|
projectId: import_zod3.z.string().describe("The project ID to create the task in"),
|
|
1568
1716
|
epicId: import_zod3.z.string().nullable().optional().describe("Optional epic ID to associate the task with"),
|
|
@@ -1608,7 +1756,7 @@ async function createMCPServer() {
|
|
|
1608
1756
|
server.registerTool(
|
|
1609
1757
|
"request_changes",
|
|
1610
1758
|
{
|
|
1611
|
-
description: "
|
|
1759
|
+
description: "Return task from REVIEW to IN_PROGRESS with feedback. Original assignee addresses changes.",
|
|
1612
1760
|
inputSchema: {
|
|
1613
1761
|
projectId: import_zod3.z.string().describe("The project ID"),
|
|
1614
1762
|
taskId: import_zod3.z.string().describe("The task ID to review"),
|
|
@@ -1646,7 +1794,7 @@ async function createMCPServer() {
|
|
|
1646
1794
|
server.registerTool(
|
|
1647
1795
|
"approve_task",
|
|
1648
1796
|
{
|
|
1649
|
-
description: "Approve
|
|
1797
|
+
description: "Approve completed work and mark DONE. Only for REVIEW state tasks.",
|
|
1650
1798
|
inputSchema: {
|
|
1651
1799
|
projectId: import_zod3.z.string().describe("The project ID"),
|
|
1652
1800
|
taskId: import_zod3.z.string().describe("The task ID to approve"),
|
|
@@ -1682,7 +1830,7 @@ async function createMCPServer() {
|
|
|
1682
1830
|
server.registerTool(
|
|
1683
1831
|
"get_version",
|
|
1684
1832
|
{
|
|
1685
|
-
description: "
|
|
1833
|
+
description: "Check MCP server version and connectivity."
|
|
1686
1834
|
},
|
|
1687
1835
|
async () => {
|
|
1688
1836
|
assertApiKeyPermission(mockApiKey, ApiKeyPermission.READ, "get_version");
|
|
@@ -1741,7 +1889,7 @@ function handleApiError(error) {
|
|
|
1741
1889
|
async function checkActiveTask() {
|
|
1742
1890
|
const fs = await import("fs");
|
|
1743
1891
|
const path = await import("path");
|
|
1744
|
-
const activeTaskPath = path.join(process.cwd(), ".
|
|
1892
|
+
const activeTaskPath = path.join(process.cwd(), ".collab", "active-task.json");
|
|
1745
1893
|
try {
|
|
1746
1894
|
await fs.promises.access(activeTaskPath);
|
|
1747
1895
|
const content = await fs.promises.readFile(activeTaskPath, "utf-8");
|
|
@@ -1762,34 +1910,34 @@ async function checkActiveTask() {
|
|
|
1762
1910
|
function handleCliFlags() {
|
|
1763
1911
|
const args = process.argv.slice(2);
|
|
1764
1912
|
if (args.includes("--version") || args.includes("-v")) {
|
|
1765
|
-
console.log(`
|
|
1913
|
+
console.log(`collab-mcp v${VERSION}`);
|
|
1766
1914
|
process.exit(0);
|
|
1767
1915
|
}
|
|
1768
1916
|
if (args.includes("--help") || args.includes("-h")) {
|
|
1769
|
-
console.log(`
|
|
1917
|
+
console.log(`collab-mcp v${VERSION}
|
|
1770
1918
|
|
|
1771
|
-
|
|
1919
|
+
Collab MCP Server - Model Context Protocol server for Collab
|
|
1772
1920
|
|
|
1773
1921
|
Usage:
|
|
1774
|
-
|
|
1922
|
+
collab-mcp [options]
|
|
1775
1923
|
|
|
1776
1924
|
Options:
|
|
1777
1925
|
-v, --version Show version number
|
|
1778
1926
|
-h, --help Show this help message
|
|
1779
1927
|
|
|
1780
1928
|
Environment Variables:
|
|
1781
|
-
|
|
1782
|
-
|
|
1929
|
+
COLLAB_API_KEY Your Collab API key (required)
|
|
1930
|
+
COLLAB_BASE_URL Collab webapp URL (required)
|
|
1783
1931
|
|
|
1784
1932
|
Example mcp.json configuration:
|
|
1785
1933
|
{
|
|
1786
1934
|
"mcpServers": {
|
|
1787
|
-
"
|
|
1935
|
+
"collab": {
|
|
1788
1936
|
"command": "npx",
|
|
1789
1937
|
"args": ["@mtaap/mcp"],
|
|
1790
1938
|
"env": {
|
|
1791
|
-
"
|
|
1792
|
-
"
|
|
1939
|
+
"COLLAB_API_KEY": "collab_your_api_key_here",
|
|
1940
|
+
"COLLAB_BASE_URL": "https://collab.mtaap.de"
|
|
1793
1941
|
}
|
|
1794
1942
|
}
|
|
1795
1943
|
}
|
|
@@ -1799,32 +1947,32 @@ Example mcp.json configuration:
|
|
|
1799
1947
|
}
|
|
1800
1948
|
function validateEnvironment() {
|
|
1801
1949
|
const errors = [];
|
|
1802
|
-
if (!process.env.
|
|
1950
|
+
if (!process.env.COLLAB_API_KEY) {
|
|
1803
1951
|
errors.push(
|
|
1804
|
-
"
|
|
1952
|
+
"COLLAB_API_KEY is required. Generate one at https://collab.mtaap.de/settings/api-keys"
|
|
1805
1953
|
);
|
|
1806
1954
|
}
|
|
1807
|
-
if (!process.env.
|
|
1955
|
+
if (!process.env.COLLAB_BASE_URL) {
|
|
1808
1956
|
errors.push(
|
|
1809
|
-
"
|
|
1957
|
+
"COLLAB_BASE_URL is required. Set to https://collab.mtaap.de for cloud or your self-hosted URL."
|
|
1810
1958
|
);
|
|
1811
1959
|
}
|
|
1812
1960
|
if (errors.length > 0) {
|
|
1813
1961
|
for (const error of errors) {
|
|
1814
|
-
console.error(`[
|
|
1962
|
+
console.error(`[collab-mcp] Error: ${error}`);
|
|
1815
1963
|
}
|
|
1816
1964
|
console.error("\nRequired environment variables:");
|
|
1817
|
-
console.error("
|
|
1818
|
-
console.error("
|
|
1965
|
+
console.error(" COLLAB_API_KEY Your Collab API key");
|
|
1966
|
+
console.error(" COLLAB_BASE_URL Collab webapp URL (e.g., https://collab.mtaap.de)");
|
|
1819
1967
|
console.error("\nExample mcp.json configuration:");
|
|
1820
1968
|
console.error(`{
|
|
1821
1969
|
"mcpServers": {
|
|
1822
|
-
"
|
|
1970
|
+
"collab": {
|
|
1823
1971
|
"command": "npx",
|
|
1824
1972
|
"args": ["@mtaap/mcp"],
|
|
1825
1973
|
"env": {
|
|
1826
|
-
"
|
|
1827
|
-
"
|
|
1974
|
+
"COLLAB_API_KEY": "collab_your_api_key_here",
|
|
1975
|
+
"COLLAB_BASE_URL": "https://collab.mtaap.de"
|
|
1828
1976
|
}
|
|
1829
1977
|
}
|
|
1830
1978
|
}
|
|
@@ -1832,20 +1980,20 @@ function validateEnvironment() {
|
|
|
1832
1980
|
process.exit(1);
|
|
1833
1981
|
}
|
|
1834
1982
|
try {
|
|
1835
|
-
new URL(process.env.
|
|
1983
|
+
new URL(process.env.COLLAB_BASE_URL);
|
|
1836
1984
|
} catch {
|
|
1837
|
-
console.error(`[
|
|
1985
|
+
console.error(`[collab-mcp] Error: COLLAB_BASE_URL is not a valid URL: ${process.env.COLLAB_BASE_URL}`);
|
|
1838
1986
|
process.exit(1);
|
|
1839
1987
|
}
|
|
1840
1988
|
}
|
|
1841
1989
|
async function checkConnectivity() {
|
|
1842
|
-
const baseUrl = process.env.
|
|
1843
|
-
console.error(`[
|
|
1990
|
+
const baseUrl = process.env.COLLAB_BASE_URL;
|
|
1991
|
+
console.error(`[collab-mcp] Checking connectivity to ${baseUrl}...`);
|
|
1844
1992
|
try {
|
|
1845
1993
|
const response = await fetch(`${baseUrl}/api/mcp/auth`, {
|
|
1846
1994
|
method: "GET",
|
|
1847
1995
|
headers: {
|
|
1848
|
-
"X-API-Key": process.env.
|
|
1996
|
+
"X-API-Key": process.env.COLLAB_API_KEY
|
|
1849
1997
|
},
|
|
1850
1998
|
signal: AbortSignal.timeout(1e4)
|
|
1851
1999
|
// 10 second timeout
|
|
@@ -1853,51 +2001,51 @@ async function checkConnectivity() {
|
|
|
1853
2001
|
if (!response.ok) {
|
|
1854
2002
|
const data = await response.json().catch(() => ({}));
|
|
1855
2003
|
if (response.status === 401) {
|
|
1856
|
-
console.error("[
|
|
2004
|
+
console.error("[collab-mcp] Error: Invalid or expired API key");
|
|
1857
2005
|
process.exit(1);
|
|
1858
2006
|
}
|
|
1859
|
-
console.error(`[
|
|
2007
|
+
console.error(`[collab-mcp] Error: API returned ${response.status}: ${data.error || "Unknown error"}`);
|
|
1860
2008
|
process.exit(1);
|
|
1861
2009
|
}
|
|
1862
|
-
console.error("[
|
|
2010
|
+
console.error("[collab-mcp] Connected successfully");
|
|
1863
2011
|
} catch (error) {
|
|
1864
2012
|
if (error instanceof Error && error.name === "TimeoutError") {
|
|
1865
|
-
console.error(`[
|
|
2013
|
+
console.error(`[collab-mcp] Error: Connection timed out to ${baseUrl}`);
|
|
1866
2014
|
} else {
|
|
1867
|
-
console.error(`[
|
|
1868
|
-
console.error(`[
|
|
2015
|
+
console.error(`[collab-mcp] Error: Could not connect to ${baseUrl}`);
|
|
2016
|
+
console.error(`[collab-mcp] Details: ${error instanceof Error ? error.message : String(error)}`);
|
|
1869
2017
|
}
|
|
1870
2018
|
process.exit(1);
|
|
1871
2019
|
}
|
|
1872
2020
|
}
|
|
1873
2021
|
async function main() {
|
|
1874
2022
|
handleCliFlags();
|
|
1875
|
-
console.error("[
|
|
2023
|
+
console.error("[collab-mcp] Starting Collab MCP server...");
|
|
1876
2024
|
validateEnvironment();
|
|
1877
2025
|
await checkConnectivity();
|
|
1878
2026
|
try {
|
|
1879
2027
|
await createMCPServer();
|
|
1880
|
-
console.error("[
|
|
2028
|
+
console.error("[collab-mcp] Server started successfully");
|
|
1881
2029
|
} catch (error) {
|
|
1882
2030
|
const message = error instanceof Error ? error.message : String(error);
|
|
1883
|
-
console.error(`[
|
|
2031
|
+
console.error(`[collab-mcp] Failed to start server: ${message}`);
|
|
1884
2032
|
process.exit(1);
|
|
1885
2033
|
}
|
|
1886
2034
|
}
|
|
1887
2035
|
function setupShutdownHandlers() {
|
|
1888
2036
|
const shutdown = (signal) => {
|
|
1889
|
-
console.error(`[
|
|
2037
|
+
console.error(`[collab-mcp] Received ${signal}, shutting down...`);
|
|
1890
2038
|
process.exit(0);
|
|
1891
2039
|
};
|
|
1892
2040
|
process.on("SIGINT", () => shutdown("SIGINT"));
|
|
1893
2041
|
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
1894
2042
|
process.on("uncaughtException", (error) => {
|
|
1895
|
-
console.error("[
|
|
2043
|
+
console.error("[collab-mcp] Uncaught exception:", error.message);
|
|
1896
2044
|
process.exit(1);
|
|
1897
2045
|
});
|
|
1898
2046
|
process.on("unhandledRejection", (reason) => {
|
|
1899
2047
|
const message = reason instanceof Error ? reason.message : String(reason);
|
|
1900
|
-
console.error("[
|
|
2048
|
+
console.error("[collab-mcp] Unhandled rejection:", message);
|
|
1901
2049
|
process.exit(1);
|
|
1902
2050
|
});
|
|
1903
2051
|
}
|