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.
- package/dist/setup.js +124 -71
- package/package.json +3 -1
package/dist/setup.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Guided setup wizard for google-tools-mcp.
|
|
2
|
-
//
|
|
3
|
-
import * as
|
|
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
|
-
|
|
82
|
-
|
|
83
|
-
|
|
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
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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
|
-
|
|
121
|
-
|
|
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
|
|
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
|
-
|
|
178
|
+
p.log.success(`Credentials saved to ${chalk.dim(displayPath)}`);
|
|
133
179
|
|
|
134
|
-
// Step
|
|
135
|
-
|
|
136
|
-
|
|
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
|
-
|
|
147
|
-
|
|
148
|
-
|
|
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
|
|
153
|
-
|
|
154
|
-
|
|
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
|
-
|
|
210
|
+
s.stop('Added to Claude Code!');
|
|
158
211
|
} catch (err) {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
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
|
-
|
|
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
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
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
|
-
|
|
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.
|
|
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",
|