google-tools-mcp 1.2.1 → 1.2.2

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.
Files changed (2) hide show
  1. package/dist/setup.js +124 -71
  2. package/package.json +3 -1
package/dist/setup.js CHANGED
@@ -1,6 +1,7 @@
1
1
  // Guided setup wizard for google-tools-mcp.
2
- // Opens the right Google Cloud Console URLs and saves credentials.
3
- import * as readline from 'readline';
2
+ // Rich terminal UI using @clack/prompts.
3
+ import * as p from '@clack/prompts';
4
+ import chalk from 'chalk';
4
5
  import * as fs from 'fs/promises';
5
6
  import * as path from 'path';
6
7
  import * as os from 'os';
@@ -44,10 +45,6 @@ function openBrowser(url) {
44
45
  exec(cmd, () => {});
45
46
  }
46
47
 
47
- function prompt(rl, question) {
48
- return new Promise((resolve) => rl.question(question, resolve));
49
- }
50
-
51
48
  function getConfigDir() {
52
49
  const xdg = process.env.XDG_CONFIG_HOME;
53
50
  const base = xdg || path.join(os.homedir(), '.config');
@@ -74,106 +71,162 @@ function runCommand(cmd) {
74
71
  });
75
72
  }
76
73
 
74
+ function cancelled() {
75
+ p.cancel('Setup cancelled.');
76
+ process.exit(0);
77
+ }
78
+
77
79
  // ---------------------------------------------------------------------------
78
80
  // Setup flow
79
81
  // ---------------------------------------------------------------------------
