@mtaap/mcp 0.2.7 → 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/README.md CHANGED
@@ -518,19 +518,6 @@ report_error -> abandon_task -> list_tasks -> assign_task (retry or pick differe
518
518
 
519
519
  3. Use the tools from your AI agent
520
520
 
521
- ## Development
522
-
523
- ```bash
524
- # Build
525
- pnpm build
526
-
527
- # Watch mode
528
- pnpm dev
529
-
530
- # Run locally
531
- COLLAB_API_KEY=your-key COLLAB_BASE_URL=https://collab.mtaap.de pnpm start
532
- ```
533
-
534
521
  ## Troubleshooting
535
522
 
536
523
  ### "COLLAB_API_KEY is required"
@@ -553,16 +540,6 @@ Ensure your firewall allows outbound connections to your Collab instance. The se
553
540
 
554
541
  The MCP API is rate limited to 100 requests per minute. If you exceed this limit, you'll receive a 429 error with a `Retry-After` header indicating when you can retry.
555
542
 
556
- ## Publishing
557
-
558
- This package is published as `@mtaap/mcp` to npm.
559
-
560
- ```bash
561
- # Build and publish
562
- pnpm build
563
- npm publish
564
- ```
565
-
566
543
  ## License
567
544
 
568
545
  Proprietary - See LICENSE file for details.
package/dist/cli.js CHANGED
@@ -420,6 +420,7 @@ var ListTasksInputSchema = import_zod2.z.object({
420
420
  includeArchived: import_zod2.z.boolean().optional()
421
421
  });
422
422
  var cuidOrPrefixedId = import_zod2.z.string().regex(/^([a-z0-9]+|[a-z]+_[a-zA-Z0-9]+)$/);
423
+ 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");
423
424
  var GetTaskInputSchema = import_zod2.z.object({
424
425
  taskId: cuidOrPrefixedId
425
426
  });
@@ -634,7 +635,7 @@ var UpdateTaskMCPInputSchema = import_zod2.z.object({
634
635
  var ReportBranchInputSchema = import_zod2.z.object({
635
636
  projectId: cuidOrPrefixedId,
636
637
  taskId: cuidOrPrefixedId,
637
- branchName: import_zod2.z.string().min(1).max(100)
638
+ branchName: gitBranchName
638
639
  });
639
640
  var ReportPRInputSchema = import_zod2.z.object({
640
641
  projectId: cuidOrPrefixedId,
@@ -941,6 +942,12 @@ var errorTrackerInstance = new NoOpErrorTracker();
941
942
 
942
943
  // src/api-client.ts
943
944
  var DEFAULT_TIMEOUT = 3e4;
945
+ function sanitizeForLogging(str) {
946
+ let sanitized = str.replace(/\bcollab_[a-zA-Z0-9_-]+\b/gi, "[REDACTED_API_KEY]");
947
+ sanitized = sanitized.replace(/\bBearer\s+[a-zA-Z0-9._-]+\b/gi, "Bearer [REDACTED]");
948
+ sanitized = sanitized.replace(/([?&](api_?key|token|auth|key|secret)=)[^&\s]+/gi, "$1[REDACTED]");
949
+ return sanitized;
950
+ }
944
951
  var ApiError = class extends Error {
945
952
  constructor(message, code, status, details) {
946
953
  super(message);
@@ -970,7 +977,7 @@ var MCPApiClient = class {
970
977
  const controller = new AbortController();
971
978
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
972
979
  if (this.debug) {
973
- console.error(`[mcp-api] ${method} ${url}`);
980
+ console.error(`[mcp-api] ${method} ${sanitizeForLogging(path)}`);
974
981
  }
975
982
  try {
976
983
  const response = await fetch(url, {
@@ -1005,8 +1012,9 @@ var MCPApiClient = class {
1005
1012
  408
1006
1013
  );
1007
1014
  }
1015
+ const rawMessage = error instanceof Error ? error.message : "Unknown error";
1008
1016
  throw new ApiError(
1009
- error instanceof Error ? error.message : "Unknown error",
1017
+ sanitizeForLogging(rawMessage),
1010
1018
  "NETWORK_ERROR",
1011
1019
  0
1012
1020
  );
@@ -2192,22 +2200,76 @@ function handleApiError(error) {
2192
2200
  isError: true
2193
2201
  };
2194
2202
  }
2203
+ var ActiveTaskSchema = import_zod3.z.object({
2204
+ taskId: import_zod3.z.string().min(1),
2205
+ projectId: import_zod3.z.string().min(1),
2206
+ branchName: import_zod3.z.string().optional(),
2207
+ startedAt: import_zod3.z.string().optional()
2208
+ });
2195
2209
  async function checkActiveTask() {
2196
2210
  const fs = await import("fs");
2197
2211
  const path = await import("path");
2198
- const activeTaskPath = path.join(process.cwd(), ".collab", "active-task.json");
2212
+ const cwd = process.cwd();
2213
+ const collabDir = path.join(cwd, ".collab");
2214
+ const activeTaskPath = path.join(collabDir, "active-task.json");
2199
2215
  try {
2200
- await fs.promises.access(activeTaskPath);
2216
+ const resolvedPath = path.resolve(activeTaskPath);
2217
+ const resolvedCollabDir = path.resolve(collabDir);
2218
+ if (!resolvedPath.startsWith(resolvedCollabDir + path.sep) && resolvedPath !== resolvedCollabDir) {
2219
+ return {
2220
+ hasActiveTask: false,
2221
+ task: null,
2222
+ error: "Invalid active task path"
2223
+ };
2224
+ }
2225
+ const stats = await fs.promises.lstat(activeTaskPath);
2226
+ if (stats.isSymbolicLink()) {
2227
+ return {
2228
+ hasActiveTask: false,
2229
+ task: null,
2230
+ error: "Symlinks not allowed for active task file"
2231
+ };
2232
+ }
2233
+ if (!stats.isFile()) {
2234
+ return {
2235
+ hasActiveTask: false,
2236
+ task: null
2237
+ };
2238
+ }
2201
2239
  const content = await fs.promises.readFile(activeTaskPath, "utf-8");
2202
- const activeTask = JSON.parse(content);
2240
+ let parsed;
2241
+ try {
2242
+ parsed = JSON.parse(content);
2243
+ } catch {
2244
+ return {
2245
+ hasActiveTask: false,
2246
+ task: null,
2247
+ error: "Invalid JSON in active task file"
2248
+ };
2249
+ }
2250
+ const validationResult = ActiveTaskSchema.safeParse(parsed);
2251
+ if (!validationResult.success) {
2252
+ return {
2253
+ hasActiveTask: false,
2254
+ task: null,
2255
+ error: "Active task file has invalid structure"
2256
+ };
2257
+ }
2203
2258
  return {
2204
2259
  hasActiveTask: true,
2205
- task: activeTask
2260
+ task: validationResult.data
2206
2261
  };
2207
- } catch {
2262
+ } catch (err) {
2263
+ if (err instanceof Error && "code" in err && err.code === "ENOENT") {
2264
+ return {
2265
+ hasActiveTask: false,
2266
+ task: null
2267
+ };
2268
+ }
2208
2269
  return {
2209
2270
  hasActiveTask: false,
2210
- task: null
2271
+ task: null,
2272
+ error: "Failed to read active task file"
2211
2273
  };
2212
2274
  }
2213
2275
  }