@mtaap/mcp 0.2.6 → 0.2.8
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/LICENSE +20 -0
- package/README.md +319 -74
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +198 -20
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +9 -0
- package/dist/index.js +198 -20
- package/dist/index.js.map +1 -1
- package/package.json +24 -17
package/dist/index.d.ts
ADDED
package/dist/index.js
CHANGED
|
@@ -37,7 +37,7 @@ var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
|
37
37
|
var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
38
38
|
|
|
39
39
|
// src/version.ts
|
|
40
|
-
var VERSION = "0.2.
|
|
40
|
+
var VERSION = "0.2.7";
|
|
41
41
|
|
|
42
42
|
// src/index.ts
|
|
43
43
|
var import_zod3 = require("zod");
|
|
@@ -429,6 +429,7 @@ var ListTasksInputSchema = import_zod2.z.object({
|
|
|
429
429
|
includeArchived: import_zod2.z.boolean().optional()
|
|
430
430
|
});
|
|
431
431
|
var cuidOrPrefixedId = import_zod2.z.string().regex(/^([a-z0-9]+|[a-z]+_[a-zA-Z0-9]+)$/);
|
|
432
|
+
var gitBranchName = import_zod2.z.string().min(1).max(100).regex(/^[a-zA-Z0-9][-a-zA-Z0-9._/]*[a-zA-Z0-9]$|^[a-zA-Z0-9]$/, "Branch name must start and end with alphanumeric character").refine((val) => !val.includes("..") && !val.includes("@{") && !val.includes("//") && !val.endsWith(".lock") && !val.includes("~") && !val.includes("^") && !val.includes(":") && !val.includes("?") && !val.includes("*") && !val.includes("[") && !val.includes("\\") && !val.includes(" ") && !val.includes(";") && !val.includes("&") && !val.includes("|") && !val.includes("$") && !val.includes("`") && !val.includes("'") && !val.includes('"') && !val.includes("<") && !val.includes(">") && !val.includes("(") && !val.includes(")"), "Invalid branch name: contains forbidden characters or sequences");
|
|
432
433
|
var GetTaskInputSchema = import_zod2.z.object({
|
|
433
434
|
taskId: cuidOrPrefixedId
|
|
434
435
|
});
|
|
@@ -640,6 +641,17 @@ var UpdateTaskMCPInputSchema = import_zod2.z.object({
|
|
|
640
641
|
description: import_zod2.z.string().min(1).max(500)
|
|
641
642
|
})).optional()
|
|
642
643
|
});
|
|
644
|
+
var ReportBranchInputSchema = import_zod2.z.object({
|
|
645
|
+
projectId: cuidOrPrefixedId,
|
|
646
|
+
taskId: cuidOrPrefixedId,
|
|
647
|
+
branchName: gitBranchName
|
|
648
|
+
});
|
|
649
|
+
var ReportPRInputSchema = import_zod2.z.object({
|
|
650
|
+
projectId: cuidOrPrefixedId,
|
|
651
|
+
taskId: cuidOrPrefixedId,
|
|
652
|
+
pullRequestUrl: import_zod2.z.string().url(),
|
|
653
|
+
pullRequestNumber: import_zod2.z.number().int().positive()
|
|
654
|
+
});
|
|
643
655
|
|
|
644
656
|
// ../../packages/core/dist/logging/metrics.js
|
|
645
657
|
var metrics = /* @__PURE__ */ new Map();
|
|
@@ -939,6 +951,12 @@ var errorTrackerInstance = new NoOpErrorTracker();
|
|
|
939
951
|
|
|
940
952
|
// src/api-client.ts
|
|
941
953
|
var DEFAULT_TIMEOUT = 3e4;
|
|
954
|
+
function sanitizeForLogging(str) {
|
|
955
|
+
let sanitized = str.replace(/\bcollab_[a-zA-Z0-9_-]+\b/gi, "[REDACTED_API_KEY]");
|
|
956
|
+
sanitized = sanitized.replace(/\bBearer\s+[a-zA-Z0-9._-]+\b/gi, "Bearer [REDACTED]");
|
|
957
|
+
sanitized = sanitized.replace(/([?&](api_?key|token|auth|key|secret)=)[^&\s]+/gi, "$1[REDACTED]");
|
|
958
|
+
return sanitized;
|
|
959
|
+
}
|
|
942
960
|
var ApiError = class extends Error {
|
|
943
961
|
constructor(message, code, status, details) {
|
|
944
962
|
super(message);
|
|
@@ -968,7 +986,7 @@ var MCPApiClient = class {
|
|
|
968
986
|
const controller = new AbortController();
|
|
969
987
|
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
970
988
|
if (this.debug) {
|
|
971
|
-
console.error(`[mcp-api] ${method} ${
|
|
989
|
+
console.error(`[mcp-api] ${method} ${sanitizeForLogging(path)}`);
|
|
972
990
|
}
|
|
973
991
|
try {
|
|
974
992
|
const response = await fetch(url, {
|
|
@@ -1003,8 +1021,9 @@ var MCPApiClient = class {
|
|
|
1003
1021
|
408
|
|
1004
1022
|
);
|
|
1005
1023
|
}
|
|
1024
|
+
const rawMessage = error instanceof Error ? error.message : "Unknown error";
|
|
1006
1025
|
throw new ApiError(
|
|
1007
|
-
|
|
1026
|
+
sanitizeForLogging(rawMessage),
|
|
1008
1027
|
"NETWORK_ERROR",
|
|
1009
1028
|
0
|
|
1010
1029
|
);
|
|
@@ -1102,7 +1121,8 @@ var MCPApiClient = class {
|
|
|
1102
1121
|
return this.request("POST", `/api/mcp/tasks/${taskId}/progress`, data);
|
|
1103
1122
|
}
|
|
1104
1123
|
/**
|
|
1105
|
-
* Complete task and
|
|
1124
|
+
* Complete task and prepare for PR creation.
|
|
1125
|
+
* Returns PR suggestions for the agent to use when creating the PR locally.
|
|
1106
1126
|
*/
|
|
1107
1127
|
async completeTask(taskId, projectId, pullRequestTitle, pullRequestBody) {
|
|
1108
1128
|
return this.request("POST", `/api/mcp/tasks/${taskId}/complete`, {
|
|
@@ -1172,11 +1192,23 @@ var MCPApiClient = class {
|
|
|
1172
1192
|
});
|
|
1173
1193
|
}
|
|
1174
1194
|
/**
|
|
1175
|
-
*
|
|
1195
|
+
* Report branch created by agent
|
|
1176
1196
|
*/
|
|
1177
|
-
async
|
|
1178
|
-
|
|
1179
|
-
|
|
1197
|
+
async reportBranch(taskId, projectId, branchName) {
|
|
1198
|
+
return this.request("POST", `/api/mcp/tasks/${taskId}/branch`, {
|
|
1199
|
+
projectId,
|
|
1200
|
+
branchName
|
|
1201
|
+
});
|
|
1202
|
+
}
|
|
1203
|
+
/**
|
|
1204
|
+
* Report PR created by agent
|
|
1205
|
+
*/
|
|
1206
|
+
async reportPR(taskId, projectId, pullRequestUrl, pullRequestNumber) {
|
|
1207
|
+
return this.request("POST", `/api/mcp/tasks/${taskId}/pr`, {
|
|
1208
|
+
projectId,
|
|
1209
|
+
pullRequestUrl,
|
|
1210
|
+
pullRequestNumber
|
|
1211
|
+
});
|
|
1180
1212
|
}
|
|
1181
1213
|
/**
|
|
1182
1214
|
* Verify a DRAFT task to move it to TODO state
|
|
@@ -1265,10 +1297,13 @@ TOOL CATEGORIES:
|
|
|
1265
1297
|
4. Task Execution (WRITE):
|
|
1266
1298
|
- assign_task, update_progress, add_note, complete_task, abandon_task, report_error
|
|
1267
1299
|
|
|
1268
|
-
5.
|
|
1300
|
+
5. Git Operations (WRITE):
|
|
1301
|
+
- report_branch, report_pr
|
|
1302
|
+
|
|
1303
|
+
6. Code Review (WRITE):
|
|
1269
1304
|
- request_changes, approve_task
|
|
1270
1305
|
|
|
1271
|
-
|
|
1306
|
+
7. Session Management (READ):
|
|
1272
1307
|
- check_active_task
|
|
1273
1308
|
|
|
1274
1309
|
WORKFLOWS:
|
|
@@ -1277,7 +1312,15 @@ Task Creation & Verification:
|
|
|
1277
1312
|
create_task -> get_task_prompt (DRAFT) -> verify_task(approved=true) -> task moves to TODO
|
|
1278
1313
|
|
|
1279
1314
|
Standard Task Workflow:
|
|
1280
|
-
list_projects -> get_project_context -> list_tasks(state=TODO) -> get_task -> get_task_prompt (TODO)
|
|
1315
|
+
list_projects -> get_project_context -> list_tasks(state=TODO) -> get_task -> get_task_prompt (TODO)
|
|
1316
|
+
-> assign_task (returns suggested branch name)
|
|
1317
|
+
-> git checkout -b <branchName> (local git command)
|
|
1318
|
+
-> git push -u origin <branchName> (local git command)
|
|
1319
|
+
-> report_branch (tell server about the branch)
|
|
1320
|
+
-> [update_progress...]
|
|
1321
|
+
-> complete_task (returns PR suggestions)
|
|
1322
|
+
-> gh pr create (local gh command)
|
|
1323
|
+
-> report_pr (tell server about the PR)
|
|
1281
1324
|
|
|
1282
1325
|
Resume Workflow:
|
|
1283
1326
|
check_active_task -> (if active) get_task -> get_task_prompt (IN_PROGRESS) -> update_progress -> complete_task
|
|
@@ -1289,9 +1332,15 @@ Task Editing:
|
|
|
1289
1332
|
update_task (DRAFT/TODO only) -> if was TODO, reverts to DRAFT -> verify_task again
|
|
1290
1333
|
|
|
1291
1334
|
Error Recovery:
|
|
1292
|
-
report_error -> abandon_task
|
|
1335
|
+
report_error -> abandon_task -> list_tasks -> assign_task (retry or pick different task)
|
|
1293
1336
|
(abandon_task returns IN_PROGRESS tasks to TODO state)
|
|
1294
1337
|
|
|
1338
|
+
GIT OPERATIONS NOTE:
|
|
1339
|
+
The agent handles all git operations locally. After assign_task returns a suggested branch name,
|
|
1340
|
+
the agent creates the branch with git, pushes it, and reports it via report_branch.
|
|
1341
|
+
After complete_task returns PR suggestions, the agent creates the PR with gh, and reports it via report_pr.
|
|
1342
|
+
This eliminates the need for GitHub tokens on the server.
|
|
1343
|
+
|
|
1295
1344
|
TASK STATE FLOW:
|
|
1296
1345
|
DRAFT -> TODO -> IN_PROGRESS -> REVIEW -> DONE
|
|
1297
1346
|
(verify_task: DRAFT -> TODO)
|
|
@@ -1308,7 +1357,8 @@ CONSTRAINTS:
|
|
|
1308
1357
|
- complete_task requires IN_PROGRESS state
|
|
1309
1358
|
- request_changes/approve_task require REVIEW state
|
|
1310
1359
|
- Always check_active_task before starting new work
|
|
1311
|
-
- Call update_progress frequently to checkpoint
|
|
1360
|
+
- Call update_progress frequently to checkpoint
|
|
1361
|
+
- Agent must have git/gh CLI configured for local git operations`;
|
|
1312
1362
|
async function createMCPServer() {
|
|
1313
1363
|
const server = new import_mcp.McpServer(
|
|
1314
1364
|
{
|
|
@@ -1498,7 +1548,7 @@ async function createMCPServer() {
|
|
|
1498
1548
|
server.registerTool(
|
|
1499
1549
|
"complete_task",
|
|
1500
1550
|
{
|
|
1501
|
-
description: "
|
|
1551
|
+
description: "Prepare task for PR creation. Returns PR suggestions. After creating PR locally, call report_pr to transition to REVIEW. Requires IN_PROGRESS state.",
|
|
1502
1552
|
inputSchema: {
|
|
1503
1553
|
projectId: import_zod3.z.string().describe("The project ID"),
|
|
1504
1554
|
taskId: import_zod3.z.string().describe("The task ID to complete"),
|
|
@@ -1689,6 +1739,80 @@ async function createMCPServer() {
|
|
|
1689
1739
|
}
|
|
1690
1740
|
}
|
|
1691
1741
|
);
|
|
1742
|
+
server.registerTool(
|
|
1743
|
+
"report_branch",
|
|
1744
|
+
{
|
|
1745
|
+
description: "Report a branch created by the agent. Call after using git to create and push a branch. Task must be IN_PROGRESS.",
|
|
1746
|
+
inputSchema: {
|
|
1747
|
+
projectId: import_zod3.z.string().describe("The project ID"),
|
|
1748
|
+
taskId: import_zod3.z.string().describe("The task ID"),
|
|
1749
|
+
branchName: import_zod3.z.string().describe("Name of the branch created (e.g., feature/TASK-123-fix-login)")
|
|
1750
|
+
}
|
|
1751
|
+
},
|
|
1752
|
+
async (args) => {
|
|
1753
|
+
assertApiKeyPermission(
|
|
1754
|
+
mockApiKey,
|
|
1755
|
+
ApiKeyPermission.WRITE,
|
|
1756
|
+
"report_branch"
|
|
1757
|
+
);
|
|
1758
|
+
const validated = ReportBranchInputSchema.parse(args);
|
|
1759
|
+
try {
|
|
1760
|
+
const result = await apiClient.reportBranch(
|
|
1761
|
+
validated.taskId,
|
|
1762
|
+
validated.projectId,
|
|
1763
|
+
validated.branchName
|
|
1764
|
+
);
|
|
1765
|
+
return {
|
|
1766
|
+
content: [
|
|
1767
|
+
{
|
|
1768
|
+
type: "text",
|
|
1769
|
+
text: JSON.stringify(result, null, 2)
|
|
1770
|
+
}
|
|
1771
|
+
]
|
|
1772
|
+
};
|
|
1773
|
+
} catch (error) {
|
|
1774
|
+
return handleApiError(error);
|
|
1775
|
+
}
|
|
1776
|
+
}
|
|
1777
|
+
);
|
|
1778
|
+
server.registerTool(
|
|
1779
|
+
"report_pr",
|
|
1780
|
+
{
|
|
1781
|
+
description: "Report a PR created by the agent. Call after using gh pr create. Transitions task to REVIEW state.",
|
|
1782
|
+
inputSchema: {
|
|
1783
|
+
projectId: import_zod3.z.string().describe("The project ID"),
|
|
1784
|
+
taskId: import_zod3.z.string().describe("The task ID"),
|
|
1785
|
+
pullRequestUrl: import_zod3.z.string().describe("Full URL of the created PR (e.g., https://github.com/owner/repo/pull/123)"),
|
|
1786
|
+
pullRequestNumber: import_zod3.z.number().describe("PR number (e.g., 123)")
|
|
1787
|
+
}
|
|
1788
|
+
},
|
|
1789
|
+
async (args) => {
|
|
1790
|
+
assertApiKeyPermission(
|
|
1791
|
+
mockApiKey,
|
|
1792
|
+
ApiKeyPermission.WRITE,
|
|
1793
|
+
"report_pr"
|
|
1794
|
+
);
|
|
1795
|
+
const validated = ReportPRInputSchema.parse(args);
|
|
1796
|
+
try {
|
|
1797
|
+
const result = await apiClient.reportPR(
|
|
1798
|
+
validated.taskId,
|
|
1799
|
+
validated.projectId,
|
|
1800
|
+
validated.pullRequestUrl,
|
|
1801
|
+
validated.pullRequestNumber
|
|
1802
|
+
);
|
|
1803
|
+
return {
|
|
1804
|
+
content: [
|
|
1805
|
+
{
|
|
1806
|
+
type: "text",
|
|
1807
|
+
text: JSON.stringify(result, null, 2)
|
|
1808
|
+
}
|
|
1809
|
+
]
|
|
1810
|
+
};
|
|
1811
|
+
} catch (error) {
|
|
1812
|
+
return handleApiError(error);
|
|
1813
|
+
}
|
|
1814
|
+
}
|
|
1815
|
+
);
|
|
1692
1816
|
server.registerTool(
|
|
1693
1817
|
"archive_task",
|
|
1694
1818
|
{
|
|
@@ -2085,22 +2209,76 @@ function handleApiError(error) {
|
|
|
2085
2209
|
isError: true
|
|
2086
2210
|
};
|
|
2087
2211
|
}
|
|
2212
|
+
var ActiveTaskSchema = import_zod3.z.object({
|
|
2213
|
+
taskId: import_zod3.z.string().min(1),
|
|
2214
|
+
projectId: import_zod3.z.string().min(1),
|
|
2215
|
+
branchName: import_zod3.z.string().optional(),
|
|
2216
|
+
startedAt: import_zod3.z.string().optional()
|
|
2217
|
+
});
|
|
2088
2218
|
async function checkActiveTask() {
|
|
2089
2219
|
const fs = await import("fs");
|
|
2090
2220
|
const path = await import("path");
|
|
2091
|
-
const
|
|
2221
|
+
const cwd = process.cwd();
|
|
2222
|
+
const collabDir = path.join(cwd, ".collab");
|
|
2223
|
+
const activeTaskPath = path.join(collabDir, "active-task.json");
|
|
2092
2224
|
try {
|
|
2093
|
-
|
|
2225
|
+
const resolvedPath = path.resolve(activeTaskPath);
|
|
2226
|
+
const resolvedCollabDir = path.resolve(collabDir);
|
|
2227
|
+
if (!resolvedPath.startsWith(resolvedCollabDir + path.sep) && resolvedPath !== resolvedCollabDir) {
|
|
2228
|
+
return {
|
|
2229
|
+
hasActiveTask: false,
|
|
2230
|
+
task: null,
|
|
2231
|
+
error: "Invalid active task path"
|
|
2232
|
+
};
|
|
2233
|
+
}
|
|
2234
|
+
const stats = await fs.promises.lstat(activeTaskPath);
|
|
2235
|
+
if (stats.isSymbolicLink()) {
|
|
2236
|
+
return {
|
|
2237
|
+
hasActiveTask: false,
|
|
2238
|
+
task: null,
|
|
2239
|
+
error: "Symlinks not allowed for active task file"
|
|
2240
|
+
};
|
|
2241
|
+
}
|
|
2242
|
+
if (!stats.isFile()) {
|
|
2243
|
+
return {
|
|
2244
|
+
hasActiveTask: false,
|
|
2245
|
+
task: null
|
|
2246
|
+
};
|
|
2247
|
+
}
|
|
2094
2248
|
const content = await fs.promises.readFile(activeTaskPath, "utf-8");
|
|
2095
|
-
|
|
2249
|
+
let parsed;
|
|
2250
|
+
try {
|
|
2251
|
+
parsed = JSON.parse(content);
|
|
2252
|
+
} catch {
|
|
2253
|
+
return {
|
|
2254
|
+
hasActiveTask: false,
|
|
2255
|
+
task: null,
|
|
2256
|
+
error: "Invalid JSON in active task file"
|
|
2257
|
+
};
|
|
2258
|
+
}
|
|
2259
|
+
const validationResult = ActiveTaskSchema.safeParse(parsed);
|
|
2260
|
+
if (!validationResult.success) {
|
|
2261
|
+
return {
|
|
2262
|
+
hasActiveTask: false,
|
|
2263
|
+
task: null,
|
|
2264
|
+
error: "Active task file has invalid structure"
|
|
2265
|
+
};
|
|
2266
|
+
}
|
|
2096
2267
|
return {
|
|
2097
2268
|
hasActiveTask: true,
|
|
2098
|
-
task:
|
|
2269
|
+
task: validationResult.data
|
|
2099
2270
|
};
|
|
2100
|
-
} catch {
|
|
2271
|
+
} catch (err) {
|
|
2272
|
+
if (err instanceof Error && "code" in err && err.code === "ENOENT") {
|
|
2273
|
+
return {
|
|
2274
|
+
hasActiveTask: false,
|
|
2275
|
+
task: null
|
|
2276
|
+
};
|
|
2277
|
+
}
|
|
2101
2278
|
return {
|
|
2102
2279
|
hasActiveTask: false,
|
|
2103
|
-
task: null
|
|
2280
|
+
task: null,
|
|
2281
|
+
error: "Failed to read active task file"
|
|
2104
2282
|
};
|
|
2105
2283
|
}
|
|
2106
2284
|
}
|