@piotr-agier/google-drive-mcp 1.7.3 → 1.7.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +49 -13
- package/dist/index.js +32 -14
- package/dist/index.js.map +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -194,7 +194,7 @@ Run the container with your credentials and tokens mounted:
|
|
|
194
194
|
```bash
|
|
195
195
|
docker run -it \
|
|
196
196
|
-v /path/to/gcp-oauth.keys.json:/config/gcp-oauth.keys.json:ro \
|
|
197
|
-
-v
|
|
197
|
+
-v "$HOME/.config/google-drive-mcp/tokens.json":/config/tokens.json \
|
|
198
198
|
google-drive-mcp
|
|
199
199
|
```
|
|
200
200
|
|
|
@@ -206,7 +206,35 @@ docker run -it \
|
|
|
206
206
|
|
|
207
207
|
### Docker Configuration for Claude Desktop
|
|
208
208
|
|
|
209
|
-
|
|
209
|
+
#### Option A: Reusable container (recommended)
|
|
210
|
+
|
|
211
|
+
Uses a wrapper script that keeps a single named container running and reuses it across client restarts — faster startup and no container churn:
|
|
212
|
+
|
|
213
|
+
```json
|
|
214
|
+
{
|
|
215
|
+
"mcpServers": {
|
|
216
|
+
"google-drive": {
|
|
217
|
+
"command": "/path/to/google-drive-mcp/scripts/docker-mcp.sh",
|
|
218
|
+
"env": {
|
|
219
|
+
"GOOGLE_DRIVE_OAUTH_CREDENTIALS": "$HOME/gcp-oauth.keys.json",
|
|
220
|
+
"GOOGLE_DRIVE_MCP_TOKEN_PATH": "$HOME/.config/google-drive-mcp/tokens.json"
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
The script will:
|
|
228
|
+
- Create the container on first run
|
|
229
|
+
- Reuse the existing container on subsequent runs
|
|
230
|
+
- Automatically restart it if it was stopped
|
|
231
|
+
|
|
232
|
+
**Note:** The container stays running in the background until explicitly stopped.
|
|
233
|
+
To stop it: `docker stop google-drive-mcp`
|
|
234
|
+
|
|
235
|
+
#### Option B: Fresh container each time
|
|
236
|
+
|
|
237
|
+
Creates and removes a new container on every client restart:
|
|
210
238
|
|
|
211
239
|
```json
|
|
212
240
|
{
|
|
@@ -240,13 +268,20 @@ Add this configuration to use the Docker container with Claude Desktop:
|
|
|
240
268
|
|
|
241
269
|
The server supports multiple methods for providing OAuth credentials (in order of priority):
|
|
242
270
|
|
|
243
|
-
#### 1. **Environment Variable** (
|
|
271
|
+
#### 1. **Environment Variable** (Highest Priority)
|
|
244
272
|
```bash
|
|
245
273
|
export GOOGLE_DRIVE_OAUTH_CREDENTIALS="/path/to/your/gcp-oauth.keys.json"
|
|
246
274
|
```
|
|
247
275
|
|
|
248
|
-
#### 2. **
|
|
249
|
-
Place `gcp-oauth.keys.json` in the
|
|
276
|
+
#### 2. **Config Directory** (Recommended)
|
|
277
|
+
Place `gcp-oauth.keys.json` in the XDG config directory:
|
|
278
|
+
```
|
|
279
|
+
~/.config/google-drive-mcp/gcp-oauth.keys.json
|
|
280
|
+
```
|
|
281
|
+
This is the recommended location — it works reliably with `npx`, global installs, and local setups.
|
|
282
|
+
|
|
283
|
+
#### 3. **Project Root** (Legacy Fallback)
|
|
284
|
+
Place `gcp-oauth.keys.json` in the project root directory. This still works for local development but is unreliable with `npx` or global installs.
|
|
250
285
|
|
|
251
286
|
### OAuth Scope Configuration
|
|
252
287
|
|
|
@@ -943,15 +978,15 @@ After revoking access, you'll need to re-authenticate the next time you use the
|
|
|
943
978
|
#### "OAuth credentials not found"
|
|
944
979
|
```
|
|
945
980
|
OAuth credentials not found. Please provide credentials using one of these methods:
|
|
946
|
-
1.
|
|
981
|
+
1. Config directory (recommended):
|
|
982
|
+
Place your gcp-oauth.keys.json file in: ~/.config/google-drive-mcp/
|
|
983
|
+
2. Environment variable:
|
|
947
984
|
export GOOGLE_DRIVE_OAUTH_CREDENTIALS="/path/to/gcp-oauth.keys.json"
|
|
948
|
-
2. Default file path:
|
|
949
|
-
Place your gcp-oauth.keys.json file in the package root directory.
|
|
950
985
|
```
|
|
951
986
|
|
|
952
987
|
**Solution:**
|
|
953
988
|
- Download credentials from Google Cloud Console
|
|
954
|
-
-
|
|
989
|
+
- Place the file in `~/.config/google-drive-mcp/gcp-oauth.keys.json` (recommended), or set the environment variable
|
|
955
990
|
- Ensure the file has proper read permissions
|
|
956
991
|
|
|
957
992
|
#### "Authentication failed" or Browser doesn't open
|
|
@@ -1049,7 +1084,7 @@ ls -la ~/.config/google-drive-mcp/tokens.json
|
|
|
1049
1084
|
# 3. Run Docker with tokens mounted
|
|
1050
1085
|
docker run -it \
|
|
1051
1086
|
-v $(pwd)/gcp-oauth.keys.json:/config/gcp-oauth.keys.json:ro \
|
|
1052
|
-
-v
|
|
1087
|
+
-v "$HOME/.config/google-drive-mcp/tokens.json":/config/tokens.json \
|
|
1053
1088
|
google-drive-mcp
|
|
1054
1089
|
```
|
|
1055
1090
|
|
|
@@ -1074,10 +1109,10 @@ The Dockerfile expects the `dist/` directory to exist from your local build.
|
|
|
1074
1109
|
**Solution:** Ensure the token file is mounted with write permissions:
|
|
1075
1110
|
```bash
|
|
1076
1111
|
# Correct: tokens can be updated
|
|
1077
|
-
-v
|
|
1112
|
+
-v "$HOME/.config/google-drive-mcp/tokens.json":/config/tokens.json
|
|
1078
1113
|
|
|
1079
1114
|
# Wrong: read-only mount prevents token refresh
|
|
1080
|
-
-v
|
|
1115
|
+
-v "$HOME/.config/google-drive-mcp/tokens.json":/config/tokens.json:ro
|
|
1081
1116
|
```
|
|
1082
1117
|
|
|
1083
1118
|
### Debug Mode
|
|
@@ -1156,7 +1191,8 @@ npm run typecheck # Type checking without compilation
|
|
|
1156
1191
|
| Variable | Description | Example |
|
|
1157
1192
|
|----------|-------------|---------|
|
|
1158
1193
|
| `GOOGLE_DRIVE_OAUTH_CREDENTIALS` | Path to your OAuth credentials JSON file | `/home/user/secrets/oauth.json` |
|
|
1159
|
-
| *(or place file at)* |
|
|
1194
|
+
| *(or place file at)* | Config directory (recommended): `~/.config/google-drive-mcp/gcp-oauth.keys.json` | `~/.config/google-drive-mcp/gcp-oauth.keys.json` |
|
|
1195
|
+
| *(or place file at)* | Project root (legacy fallback): `gcp-oauth.keys.json` | `./gcp-oauth.keys.json` |
|
|
1160
1196
|
|
|
1161
1197
|
**Optional** (for customization):
|
|
1162
1198
|
| Variable | Description | Default | Example |
|
package/dist/index.js
CHANGED
|
@@ -29,14 +29,16 @@ function getProjectRoot() {
|
|
|
29
29
|
const projectRoot = path.join(__dirname2, "..", "..");
|
|
30
30
|
return path.resolve(projectRoot);
|
|
31
31
|
}
|
|
32
|
+
function getConfigDir() {
|
|
33
|
+
const configHome = process.env.XDG_CONFIG_HOME || path.join(os.homedir(), ".config");
|
|
34
|
+
return path.join(configHome, "google-drive-mcp");
|
|
35
|
+
}
|
|
32
36
|
function getSecureTokenPath() {
|
|
33
37
|
const customTokenPath = process.env.GOOGLE_DRIVE_MCP_TOKEN_PATH;
|
|
34
38
|
if (customTokenPath) {
|
|
35
39
|
return path.resolve(customTokenPath);
|
|
36
40
|
}
|
|
37
|
-
|
|
38
|
-
const tokenDir = path.join(configHome, "google-drive-mcp");
|
|
39
|
-
return path.join(tokenDir, "tokens.json");
|
|
41
|
+
return path.join(getConfigDir(), "tokens.json");
|
|
40
42
|
}
|
|
41
43
|
function getLegacyTokenPath() {
|
|
42
44
|
const projectRoot = getProjectRoot();
|
|
@@ -49,26 +51,29 @@ function getAdditionalLegacyPaths() {
|
|
|
49
51
|
path.join(process.cwd(), ".gcp-saved-tokens.json")
|
|
50
52
|
].filter(Boolean);
|
|
51
53
|
}
|
|
52
|
-
function
|
|
54
|
+
function getKeysFilePaths() {
|
|
55
|
+
const paths = [];
|
|
53
56
|
const envCredentialsPath = process.env.GOOGLE_DRIVE_OAUTH_CREDENTIALS;
|
|
54
57
|
if (envCredentialsPath) {
|
|
55
|
-
|
|
58
|
+
paths.push(path.resolve(envCredentialsPath));
|
|
56
59
|
}
|
|
60
|
+
paths.push(path.join(getConfigDir(), "gcp-oauth.keys.json"));
|
|
57
61
|
const projectRoot = getProjectRoot();
|
|
58
|
-
|
|
59
|
-
return
|
|
62
|
+
paths.push(path.join(projectRoot, "gcp-oauth.keys.json"));
|
|
63
|
+
return paths;
|
|
60
64
|
}
|
|
61
65
|
function generateCredentialsErrorMessage() {
|
|
66
|
+
const configDir = getConfigDir();
|
|
62
67
|
return `
|
|
63
68
|
OAuth credentials not found. Please provide credentials using one of these methods:
|
|
64
69
|
|
|
65
|
-
1.
|
|
70
|
+
1. Config directory (recommended):
|
|
71
|
+
Place your gcp-oauth.keys.json file in: ${configDir}/
|
|
72
|
+
|
|
73
|
+
2. Environment variable:
|
|
66
74
|
Set GOOGLE_DRIVE_OAUTH_CREDENTIALS to the path of your credentials file:
|
|
67
75
|
export GOOGLE_DRIVE_OAUTH_CREDENTIALS="/path/to/gcp-oauth.keys.json"
|
|
68
76
|
|
|
69
|
-
2. Default file path:
|
|
70
|
-
Place your gcp-oauth.keys.json file in the package root directory.
|
|
71
|
-
|
|
72
77
|
Token storage:
|
|
73
78
|
- Tokens are saved to: ${getSecureTokenPath()}
|
|
74
79
|
- To use a custom token location, set GOOGLE_DRIVE_MCP_TOKEN_PATH environment variable
|
|
@@ -83,9 +88,7 @@ To get OAuth credentials:
|
|
|
83
88
|
}
|
|
84
89
|
|
|
85
90
|
// src/auth/client.ts
|
|
86
|
-
|
|
87
|
-
const keysContent = await fs.readFile(getKeysFilePath(), "utf-8");
|
|
88
|
-
const keys = JSON.parse(keysContent);
|
|
91
|
+
function parseCredentialsFile(keys) {
|
|
89
92
|
if (keys.installed) {
|
|
90
93
|
const { client_id, client_secret, redirect_uris } = keys.installed;
|
|
91
94
|
return { client_id, client_secret, redirect_uris };
|
|
@@ -102,6 +105,21 @@ async function loadCredentialsFromFile() {
|
|
|
102
105
|
throw new Error('Invalid credentials file format. Expected either "installed", "web" object or direct client_id field.');
|
|
103
106
|
}
|
|
104
107
|
}
|
|
108
|
+
async function loadCredentialsFromFile() {
|
|
109
|
+
const paths = getKeysFilePaths();
|
|
110
|
+
for (const keysPath of paths) {
|
|
111
|
+
try {
|
|
112
|
+
const keysContent = await fs.readFile(keysPath, "utf-8");
|
|
113
|
+
const keys = JSON.parse(keysContent);
|
|
114
|
+
return parseCredentialsFile(keys);
|
|
115
|
+
} catch (err) {
|
|
116
|
+
if (err instanceof SyntaxError || err instanceof Error && err.message.includes("Invalid credentials")) {
|
|
117
|
+
throw new Error(`Invalid credentials file at ${keysPath}: ${err.message}`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
throw new Error(`Credentials file not found. Searched: ${paths.join(", ")}`);
|
|
122
|
+
}
|
|
105
123
|
async function loadCredentialsWithFallback() {
|
|
106
124
|
try {
|
|
107
125
|
return await loadCredentialsFromFile();
|