@mtaap/mcp 0.2.13 → 0.4.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/server.js CHANGED
@@ -36,7 +36,7 @@ var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
36
36
  // package.json
37
37
  var package_default = {
38
38
  name: "@mtaap/mcp",
39
- version: "0.2.12",
39
+ version: "0.4.1",
40
40
  description: "Model Context Protocol (MCP) server for AI agents to interact with Collab - the multi-tenant collaborative agent development platform",
41
41
  mcpName: "collab",
42
42
  scripts: {
@@ -45,6 +45,7 @@ var package_default = {
45
45
  main: "./dist/index.js",
46
46
  types: "./dist/index.d.ts",
47
47
  bin: {
48
+ mcp: "./dist/cli.js",
48
49
  "collab-mcp": "./dist/cli.js",
49
50
  "collab-mcp-server": "./dist/server.js"
50
51
  },
@@ -94,7 +95,7 @@ var package_default = {
94
95
  var VERSION = package_default.version;
95
96
 
96
97
  // src/index.ts
97
- var import_zod3 = require("zod");
98
+ var import_zod4 = require("zod");
98
99
 
99
100
  // ../../packages/core/dist/constants/enums.js
100
101
  var TaskState;
@@ -181,12 +182,6 @@ var WebSocketEventType;
181
182
  WebSocketEventType2["TASK_DELETED"] = "task.deleted";
182
183
  WebSocketEventType2["MEMBER_JOINED"] = "member.joined";
183
184
  })(WebSocketEventType || (WebSocketEventType = {}));
184
- var AuthProvider;
185
- (function(AuthProvider2) {
186
- AuthProvider2["CREDENTIALS"] = "credentials";
187
- AuthProvider2["LDAP"] = "ldap";
188
- AuthProvider2["SSO"] = "sso";
189
- })(AuthProvider || (AuthProvider = {}));
190
185
  var SubscriptionStatus;
191
186
  (function(SubscriptionStatus2) {
192
187
  SubscriptionStatus2["ACTIVE"] = "ACTIVE";
@@ -202,6 +197,12 @@ var EventType;
202
197
  EventType2["ACCESS"] = "ACCESS";
203
198
  EventType2["MODIFICATION"] = "MODIFICATION";
204
199
  })(EventType || (EventType = {}));
200
+ var CreatedVia;
201
+ (function(CreatedVia2) {
202
+ CreatedVia2["UI"] = "UI";
203
+ CreatedVia2["API_KEY"] = "API_KEY";
204
+ CreatedVia2["OAUTH"] = "OAUTH";
205
+ })(CreatedVia || (CreatedVia = {}));
205
206
 
206
207
  // ../../packages/core/dist/constants/state-machine.js
207
208
  var VALID_TRANSITIONS = {
@@ -225,6 +226,62 @@ var VALID_TRANSITIONS = {
225
226
  [TaskState.DONE]: []
226
227
  };
227
228
 
229
+ // ../../packages/core/dist/constants/oauth.js
230
+ var OAuthScopes = {
231
+ /** Read-only access to MCP resources */
232
+ READ: "mcp:read",
233
+ /** Read and write access to MCP resources */
234
+ WRITE: "mcp:write",
235
+ /** Full administrative access */
236
+ ADMIN: "mcp:admin"
237
+ };
238
+ var VALID_OAUTH_SCOPES = [
239
+ OAuthScopes.READ,
240
+ OAuthScopes.WRITE,
241
+ OAuthScopes.ADMIN
242
+ ];
243
+ var DEFAULT_OAUTH_SCOPES = `${OAuthScopes.READ} ${OAuthScopes.WRITE}`;
244
+ var OAUTH_SCOPE_TO_PERMISSION = {
245
+ [OAuthScopes.READ]: ApiKeyPermission.READ,
246
+ [OAuthScopes.WRITE]: ApiKeyPermission.WRITE,
247
+ [OAuthScopes.ADMIN]: ApiKeyPermission.ADMIN
248
+ };
249
+ var PERMISSION_TO_OAUTH_SCOPE = {
250
+ [ApiKeyPermission.READ]: OAuthScopes.READ,
251
+ [ApiKeyPermission.WRITE]: OAuthScopes.WRITE,
252
+ [ApiKeyPermission.ADMIN]: OAuthScopes.ADMIN
253
+ };
254
+ var OAuthTokenLifetimes = {
255
+ /** Access token lifetime: 1 hour */
256
+ ACCESS_TOKEN_MS: 60 * 60 * 1e3,
257
+ /** Refresh token lifetime: 30 days */
258
+ REFRESH_TOKEN_MS: 30 * 24 * 60 * 60 * 1e3,
259
+ /** Authorization code lifetime: 10 minutes */
260
+ AUTHORIZATION_CODE_MS: 10 * 60 * 1e3
261
+ };
262
+ var OAuthGrantTypes = {
263
+ AUTHORIZATION_CODE: "authorization_code",
264
+ REFRESH_TOKEN: "refresh_token"
265
+ };
266
+ var SUPPORTED_GRANT_TYPES = [
267
+ OAuthGrantTypes.AUTHORIZATION_CODE,
268
+ OAuthGrantTypes.REFRESH_TOKEN
269
+ ];
270
+ var OAuthResponseTypes = {
271
+ CODE: "code"
272
+ };
273
+ var OAuthCodeChallengeMethods = {
274
+ S256: "S256"
275
+ };
276
+ var OAuthRateLimits = {
277
+ /** /oauth/token: 30 requests per minute per client */
278
+ TOKEN_ENDPOINT: { limit: 30, windowMs: 60 * 1e3 },
279
+ /** /oauth/authorize: 10 requests per minute per user */
280
+ AUTHORIZE_ENDPOINT: { limit: 10, windowMs: 60 * 1e3 },
281
+ /** /oauth/register: 5 requests per minute per IP */
282
+ REGISTER_ENDPOINT: { limit: 5, windowMs: 60 * 1e3 }
283
+ };
284
+
228
285
  // ../../packages/core/dist/config/deployment.js
229
286
  var config = {
230
287
  deploymentMode: process.env.DEPLOYMENT_MODE || "saas"
@@ -232,20 +289,24 @@ var config = {
232
289
  var isSaas = config.deploymentMode === "saas";
233
290
  var isOnPrem = config.deploymentMode === "onprem";
234
291
 
235
- // ../../packages/core/dist/version.js
236
- var VERSION2 = "0.1.0";
292
+ // ../../packages/core/dist/versions.js
293
+ var VERSIONS = {
294
+ core: "0.3.0",
295
+ web: "0.3.0",
296
+ mcp: "0.4.1"
297
+ };
298
+ var VERSION2 = VERSIONS.core;
237
299
 
238
300
  // ../../packages/core/dist/config/index.js
239
301
  var DEPLOYMENT_MODE = process.env.DEPLOYMENT_MODE || "saas";
240
302
  var config2 = {
241
303
  version: VERSION2,
304
+ packages: VERSIONS,
242
305
  deploymentMode: DEPLOYMENT_MODE,
243
306
  billing: {
244
307
  enabled: DEPLOYMENT_MODE === "saas",
245
308
  revenuecat: {
246
- publicKey: process.env.REVENUECAT_PUBLIC_API_KEY,
247
- stripeKey: process.env.STRIPE_SECRET_KEY
248
- // Required by RevenueCat Web Billing
309
+ publicKey: process.env.NEXT_PUBLIC_REVENUECAT_PUBLIC_KEY
249
310
  }
250
311
  },
251
312
  licensing: {
@@ -351,7 +412,6 @@ var OrganizationIdSchema = import_zod.z.string().regex(/^org_[a-zA-Z0-9]+$/);
351
412
  var OrganizationSchema = import_zod.z.object({
352
413
  id: OrganizationIdSchema,
353
414
  name: import_zod.z.string().min(1).max(255),
354
- slug: import_zod.z.string().min(1).max(100).regex(/^[a-z0-9-]+$/),
355
415
  logoUrl: import_zod.z.string().url().nullable(),
356
416
  accentColor: import_zod.z.string().regex(/^#[0-9A-Fa-f]{6}$/).nullable(),
357
417
  tenantName: import_zod.z.string().nullable(),
@@ -479,239 +539,375 @@ var ProjectCollaboratorSchema = import_zod.z.object({
479
539
  });
480
540
 
481
541
  // ../../packages/core/dist/validation/index.js
542
+ var import_zod3 = require("zod");
543
+
544
+ // ../../packages/core/dist/validation/oauth.js
482
545
  var import_zod2 = require("zod");
483
- var ListProjectsInputSchema = import_zod2.z.object({
484
- workspaceType: import_zod2.z.preprocess((val) => typeof val === "string" ? val.toUpperCase() : val, import_zod2.z.enum(["TEAM", "PERSONAL", "ALL"]).optional())
485
- });
486
- var ListTasksInputSchema = import_zod2.z.object({
487
- projectId: import_zod2.z.string().optional(),
488
- state: import_zod2.z.nativeEnum(TaskState).optional(),
489
- assigneeId: import_zod2.z.string().optional(),
490
- includeArchived: import_zod2.z.boolean().optional()
491
- });
492
- var cuidOrPrefixedId = import_zod2.z.string().regex(/^([a-z0-9]+|[a-z]+_[a-zA-Z0-9]+)$/);
493
- 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");
494
- var GetTaskInputSchema = import_zod2.z.object({
546
+ var scopeString = import_zod2.z.string().optional().transform((val) => {
547
+ if (!val)
548
+ return void 0;
549
+ const scopes = val.split(" ").filter(Boolean);
550
+ const validScopes = scopes.filter((s) => VALID_OAUTH_SCOPES.includes(s));
551
+ return validScopes.length > 0 ? validScopes.join(" ") : void 0;
552
+ });
553
+ var redirectUri = import_zod2.z.string().url().refine((uri) => {
554
+ const url = new URL(uri);
555
+ return url.protocol === "https:" || url.hostname === "localhost" || url.hostname === "127.0.0.1";
556
+ }, { message: "redirect_uri must use HTTPS or be localhost" });
557
+ var codeVerifier = import_zod2.z.string().min(43).max(128).regex(/^[A-Za-z0-9._~-]+$/, "code_verifier must only contain unreserved characters");
558
+ var codeChallenge = import_zod2.z.string().min(43).max(128).regex(/^[A-Za-z0-9_-]+$/, "code_challenge must be base64url encoded (no padding)");
559
+ var DynamicClientRegistrationSchema = import_zod2.z.object({
560
+ redirect_uris: import_zod2.z.array(redirectUri).min(1),
561
+ client_name: import_zod2.z.string().min(1).max(255),
562
+ client_uri: import_zod2.z.string().url().optional(),
563
+ logo_uri: import_zod2.z.string().url().optional(),
564
+ // Accept lowercase OAuth spec values
565
+ grant_types: import_zod2.z.array(import_zod2.z.enum(["authorization_code", "refresh_token"])).default(["authorization_code", "refresh_token"]),
566
+ response_types: import_zod2.z.array(import_zod2.z.enum([OAuthResponseTypes.CODE])).default([OAuthResponseTypes.CODE]),
567
+ scope: scopeString,
568
+ // Accept lowercase OAuth spec values
569
+ token_endpoint_auth_method: import_zod2.z.enum(["none", "client_secret_post", "client_secret_basic"]).default("none")
570
+ });
571
+ var DynamicClientRegistrationResponseSchema = import_zod2.z.object({
572
+ client_id: import_zod2.z.string(),
573
+ client_secret: import_zod2.z.string().optional(),
574
+ client_id_issued_at: import_zod2.z.number(),
575
+ client_secret_expires_at: import_zod2.z.number().optional(),
576
+ redirect_uris: import_zod2.z.array(import_zod2.z.string()),
577
+ client_name: import_zod2.z.string(),
578
+ client_uri: import_zod2.z.string().optional(),
579
+ logo_uri: import_zod2.z.string().optional(),
580
+ grant_types: import_zod2.z.array(import_zod2.z.string()),
581
+ response_types: import_zod2.z.array(import_zod2.z.string()),
582
+ scope: import_zod2.z.string(),
583
+ token_endpoint_auth_method: import_zod2.z.string(),
584
+ registration_access_token: import_zod2.z.string().optional(),
585
+ registration_client_uri: import_zod2.z.string().optional()
586
+ });
587
+ var AuthorizationRequestSchema = import_zod2.z.object({
588
+ response_type: import_zod2.z.literal(OAuthResponseTypes.CODE),
589
+ client_id: import_zod2.z.string().min(1),
590
+ redirect_uri: redirectUri,
591
+ scope: scopeString,
592
+ state: import_zod2.z.string().max(255).optional(),
593
+ // PKCE is mandatory in OAuth 2.1
594
+ code_challenge: codeChallenge,
595
+ code_challenge_method: import_zod2.z.literal(OAuthCodeChallengeMethods.S256)
596
+ });
597
+ var TokenRequestAuthorizationCodeSchema = import_zod2.z.object({
598
+ grant_type: import_zod2.z.literal(OAuthGrantTypes.AUTHORIZATION_CODE),
599
+ code: import_zod2.z.string().min(1),
600
+ redirect_uri: redirectUri,
601
+ client_id: import_zod2.z.string().min(1),
602
+ // PKCE code verifier is mandatory
603
+ code_verifier: codeVerifier,
604
+ // Client secret is optional (for confidential clients)
605
+ client_secret: import_zod2.z.string().optional()
606
+ });
607
+ var TokenRequestRefreshTokenSchema = import_zod2.z.object({
608
+ grant_type: import_zod2.z.literal(OAuthGrantTypes.REFRESH_TOKEN),
609
+ refresh_token: import_zod2.z.string().min(1),
610
+ client_id: import_zod2.z.string().min(1),
611
+ // Optional: request reduced scope
612
+ scope: scopeString,
613
+ // Client secret is optional (for confidential clients)
614
+ client_secret: import_zod2.z.string().optional()
615
+ });
616
+ var TokenRequestSchema = import_zod2.z.discriminatedUnion("grant_type", [
617
+ TokenRequestAuthorizationCodeSchema,
618
+ TokenRequestRefreshTokenSchema
619
+ ]);
620
+ var TokenResponseSchema = import_zod2.z.object({
621
+ access_token: import_zod2.z.string(),
622
+ token_type: import_zod2.z.literal("Bearer"),
623
+ expires_in: import_zod2.z.number(),
624
+ refresh_token: import_zod2.z.string().optional(),
625
+ scope: import_zod2.z.string()
626
+ });
627
+ var TokenRevocationRequestSchema = import_zod2.z.object({
628
+ token: import_zod2.z.string().min(1),
629
+ token_type_hint: import_zod2.z.enum(["access_token", "refresh_token"]).optional(),
630
+ client_id: import_zod2.z.string().min(1),
631
+ client_secret: import_zod2.z.string().optional()
632
+ });
633
+ var OAuthErrorResponseSchema = import_zod2.z.object({
634
+ error: import_zod2.z.string(),
635
+ error_description: import_zod2.z.string().optional(),
636
+ error_uri: import_zod2.z.string().url().optional(),
637
+ state: import_zod2.z.string().optional()
638
+ });
639
+ var AuthorizationServerMetadataSchema = import_zod2.z.object({
640
+ issuer: import_zod2.z.string().url(),
641
+ authorization_endpoint: import_zod2.z.string().url(),
642
+ token_endpoint: import_zod2.z.string().url(),
643
+ registration_endpoint: import_zod2.z.string().url().optional(),
644
+ revocation_endpoint: import_zod2.z.string().url().optional(),
645
+ scopes_supported: import_zod2.z.array(import_zod2.z.string()),
646
+ response_types_supported: import_zod2.z.array(import_zod2.z.string()),
647
+ grant_types_supported: import_zod2.z.array(import_zod2.z.string()),
648
+ token_endpoint_auth_methods_supported: import_zod2.z.array(import_zod2.z.string()),
649
+ code_challenge_methods_supported: import_zod2.z.array(import_zod2.z.string()),
650
+ service_documentation: import_zod2.z.string().url().optional()
651
+ });
652
+ var ProtectedResourceMetadataSchema = import_zod2.z.object({
653
+ resource: import_zod2.z.string().url(),
654
+ authorization_servers: import_zod2.z.array(import_zod2.z.string().url()),
655
+ scopes_supported: import_zod2.z.array(import_zod2.z.string()).optional(),
656
+ bearer_methods_supported: import_zod2.z.array(import_zod2.z.string()).optional(),
657
+ resource_signing_alg_values_supported: import_zod2.z.array(import_zod2.z.string()).optional(),
658
+ resource_documentation: import_zod2.z.string().url().optional()
659
+ });
660
+ var InternalTokenValidationRequestSchema = import_zod2.z.object({
661
+ access_token: import_zod2.z.string().min(1)
662
+ });
663
+ var InternalTokenValidationResponseSchema = import_zod2.z.object({
664
+ valid: import_zod2.z.boolean(),
665
+ userId: import_zod2.z.string().optional(),
666
+ userEmail: import_zod2.z.string().optional(),
667
+ userName: import_zod2.z.string().optional(),
668
+ scope: import_zod2.z.string().optional(),
669
+ permissions: import_zod2.z.string().optional(),
670
+ clientId: import_zod2.z.string().optional(),
671
+ expiresAt: import_zod2.z.string().optional()
672
+ });
673
+
674
+ // ../../packages/core/dist/validation/index.js
675
+ var ListProjectsInputSchema = import_zod3.z.object({
676
+ workspaceType: import_zod3.z.preprocess((val) => typeof val === "string" ? val.toUpperCase() : val, import_zod3.z.enum(["TEAM", "PERSONAL", "ALL"]).optional())
677
+ });
678
+ var ListTasksInputSchema = import_zod3.z.object({
679
+ projectId: import_zod3.z.string().optional(),
680
+ state: import_zod3.z.nativeEnum(TaskState).optional(),
681
+ assigneeId: import_zod3.z.string().optional(),
682
+ includeArchived: import_zod3.z.boolean().optional()
683
+ });
684
+ var cuidOrPrefixedId = import_zod3.z.string().regex(/^([a-z0-9]+|[a-z]+_[a-zA-Z0-9]+)$/);
685
+ var gitBranchName = import_zod3.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");
686
+ var GetTaskInputSchema = import_zod3.z.object({
495
687
  taskId: cuidOrPrefixedId
496
688
  });
497
- var AssignTaskInputSchema = import_zod2.z.object({
689
+ var AssignTaskInputSchema = import_zod3.z.object({
498
690
  projectId: cuidOrPrefixedId,
499
691
  taskId: cuidOrPrefixedId,
500
- expectedState: import_zod2.z.nativeEnum(TaskState).default(TaskState.TODO)
692
+ expectedState: import_zod3.z.nativeEnum(TaskState).default(TaskState.TODO)
501
693
  });
502
- var UpdateProgressInputSchema = import_zod2.z.object({
694
+ var UpdateProgressInputSchema = import_zod3.z.object({
503
695
  taskId: cuidOrPrefixedId,
504
- statusMessage: import_zod2.z.string().max(1e3).optional(),
505
- completedCheckpointIds: import_zod2.z.array(import_zod2.z.string()).optional(),
506
- currentCheckpointIndex: import_zod2.z.number().int().optional()
696
+ statusMessage: import_zod3.z.string().max(1e3).optional(),
697
+ completedCheckpointIds: import_zod3.z.array(import_zod3.z.string()).optional(),
698
+ currentCheckpointIndex: import_zod3.z.number().int().optional()
507
699
  });
508
- var CompleteTaskInputSchema = import_zod2.z.object({
700
+ var CompleteTaskInputSchema = import_zod3.z.object({
509
701
  projectId: cuidOrPrefixedId,
510
702
  taskId: cuidOrPrefixedId,
511
- pullRequestTitle: import_zod2.z.string().min(1).max(300).optional(),
512
- pullRequestBody: import_zod2.z.string().max(1e4).optional()
703
+ pullRequestTitle: import_zod3.z.string().min(1).max(300).optional(),
704
+ pullRequestBody: import_zod3.z.string().max(1e4).optional()
513
705
  });
514
- var ReportErrorInputSchema = import_zod2.z.object({
706
+ var ReportErrorInputSchema = import_zod3.z.object({
515
707
  taskId: cuidOrPrefixedId,
516
- errorType: import_zod2.z.nativeEnum(ErrorType),
517
- errorMessage: import_zod2.z.string().min(1).max(1e3),
518
- context: import_zod2.z.string().max(2e3).optional()
708
+ errorType: import_zod3.z.nativeEnum(ErrorType),
709
+ errorMessage: import_zod3.z.string().min(1).max(1e3),
710
+ context: import_zod3.z.string().max(2e3).optional()
519
711
  });
520
- var GetProjectContextInputSchema = import_zod2.z.object({
712
+ var GetProjectContextInputSchema = import_zod3.z.object({
521
713
  projectId: cuidOrPrefixedId
522
714
  });
523
- var AddNoteInputSchema = import_zod2.z.object({
715
+ var AddNoteInputSchema = import_zod3.z.object({
524
716
  taskId: cuidOrPrefixedId,
525
- content: import_zod2.z.string().min(1).max(500)
717
+ content: import_zod3.z.string().min(1).max(500)
526
718
  });
527
- var AbandonTaskInputSchema = import_zod2.z.object({
719
+ var AbandonTaskInputSchema = import_zod3.z.object({
528
720
  projectId: cuidOrPrefixedId,
529
721
  taskId: cuidOrPrefixedId,
530
- deleteBranch: import_zod2.z.boolean().optional()
722
+ deleteBranch: import_zod3.z.boolean().optional()
531
723
  });
532
- var RequestChangesInputSchema = import_zod2.z.object({
724
+ var RequestChangesInputSchema = import_zod3.z.object({
533
725
  projectId: cuidOrPrefixedId,
534
726
  taskId: cuidOrPrefixedId,
535
- reviewComments: import_zod2.z.string().min(1).max(5e3),
536
- requestedChanges: import_zod2.z.array(import_zod2.z.string().min(1).max(500)).optional()
727
+ reviewComments: import_zod3.z.string().min(1).max(5e3),
728
+ requestedChanges: import_zod3.z.array(import_zod3.z.string().min(1).max(500)).optional()
537
729
  });
538
- var ApproveTaskInputSchema = import_zod2.z.object({
730
+ var ApproveTaskInputSchema = import_zod3.z.object({
539
731
  projectId: cuidOrPrefixedId,
540
732
  taskId: cuidOrPrefixedId,
541
- reviewComments: import_zod2.z.string().max(2e3).optional()
733
+ reviewComments: import_zod3.z.string().max(2e3).optional()
542
734
  });
543
- var ArchiveTaskInputSchema = import_zod2.z.object({
735
+ var ArchiveTaskInputSchema = import_zod3.z.object({
544
736
  projectId: cuidOrPrefixedId,
545
737
  taskId: cuidOrPrefixedId
546
738
  });
547
- var UnarchiveTaskInputSchema = import_zod2.z.object({
739
+ var UnarchiveTaskInputSchema = import_zod3.z.object({
548
740
  projectId: cuidOrPrefixedId,
549
741
  taskId: cuidOrPrefixedId
550
742
  });
551
- var CreatePersonalProjectInputSchema = import_zod2.z.object({
552
- name: import_zod2.z.string().min(1).max(100),
553
- description: import_zod2.z.string().max(500).optional(),
554
- repositoryUrl: import_zod2.z.string().url()
743
+ var CreatePersonalProjectInputSchema = import_zod3.z.object({
744
+ name: import_zod3.z.string().min(1).max(100),
745
+ description: import_zod3.z.string().max(500).optional(),
746
+ repositoryUrl: import_zod3.z.string().url()
555
747
  });
556
- var CheckActiveTaskInputSchema = import_zod2.z.object({});
557
- var CreateTaskMCPInputSchema = import_zod2.z.object({
748
+ var CheckActiveTaskInputSchema = import_zod3.z.object({});
749
+ var CreateTaskMCPInputSchema = import_zod3.z.object({
558
750
  projectId: cuidOrPrefixedId,
559
751
  epicId: cuidOrPrefixedId.nullable().optional(),
560
- title: import_zod2.z.string().min(1).max(200),
561
- description: import_zod2.z.string().max(5e3),
562
- priority: import_zod2.z.nativeEnum(TaskPriority).default(TaskPriority.MEDIUM),
563
- acceptanceCriteria: import_zod2.z.array(import_zod2.z.object({
564
- description: import_zod2.z.string().min(1).max(500)
752
+ title: import_zod3.z.string().min(1).max(200),
753
+ description: import_zod3.z.string().max(5e3),
754
+ priority: import_zod3.z.nativeEnum(TaskPriority).default(TaskPriority.MEDIUM),
755
+ acceptanceCriteria: import_zod3.z.array(import_zod3.z.object({
756
+ description: import_zod3.z.string().min(1).max(500)
565
757
  })).min(1)
566
758
  });
567
- var CreateOrganizationInputSchema = import_zod2.z.object({
568
- name: import_zod2.z.string().min(1).max(255),
569
- slug: import_zod2.z.string().min(1).max(100).regex(/^[a-z0-9-]+$/).optional()
759
+ var CreateOrganizationInputSchema = import_zod3.z.object({
760
+ name: import_zod3.z.string().min(1).max(255)
570
761
  });
571
- var UpdateOrganizationInputSchema = import_zod2.z.object({
762
+ var UpdateOrganizationInputSchema = import_zod3.z.object({
572
763
  organizationId: cuidOrPrefixedId,
573
- name: import_zod2.z.string().min(1).max(255).optional(),
574
- logoUrl: import_zod2.z.string().url().nullable().optional(),
575
- accentColor: import_zod2.z.string().regex(/^#[0-9A-Fa-f]{6}$/, "Invalid hex color format. Expected #RRGGBB").nullable().optional(),
576
- tenantName: import_zod2.z.string().max(255).nullable().optional()
577
- });
578
- var CreateProjectInputSchema = import_zod2.z.object({
579
- name: import_zod2.z.string().min(1).max(100),
580
- description: import_zod2.z.string().max(500).optional(),
581
- type: import_zod2.z.nativeEnum(ProjectType),
582
- repositoryUrl: import_zod2.z.string().url(),
583
- baseBranch: import_zod2.z.string().default("develop").optional(),
584
- tags: import_zod2.z.array(import_zod2.z.string()).default([])
585
- });
586
- var UpdateProjectInputSchema = import_zod2.z.object({
587
- projectId: import_zod2.z.string().min(1).optional(),
588
- name: import_zod2.z.string().min(1).max(100).optional(),
589
- description: import_zod2.z.string().max(500).optional(),
590
- repositoryUrl: import_zod2.z.string().url().optional(),
591
- baseBranch: import_zod2.z.string().optional(),
592
- tags: import_zod2.z.array(import_zod2.z.string()).optional(),
593
- allowMemberArchive: import_zod2.z.boolean().optional()
594
- });
595
- var CreateEpicInputSchema = import_zod2.z.object({
764
+ name: import_zod3.z.string().min(1).max(255).optional(),
765
+ logoUrl: import_zod3.z.string().url().nullable().optional(),
766
+ accentColor: import_zod3.z.string().regex(/^#[0-9A-Fa-f]{6}$/, "Invalid hex color format. Expected #RRGGBB").nullable().optional(),
767
+ tenantName: import_zod3.z.string().max(255).nullable().optional()
768
+ });
769
+ var CreateProjectInputSchema = import_zod3.z.object({
770
+ name: import_zod3.z.string().min(1).max(100),
771
+ description: import_zod3.z.string().max(500).optional(),
772
+ type: import_zod3.z.nativeEnum(ProjectType),
773
+ repositoryUrl: import_zod3.z.string().url(),
774
+ baseBranch: import_zod3.z.string().default("develop").optional(),
775
+ tags: import_zod3.z.array(import_zod3.z.string()).default([])
776
+ });
777
+ var UpdateProjectInputSchema = import_zod3.z.object({
778
+ projectId: import_zod3.z.string().min(1).optional(),
779
+ name: import_zod3.z.string().min(1).max(100).optional(),
780
+ description: import_zod3.z.string().max(500).optional(),
781
+ repositoryUrl: import_zod3.z.string().url().optional(),
782
+ baseBranch: import_zod3.z.string().optional(),
783
+ tags: import_zod3.z.array(import_zod3.z.string()).optional(),
784
+ allowMemberArchive: import_zod3.z.boolean().optional()
785
+ });
786
+ var CreateEpicInputSchema = import_zod3.z.object({
596
787
  projectId: cuidOrPrefixedId,
597
- name: import_zod2.z.string().min(1).max(200),
598
- description: import_zod2.z.string().max(2e3).optional()
599
- });
600
- var CreateTaskInputSchema = import_zod2.z.object({
601
- projectId: import_zod2.z.string().min(1),
602
- epicId: import_zod2.z.string().min(1).nullable().optional(),
603
- title: import_zod2.z.string().min(1).max(200),
604
- description: import_zod2.z.string().max(5e3),
605
- priority: import_zod2.z.nativeEnum(TaskPriority).default(TaskPriority.MEDIUM),
606
- acceptanceCriteria: import_zod2.z.array(import_zod2.z.object({
607
- description: import_zod2.z.string().min(1).max(500)
788
+ name: import_zod3.z.string().min(1).max(200),
789
+ description: import_zod3.z.string().max(2e3).optional()
790
+ });
791
+ var CreateTaskInputSchema = import_zod3.z.object({
792
+ projectId: import_zod3.z.string().min(1),
793
+ epicId: import_zod3.z.string().min(1).nullable().optional(),
794
+ title: import_zod3.z.string().min(1).max(200),
795
+ description: import_zod3.z.string().max(5e3),
796
+ priority: import_zod3.z.nativeEnum(TaskPriority).default(TaskPriority.MEDIUM),
797
+ acceptanceCriteria: import_zod3.z.array(import_zod3.z.object({
798
+ description: import_zod3.z.string().min(1).max(500)
608
799
  })).min(1)
609
800
  });
610
- var UpdateTaskInputSchema = import_zod2.z.object({
611
- taskId: import_zod2.z.string().min(1),
612
- title: import_zod2.z.string().min(1).max(200).optional(),
613
- description: import_zod2.z.string().max(5e3).optional(),
614
- priority: import_zod2.z.nativeEnum(TaskPriority).optional(),
615
- state: import_zod2.z.nativeEnum(TaskState).optional(),
616
- assigneeId: import_zod2.z.string().nullable().optional(),
617
- acceptanceCriteria: import_zod2.z.array(import_zod2.z.object({
618
- id: import_zod2.z.string().optional(),
619
- description: import_zod2.z.string().min(1).max(500),
620
- completed: import_zod2.z.boolean().optional()
801
+ var UpdateTaskInputSchema = import_zod3.z.object({
802
+ taskId: import_zod3.z.string().min(1),
803
+ title: import_zod3.z.string().min(1).max(200).optional(),
804
+ description: import_zod3.z.string().max(5e3).optional(),
805
+ priority: import_zod3.z.nativeEnum(TaskPriority).optional(),
806
+ state: import_zod3.z.nativeEnum(TaskState).optional(),
807
+ assigneeId: import_zod3.z.string().nullable().optional(),
808
+ acceptanceCriteria: import_zod3.z.array(import_zod3.z.object({
809
+ id: import_zod3.z.string().optional(),
810
+ description: import_zod3.z.string().min(1).max(500),
811
+ completed: import_zod3.z.boolean().optional()
621
812
  })).optional()
622
813
  });
623
- var AssignTaskWebappInputSchema = import_zod2.z.object({
624
- taskId: import_zod2.z.string().min(1),
625
- userId: import_zod2.z.string().min(1)
814
+ var AssignTaskWebappInputSchema = import_zod3.z.object({
815
+ taskId: import_zod3.z.string().min(1),
816
+ userId: import_zod3.z.string().min(1)
626
817
  });
627
- var CreateTagInputSchema = import_zod2.z.object({
818
+ var CreateTagInputSchema = import_zod3.z.object({
628
819
  organizationId: cuidOrPrefixedId,
629
- name: import_zod2.z.string().min(1).max(50).regex(/^[a-zA-Z0-9\s-]+$/)
820
+ name: import_zod3.z.string().min(1).max(50).regex(/^[a-zA-Z0-9\s-]+$/)
630
821
  });
631
- var UpdateTagInputSchema = import_zod2.z.object({
632
- name: import_zod2.z.string().min(1).max(50).regex(/^[a-zA-Z0-9\s-]+$/)
822
+ var UpdateTagInputSchema = import_zod3.z.object({
823
+ name: import_zod3.z.string().min(1).max(50).regex(/^[a-zA-Z0-9\s-]+$/)
633
824
  });
634
- var UpdateOrganizationSettingsInputSchema = import_zod2.z.object({
825
+ var UpdateOrganizationSettingsInputSchema = import_zod3.z.object({
635
826
  organizationId: cuidOrPrefixedId,
636
- ldapEnabled: import_zod2.z.boolean().optional(),
637
- ldapUrl: import_zod2.z.string().url().nullable().optional(),
638
- ldapBindDN: import_zod2.z.string().nullable().optional(),
639
- ldapSearchBase: import_zod2.z.string().nullable().optional(),
640
- deleteMergedBranches: import_zod2.z.boolean().optional(),
641
- enforceConventionalCommits: import_zod2.z.boolean().optional(),
642
- maxPersonalProjectsPerUser: import_zod2.z.number().int().min(0).optional(),
643
- logoUrl: import_zod2.z.string().url().nullable().optional(),
644
- accentColor: import_zod2.z.string().regex(/^#[0-9A-Fa-f]{6}$/, "Invalid hex color format. Expected #RRGGBB").nullable().optional(),
645
- tenantName: import_zod2.z.string().max(255).nullable().optional()
646
- });
647
- var InviteUserInputSchema = import_zod2.z.object({
827
+ ldapEnabled: import_zod3.z.boolean().optional(),
828
+ ldapUrl: import_zod3.z.string().url().nullable().optional(),
829
+ ldapBindDN: import_zod3.z.string().nullable().optional(),
830
+ ldapSearchBase: import_zod3.z.string().nullable().optional(),
831
+ deleteMergedBranches: import_zod3.z.boolean().optional(),
832
+ enforceConventionalCommits: import_zod3.z.boolean().optional(),
833
+ maxPersonalProjectsPerUser: import_zod3.z.number().int().min(0).optional(),
834
+ logoUrl: import_zod3.z.string().url().nullable().optional(),
835
+ accentColor: import_zod3.z.string().regex(/^#[0-9A-Fa-f]{6}$/, "Invalid hex color format. Expected #RRGGBB").nullable().optional(),
836
+ tenantName: import_zod3.z.string().max(255).nullable().optional()
837
+ });
838
+ var InviteUserInputSchema = import_zod3.z.object({
648
839
  organizationId: cuidOrPrefixedId,
649
- email: import_zod2.z.string().email(),
650
- role: import_zod2.z.nativeEnum(UserRole).default(UserRole.MEMBER),
651
- tags: import_zod2.z.array(import_zod2.z.string()).default([])
840
+ email: import_zod3.z.string().email(),
841
+ role: import_zod3.z.nativeEnum(UserRole).default(UserRole.MEMBER),
842
+ tags: import_zod3.z.array(import_zod3.z.string()).default([])
652
843
  });
653
- var AssignUserTagsInputSchema = import_zod2.z.object({
844
+ var AssignUserTagsInputSchema = import_zod3.z.object({
654
845
  userId: cuidOrPrefixedId,
655
- tags: import_zod2.z.array(import_zod2.z.string()).min(0)
846
+ tags: import_zod3.z.array(import_zod3.z.string()).min(0)
656
847
  });
657
- var InviteCollaboratorInputSchema = import_zod2.z.object({
848
+ var InviteCollaboratorInputSchema = import_zod3.z.object({
658
849
  projectId: cuidOrPrefixedId,
659
- email: import_zod2.z.string().email()
850
+ email: import_zod3.z.string().email()
660
851
  });
661
- var PublishProjectInputSchema = import_zod2.z.object({
852
+ var PublishProjectInputSchema = import_zod3.z.object({
662
853
  projectId: cuidOrPrefixedId,
663
- transferOwnership: import_zod2.z.boolean().default(false),
664
- tags: import_zod2.z.array(import_zod2.z.string()).min(1)
854
+ transferOwnership: import_zod3.z.boolean().default(false),
855
+ tags: import_zod3.z.array(import_zod3.z.string()).min(1)
856
+ });
857
+ var GenerateApiKeyInputSchema = import_zod3.z.object({
858
+ name: import_zod3.z.string().min(1).max(100),
859
+ publicNickname: import_zod3.z.string().max(50).optional(),
860
+ expiresInDays: import_zod3.z.number().int().min(1).max(365).default(90),
861
+ permissions: import_zod3.z.nativeEnum(ApiKeyPermission).default(ApiKeyPermission.WRITE)
665
862
  });
666
- var GenerateApiKeyInputSchema = import_zod2.z.object({
667
- name: import_zod2.z.string().min(1).max(100),
668
- expiresInDays: import_zod2.z.number().int().min(1).max(365).default(90),
669
- permissions: import_zod2.z.nativeEnum(ApiKeyPermission).default(ApiKeyPermission.WRITE)
863
+ var UpdateApiKeyInputSchema = import_zod3.z.object({
864
+ publicNickname: import_zod3.z.string().max(50).nullable().optional(),
865
+ scopedOrganizationId: import_zod3.z.string().optional().nullable(),
866
+ scopedProjectIds: import_zod3.z.array(import_zod3.z.string()).optional()
670
867
  });
671
- var RevokeApiKeyInputSchema = import_zod2.z.object({
868
+ var RevokeApiKeyInputSchema = import_zod3.z.object({
672
869
  keyId: cuidOrPrefixedId
673
870
  });
674
- var LoginInputSchema = import_zod2.z.object({
675
- email: import_zod2.z.string().email(),
676
- password: import_zod2.z.string().min(8).max(255)
871
+ var LoginInputSchema = import_zod3.z.object({
872
+ email: import_zod3.z.string().email(),
873
+ password: import_zod3.z.string().min(8).max(255)
677
874
  });
678
- var RegisterInputSchema = import_zod2.z.object({
679
- email: import_zod2.z.string().email(),
680
- password: import_zod2.z.string().min(8).max(255),
681
- name: import_zod2.z.string().min(1).max(255),
682
- organizationSlug: import_zod2.z.string().min(1).max(100).regex(/^[a-z0-9-]+$/).optional()
875
+ var RegisterInputSchema = import_zod3.z.object({
876
+ email: import_zod3.z.string().email(),
877
+ password: import_zod3.z.string().min(8).max(255),
878
+ name: import_zod3.z.string().min(1).max(255)
683
879
  });
684
- var VerifyTaskInputSchema = import_zod2.z.object({
880
+ var VerifyTaskInputSchema = import_zod3.z.object({
685
881
  projectId: cuidOrPrefixedId,
686
882
  taskId: cuidOrPrefixedId,
687
- approved: import_zod2.z.boolean(),
688
- feedback: import_zod2.z.string().max(5e3).optional()
883
+ approved: import_zod3.z.boolean(),
884
+ feedback: import_zod3.z.string().max(5e3).optional()
689
885
  });
690
- var GetTaskPromptInputSchema = import_zod2.z.object({
886
+ var GetTaskPromptInputSchema = import_zod3.z.object({
691
887
  projectId: cuidOrPrefixedId,
692
888
  taskId: cuidOrPrefixedId
693
889
  });
694
- var UpdateTaskMCPInputSchema = import_zod2.z.object({
890
+ var UpdateTaskMCPInputSchema = import_zod3.z.object({
695
891
  projectId: cuidOrPrefixedId,
696
892
  taskId: cuidOrPrefixedId,
697
- title: import_zod2.z.string().min(1).max(200).optional(),
698
- description: import_zod2.z.string().max(5e3).optional(),
699
- priority: import_zod2.z.nativeEnum(TaskPriority).optional(),
700
- acceptanceCriteria: import_zod2.z.array(import_zod2.z.object({
701
- id: import_zod2.z.string().optional(),
702
- description: import_zod2.z.string().min(1).max(500)
893
+ title: import_zod3.z.string().min(1).max(200).optional(),
894
+ description: import_zod3.z.string().max(5e3).optional(),
895
+ priority: import_zod3.z.nativeEnum(TaskPriority).optional(),
896
+ acceptanceCriteria: import_zod3.z.array(import_zod3.z.object({
897
+ id: import_zod3.z.string().optional(),
898
+ description: import_zod3.z.string().min(1).max(500)
703
899
  })).optional()
704
900
  });
705
- var ReportBranchInputSchema = import_zod2.z.object({
901
+ var ReportBranchInputSchema = import_zod3.z.object({
706
902
  projectId: cuidOrPrefixedId,
707
903
  taskId: cuidOrPrefixedId,
708
904
  branchName: gitBranchName
709
905
  });
710
- var ReportPRInputSchema = import_zod2.z.object({
906
+ var ReportPRInputSchema = import_zod3.z.object({
711
907
  projectId: cuidOrPrefixedId,
712
908
  taskId: cuidOrPrefixedId,
713
- pullRequestUrl: import_zod2.z.string().url(),
714
- pullRequestNumber: import_zod2.z.number().int().positive()
909
+ pullRequestUrl: import_zod3.z.string().url(),
910
+ pullRequestNumber: import_zod3.z.number().int().positive()
715
911
  });
716
912
 
717
913
  // ../../packages/core/dist/logging/metrics.js
@@ -792,23 +988,16 @@ function createHistogram(name, help, buckets = [5e-3, 0.01, 0.025, 0.05, 0.1, 0.
792
988
  var httpRequestsTotal = createCounter("mtaap_http_requests_total", "Total number of HTTP requests");
793
989
  var httpRequestDuration = createHistogram("mtaap_http_request_duration_seconds", "HTTP request duration in seconds");
794
990
  var activeUsers = createGauge("mtaap_active_users", "Number of active users");
795
- var tasksTotal = createCounter("mtaap_tasks_total", "Total number of tasks by state");
796
- var taskStateChanges = createCounter("mtaap_task_state_changes_total", "Total number of task state changes");
797
991
  var httpErrorsTotal = createCounter("mtaap_http_errors_total", "Total number of HTTP errors");
798
992
  var httpActiveConnections = createGauge("mtaap_http_active_connections", "Number of active HTTP connections");
799
993
  var newSignupsTotal = createCounter("mtaap_new_signups_total", "Total number of new user signups");
800
994
  var loginSuccessTotal = createCounter("mtaap_login_success_total", "Total number of successful logins");
801
995
  var loginFailureTotal = createCounter("mtaap_login_failure_total", "Total number of failed logins");
802
- var dbConnectionPoolActive = createGauge("mtaap_db_connection_pool_active", "Number of active database connections");
803
- var dbConnectionPoolIdle = createGauge("mtaap_db_connection_pool_idle", "Number of idle database connections");
804
- var dbConnectionPoolMax = createGauge("mtaap_db_connection_pool_max", "Maximum number of database connections");
805
996
  var dbQueryDuration = createHistogram("mtaap_db_query_duration_seconds", "Database query duration in seconds");
806
997
  var dbSlowQueriesTotal = createCounter("mtaap_db_slow_queries_total", "Total number of slow database queries (>1s)");
807
- var dbErrorsTotal = createCounter("mtaap_db_errors_total", "Total number of database errors");
808
998
  var tasksCreatedTotal = createCounter("mtaap_tasks_created_total", "Total number of tasks created");
809
999
  var tasksAssignedTotal = createCounter("mtaap_tasks_assigned_total", "Total number of tasks assigned");
810
1000
  var tasksCompletedTotal = createCounter("mtaap_tasks_completed_total", "Total number of tasks completed");
811
- var tasksByState = createGauge("mtaap_tasks_by_state", "Number of tasks by state");
812
1001
 
813
1002
  // ../../packages/core/dist/logging/performance-monitor.js
814
1003
  var MAX_SAMPLES = 1e3;
@@ -1030,12 +1219,17 @@ var ApiError = class extends Error {
1030
1219
  var MCPApiClient = class {
1031
1220
  baseUrl;
1032
1221
  apiKey;
1222
+ oauthToken;
1033
1223
  timeout;
1034
1224
  debug;
1035
1225
  authContext = null;
1036
1226
  constructor(config3) {
1227
+ if (!config3.apiKey && !config3.oauthToken) {
1228
+ throw new Error("Either apiKey or oauthToken must be provided");
1229
+ }
1037
1230
  this.baseUrl = config3.baseUrl.replace(/\/$/, "");
1038
1231
  this.apiKey = config3.apiKey;
1232
+ this.oauthToken = config3.oauthToken;
1039
1233
  this.timeout = config3.timeout ?? DEFAULT_TIMEOUT;
1040
1234
  this.debug = config3.debug ?? false;
1041
1235
  }
@@ -1050,18 +1244,33 @@ var MCPApiClient = class {
1050
1244
  console.error(`[mcp-api] ${method} ${sanitizeForLogging(path)}`);
1051
1245
  }
1052
1246
  try {
1247
+ const headers = {
1248
+ "Content-Type": "application/json"
1249
+ };
1250
+ if (this.oauthToken) {
1251
+ headers["Authorization"] = `Bearer ${this.oauthToken}`;
1252
+ } else if (this.apiKey) {
1253
+ headers["X-API-Key"] = this.apiKey;
1254
+ }
1053
1255
  const response = await fetch(url, {
1054
1256
  method,
1055
- headers: {
1056
- "Content-Type": "application/json",
1057
- "X-API-Key": this.apiKey
1058
- },
1257
+ headers,
1059
1258
  body: body ? JSON.stringify(body) : void 0,
1060
1259
  signal: controller.signal
1061
1260
  });
1062
1261
  clearTimeout(timeoutId);
1063
1262
  const data = await response.json();
1064
1263
  if (!response.ok) {
1264
+ if (response.status === 403 && data.code === "EMAIL_NOT_VERIFIED" && data.verificationUrl) {
1265
+ throw new ApiError(
1266
+ `${data.error}
1267
+
1268
+ To verify your email, visit: ${data.verificationUrl}
1269
+ ${data.hint ? `Hint: ${data.hint}` : ""}`,
1270
+ "EMAIL_NOT_VERIFIED",
1271
+ 403
1272
+ );
1273
+ }
1065
1274
  throw new ApiError(
1066
1275
  data.error || "API request failed",
1067
1276
  data.code || "UNKNOWN_ERROR",
@@ -1309,7 +1518,7 @@ var PERMISSION_RANK = {
1309
1518
  ADMIN: 3
1310
1519
  };
1311
1520
  function assertApiKeyPermission(apiKey, required, toolName) {
1312
- const actualRank = PERMISSION_RANK[apiKey.permissions] ?? 0;
1521
+ const actualRank = apiKey.permissions ? PERMISSION_RANK[apiKey.permissions] ?? 0 : 0;
1313
1522
  const requiredRank = PERMISSION_RANK[required] ?? 0;
1314
1523
  if (actualRank >= requiredRank) {
1315
1524
  return;
@@ -1430,7 +1639,7 @@ function initializeMCPServer(apiClient, authContext) {
1430
1639
  {
1431
1640
  description: "Discover all accessible projects. Use first to find project IDs. Filter by TEAM, PERSONAL, or ALL workspaces.",
1432
1641
  inputSchema: {
1433
- workspaceType: import_zod3.z.enum(["TEAM", "PERSONAL", "ALL"]).optional().describe("Filter by workspace type")
1642
+ workspaceType: import_zod4.z.enum(["TEAM", "PERSONAL", "ALL"]).optional().describe("Filter by workspace type")
1434
1643
  }
1435
1644
  },
1436
1645
  async (args) => {
@@ -1460,10 +1669,10 @@ function initializeMCPServer(apiClient, authContext) {
1460
1669
  {
1461
1670
  description: "Query tasks with filters. Use state=TODO for assignable tasks, state=REVIEW for pending reviews.",
1462
1671
  inputSchema: {
1463
- projectId: import_zod3.z.string().optional().describe("Filter by project ID"),
1464
- state: import_zod3.z.nativeEnum(TaskState).optional().describe("Filter by task state"),
1465
- assigneeId: import_zod3.z.string().optional().describe("Filter by assignee ID"),
1466
- includeArchived: import_zod3.z.boolean().optional().describe("Include archived tasks (default: false)")
1672
+ projectId: import_zod4.z.string().optional().describe("Filter by project ID"),
1673
+ state: import_zod4.z.nativeEnum(TaskState).optional().describe("Filter by task state"),
1674
+ assigneeId: import_zod4.z.string().optional().describe("Filter by assignee ID"),
1675
+ includeArchived: import_zod4.z.boolean().optional().describe("Include archived tasks (default: false)")
1467
1676
  }
1468
1677
  },
1469
1678
  async (args) => {
@@ -1494,7 +1703,7 @@ function initializeMCPServer(apiClient, authContext) {
1494
1703
  {
1495
1704
  description: "Get complete task details with acceptance criteria and notes. Call before assign_task to understand requirements.",
1496
1705
  inputSchema: {
1497
- taskId: import_zod3.z.string().describe("The task ID to retrieve")
1706
+ taskId: import_zod4.z.string().describe("The task ID to retrieve")
1498
1707
  }
1499
1708
  },
1500
1709
  async (args) => {
@@ -1520,9 +1729,9 @@ function initializeMCPServer(apiClient, authContext) {
1520
1729
  {
1521
1730
  description: "Atomically claim a task. Race-safe - fails if already assigned. Task must be TODO. Returns suggested branch name and worktree path for isolated parallel development.",
1522
1731
  inputSchema: {
1523
- projectId: import_zod3.z.string().describe("The project ID"),
1524
- taskId: import_zod3.z.string().describe("The task ID to assign"),
1525
- expectedState: import_zod3.z.nativeEnum(TaskState).optional().describe("Expected task state (default: TODO)")
1732
+ projectId: import_zod4.z.string().describe("The project ID"),
1733
+ taskId: import_zod4.z.string().describe("The task ID to assign"),
1734
+ expectedState: import_zod4.z.nativeEnum(TaskState).optional().describe("Expected task state (default: TODO)")
1526
1735
  }
1527
1736
  },
1528
1737
  async (args) => {
@@ -1556,10 +1765,10 @@ function initializeMCPServer(apiClient, authContext) {
1556
1765
  {
1557
1766
  description: "Report progress and checkpoint work. Call frequently during execution. Marks acceptance criteria complete.",
1558
1767
  inputSchema: {
1559
- taskId: import_zod3.z.string().describe("The task ID to update"),
1560
- statusMessage: import_zod3.z.string().optional().describe("Status message (max 1000 chars)"),
1561
- completedCheckpointIds: import_zod3.z.array(import_zod3.z.string()).optional().describe("Array of completed checkpoint IDs"),
1562
- currentCheckpointIndex: import_zod3.z.number().optional().describe("Current checkpoint index")
1768
+ taskId: import_zod4.z.string().describe("The task ID to update"),
1769
+ statusMessage: import_zod4.z.string().optional().describe("Status message (max 1000 chars)"),
1770
+ completedCheckpointIds: import_zod4.z.array(import_zod4.z.string()).optional().describe("Array of completed checkpoint IDs"),
1771
+ currentCheckpointIndex: import_zod4.z.number().optional().describe("Current checkpoint index")
1563
1772
  }
1564
1773
  },
1565
1774
  async (args) => {
@@ -1593,10 +1802,10 @@ function initializeMCPServer(apiClient, authContext) {
1593
1802
  {
1594
1803
  description: "Prepare task for PR creation. Returns PR suggestions. After creating PR locally, call report_pr to transition to REVIEW. Requires IN_PROGRESS state.",
1595
1804
  inputSchema: {
1596
- projectId: import_zod3.z.string().describe("The project ID"),
1597
- taskId: import_zod3.z.string().describe("The task ID to complete"),
1598
- pullRequestTitle: import_zod3.z.string().optional().describe("PR title (max 300 chars)"),
1599
- pullRequestBody: import_zod3.z.string().optional().describe("PR body/description (max 10000 chars)")
1805
+ projectId: import_zod4.z.string().describe("The project ID"),
1806
+ taskId: import_zod4.z.string().describe("The task ID to complete"),
1807
+ pullRequestTitle: import_zod4.z.string().optional().describe("PR title (max 300 chars)"),
1808
+ pullRequestBody: import_zod4.z.string().optional().describe("PR body/description (max 10000 chars)")
1600
1809
  }
1601
1810
  },
1602
1811
  async (args) => {
@@ -1653,10 +1862,10 @@ function initializeMCPServer(apiClient, authContext) {
1653
1862
  {
1654
1863
  description: "Report unrecoverable errors (BUILD_FAILURE, TEST_FAILURE, CONFLICT, AUTH_ERROR). Consider abandon_task after.",
1655
1864
  inputSchema: {
1656
- taskId: import_zod3.z.string().describe("The task ID"),
1657
- errorType: import_zod3.z.nativeEnum(ErrorType).describe("Error type: BUILD_FAILURE, TEST_FAILURE, CONFLICT, AUTH_ERROR, OTHER"),
1658
- errorMessage: import_zod3.z.string().describe("Error message (max 1000 chars)"),
1659
- context: import_zod3.z.string().optional().describe("Additional context (max 2000 chars)")
1865
+ taskId: import_zod4.z.string().describe("The task ID"),
1866
+ errorType: import_zod4.z.nativeEnum(ErrorType).describe("Error type: BUILD_FAILURE, TEST_FAILURE, CONFLICT, AUTH_ERROR, OTHER"),
1867
+ errorMessage: import_zod4.z.string().describe("Error message (max 1000 chars)"),
1868
+ context: import_zod4.z.string().optional().describe("Additional context (max 2000 chars)")
1660
1869
  }
1661
1870
  },
1662
1871
  async (args) => {
@@ -1691,7 +1900,7 @@ function initializeMCPServer(apiClient, authContext) {
1691
1900
  {
1692
1901
  description: "Load project README, tech stack, and coding conventions. Call after selecting project.",
1693
1902
  inputSchema: {
1694
- projectId: import_zod3.z.string().describe("The project ID")
1903
+ projectId: import_zod4.z.string().describe("The project ID")
1695
1904
  }
1696
1905
  },
1697
1906
  async (args) => {
@@ -1721,8 +1930,8 @@ function initializeMCPServer(apiClient, authContext) {
1721
1930
  {
1722
1931
  description: "Document implementation decisions. Notes persist for future reference and handoff.",
1723
1932
  inputSchema: {
1724
- taskId: import_zod3.z.string().describe("The task ID"),
1725
- content: import_zod3.z.string().describe("Note content (max 500 chars)")
1933
+ taskId: import_zod4.z.string().describe("The task ID"),
1934
+ content: import_zod4.z.string().describe("Note content (max 500 chars)")
1726
1935
  }
1727
1936
  },
1728
1937
  async (args) => {
@@ -1751,9 +1960,9 @@ function initializeMCPServer(apiClient, authContext) {
1751
1960
  {
1752
1961
  description: "Release task assignment and optionally clean up branch. Task returns to TODO. Use after errors.",
1753
1962
  inputSchema: {
1754
- projectId: import_zod3.z.string().describe("The project ID"),
1755
- taskId: import_zod3.z.string().describe("The task ID to abandon"),
1756
- deleteBranch: import_zod3.z.boolean().optional().describe("Whether to delete the associated branch")
1963
+ projectId: import_zod4.z.string().describe("The project ID"),
1964
+ taskId: import_zod4.z.string().describe("The task ID to abandon"),
1965
+ deleteBranch: import_zod4.z.boolean().optional().describe("Whether to delete the associated branch")
1757
1966
  }
1758
1967
  },
1759
1968
  async (args) => {
@@ -1787,9 +1996,9 @@ function initializeMCPServer(apiClient, authContext) {
1787
1996
  {
1788
1997
  description: "Report a branch created by the agent. Call after using git to create and push a branch. Task must be IN_PROGRESS.",
1789
1998
  inputSchema: {
1790
- projectId: import_zod3.z.string().describe("The project ID"),
1791
- taskId: import_zod3.z.string().describe("The task ID"),
1792
- branchName: import_zod3.z.string().describe("Name of the branch created (e.g., feature/TASK-123-fix-login)")
1999
+ projectId: import_zod4.z.string().describe("The project ID"),
2000
+ taskId: import_zod4.z.string().describe("The task ID"),
2001
+ branchName: import_zod4.z.string().describe("Name of the branch created (e.g., feature/TASK-123-fix-login)")
1793
2002
  }
1794
2003
  },
1795
2004
  async (args) => {
@@ -1823,10 +2032,10 @@ function initializeMCPServer(apiClient, authContext) {
1823
2032
  {
1824
2033
  description: "Report a PR created by the agent. Call after using gh pr create. Transitions task to REVIEW state.",
1825
2034
  inputSchema: {
1826
- projectId: import_zod3.z.string().describe("The project ID"),
1827
- taskId: import_zod3.z.string().describe("The task ID"),
1828
- pullRequestUrl: import_zod3.z.string().describe("Full URL of the created PR (e.g., https://github.com/owner/repo/pull/123)"),
1829
- pullRequestNumber: import_zod3.z.number().describe("PR number (e.g., 123)")
2035
+ projectId: import_zod4.z.string().describe("The project ID"),
2036
+ taskId: import_zod4.z.string().describe("The task ID"),
2037
+ pullRequestUrl: import_zod4.z.string().describe("Full URL of the created PR (e.g., https://github.com/owner/repo/pull/123)"),
2038
+ pullRequestNumber: import_zod4.z.number().describe("PR number (e.g., 123)")
1830
2039
  }
1831
2040
  },
1832
2041
  async (args) => {
@@ -1861,8 +2070,8 @@ function initializeMCPServer(apiClient, authContext) {
1861
2070
  {
1862
2071
  description: "Soft-delete a task. Hidden but restorable via unarchive_task.",
1863
2072
  inputSchema: {
1864
- projectId: import_zod3.z.string().describe("The project ID"),
1865
- taskId: import_zod3.z.string().describe("The task ID to archive")
2073
+ projectId: import_zod4.z.string().describe("The project ID"),
2074
+ taskId: import_zod4.z.string().describe("The task ID to archive")
1866
2075
  }
1867
2076
  },
1868
2077
  async (args) => {
@@ -1895,8 +2104,8 @@ function initializeMCPServer(apiClient, authContext) {
1895
2104
  {
1896
2105
  description: "Restore previously archived task to original state.",
1897
2106
  inputSchema: {
1898
- projectId: import_zod3.z.string().describe("The project ID"),
1899
- taskId: import_zod3.z.string().describe("The task ID to restore")
2107
+ projectId: import_zod4.z.string().describe("The project ID"),
2108
+ taskId: import_zod4.z.string().describe("The task ID to restore")
1900
2109
  }
1901
2110
  },
1902
2111
  async (args) => {
@@ -1929,9 +2138,9 @@ function initializeMCPServer(apiClient, authContext) {
1929
2138
  {
1930
2139
  description: "Create new project in personal workspace linked to GitHub repository.",
1931
2140
  inputSchema: {
1932
- name: import_zod3.z.string().describe("Project name (max 100 chars)"),
1933
- description: import_zod3.z.string().optional().describe("Project description (max 500 chars)"),
1934
- repositoryUrl: import_zod3.z.string().describe("GitHub repository URL")
2141
+ name: import_zod4.z.string().describe("Project name (max 100 chars)"),
2142
+ description: import_zod4.z.string().optional().describe("Project description (max 500 chars)"),
2143
+ repositoryUrl: import_zod4.z.string().describe("GitHub repository URL")
1935
2144
  }
1936
2145
  },
1937
2146
  async (args) => {
@@ -1965,14 +2174,14 @@ function initializeMCPServer(apiClient, authContext) {
1965
2174
  {
1966
2175
  description: "Create task with title, description, acceptance criteria. Starts in DRAFT. Priority: LOW/MEDIUM/HIGH/CRITICAL.",
1967
2176
  inputSchema: {
1968
- projectId: import_zod3.z.string().describe("The project ID to create the task in"),
1969
- epicId: import_zod3.z.string().nullable().optional().describe("Optional epic ID to associate the task with"),
1970
- title: import_zod3.z.string().describe("Task title (max 200 chars)"),
1971
- description: import_zod3.z.string().describe("Task description (max 5000 chars)"),
1972
- priority: import_zod3.z.nativeEnum(TaskPriority).optional().describe("Task priority: LOW, MEDIUM, HIGH, CRITICAL (default: MEDIUM)"),
1973
- acceptanceCriteria: import_zod3.z.array(
1974
- import_zod3.z.object({
1975
- description: import_zod3.z.string().describe("Acceptance criterion description (max 500 chars)")
2177
+ projectId: import_zod4.z.string().describe("The project ID to create the task in"),
2178
+ epicId: import_zod4.z.string().nullable().optional().describe("Optional epic ID to associate the task with"),
2179
+ title: import_zod4.z.string().describe("Task title (max 200 chars)"),
2180
+ description: import_zod4.z.string().describe("Task description (max 5000 chars)"),
2181
+ priority: import_zod4.z.nativeEnum(TaskPriority).optional().describe("Task priority: LOW, MEDIUM, HIGH, CRITICAL (default: MEDIUM)"),
2182
+ acceptanceCriteria: import_zod4.z.array(
2183
+ import_zod4.z.object({
2184
+ description: import_zod4.z.string().describe("Acceptance criterion description (max 500 chars)")
1976
2185
  })
1977
2186
  ).describe("Array of acceptance criteria (at least 1 required)")
1978
2187
  }
@@ -2011,10 +2220,10 @@ function initializeMCPServer(apiClient, authContext) {
2011
2220
  {
2012
2221
  description: "Return task from REVIEW to IN_PROGRESS with feedback. Original assignee addresses changes.",
2013
2222
  inputSchema: {
2014
- projectId: import_zod3.z.string().describe("The project ID"),
2015
- taskId: import_zod3.z.string().describe("The task ID to review"),
2016
- reviewComments: import_zod3.z.string().describe("Review comments explaining requested changes (max 5000 chars)"),
2017
- requestedChanges: import_zod3.z.array(import_zod3.z.string()).optional().describe("List of specific changes requested")
2223
+ projectId: import_zod4.z.string().describe("The project ID"),
2224
+ taskId: import_zod4.z.string().describe("The task ID to review"),
2225
+ reviewComments: import_zod4.z.string().describe("Review comments explaining requested changes (max 5000 chars)"),
2226
+ requestedChanges: import_zod4.z.array(import_zod4.z.string()).optional().describe("List of specific changes requested")
2018
2227
  }
2019
2228
  },
2020
2229
  async (args) => {
@@ -2049,9 +2258,9 @@ function initializeMCPServer(apiClient, authContext) {
2049
2258
  {
2050
2259
  description: "Approve completed work and mark DONE. Only for REVIEW state tasks.",
2051
2260
  inputSchema: {
2052
- projectId: import_zod3.z.string().describe("The project ID"),
2053
- taskId: import_zod3.z.string().describe("The task ID to approve"),
2054
- reviewComments: import_zod3.z.string().optional().describe("Optional approval comments (max 2000 chars)")
2261
+ projectId: import_zod4.z.string().describe("The project ID"),
2262
+ taskId: import_zod4.z.string().describe("The task ID to approve"),
2263
+ reviewComments: import_zod4.z.string().optional().describe("Optional approval comments (max 2000 chars)")
2055
2264
  }
2056
2265
  },
2057
2266
  async (args) => {
@@ -2085,10 +2294,10 @@ function initializeMCPServer(apiClient, authContext) {
2085
2294
  {
2086
2295
  description: "Verify a DRAFT task and move it to TODO state. Requires task to pass programmatic validation (title 10+ chars, description 50+ chars, each criterion 20+ chars). If approved=false, stores feedback with NEEDS_REVISION status.",
2087
2296
  inputSchema: {
2088
- projectId: import_zod3.z.string().describe("The project ID"),
2089
- taskId: import_zod3.z.string().describe("The task ID to verify"),
2090
- approved: import_zod3.z.boolean().describe("Whether to approve the task"),
2091
- feedback: import_zod3.z.string().optional().describe("Feedback for the task (required if not approved)")
2297
+ projectId: import_zod4.z.string().describe("The project ID"),
2298
+ taskId: import_zod4.z.string().describe("The task ID to verify"),
2299
+ approved: import_zod4.z.boolean().describe("Whether to approve the task"),
2300
+ feedback: import_zod4.z.string().optional().describe("Feedback for the task (required if not approved)")
2092
2301
  }
2093
2302
  },
2094
2303
  async (args) => {
@@ -2119,8 +2328,8 @@ function initializeMCPServer(apiClient, authContext) {
2119
2328
  {
2120
2329
  description: "Get state-appropriate prompt for a task. Returns verify prompt for DRAFT, assignment prompt for TODO, or continue prompt for IN_PROGRESS tasks.",
2121
2330
  inputSchema: {
2122
- projectId: import_zod3.z.string().describe("The project ID"),
2123
- taskId: import_zod3.z.string().describe("The task ID")
2331
+ projectId: import_zod4.z.string().describe("The project ID"),
2332
+ taskId: import_zod4.z.string().describe("The task ID")
2124
2333
  }
2125
2334
  },
2126
2335
  async (args) => {
@@ -2153,15 +2362,15 @@ function initializeMCPServer(apiClient, authContext) {
2153
2362
  {
2154
2363
  description: "Update task details (title, description, priority, acceptanceCriteria). Only works for DRAFT and TODO states. If task is in TODO state, it reverts to DRAFT and requires re-verification.",
2155
2364
  inputSchema: {
2156
- projectId: import_zod3.z.string().describe("The project ID"),
2157
- taskId: import_zod3.z.string().describe("The task ID to update"),
2158
- title: import_zod3.z.string().optional().describe("New task title"),
2159
- description: import_zod3.z.string().optional().describe("New task description"),
2160
- priority: import_zod3.z.nativeEnum(TaskPriority).optional().describe("New task priority"),
2161
- acceptanceCriteria: import_zod3.z.array(
2162
- import_zod3.z.object({
2163
- id: import_zod3.z.string().optional().describe("Existing criterion ID (for updates)"),
2164
- description: import_zod3.z.string().describe("Criterion description")
2365
+ projectId: import_zod4.z.string().describe("The project ID"),
2366
+ taskId: import_zod4.z.string().describe("The task ID to update"),
2367
+ title: import_zod4.z.string().optional().describe("New task title"),
2368
+ description: import_zod4.z.string().optional().describe("New task description"),
2369
+ priority: import_zod4.z.nativeEnum(TaskPriority).optional().describe("New task priority"),
2370
+ acceptanceCriteria: import_zod4.z.array(
2371
+ import_zod4.z.object({
2372
+ id: import_zod4.z.string().optional().describe("Existing criterion ID (for updates)"),
2373
+ description: import_zod4.z.string().describe("Criterion description")
2165
2374
  })
2166
2375
  ).optional().describe("New acceptance criteria (replaces existing)")
2167
2376
  }
@@ -2251,12 +2460,12 @@ function handleApiError(error) {
2251
2460
  isError: true
2252
2461
  };
2253
2462
  }
2254
- var ActiveTaskSchema = import_zod3.z.object({
2255
- taskId: import_zod3.z.string().min(1),
2256
- projectId: import_zod3.z.string().min(1),
2257
- branchName: import_zod3.z.string().optional(),
2258
- worktreePath: import_zod3.z.string().optional(),
2259
- startedAt: import_zod3.z.string().optional()
2463
+ var ActiveTaskSchema = import_zod4.z.object({
2464
+ taskId: import_zod4.z.string().min(1),
2465
+ projectId: import_zod4.z.string().min(1),
2466
+ branchName: import_zod4.z.string().optional(),
2467
+ worktreePath: import_zod4.z.string().optional(),
2468
+ startedAt: import_zod4.z.string().optional()
2260
2469
  });
2261
2470
  async function checkActiveTask() {
2262
2471
  const fs = await import("fs");
@@ -2327,15 +2536,91 @@ async function checkActiveTask() {
2327
2536
  }
2328
2537
 
2329
2538
  // src/auth.ts
2539
+ function extractBearerToken(authorizationHeader) {
2540
+ if (!authorizationHeader) return null;
2541
+ const parts = authorizationHeader.split(" ");
2542
+ if (parts.length !== 2 || parts[0].toLowerCase() !== "bearer") {
2543
+ return null;
2544
+ }
2545
+ return parts[1];
2546
+ }
2547
+ async function validateOAuthToken(baseUrl, accessToken) {
2548
+ const internalUrl = process.env.COLLAB_INTERNAL_URL || baseUrl;
2549
+ const response = await fetch(`${internalUrl}/api/oauth/validate`, {
2550
+ method: "POST",
2551
+ headers: {
2552
+ "Content-Type": "application/json"
2553
+ },
2554
+ body: JSON.stringify({ access_token: accessToken })
2555
+ });
2556
+ if (!response.ok) {
2557
+ throw new Error(`Token validation failed: ${response.status}`);
2558
+ }
2559
+ return response.json();
2560
+ }
2330
2561
  function createAuthMiddleware(baseUrl) {
2331
2562
  return async (req, res, next) => {
2563
+ const authHeader = req.headers.authorization;
2564
+ const bearerToken = extractBearerToken(authHeader);
2565
+ if (bearerToken) {
2566
+ try {
2567
+ const validation = await validateOAuthToken(baseUrl, bearerToken);
2568
+ if (!validation.valid) {
2569
+ res.status(401).json({
2570
+ jsonrpc: "2.0",
2571
+ error: {
2572
+ code: -32001,
2573
+ message: validation.userId ? "Token expired" : "Invalid access token"
2574
+ },
2575
+ id: null
2576
+ });
2577
+ return;
2578
+ }
2579
+ const rawPermissions = validation.permissions || "WRITE";
2580
+ const validPermissions = ["READ", "WRITE", "ADMIN"];
2581
+ let permissions;
2582
+ if (validPermissions.includes(rawPermissions)) {
2583
+ permissions = rawPermissions;
2584
+ } else {
2585
+ console.warn(`[collab-mcp-server] Unexpected permissions value "${rawPermissions}", defaulting to WRITE`);
2586
+ permissions = "WRITE";
2587
+ }
2588
+ const authContext = {
2589
+ userId: validation.userId,
2590
+ userEmail: validation.userEmail,
2591
+ userName: validation.userName || validation.userEmail,
2592
+ permissions
2593
+ };
2594
+ const apiClient = new MCPApiClient({
2595
+ baseUrl,
2596
+ oauthToken: bearerToken,
2597
+ timeout: 3e4
2598
+ });
2599
+ req.apiClient = apiClient;
2600
+ req.authContext = authContext;
2601
+ req.authMethod = "oauth";
2602
+ next();
2603
+ return;
2604
+ } catch (error) {
2605
+ console.error("[collab-mcp-server] OAuth validation error:", error);
2606
+ res.status(401).json({
2607
+ jsonrpc: "2.0",
2608
+ error: {
2609
+ code: -32001,
2610
+ message: "OAuth token validation failed"
2611
+ },
2612
+ id: null
2613
+ });
2614
+ return;
2615
+ }
2616
+ }
2332
2617
  const apiKey = req.headers["x-api-key"];
2333
2618
  if (!apiKey || typeof apiKey !== "string") {
2334
2619
  res.status(401).json({
2335
2620
  jsonrpc: "2.0",
2336
2621
  error: {
2337
2622
  code: -32001,
2338
- message: "Missing or invalid X-API-Key header"
2623
+ message: "Missing authentication. Provide Authorization: Bearer <token> or X-API-Key header"
2339
2624
  },
2340
2625
  id: null
2341
2626
  });
@@ -2361,6 +2646,7 @@ function createAuthMiddleware(baseUrl) {
2361
2646
  const authContext = await apiClient.authenticate();
2362
2647
  req.apiClient = apiClient;
2363
2648
  req.authContext = authContext;
2649
+ req.authMethod = "api_key";
2364
2650
  next();
2365
2651
  } catch (error) {
2366
2652
  if (error instanceof ApiError) {
@@ -2408,7 +2694,9 @@ function startSessionCleanup() {
2408
2694
  }
2409
2695
  }
2410
2696
  if (cleanedCount > 0) {
2411
- console.error(`[collab-mcp-server] Cleaned up ${cleanedCount} expired session(s)`);
2697
+ console.error(
2698
+ `[collab-mcp-server] Cleaned up ${cleanedCount} expired session(s)`
2699
+ );
2412
2700
  }
2413
2701
  }, SESSION_CLEANUP_INTERVAL_MS);
2414
2702
  }
@@ -2423,17 +2711,27 @@ async function createHTTPServer() {
2423
2711
  const port = parseInt(process.env.PORT || String(DEFAULT_PORT), 10);
2424
2712
  const baseUrl = process.env.COLLAB_BASE_URL;
2425
2713
  if (!baseUrl) {
2426
- console.error("[collab-mcp-server] Error: COLLAB_BASE_URL environment variable is required");
2714
+ console.error(
2715
+ "[collab-mcp-server] Error: COLLAB_BASE_URL environment variable is required"
2716
+ );
2427
2717
  console.error("\nRequired environment variables:");
2428
- console.error(" COLLAB_BASE_URL Collab webapp URL (e.g., https://collab.mtaap.de)");
2718
+ console.error(
2719
+ " COLLAB_BASE_URL Collab webapp URL (e.g., https://collab.mtaap.de)"
2720
+ );
2429
2721
  console.error(" PORT Server port (default: 3001)");
2430
- console.error("\nClients must provide X-API-Key header with their Collab API key.");
2722
+ console.error("\nClients must authenticate using one of:");
2723
+ console.error(
2724
+ " - Authorization: Bearer <token> header with OAuth access token"
2725
+ );
2726
+ console.error(" - X-API-Key header with their Collab API key");
2431
2727
  process.exit(1);
2432
2728
  }
2433
2729
  try {
2434
2730
  new URL(baseUrl);
2435
2731
  } catch {
2436
- console.error(`[collab-mcp-server] Error: COLLAB_BASE_URL is not a valid URL: ${baseUrl}`);
2732
+ console.error(
2733
+ `[collab-mcp-server] Error: COLLAB_BASE_URL is not a valid URL: ${baseUrl}`
2734
+ );
2437
2735
  process.exit(1);
2438
2736
  }
2439
2737
  const app = (0, import_express.default)();
@@ -2446,6 +2744,22 @@ async function createHTTPServer() {
2446
2744
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
2447
2745
  });
2448
2746
  });
2747
+ app.get("/mcp/.well-known/oauth-protected-resource", (_req, res) => {
2748
+ const protocol = _req.headers["x-forwarded-proto"] || _req.protocol || "https";
2749
+ const host = _req.headers["x-forwarded-host"] || _req.headers.host;
2750
+ const resourceUrl = `${protocol}://${host}/mcp`;
2751
+ res.json({
2752
+ resource: resourceUrl,
2753
+ authorization_servers: [baseUrl],
2754
+ scopes_supported: [
2755
+ OAuthScopes.READ,
2756
+ OAuthScopes.WRITE,
2757
+ OAuthScopes.ADMIN
2758
+ ],
2759
+ bearer_methods_supported: ["header"],
2760
+ resource_documentation: `${baseUrl}/docs/mcp`
2761
+ });
2762
+ });
2449
2763
  const authMiddleware = createAuthMiddleware(baseUrl);
2450
2764
  app.post("/mcp", authMiddleware, async (req, res) => {
2451
2765
  const authReq = req;
@@ -2477,7 +2791,9 @@ async function createHTTPServer() {
2477
2791
  createdAt: now,
2478
2792
  lastAccessedAt: now
2479
2793
  });
2480
- console.error(`[collab-mcp-server] Session initialized: ${id} (user: ${authReq.authContext.userEmail})`);
2794
+ console.error(
2795
+ `[collab-mcp-server] Session initialized: ${id} (user: ${authReq.authContext.userEmail})`
2796
+ );
2481
2797
  },
2482
2798
  onsessionclosed: (id) => {
2483
2799
  sessions.delete(id);
@@ -2487,10 +2803,15 @@ async function createHTTPServer() {
2487
2803
  transport.onclose = () => {
2488
2804
  if (transport.sessionId) {
2489
2805
  sessions.delete(transport.sessionId);
2490
- console.error(`[collab-mcp-server] Transport closed for session: ${transport.sessionId}`);
2806
+ console.error(
2807
+ `[collab-mcp-server] Transport closed for session: ${transport.sessionId}`
2808
+ );
2491
2809
  }
2492
2810
  };
2493
- const server = initializeMCPServer(authReq.apiClient, authReq.authContext);
2811
+ const server = initializeMCPServer(
2812
+ authReq.apiClient,
2813
+ authReq.authContext
2814
+ );
2494
2815
  await server.connect(transport);
2495
2816
  sessionData = {
2496
2817
  transport,
@@ -2573,8 +2894,13 @@ async function createHTTPServer() {
2573
2894
  console.error(`[collab-mcp-server] Listening on http://0.0.0.0:${port}`);
2574
2895
  console.error(`[collab-mcp-server] MCP endpoint: POST/GET/DELETE /mcp`);
2575
2896
  console.error(`[collab-mcp-server] Health check: GET /mcp/health`);
2897
+ console.error(
2898
+ `[collab-mcp-server] OAuth metadata: GET /mcp/.well-known/oauth-protected-resource`
2899
+ );
2576
2900
  console.error(`[collab-mcp-server] API URL: ${baseUrl}`);
2577
- console.error(`[collab-mcp-server] Session timeout: ${SESSION_TIMEOUT_MS / 1e3 / 60} minutes`);
2901
+ console.error(
2902
+ `[collab-mcp-server] Session timeout: ${SESSION_TIMEOUT_MS / 1e3 / 60} minutes`
2903
+ );
2578
2904
  });
2579
2905
  }
2580
2906
  function handleCliFlags() {
@@ -2600,7 +2926,9 @@ Environment Variables:
2600
2926
  PORT Server port (default: 3001)
2601
2927
 
2602
2928
  Client Authentication:
2603
- Clients must provide an X-API-Key header with their Collab API key.
2929
+ Clients must authenticate using one of these methods:
2930
+ - X-API-Key header with their Collab API key
2931
+ - Authorization: Bearer <token> header with OAuth access token
2604
2932
  Each session is authenticated independently.
2605
2933
 
2606
2934
  Example deployment with Docker: