groove-dev 0.17.6 → 0.17.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.
@@ -99,12 +99,13 @@
99
99
  "transport": "stdio",
100
100
  "command": "npx",
101
101
  "args": ["-y", "@gongrzhe/server-calendar-autoauth-mcp"],
102
- "authType": "none",
102
+ "authType": "google-autoauth",
103
+ "oauthKeysDir": ".calendar-mcp",
103
104
  "envKeys": [],
104
105
  "setupSteps": [
105
- "Click Install, then click 'Sign in with Google'",
106
- "A browser window will openauthorize Groove",
107
- "Done — no API keys or tokens needed"
106
+ "One-time: link your Google Cloud OAuth app (shared across all Google integrations)",
107
+ "Click 'Sign in with Google'a browser opens for authorization",
108
+ "Done — the MCP server handles token refresh automatically"
108
109
  ],
109
110
  "featured": false,
110
111
  "downloads": 0,
@@ -124,12 +125,13 @@
124
125
  "transport": "stdio",
125
126
  "command": "npx",
126
127
  "args": ["-y", "@gongrzhe/server-gmail-autoauth-mcp"],
127
- "authType": "none",
128
+ "authType": "google-autoauth",
129
+ "oauthKeysDir": ".gmail-mcp",
128
130
  "envKeys": [],
129
131
  "setupSteps": [
130
- "Click Install, then click 'Sign in with Google'",
131
- "A browser window will openauthorize Groove",
132
- "Done — no API keys or tokens needed"
132
+ "One-time: link your Google Cloud OAuth app (shared across all Google integrations)",
133
+ "Click 'Sign in with Google'a browser opens for authorization",
134
+ "Done — the MCP server handles token refresh automatically"
133
135
  ],
134
136
  "featured": false,
135
137
  "downloads": 0,
@@ -458,15 +458,21 @@ export class IntegrationStore {
458
458
  }
459
459
 
460
460
  /**
461
- * Pre-authenticate an auto-auth integration by running its MCP server briefly.
462
- * The server will open a browser for OAuth. Once auth completes, the server
463
- * stores tokens locally so future agent spawns work without prompting.
461
+ * Pre-authenticate an auto-auth integration by running its MCP server
462
+ * and sending the MCP handshake (initialize + tools/list). This triggers
463
+ * the server's built-in OAuth flow which opens a browser for sign-in.
464
464
  * Returns a handle to track the auth process.
465
465
  */
466
466
  authenticate(integrationId) {
467
467
  const entry = this.registry.find((s) => s.id === integrationId);
468
468
  if (!entry) throw new Error(`Integration not found: ${integrationId}`);
469
469
 
470
+ // For google-autoauth integrations, write the gcp-oauth.keys.json file
471
+ // that the MCP server expects before it can start the OAuth browser flow
472
+ if (entry.authType === 'google-autoauth') {
473
+ this._writeGoogleOAuthKeys(entry);
474
+ }
475
+
470
476
  const command = entry.command || 'npx';
471
477
  const args = entry.args || ['-y', entry.npmPackage];
472
478
 
@@ -477,13 +483,45 @@ export class IntegrationStore {
477
483
  if (val) env[ek.key] = val;
478
484
  }
479
485
 
480
- // Spawn the MCP server it will trigger OAuth on startup
486
+ // Spawn the MCP server with stdin/stdout for JSON-RPC,
487
+ // stderr inherited so it can open browsers and show auth prompts
481
488
  const proc = cpSpawn(command, args, {
482
489
  env: { ...process.env, ...env },
483
- stdio: ['pipe', 'pipe', 'pipe'],
490
+ stdio: ['pipe', 'pipe', 'inherit'],
484
491
  detached: false,
485
492
  });
486
493
 
494
+ // Send MCP handshake to initialize the server — this triggers auth
495
+ const initMsg = JSON.stringify({
496
+ jsonrpc: '2.0', id: 1, method: 'initialize',
497
+ params: {
498
+ protocolVersion: '2024-11-05',
499
+ capabilities: {},
500
+ clientInfo: { name: 'groove', version: '1.0.0' },
501
+ },
502
+ });
503
+ const listToolsMsg = JSON.stringify({
504
+ jsonrpc: '2.0', id: 2, method: 'tools/list', params: {},
505
+ });
506
+ const initializedNotif = JSON.stringify({
507
+ jsonrpc: '2.0', method: 'notifications/initialized',
508
+ });
509
+
510
+ // Wait a moment for npx to download + start, then send handshake
511
+ proc.stdout.on('data', (chunk) => {
512
+ const text = chunk.toString();
513
+ // After initialize response, send initialized notification + tools/list
514
+ if (text.includes('"id":1') || text.includes('"id": 1')) {
515
+ proc.stdin.write(initializedNotif + '\n');
516
+ setTimeout(() => proc.stdin.write(listToolsMsg + '\n'), 500);
517
+ }
518
+ });
519
+
520
+ // Send initialize after a brief delay for npx startup
521
+ setTimeout(() => {
522
+ try { proc.stdin.write(initMsg + '\n'); } catch { /* process may have exited */ }
523
+ }, 3000);
524
+
487
525
  // Auto-kill after 2 minutes (auth should complete well before that)
488
526
  const timeout = setTimeout(() => {
489
527
  try { proc.kill('SIGTERM'); } catch { /* ignore */ }
@@ -499,6 +537,39 @@ export class IntegrationStore {
499
537
  };
500
538
  }
501
539
 
540
+ /**
541
+ * Write gcp-oauth.keys.json for Google auto-auth MCP servers.
542
+ * These servers need a Google Cloud OAuth client file at a specific path
543
+ * before they can open the browser for user consent.
544
+ */
545
+ _writeGoogleOAuthKeys(entry) {
546
+ const clientId = this.getCredential('google-oauth', 'GOOGLE_CLIENT_ID');
547
+ const clientSecret = this.getCredential('google-oauth', 'GOOGLE_CLIENT_SECRET');
548
+ if (!clientId || !clientSecret) {
549
+ throw new Error('Google OAuth not configured. Click "Sign in with Google" to set up your Google Cloud credentials first.');
550
+ }
551
+
552
+ const keysContent = JSON.stringify({
553
+ installed: {
554
+ client_id: clientId,
555
+ client_secret: clientSecret,
556
+ auth_uri: 'https://accounts.google.com/o/oauth2/auth',
557
+ token_uri: 'https://oauth2.googleapis.com/token',
558
+ redirect_uris: ['http://localhost'],
559
+ },
560
+ }, null, 2);
561
+
562
+ // Write to the directory the MCP server expects (e.g., ~/.gmail-mcp/)
563
+ const keysDir = entry.oauthKeysDir;
564
+ if (keysDir) {
565
+ const homedir = process.env.HOME || process.env.USERPROFILE || '~';
566
+ const dirPath = resolve(homedir, keysDir);
567
+ mkdirSync(dirPath, { recursive: true });
568
+ const keysPath = resolve(dirPath, 'gcp-oauth.keys.json');
569
+ writeFileSync(keysPath, keysContent, { mode: 0o600 });
570
+ }
571
+ }
572
+
502
573
  // --- Internal ---
503
574
 
504
575
  _isInstalled(integrationId) {