80
82
  export async function runSetup() {
81
- const rl = readline.createInterface({
82
- input: process.stdin,
83
- output: process.stdout,
83
+ console.clear();
84
+
85
+ p.intro(chalk.bgCyan.bold.white(' google-tools-mcp setup '));
86
+
87
+ // ── Step 1: Enable APIs ──────────────────────────────────────────────
88
+ p.log.step(chalk.cyan.bold('Step 1') + chalk.dim(' · ') + 'Enable Google APIs');
89
+ p.log.message([
90
+ 'This will open Google Cloud Console to enable all required APIs.',
91
+ chalk.dim('If you don\'t have a project yet, it will ask you to create one.'),
92
+ '',
93
+ chalk.dim('APIs: ') + APIS.map(a => chalk.yellow(a.replace('.googleapis.com', ''))).join(chalk.dim(', ')),
94
+ ].join('\n'));
95
+
96
+ const ready1 = await p.confirm({
97
+ message: 'Ready? This will open your browser.',
98
+ active: 'open browser',
99
+ inactive: 'not yet',
84
100
  });
85
-
86
- console.log('\n🔧 google-tools-mcp setup\n');
87
-
88
- // Step 1: Enable APIs
89
- console.log('Step 1: Enable Google APIs');
90
- console.log('─────────────────────────');
91
- console.log('Opening Google Cloud Console to enable all required APIs.');
92
- console.log('If you don\'t have a project yet, it will ask you to create one.\n');
101
+ if (p.isCancel(ready1)) cancelled();
93
102
  openBrowser(ENABLE_APIS_URL);
94
- await prompt(rl, 'Press Enter when done...');
95
-
96
- // Step 2: OAuth consent screen
97
- console.log('\nStep 2: Configure OAuth consent screen');
98
- console.log('──────────────────────────────────────');
99
- console.log('Opening the OAuth consent screen configuration.');
100
- console.log(' • Choose "External" for the user type');
101
- console.log(' • Fill in the app name (anything is fine, e.g. "MCP")');
102
- console.log(' • Add your email as a test user\n');
103
+
104
+ const step1 = await p.confirm({
105
+ message: 'Done enabling APIs?',
106
+ active: 'yes, continue',
107
+ inactive: 'not yet',
108
+ });
109
+ if (p.isCancel(step1)) cancelled();
110
+
111
+ // ── Step 2: OAuth consent screen ─────────────────────────────────────
112
+ p.log.step(chalk.cyan.bold('Step 2') + chalk.dim(' · ') + 'Configure OAuth consent screen');
113
+ p.log.message([
114
+ `${chalk.white('›')} Choose ${chalk.bold('"External"')} for the user type`,
115
+ `${chalk.white('›')} Fill in the app name ${chalk.dim('(anything works, e.g. "MCP")')}`,
116
+ `${chalk.white('›')} Add your email as a ${chalk.bold('test user')}`,
117
+ ].join('\n'));
118
+
119
+ const ready2 = await p.confirm({
120
+ message: 'Ready? This will open your browser.',
121
+ active: 'open browser',
122
+ inactive: 'not yet',
123
+ });
124
+ if (p.isCancel(ready2)) cancelled();
103
125
  openBrowser(CONSENT_SCREEN_URL);
104
- await prompt(rl, 'Press Enter when done...');
105
-
106
- // Step 3: Create OAuth credentials
107
- console.log('\nStep 3: Create OAuth Client ID');
108
- console.log('──────────────────────────────');
109
- console.log('Opening the credentials page.');
110
- console.log(' • Select "Desktop application" as the type');
111
- console.log(' • Click Create, then copy the Client ID and Client Secret\n');
126
+
127
+ const step2 = await p.confirm({
128
+ message: 'Done configuring consent screen?',
129
+ active: 'yes, continue',
130
+ inactive: 'not yet',
131
+ });
132
+ if (p.isCancel(step2)) cancelled();
133
+
134
+ // ── Step 3: Create OAuth credentials ─────────────────────────────────
135
+ p.log.step(chalk.cyan.bold('Step 3') + chalk.dim(' · ') + 'Create OAuth Client ID');
136
+ p.log.message([
137
+ `${chalk.white('›')} Select ${chalk.bold('"Desktop application"')} as the type`,
138
+ `${chalk.white('›')} Click ${chalk.bold('Create')}`,
139
+ `${chalk.white('›')} Copy the ${chalk.bold('Client ID')} and ${chalk.bold('Client Secret')}`,
140
+ ].join('\n'));
141
+
142
+ const ready3 = await p.confirm({
143
+ message: 'Ready? This will open your browser.',
144
+ active: 'open browser',
145
+ inactive: 'not yet',
146
+ });
147
+ if (p.isCancel(ready3)) cancelled();
112
148
  openBrowser(CREATE_CREDENTIALS_URL);
113
- await prompt(rl, 'Press Enter when you have your Client ID and Secret...');
114
149
 
115
- // Step 4: Collect credentials
116
- console.log('');
117
- const clientId = (await prompt(rl, 'Client ID: ')).trim();
118
- const clientSecret = (await prompt(rl, 'Client Secret: ')).trim();
150
+ const credentials = await p.group({
151
+ clientId: () => p.text({
152
+ message: 'Client ID',
153
+ placeholder: 'xxxx.apps.googleusercontent.com',
154
+ validate: (v) => {
155
+ if (!v?.trim()) return 'Client ID is required';
156
+ },
157
+ }),
158
+ clientSecret: () => p.text({
159
+ message: 'Client Secret',
160
+ placeholder: 'GOCSPX-xxxx',
161
+ validate: (v) => {
162
+ if (!v?.trim()) return 'Client Secret is required';
163
+ },
164
+ }),
165
+ });
166
+ if (p.isCancel(credentials)) cancelled();
119
167
 
120
- if (!clientId || !clientSecret) {
121
- rl.close();
122
- throw new Error('Client ID and Client Secret are required.');
123
- }
168
+ const clientId = credentials.clientId.trim();
169
+ const clientSecret = credentials.clientSecret.trim();
124
170
 
125
- // Save to config dir
171
+ // ── Save credentials ─────────────────────────────────────────────────
126
172
  const configDir = getConfigDir();
127
173
  await fs.mkdir(configDir, { recursive: true });
128
174
  const envPath = path.join(configDir, '.env');
129
175
  const envContent = `GOOGLE_CLIENT_ID=${clientId}\nGOOGLE_CLIENT_SECRET=${clientSecret}\n`;
130
176
  await fs.writeFile(envPath, envContent);
131
177
  const displayPath = envPath.replace(os.homedir(), '~');
132
- console.log(`\nCredentials saved to ${displayPath}`);
178
+ p.log.success(`Credentials saved to ${chalk.dim(displayPath)}`);
133
179
 
134
- // Step 5: Run OAuth flow
135
- console.log('\nStep 4: Authenticate with Google');
136
- console.log('────────────────────────────────');
137
- console.log('Opening browser for OAuth consent...\n');
180
+ // ── Step 4: Authenticate ─────────────────────────────────────────────
181
+ p.log.step(chalk.cyan.bold('Step 4') + chalk.dim(' · ') + 'Authenticate with Google');
182
+ p.log.message('Opening browser for OAuth consent...');
138
183
 
139
- // Set env vars so auth picks them up immediately
140
184
  process.env.GOOGLE_CLIENT_ID = clientId;
141
185
  process.env.GOOGLE_CLIENT_SECRET = clientSecret;
142
186
 
143
187
  const { runAuthFlow } = await import('./auth.js');
144
188
  await runAuthFlow();
145
189
 
146
- // Step 6: Install into MCP client
147
- console.log('\nStep 5: Install');
148
- console.log('───────────────');
190
+ p.log.success('Authenticated with Google!');
191
+
192
+ // ── Step 5: Install ──────────────────────────────────────────────────
193
+ p.log.step(chalk.cyan.bold('Step 5') + chalk.dim(' · ') + 'Install MCP server');
149
194
 
150
195
  const hasClaude = hasCli('claude');
151
196
  if (hasClaude) {
152
- const answer = (await prompt(rl, 'Add to Claude Code as a user-scope MCP server? (Y/n) ')).trim().toLowerCase();
153
- if (answer === '' || answer === 'y' || answer === 'yes') {
154
- console.log('Running: claude mcp add -s user google -- npx -y google-tools-mcp');
197
+ const install = await p.confirm({
198
+ message: 'Add to Claude Code as a user-scope MCP server?',
199
+ active: 'yes',
200
+ inactive: 'no',
201
+ initialValue: true,
202
+ });
203
+ if (p.isCancel(install)) cancelled();
204
+
205
+ if (install) {
206
+ const s = p.spinner();
207
+ s.start('Adding to Claude Code...');
155
208
  try {
156
209
  await runCommand('claude mcp add -s user google -- npx -y google-tools-mcp');
157
- console.log('Added to Claude Code!');
210
+ s.stop('Added to Claude Code!');
158
211
  } catch (err) {
159
- console.error('Failed to add:', err.message);
160
- console.log('You can add it manually:');
161
- console.log(' claude mcp add -s user google -- npx -y google-tools-mcp');
212
+ s.stop('Failed to add automatically');
213
+ p.log.warn(`Error: ${err.message}`);
214
+ p.log.message(`Run manually:\n${chalk.cyan('claude mcp add -s user google -- npx -y google-tools-mcp')}`);
162
215
  }
163
216
  } else {
164
- console.log('\nTo add it later:');
165
- console.log(' claude mcp add -s user google -- npx -y google-tools-mcp');
217
+ p.log.message(`To add later:\n${chalk.cyan('claude mcp add -s user google -- npx -y google-tools-mcp')}`);
166
218
  }
167
219
  } else {
168
- console.log('Add google-tools-mcp to your MCP client config:');
169
- console.log('');
170
- console.log(' Claude Code:');
171
- console.log(' claude mcp add -s user google -- npx -y google-tools-mcp');
172
- console.log('');
173
- console.log(' Other clients (.mcp.json / claude_desktop_config.json):');
174
- console.log(' { "mcpServers": { "google": { "command": "npx", "args": ["-y", "google-tools-mcp"] } } }');
220
+ p.log.message([
221
+ 'Add to your MCP client:',
222
+ '',
223
+ chalk.dim('Claude Code:'),
224
+ chalk.cyan(' claude mcp add -s user google -- npx -y google-tools-mcp'),
225
+ '',
226
+ chalk.dim('Other clients') + chalk.dim(' (.mcp.json):'),
227
+ chalk.cyan(' { "mcpServers": { "google": { "command": "npx", "args": ["-y", "google-tools-mcp"] } } }'),
228
+ ].join('\n'));
175
229
  }
176
230
 
177
- rl.close();
178
- console.log('\n✅ Setup complete! You\'re ready to use google-tools-mcp.\n');
231
+ p.outro(chalk.green.bold('Setup complete!') + chalk.dim(' You\'re ready to use google-tools-mcp.'));
179
232
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "google-tools-mcp",
3
- "version": "1.2.1",
3
+ "version": "1.2.2",
4
4
  "description": "The easiest MCP server for Google Workspace — Drive, Docs, Sheets, Gmail, Calendar, and Forms. 153 tools with one-click browser auth. Read Word docs, PDFs, and spreadsheets straight from Drive.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -62,6 +62,8 @@
62
62
  },
63
63
  "license": "MIT",
64
64
  "dependencies": {
65
+ "@clack/prompts": "^1.2.0",
66
+ "chalk": "^5.6.2",
65
67
  "fastmcp": "^3.24.0",
66
68
  "google-auth-library": "^10.5.0",
67
69
  "googleapis": "^171.4.0",