mcp-google-gdrive 0.1.0
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/LICENSE +21 -0
- package/README.md +105 -0
- package/SPEC.md +917 -0
- package/package.json +35 -0
- package/src/index.js +487 -0
package/SPEC.md
ADDED
|
@@ -0,0 +1,917 @@
|
|
|
1
|
+
# mcp-google-gdrive — Development Specification
|
|
2
|
+
|
|
3
|
+
## 1. Project Overview
|
|
4
|
+
|
|
5
|
+
MCP server providing Claude Code with full read/write access to a personal Google Drive account. Implements Google Drive API v3 operations as MCP tools with automatic Google Workspace format conversion.
|
|
6
|
+
|
|
7
|
+
### Key Facts
|
|
8
|
+
|
|
9
|
+
| Item | Value |
|
|
10
|
+
|------|-------|
|
|
11
|
+
| Package name | mcp-google-gdrive |
|
|
12
|
+
| Version | 0.1.0 |
|
|
13
|
+
| Runtime | Node.js 18+ (ESM), verified 22.22.0 in WSL |
|
|
14
|
+
| MCP SDK | @modelcontextprotocol/sdk ^1.26.0 |
|
|
15
|
+
| Validation | zod ^3.25.0 |
|
|
16
|
+
| Auth | Google OAuth2 (desktop app flow) |
|
|
17
|
+
| API | Google Drive API v3 |
|
|
18
|
+
| Extra deps | googleapis ^144.0.0, turndown ^7.2.0, marked ^15.0.0 |
|
|
19
|
+
| Location | WSL ~/projects/mcp-servers/mcp-google-gdrive/ |
|
|
20
|
+
| Entry point | src/index.js |
|
|
21
|
+
| Transport | stdio (JSON-RPC) |
|
|
22
|
+
| License | MIT |
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## 2. Prerequisites and Setup
|
|
27
|
+
|
|
28
|
+
### 2.1 System Requirements
|
|
29
|
+
|
|
30
|
+
- Node.js 18+ (verified: v22.22.0 in WSL Fedora 43)
|
|
31
|
+
- npm 10+ (verified: 10.9.4)
|
|
32
|
+
- Google account with Drive access
|
|
33
|
+
- Web browser accessible from WSL (for one-time OAuth2 consent)
|
|
34
|
+
|
|
35
|
+
### 2.2 Google Cloud Console Setup
|
|
36
|
+
|
|
37
|
+
1. Go to https://console.cloud.google.com/
|
|
38
|
+
2. Create a new project (e.g., "PAI MCP Servers")
|
|
39
|
+
3. Enable the Google Drive API:
|
|
40
|
+
- APIs & Services → Library → search "Google Drive API" → Enable
|
|
41
|
+
4. Configure OAuth consent screen:
|
|
42
|
+
- APIs & Services → OAuth consent screen
|
|
43
|
+
- User type: External (or Internal if using Google Workspace)
|
|
44
|
+
- App name: "PAI Google Drive MCP"
|
|
45
|
+
- Scopes: Add `https://www.googleapis.com/auth/drive` (full Drive access)
|
|
46
|
+
- Test users: Add your Google email
|
|
47
|
+
5. Create OAuth2 credentials:
|
|
48
|
+
- APIs & Services → Credentials → Create Credentials → OAuth client ID
|
|
49
|
+
- Application type: Desktop app
|
|
50
|
+
- Name: "mcp-google-gdrive"
|
|
51
|
+
- Download the JSON file → save as `credentials.json`
|
|
52
|
+
|
|
53
|
+
### 2.3 Required OAuth2 Scopes
|
|
54
|
+
|
|
55
|
+
| Scope | Purpose |
|
|
56
|
+
|-------|---------|
|
|
57
|
+
| `https://www.googleapis.com/auth/drive` | Full read/write access to all Drive files |
|
|
58
|
+
| `https://www.googleapis.com/auth/drive.file` | Access to files created/opened by this app only (alternative, more restrictive) |
|
|
59
|
+
|
|
60
|
+
Recommendation: Use `drive` scope for full access. This is a personal tool — scope restriction adds friction without meaningful security benefit for a single-user local tool.
|
|
61
|
+
|
|
62
|
+
### 2.4 Token Storage
|
|
63
|
+
|
|
64
|
+
- Credentials file: `~/.config/mcp-google-gdrive/credentials.json`
|
|
65
|
+
- Token file: `~/.config/mcp-google-gdrive/token.json`
|
|
66
|
+
- Token contains: access_token, refresh_token, expiry_date
|
|
67
|
+
- Refresh tokens do not expire unless revoked or unused for 6 months
|
|
68
|
+
- Access tokens expire after 1 hour; auto-refresh via googleapis client
|
|
69
|
+
|
|
70
|
+
### 2.5 First-Run OAuth2 Flow (WSL → Windows Browser)
|
|
71
|
+
|
|
72
|
+
Since WSL doesn't have a native browser, the first-run consent flow requires:
|
|
73
|
+
|
|
74
|
+
1. Server starts, detects no token.json
|
|
75
|
+
2. Generates authorization URL and prints it to stderr
|
|
76
|
+
3. User copies URL to Windows browser, completes consent
|
|
77
|
+
4. Google redirects to `http://localhost:PORT/callback` with auth code
|
|
78
|
+
5. Server exchanges auth code for tokens, saves to token.json
|
|
79
|
+
6. Subsequent runs use refresh token automatically
|
|
80
|
+
|
|
81
|
+
Alternative approach if localhost redirect doesn't work in WSL:
|
|
82
|
+
- Use `redirect_uri: urn:ietf:wg:oauth:2.0:oob` (manual copy-paste of auth code)
|
|
83
|
+
- Server prompts "Enter the authorization code:" on stderr
|
|
84
|
+
- User pastes code from browser
|
|
85
|
+
|
|
86
|
+
### 2.6 Project Scaffolding
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
mcp-google-gdrive/
|
|
90
|
+
├── .gitignore
|
|
91
|
+
├── LICENSE (MIT)
|
|
92
|
+
├── README.md
|
|
93
|
+
├── package.json
|
|
94
|
+
└── src/
|
|
95
|
+
└── index.js
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### 2.7 package.json
|
|
99
|
+
|
|
100
|
+
```json
|
|
101
|
+
{
|
|
102
|
+
"name": "mcp-google-gdrive",
|
|
103
|
+
"version": "0.1.0",
|
|
104
|
+
"description": "MCP server for Google Drive API with full file management and Workspace format conversion",
|
|
105
|
+
"type": "module",
|
|
106
|
+
"bin": {
|
|
107
|
+
"mcp-google-gdrive": "./src/index.js"
|
|
108
|
+
},
|
|
109
|
+
"main": "./src/index.js",
|
|
110
|
+
"scripts": {
|
|
111
|
+
"start": "node src/index.js",
|
|
112
|
+
"auth": "node src/index.js --auth"
|
|
113
|
+
},
|
|
114
|
+
"keywords": [
|
|
115
|
+
"mcp",
|
|
116
|
+
"google-drive",
|
|
117
|
+
"google-workspace",
|
|
118
|
+
"file-management"
|
|
119
|
+
],
|
|
120
|
+
"license": "MIT",
|
|
121
|
+
"repository": {
|
|
122
|
+
"type": "git",
|
|
123
|
+
"url": "git+https://github.com/sleepytimeshon/mcp-google-gdrive.git"
|
|
124
|
+
},
|
|
125
|
+
"homepage": "https://github.com/sleepytimeshon/mcp-google-gdrive#readme",
|
|
126
|
+
"bugs": {
|
|
127
|
+
"url": "https://github.com/sleepytimeshon/mcp-google-gdrive/issues"
|
|
128
|
+
},
|
|
129
|
+
"dependencies": {
|
|
130
|
+
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
131
|
+
"googleapis": "^144.0.0",
|
|
132
|
+
"marked": "^15.0.0",
|
|
133
|
+
"turndown": "^7.2.0",
|
|
134
|
+
"zod": "^3.25.0"
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### 2.8 .gitignore
|
|
140
|
+
|
|
141
|
+
```
|
|
142
|
+
node_modules/
|
|
143
|
+
credentials.json
|
|
144
|
+
token.json
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## 3. Architecture
|
|
150
|
+
|
|
151
|
+
See section 11 for full C4 model diagrams (Context, Container, Deployment) and security posture.
|
|
152
|
+
|
|
153
|
+
### 3.1 Internal Components
|
|
154
|
+
|
|
155
|
+
| Component | Responsibility |
|
|
156
|
+
|-----------|---------------|
|
|
157
|
+
| MCP Protocol Handler | McpServer + StdioServerTransport, receives tool calls |
|
|
158
|
+
| Tool Registry | 14 registerTool calls with Zod schemas and annotations |
|
|
159
|
+
| Auth Manager | OAuth2 token load/refresh/save using googleapis auth client |
|
|
160
|
+
| Drive API Client | Thin wrapper around googleapis drive.files.* methods |
|
|
161
|
+
| Format Converter | HTML→Markdown (turndown), MD→HTML (marked), Sheets→CSV/JSON parsing |
|
|
162
|
+
|
|
163
|
+
### 3.2 Data Flow
|
|
164
|
+
|
|
165
|
+
```
|
|
166
|
+
Claude Code (Windows)
|
|
167
|
+
│ stdio (JSON-RPC)
|
|
168
|
+
▼
|
|
169
|
+
MCP Server (WSL Node.js)
|
|
170
|
+
│
|
|
171
|
+
├── Auth Manager → token.json (local file)
|
|
172
|
+
│
|
|
173
|
+
├── Drive API Client → Google Drive API v3 (HTTPS)
|
|
174
|
+
│ │
|
|
175
|
+
│ └── Response (file content, metadata, etc.)
|
|
176
|
+
│
|
|
177
|
+
└── Format Converter (if Google Workspace type)
|
|
178
|
+
│
|
|
179
|
+
└── Converted content (Markdown, CSV, JSON, text)
|
|
180
|
+
│
|
|
181
|
+
▼
|
|
182
|
+
MCP Response → Claude Code
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## 4. Tool Specifications
|
|
188
|
+
|
|
189
|
+
### Naming Convention
|
|
190
|
+
|
|
191
|
+
Tools use snake_case prefixed with `gdrive_` to namespace and avoid collisions:
|
|
192
|
+
|
|
193
|
+
| Tool Name | Operation | Read/Write |
|
|
194
|
+
|-----------|-----------|------------|
|
|
195
|
+
| gdrive_list_files | List/search files | Read |
|
|
196
|
+
| gdrive_get_metadata | Get file metadata | Read |
|
|
197
|
+
| gdrive_read_file | Read file content | Read |
|
|
198
|
+
| gdrive_create_file | Create/upload file | Write |
|
|
199
|
+
| gdrive_update_file | Update file content | Write |
|
|
200
|
+
| gdrive_delete_file | Trash or delete file | Write (destructive) |
|
|
201
|
+
| gdrive_move_file | Move file between folders | Write |
|
|
202
|
+
| gdrive_copy_file | Copy a file | Write |
|
|
203
|
+
| gdrive_create_folder | Create a folder | Write |
|
|
204
|
+
| gdrive_export_doc | Export Google Doc | Read |
|
|
205
|
+
| gdrive_export_sheet | Export Google Sheet | Read |
|
|
206
|
+
| gdrive_export_slides | Export Google Slides | Read |
|
|
207
|
+
| gdrive_create_doc | Create Google Doc from Markdown | Write |
|
|
208
|
+
| gdrive_update_doc | Update Google Doc content | Write |
|
|
209
|
+
|
|
210
|
+
### 4.1 gdrive_list_files
|
|
211
|
+
|
|
212
|
+
List files in Google Drive with optional search query and folder filtering.
|
|
213
|
+
|
|
214
|
+
| Field | Value |
|
|
215
|
+
|-------|-------|
|
|
216
|
+
| Drive API | files.list |
|
|
217
|
+
| Annotations | readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true |
|
|
218
|
+
|
|
219
|
+
Parameters:
|
|
220
|
+
|
|
221
|
+
| Param | Type | Required | Default | Description |
|
|
222
|
+
|-------|------|----------|---------|-------------|
|
|
223
|
+
| query | string | no | — | Drive search query (e.g., "name contains 'report'") |
|
|
224
|
+
| folderId | string | no | — | List files in this folder only |
|
|
225
|
+
| pageSize | number | no | 20 | Results per page (max 100) |
|
|
226
|
+
| pageToken | string | no | — | Token for next page of results |
|
|
227
|
+
| orderBy | string | no | "modifiedTime desc" | Sort order |
|
|
228
|
+
|
|
229
|
+
Response: JSON array of file objects with id, name, mimeType, modifiedTime, size, parents.
|
|
230
|
+
|
|
231
|
+
### 4.2 gdrive_get_metadata
|
|
232
|
+
|
|
233
|
+
Get detailed metadata for a specific file.
|
|
234
|
+
|
|
235
|
+
| Field | Value |
|
|
236
|
+
|-------|-------|
|
|
237
|
+
| Drive API | files.get (fields parameter for metadata) |
|
|
238
|
+
| Annotations | readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true |
|
|
239
|
+
|
|
240
|
+
Parameters:
|
|
241
|
+
|
|
242
|
+
| Param | Type | Required | Default | Description |
|
|
243
|
+
|-------|------|----------|---------|-------------|
|
|
244
|
+
| fileId | string | yes | — | Google Drive file ID |
|
|
245
|
+
|
|
246
|
+
Response: Full file metadata — id, name, mimeType, size, createdTime, modifiedTime, parents, webViewLink, owners, shared, description.
|
|
247
|
+
|
|
248
|
+
### 4.3 gdrive_read_file
|
|
249
|
+
|
|
250
|
+
Read file content with automatic format detection and conversion.
|
|
251
|
+
|
|
252
|
+
| Field | Value |
|
|
253
|
+
|-------|-------|
|
|
254
|
+
| Drive API | files.get (alt=media) for binary; files.export for Workspace types |
|
|
255
|
+
| Annotations | readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true |
|
|
256
|
+
|
|
257
|
+
Parameters:
|
|
258
|
+
|
|
259
|
+
| Param | Type | Required | Default | Description |
|
|
260
|
+
|-------|------|----------|---------|-------------|
|
|
261
|
+
| fileId | string | yes | — | Google Drive file ID |
|
|
262
|
+
|
|
263
|
+
Auto-detection logic:
|
|
264
|
+
- `application/vnd.google-apps.document` → export as HTML → convert to Markdown via turndown
|
|
265
|
+
- `application/vnd.google-apps.spreadsheet` → export as CSV (first sheet)
|
|
266
|
+
- `application/vnd.google-apps.presentation` → export as plain text
|
|
267
|
+
- `application/vnd.google-apps.drawing` → export as PNG (base64)
|
|
268
|
+
- `text/*` → download raw content
|
|
269
|
+
- Other binary → download up to 10MB, return metadata if larger
|
|
270
|
+
|
|
271
|
+
Response: File content as text, or metadata + size warning for oversized binary files.
|
|
272
|
+
|
|
273
|
+
### 4.4 gdrive_create_file
|
|
274
|
+
|
|
275
|
+
Create a new file in Google Drive.
|
|
276
|
+
|
|
277
|
+
| Field | Value |
|
|
278
|
+
|-------|-------|
|
|
279
|
+
| Drive API | files.create (with media upload) |
|
|
280
|
+
| Annotations | readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true |
|
|
281
|
+
|
|
282
|
+
Parameters:
|
|
283
|
+
|
|
284
|
+
| Param | Type | Required | Default | Description |
|
|
285
|
+
|-------|------|----------|---------|-------------|
|
|
286
|
+
| name | string | yes | — | File name including extension |
|
|
287
|
+
| content | string | yes | — | File content (text) |
|
|
288
|
+
| mimeType | string | no | auto-detect | MIME type of content |
|
|
289
|
+
| parentFolderId | string | no | root | Parent folder ID |
|
|
290
|
+
|
|
291
|
+
Response: Created file metadata (id, name, webViewLink).
|
|
292
|
+
|
|
293
|
+
### 4.5 gdrive_update_file
|
|
294
|
+
|
|
295
|
+
Update content of an existing file.
|
|
296
|
+
|
|
297
|
+
| Field | Value |
|
|
298
|
+
|-------|-------|
|
|
299
|
+
| Drive API | files.update (with media upload) |
|
|
300
|
+
| Annotations | readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true |
|
|
301
|
+
|
|
302
|
+
Parameters:
|
|
303
|
+
|
|
304
|
+
| Param | Type | Required | Default | Description |
|
|
305
|
+
|-------|------|----------|---------|-------------|
|
|
306
|
+
| fileId | string | yes | — | File ID to update |
|
|
307
|
+
| content | string | yes | — | New file content |
|
|
308
|
+
| mimeType | string | no | preserve original | MIME type of new content |
|
|
309
|
+
|
|
310
|
+
Response: Updated file metadata (id, name, modifiedTime).
|
|
311
|
+
|
|
312
|
+
### 4.6 gdrive_delete_file
|
|
313
|
+
|
|
314
|
+
Delete or trash a file.
|
|
315
|
+
|
|
316
|
+
| Field | Value |
|
|
317
|
+
|-------|-------|
|
|
318
|
+
| Drive API | files.update (trashed: true) or files.delete |
|
|
319
|
+
| Annotations | readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: true |
|
|
320
|
+
|
|
321
|
+
Parameters:
|
|
322
|
+
|
|
323
|
+
| Param | Type | Required | Default | Description |
|
|
324
|
+
|-------|------|----------|---------|-------------|
|
|
325
|
+
| fileId | string | yes | — | File ID to delete |
|
|
326
|
+
| permanent | boolean | no | false | true = permanent delete, false = move to trash |
|
|
327
|
+
|
|
328
|
+
Response: Confirmation message with file name and action taken.
|
|
329
|
+
|
|
330
|
+
### 4.7 gdrive_move_file
|
|
331
|
+
|
|
332
|
+
Move a file to a different folder.
|
|
333
|
+
|
|
334
|
+
| Field | Value |
|
|
335
|
+
|-------|-------|
|
|
336
|
+
| Drive API | files.update (addParents + removeParents) |
|
|
337
|
+
| Annotations | readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true |
|
|
338
|
+
|
|
339
|
+
Parameters:
|
|
340
|
+
|
|
341
|
+
| Param | Type | Required | Default | Description |
|
|
342
|
+
|-------|------|----------|---------|-------------|
|
|
343
|
+
| fileId | string | yes | — | File ID to move |
|
|
344
|
+
| destinationFolderId | string | yes | — | Target folder ID |
|
|
345
|
+
|
|
346
|
+
Response: Updated file metadata with new parent.
|
|
347
|
+
|
|
348
|
+
### 4.8 gdrive_copy_file
|
|
349
|
+
|
|
350
|
+
Copy a file, optionally to a different folder with a new name.
|
|
351
|
+
|
|
352
|
+
| Field | Value |
|
|
353
|
+
|-------|-------|
|
|
354
|
+
| Drive API | files.copy |
|
|
355
|
+
| Annotations | readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true |
|
|
356
|
+
|
|
357
|
+
Parameters:
|
|
358
|
+
|
|
359
|
+
| Param | Type | Required | Default | Description |
|
|
360
|
+
|-------|------|----------|---------|-------------|
|
|
361
|
+
| fileId | string | yes | — | Source file ID |
|
|
362
|
+
| name | string | no | "Copy of {original}" | Name for the copy |
|
|
363
|
+
| parentFolderId | string | no | same as original | Destination folder ID |
|
|
364
|
+
|
|
365
|
+
Response: New file metadata (id, name, webViewLink).
|
|
366
|
+
|
|
367
|
+
### 4.9 gdrive_create_folder
|
|
368
|
+
|
|
369
|
+
Create a new folder.
|
|
370
|
+
|
|
371
|
+
| Field | Value |
|
|
372
|
+
|-------|-------|
|
|
373
|
+
| Drive API | files.create (mimeType: application/vnd.google-apps.folder) |
|
|
374
|
+
| Annotations | readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true |
|
|
375
|
+
|
|
376
|
+
Parameters:
|
|
377
|
+
|
|
378
|
+
| Param | Type | Required | Default | Description |
|
|
379
|
+
|-------|------|----------|---------|-------------|
|
|
380
|
+
| name | string | yes | — | Folder name |
|
|
381
|
+
| parentFolderId | string | no | root | Parent folder ID |
|
|
382
|
+
|
|
383
|
+
Response: Created folder metadata (id, name, webViewLink).
|
|
384
|
+
|
|
385
|
+
### 4.10 gdrive_export_doc
|
|
386
|
+
|
|
387
|
+
Export a Google Doc to a specified format. Default: Markdown.
|
|
388
|
+
|
|
389
|
+
Note: For the default Markdown export, this tool produces the same result as gdrive_read_file on a Google Doc. The distinction: read_file always returns Markdown (optimized for Claude's consumption), while export_doc lets you choose the output format (HTML, plain text, DOCX, PDF).
|
|
390
|
+
|
|
391
|
+
| Field | Value |
|
|
392
|
+
|-------|-------|
|
|
393
|
+
| Drive API | files.export |
|
|
394
|
+
| Annotations | readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true |
|
|
395
|
+
|
|
396
|
+
Parameters:
|
|
397
|
+
|
|
398
|
+
| Param | Type | Required | Default | Description |
|
|
399
|
+
|-------|------|----------|---------|-------------|
|
|
400
|
+
| fileId | string | yes | — | Google Doc file ID |
|
|
401
|
+
| format | enum | no | "markdown" | "markdown", "html", "plain_text", "docx", "pdf" |
|
|
402
|
+
|
|
403
|
+
Format mapping:
|
|
404
|
+
- "markdown" → export as text/html → convert via turndown → return Markdown
|
|
405
|
+
- "html" → export as text/html → return raw HTML
|
|
406
|
+
- "plain_text" → export as text/plain
|
|
407
|
+
- "docx" → export as application/vnd.openxmlformats-officedocument.wordprocessingml.document (base64)
|
|
408
|
+
- "pdf" → export as application/pdf (base64)
|
|
409
|
+
|
|
410
|
+
Response: Exported content in requested format.
|
|
411
|
+
|
|
412
|
+
### 4.11 gdrive_export_sheet
|
|
413
|
+
|
|
414
|
+
Export a Google Sheet to CSV or JSON.
|
|
415
|
+
|
|
416
|
+
| Field | Value |
|
|
417
|
+
|-------|-------|
|
|
418
|
+
| Drive API | files.export |
|
|
419
|
+
| Annotations | readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true |
|
|
420
|
+
|
|
421
|
+
Parameters:
|
|
422
|
+
|
|
423
|
+
| Param | Type | Required | Default | Description |
|
|
424
|
+
|-------|------|----------|---------|-------------|
|
|
425
|
+
| fileId | string | yes | — | Google Sheet file ID |
|
|
426
|
+
| format | enum | no | "csv" | "csv" or "json" |
|
|
427
|
+
| sheetName | string | no | first sheet | Specific sheet/tab name (NOTE: requires Sheets API — see limitation below) |
|
|
428
|
+
|
|
429
|
+
Limitation: The Drive API `files.export` exports the first sheet only for CSV. Exporting a specific sheet by name requires the Google Sheets API (`spreadsheets.values.get`). If sheetName is specified, the implementation should fall back to the Sheets API. This may require adding the `https://www.googleapis.com/auth/spreadsheets.readonly` scope.
|
|
430
|
+
|
|
431
|
+
Format mapping:
|
|
432
|
+
- "csv" → export as text/csv
|
|
433
|
+
- "json" → export as text/csv → parse to JSON array of objects (headers as keys)
|
|
434
|
+
|
|
435
|
+
Response: Sheet data in requested format.
|
|
436
|
+
|
|
437
|
+
### 4.12 gdrive_export_slides
|
|
438
|
+
|
|
439
|
+
Export Google Slides to text or PDF.
|
|
440
|
+
|
|
441
|
+
| Field | Value |
|
|
442
|
+
|-------|-------|
|
|
443
|
+
| Drive API | files.export |
|
|
444
|
+
| Annotations | readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true |
|
|
445
|
+
|
|
446
|
+
Parameters:
|
|
447
|
+
|
|
448
|
+
| Param | Type | Required | Default | Description |
|
|
449
|
+
|-------|------|----------|---------|-------------|
|
|
450
|
+
| fileId | string | yes | — | Google Slides file ID |
|
|
451
|
+
| format | enum | no | "text" | "text" or "pdf" |
|
|
452
|
+
|
|
453
|
+
Format mapping:
|
|
454
|
+
- "text" → export as text/plain
|
|
455
|
+
- "pdf" → export as application/pdf (base64)
|
|
456
|
+
|
|
457
|
+
Response: Slides content in requested format.
|
|
458
|
+
|
|
459
|
+
### 4.13 gdrive_create_doc
|
|
460
|
+
|
|
461
|
+
Create a new Google Doc from Markdown content.
|
|
462
|
+
|
|
463
|
+
| Field | Value |
|
|
464
|
+
|-------|-------|
|
|
465
|
+
| Drive API | files.create (with conversion) |
|
|
466
|
+
| Annotations | readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true |
|
|
467
|
+
|
|
468
|
+
Parameters:
|
|
469
|
+
|
|
470
|
+
| Param | Type | Required | Default | Description |
|
|
471
|
+
|-------|------|----------|---------|-------------|
|
|
472
|
+
| name | string | yes | — | Document title |
|
|
473
|
+
| markdownContent | string | yes | — | Markdown content to convert |
|
|
474
|
+
| parentFolderId | string | no | root | Parent folder ID |
|
|
475
|
+
|
|
476
|
+
Implementation: Convert Markdown → HTML, upload as text/html with `mimeType: application/vnd.google-apps.document` to trigger Google's conversion.
|
|
477
|
+
|
|
478
|
+
Response: Created doc metadata (id, name, webViewLink).
|
|
479
|
+
|
|
480
|
+
### 4.14 gdrive_update_doc
|
|
481
|
+
|
|
482
|
+
Update an existing Google Doc with new Markdown content.
|
|
483
|
+
|
|
484
|
+
| Field | Value |
|
|
485
|
+
|-------|-------|
|
|
486
|
+
| Drive API | files.update (with media upload and conversion) |
|
|
487
|
+
| Annotations | readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true |
|
|
488
|
+
|
|
489
|
+
Parameters:
|
|
490
|
+
|
|
491
|
+
| Param | Type | Required | Default | Description |
|
|
492
|
+
|-------|------|----------|---------|-------------|
|
|
493
|
+
| fileId | string | yes | — | Google Doc file ID |
|
|
494
|
+
| markdownContent | string | yes | — | New Markdown content (replaces entire doc) |
|
|
495
|
+
|
|
496
|
+
Implementation: Convert Markdown → HTML, upload as text/html to replace doc content.
|
|
497
|
+
|
|
498
|
+
Response: Updated doc metadata (id, name, modifiedTime).
|
|
499
|
+
|
|
500
|
+
---
|
|
501
|
+
|
|
502
|
+
## 5. Format Conversion Strategy
|
|
503
|
+
|
|
504
|
+
### 5.1 Google Workspace MIME Types
|
|
505
|
+
|
|
506
|
+
| Google Type | MIME Type | Default Export |
|
|
507
|
+
|-------------|-----------|----------------|
|
|
508
|
+
| Document | application/vnd.google-apps.document | HTML → Markdown (turndown) |
|
|
509
|
+
| Spreadsheet | application/vnd.google-apps.spreadsheet | text/csv |
|
|
510
|
+
| Presentation | application/vnd.google-apps.presentation | text/plain |
|
|
511
|
+
| Drawing | application/vnd.google-apps.drawing | image/png |
|
|
512
|
+
| Form | application/vnd.google-apps.form | N/A (not supported) |
|
|
513
|
+
|
|
514
|
+
### 5.2 Turndown Configuration
|
|
515
|
+
|
|
516
|
+
```javascript
|
|
517
|
+
const turndownService = new TurndownService({
|
|
518
|
+
headingStyle: "atx", // # style headings
|
|
519
|
+
codeBlockStyle: "fenced", // ``` code blocks
|
|
520
|
+
bulletListMarker: "-",
|
|
521
|
+
emDelimiter: "_",
|
|
522
|
+
strongDelimiter: "**",
|
|
523
|
+
});
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
### 5.3 Markdown → HTML for Doc Creation
|
|
527
|
+
|
|
528
|
+
For creating/updating Google Docs from Markdown, a simple MD→HTML conversion is needed. Options:
|
|
529
|
+
- **marked** (npm) — lightweight, fast, well-maintained
|
|
530
|
+
- **showdown** (npm) — CommonMark compliant
|
|
531
|
+
- Recommendation: Use **marked** (~200KB, zero deps, CommonMark)
|
|
532
|
+
|
|
533
|
+
This adds one more dependency: `marked ^15.0.0`
|
|
534
|
+
|
|
535
|
+
Updated dependencies:
|
|
536
|
+
```json
|
|
537
|
+
{
|
|
538
|
+
"googleapis": "^144.0.0",
|
|
539
|
+
"turndown": "^7.2.0",
|
|
540
|
+
"marked": "^15.0.0",
|
|
541
|
+
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
542
|
+
"zod": "^3.25.0"
|
|
543
|
+
}
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
---
|
|
547
|
+
|
|
548
|
+
## 6. Error Handling Strategy
|
|
549
|
+
|
|
550
|
+
### 6.1 Error Categories
|
|
551
|
+
|
|
552
|
+
| Category | HTTP Code | MCP Response | User Message |
|
|
553
|
+
|----------|-----------|--------------|--------------|
|
|
554
|
+
| Auth expired | 401 | Error | "Authentication expired. Run `mcp-google-gdrive --auth` to re-authenticate." |
|
|
555
|
+
| Token missing | — | Error | "No token.json found. Run `mcp-google-gdrive --auth` for first-time setup." |
|
|
556
|
+
| File not found | 404 | Error | "File not found: {fileId}. Verify the file ID exists and you have access." |
|
|
557
|
+
| Permission denied | 403 | Error | "Permission denied for file {fileId}. Check sharing settings." |
|
|
558
|
+
| Rate limited | 429 | Error | "Rate limited by Google API. Wait and retry." (NOTE: write limit is 3 req/sec/account, hard cap) |
|
|
559
|
+
| Quota exceeded | 403 (reason: dailyLimitExceeded) | Error | "Daily API quota exceeded. Try again tomorrow." |
|
|
560
|
+
| File too large | — | Error | "File exceeds 10MB limit. File metadata: {name}, {size}." |
|
|
561
|
+
| Invalid file type | — | Error | "Cannot export: {mimeType} is not a Google Workspace file." |
|
|
562
|
+
| Network error | — | Error | "Network error connecting to Google APIs. Check internet connection." |
|
|
563
|
+
|
|
564
|
+
### 6.2 Error Response Format
|
|
565
|
+
|
|
566
|
+
All errors return standard MCP error content:
|
|
567
|
+
```javascript
|
|
568
|
+
return {
|
|
569
|
+
content: [{ type: "text", text: `Error: ${message}` }],
|
|
570
|
+
isError: true
|
|
571
|
+
};
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
### 6.3 Token Auto-Refresh
|
|
575
|
+
|
|
576
|
+
The googleapis client handles token refresh automatically:
|
|
577
|
+
- On 401 response, client uses refresh_token to get new access_token
|
|
578
|
+
- New access_token saved to token.json
|
|
579
|
+
- Original request retried with new token
|
|
580
|
+
- If refresh fails (revoked token), return auth expired error
|
|
581
|
+
|
|
582
|
+
---
|
|
583
|
+
|
|
584
|
+
## 7. File Size Handling
|
|
585
|
+
|
|
586
|
+
| Scenario | Behavior |
|
|
587
|
+
|----------|----------|
|
|
588
|
+
| Text file < 10MB | Return full content |
|
|
589
|
+
| Text file > 10MB | Return first 10MB + warning + total size |
|
|
590
|
+
| Binary file < 10MB | Return base64-encoded content |
|
|
591
|
+
| Binary file > 10MB | Return metadata only: name, size, mimeType, webViewLink |
|
|
592
|
+
| Google Doc/Sheet/Slides | Always export (size is post-conversion, usually small) |
|
|
593
|
+
|
|
594
|
+
---
|
|
595
|
+
|
|
596
|
+
## 8. Claude Code MCP Configuration
|
|
597
|
+
|
|
598
|
+
Add to `~/.claude/settings.json` under `mcpServers`:
|
|
599
|
+
|
|
600
|
+
```json
|
|
601
|
+
{
|
|
602
|
+
"mcpServers": {
|
|
603
|
+
"google-drive": {
|
|
604
|
+
"command": "wsl",
|
|
605
|
+
"args": ["-d", "FedoraLinux-43", "--", "bash", "-c", "node ~/projects/mcp-servers/mcp-google-gdrive/src/index.js"],
|
|
606
|
+
"env": {}
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
```
|
|
611
|
+
|
|
612
|
+
Alternative using npx (after npm link):
|
|
613
|
+
```json
|
|
614
|
+
{
|
|
615
|
+
"mcpServers": {
|
|
616
|
+
"google-drive": {
|
|
617
|
+
"command": "wsl",
|
|
618
|
+
"args": ["-d", "FedoraLinux-43", "--", "npx", "mcp-google-gdrive"],
|
|
619
|
+
"env": {}
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
```
|
|
624
|
+
|
|
625
|
+
---
|
|
626
|
+
|
|
627
|
+
## 9. Build Phases
|
|
628
|
+
|
|
629
|
+
### Phase 1: Core (MVP) — Priority: Immediate
|
|
630
|
+
|
|
631
|
+
1. Project scaffolding (package.json, .gitignore, LICENSE, README)
|
|
632
|
+
2. OAuth2 auth flow (credentials.json → token.json, auto-refresh)
|
|
633
|
+
3. gdrive_list_files (search and browse)
|
|
634
|
+
4. gdrive_read_file (with auto-detection for Docs/Sheets/Slides)
|
|
635
|
+
5. gdrive_get_metadata
|
|
636
|
+
6. gdrive_create_file
|
|
637
|
+
7. gdrive_create_folder
|
|
638
|
+
8. Claude Code MCP configuration and end-to-end test
|
|
639
|
+
|
|
640
|
+
Rationale: These 5 tools cover the primary use case (browse, read, create). Auth must work first. End-to-end test validates the WSL↔Windows↔Google pipeline.
|
|
641
|
+
|
|
642
|
+
### Phase 2: Full CRUD — Priority: Next
|
|
643
|
+
|
|
644
|
+
9. gdrive_update_file
|
|
645
|
+
10. gdrive_delete_file
|
|
646
|
+
11. gdrive_move_file
|
|
647
|
+
12. gdrive_copy_file
|
|
648
|
+
|
|
649
|
+
Rationale: Complete file management operations. Each builds on the Phase 1 foundation.
|
|
650
|
+
|
|
651
|
+
### Phase 3: Workspace — Priority: After CRUD
|
|
652
|
+
|
|
653
|
+
13. gdrive_export_doc (with turndown HTML→MD)
|
|
654
|
+
14. gdrive_export_sheet (CSV + JSON)
|
|
655
|
+
15. gdrive_export_slides
|
|
656
|
+
16. gdrive_create_doc (MD→HTML→Google Doc)
|
|
657
|
+
17. gdrive_update_doc
|
|
658
|
+
|
|
659
|
+
Rationale: Format conversion is valuable but builds on top of working read/write. Turndown and marked dependencies only needed for this phase.
|
|
660
|
+
|
|
661
|
+
### Phase 4: Polish — Priority: As needed
|
|
662
|
+
|
|
663
|
+
18. README with full documentation
|
|
664
|
+
19. Error handling hardening
|
|
665
|
+
20. Edge case coverage (shared drives, shortcuts, trashed files)
|
|
666
|
+
21. npm publish (if desired)
|
|
667
|
+
|
|
668
|
+
---
|
|
669
|
+
|
|
670
|
+
## 10. BDD Acceptance Criteria
|
|
671
|
+
|
|
672
|
+
### gdrive_list_files
|
|
673
|
+
|
|
674
|
+
**Story:** As a Claude Code user, I want to list and search files in my Drive so that I can find files to work with.
|
|
675
|
+
|
|
676
|
+
- Given a Drive with files, when I call gdrive_list_files with no params, then I receive up to 20 files sorted by modifiedTime desc with id, name, mimeType, modifiedTime, size, parents.
|
|
677
|
+
- Given a folder with ID "abc123", when I call gdrive_list_files with folderId "abc123", then I receive only files whose parents include "abc123".
|
|
678
|
+
- Given a query "name contains 'report'", when I call gdrive_list_files with that query, then I receive only files matching the search.
|
|
679
|
+
- Given more than 20 files match, when I call gdrive_list_files with pageSize 20, then the response includes a nextPageToken for pagination.
|
|
680
|
+
- Given an invalid folderId, when I call gdrive_list_files, then I receive an error with "File not found" message.
|
|
681
|
+
|
|
682
|
+
### gdrive_get_metadata
|
|
683
|
+
|
|
684
|
+
**Story:** As a Claude Code user, I want to get detailed file metadata so that I can make informed decisions about file operations.
|
|
685
|
+
|
|
686
|
+
- Given a valid fileId, when I call gdrive_get_metadata, then I receive id, name, mimeType, size, createdTime, modifiedTime, parents, webViewLink, owners, shared, description.
|
|
687
|
+
- Given an invalid fileId, when I call gdrive_get_metadata, then I receive a 404 error with descriptive message.
|
|
688
|
+
|
|
689
|
+
### gdrive_read_file
|
|
690
|
+
|
|
691
|
+
**Story:** As a Claude Code user, I want to read file contents so that I can analyze and work with Drive data.
|
|
692
|
+
|
|
693
|
+
- Given a text file (text/plain), when I call gdrive_read_file, then I receive the raw text content.
|
|
694
|
+
- Given a Google Doc, when I call gdrive_read_file, then the Doc is exported as HTML and converted to Markdown via turndown.
|
|
695
|
+
- Given a Google Sheet, when I call gdrive_read_file, then the first sheet is exported as CSV.
|
|
696
|
+
- Given a Google Slides presentation, when I call gdrive_read_file, then slides are exported as plain text.
|
|
697
|
+
- Given a binary file under 10MB, when I call gdrive_read_file, then I receive base64-encoded content.
|
|
698
|
+
- Given a binary file over 10MB, when I call gdrive_read_file, then I receive metadata (name, size, mimeType, webViewLink) with a size warning.
|
|
699
|
+
|
|
700
|
+
### gdrive_create_file
|
|
701
|
+
|
|
702
|
+
**Story:** As a Claude Code user, I want to create files in Drive so that I can store new content.
|
|
703
|
+
|
|
704
|
+
- Given a name "notes.txt" and content "hello world", when I call gdrive_create_file, then a new file is created in root and I receive id, name, webViewLink.
|
|
705
|
+
- Given a parentFolderId, when I call gdrive_create_file with that param, then the file is created inside that folder.
|
|
706
|
+
- Given an invalid parentFolderId, when I call gdrive_create_file, then I receive a 404 error.
|
|
707
|
+
|
|
708
|
+
### gdrive_update_file
|
|
709
|
+
|
|
710
|
+
**Story:** As a Claude Code user, I want to update file contents so that I can modify existing Drive files.
|
|
711
|
+
|
|
712
|
+
- Given a valid fileId and new content, when I call gdrive_update_file, then the file content is replaced and I receive id, name, modifiedTime.
|
|
713
|
+
- Given an invalid fileId, when I call gdrive_update_file, then I receive a 404 error.
|
|
714
|
+
- Given a file I don't own, when I call gdrive_update_file, then I receive a 403 permission denied error.
|
|
715
|
+
|
|
716
|
+
### gdrive_delete_file
|
|
717
|
+
|
|
718
|
+
**Story:** As a Claude Code user, I want to delete files so that I can manage Drive contents.
|
|
719
|
+
|
|
720
|
+
- Given a valid fileId with permanent=false (default), when I call gdrive_delete_file, then the file is moved to trash and I receive confirmation.
|
|
721
|
+
- Given a valid fileId with permanent=true, when I call gdrive_delete_file, then the file is permanently deleted and I receive confirmation.
|
|
722
|
+
- Given an invalid fileId, when I call gdrive_delete_file, then I receive a 404 error.
|
|
723
|
+
|
|
724
|
+
### gdrive_move_file
|
|
725
|
+
|
|
726
|
+
**Story:** As a Claude Code user, I want to move files between folders so that I can organize my Drive.
|
|
727
|
+
|
|
728
|
+
- Given a file in folder A and destination folder B, when I call gdrive_move_file, then the file's parents change from A to B.
|
|
729
|
+
- Given an invalid destinationFolderId, when I call gdrive_move_file, then I receive a 404 error.
|
|
730
|
+
|
|
731
|
+
### gdrive_copy_file
|
|
732
|
+
|
|
733
|
+
**Story:** As a Claude Code user, I want to copy files so that I can duplicate content.
|
|
734
|
+
|
|
735
|
+
- Given a valid fileId, when I call gdrive_copy_file with no name, then a copy is created named "Copy of {original}" in the same folder.
|
|
736
|
+
- Given a valid fileId and name "backup.txt", when I call gdrive_copy_file, then the copy is created with the specified name.
|
|
737
|
+
- Given a parentFolderId, when I call gdrive_copy_file with that param, then the copy is placed in the specified folder.
|
|
738
|
+
|
|
739
|
+
### gdrive_create_folder
|
|
740
|
+
|
|
741
|
+
**Story:** As a Claude Code user, I want to create folders so that I can organize Drive files.
|
|
742
|
+
|
|
743
|
+
- Given a name "Projects", when I call gdrive_create_folder, then a folder is created in root with mimeType application/vnd.google-apps.folder and I receive id, name, webViewLink.
|
|
744
|
+
- Given a parentFolderId, when I call gdrive_create_folder with that param, then the folder is created as a subfolder.
|
|
745
|
+
|
|
746
|
+
### gdrive_export_doc
|
|
747
|
+
|
|
748
|
+
**Story:** As a Claude Code user, I want to export Google Docs in various formats so that I can work with their content.
|
|
749
|
+
|
|
750
|
+
- Given a Google Doc fileId with format="markdown" (default), when I call gdrive_export_doc, then the doc is exported as HTML and converted to Markdown via turndown.
|
|
751
|
+
- Given format="html", when I call gdrive_export_doc, then I receive raw HTML content.
|
|
752
|
+
- Given format="plain_text", when I call gdrive_export_doc, then I receive plain text content.
|
|
753
|
+
- Given a non-Doc fileId, when I call gdrive_export_doc, then I receive an error "Cannot export: {mimeType} is not a Google Workspace file."
|
|
754
|
+
|
|
755
|
+
### gdrive_export_sheet
|
|
756
|
+
|
|
757
|
+
**Story:** As a Claude Code user, I want to export Google Sheets so that I can analyze spreadsheet data.
|
|
758
|
+
|
|
759
|
+
- Given a Google Sheet fileId with format="csv" (default), when I call gdrive_export_sheet, then I receive CSV content of the first sheet.
|
|
760
|
+
- Given format="json", when I call gdrive_export_sheet, then I receive a JSON array of objects with column headers as keys.
|
|
761
|
+
- Given a sheetName param, when I call gdrive_export_sheet, then only that specific sheet/tab is exported.
|
|
762
|
+
- Given a non-Sheet fileId, when I call gdrive_export_sheet, then I receive an error.
|
|
763
|
+
|
|
764
|
+
### gdrive_export_slides
|
|
765
|
+
|
|
766
|
+
**Story:** As a Claude Code user, I want to export Google Slides so that I can work with presentation content.
|
|
767
|
+
|
|
768
|
+
- Given a Google Slides fileId with format="text" (default), when I call gdrive_export_slides, then I receive plain text content of all slides.
|
|
769
|
+
- Given format="pdf", when I call gdrive_export_slides, then I receive base64-encoded PDF content.
|
|
770
|
+
|
|
771
|
+
### gdrive_create_doc
|
|
772
|
+
|
|
773
|
+
**Story:** As a Claude Code user, I want to create Google Docs from Markdown so that I can produce formatted documents.
|
|
774
|
+
|
|
775
|
+
- Given a name and markdownContent, when I call gdrive_create_doc, then a new Google Doc is created with the Markdown converted to HTML and then to Google Doc format, and I receive id, name, webViewLink.
|
|
776
|
+
- Given a parentFolderId, when I call gdrive_create_doc with that param, then the doc is created in that folder.
|
|
777
|
+
|
|
778
|
+
### gdrive_update_doc
|
|
779
|
+
|
|
780
|
+
**Story:** As a Claude Code user, I want to update Google Docs with new Markdown so that I can revise formatted documents.
|
|
781
|
+
|
|
782
|
+
- Given a valid Google Doc fileId and markdownContent, when I call gdrive_update_doc, then the entire doc content is replaced with the new Markdown (converted via MD→HTML→Doc), and I receive id, name, modifiedTime.
|
|
783
|
+
- Given a non-Doc fileId, when I call gdrive_update_doc, then I receive an error.
|
|
784
|
+
|
|
785
|
+
---
|
|
786
|
+
|
|
787
|
+
## 11. Design Document (C4 Architecture)
|
|
788
|
+
|
|
789
|
+
### 11.1 Business Posture
|
|
790
|
+
|
|
791
|
+
| Priority | Goal | Description |
|
|
792
|
+
|----------|------|-------------|
|
|
793
|
+
| P0 | Full Drive access for AI assistant | Give Claude Code (Pallas) read/write access to personal Google Drive, closing the last major Google integration gap in PAI |
|
|
794
|
+
| P1 | Workspace format interop | Convert Google Docs, Sheets, Slides into AI-consumable formats (Markdown, CSV, JSON, plain text) |
|
|
795
|
+
| P2 | File lifecycle management | Create, read, update, delete, search, move, copy operations on Drive files and folders |
|
|
796
|
+
| P3 | Local-only deployment | Run entirely on local hardware (WSL2) with no cloud hosting, no exposed endpoints |
|
|
797
|
+
|
|
798
|
+
### 11.2 Security Posture
|
|
799
|
+
|
|
800
|
+
Existing Controls:
|
|
801
|
+
- SC-1: OAuth2 desktop app flow (Google-recommended, PKCE)
|
|
802
|
+
- SC-2: Token stored at ~/.config/mcp-google-gdrive/token.json with 0600 permissions
|
|
803
|
+
- SC-3: Single scope (drive), no Gmail or Calendar scopes
|
|
804
|
+
- SC-4: stdio transport only — no network listeners, no HTTP endpoints
|
|
805
|
+
- SC-5: Single-user model, runs as local user
|
|
806
|
+
- SC-6: WSL2 VM isolation from Windows host
|
|
807
|
+
- SC-7: Stateless between invocations (no database, no cache)
|
|
808
|
+
|
|
809
|
+
Accepted Risks:
|
|
810
|
+
- AR-1: Full Drive scope (required for Workspace export/conversion)
|
|
811
|
+
- AR-2: Token on local filesystem (single-user machine, encrypted disk + file permissions sufficient)
|
|
812
|
+
- AR-3: No audit logging (personal tool; Google Admin audit log available if needed)
|
|
813
|
+
- AR-4: AI can invoke destructive operations (Drive trash provides recovery; user approves tool calls)
|
|
814
|
+
|
|
815
|
+
### 11.3 C4 Context Diagram
|
|
816
|
+
|
|
817
|
+
```mermaid
|
|
818
|
+
C4Context
|
|
819
|
+
title System Context - Google Drive MCP Server
|
|
820
|
+
|
|
821
|
+
Person(user, "Shon", "PAI user interacting via Claude Code")
|
|
822
|
+
System(claudeCode, "Claude Code", "AI coding assistant running on Windows 11")
|
|
823
|
+
System(mcpServer, "mcp-google-gdrive", "MCP server in WSL providing Drive tools")
|
|
824
|
+
System_Ext(googleApi, "Google Drive API v3", "Google cloud service for file storage")
|
|
825
|
+
System_Ext(googleDrive, "Google Drive", "Personal cloud storage with files and Workspace docs")
|
|
826
|
+
|
|
827
|
+
Rel(user, claudeCode, "Sends requests via CLI/IDE")
|
|
828
|
+
Rel(claudeCode, mcpServer, "JSON-RPC over stdio", "MCP protocol")
|
|
829
|
+
Rel(mcpServer, googleApi, "HTTPS REST calls", "OAuth2 bearer token")
|
|
830
|
+
Rel(googleApi, googleDrive, "Internal Google infrastructure")
|
|
831
|
+
```
|
|
832
|
+
|
|
833
|
+
| Element | Type | Responsibilities |
|
|
834
|
+
|---------|------|-----------------|
|
|
835
|
+
| Shon | Person | Issues file management commands through Claude Code |
|
|
836
|
+
| Claude Code | System | Discovers MCP tools, selects appropriate tool for user request, displays results |
|
|
837
|
+
| mcp-google-gdrive | System | Authenticates to Google, translates MCP tool calls to Drive API requests, converts formats |
|
|
838
|
+
| Google Drive API v3 | External System | Provides REST endpoints for file CRUD, export, metadata |
|
|
839
|
+
| Google Drive | External System | Stores files, Google Workspace documents, folder structure |
|
|
840
|
+
|
|
841
|
+
### 11.4 C4 Container Diagram
|
|
842
|
+
|
|
843
|
+
```mermaid
|
|
844
|
+
C4Container
|
|
845
|
+
title Container Diagram - mcp-google-gdrive
|
|
846
|
+
|
|
847
|
+
Person(user, "Claude Code", "MCP client")
|
|
848
|
+
|
|
849
|
+
Container_Boundary(server, "mcp-google-gdrive (Node.js ESM)") {
|
|
850
|
+
Container(protocol, "MCP Protocol Handler", "McpServer + StdioServerTransport", "Receives JSON-RPC tool calls, routes to handlers")
|
|
851
|
+
Container(registry, "Tool Registry", "14 registerTool calls + Zod schemas", "Validates inputs, dispatches to API client")
|
|
852
|
+
Container(auth, "Auth Manager", "googleapis OAuth2Client", "Loads/refreshes/saves OAuth2 tokens")
|
|
853
|
+
Container(client, "Drive API Client", "googleapis drive.files.*", "Executes Drive API v3 HTTP requests")
|
|
854
|
+
Container(converter, "Format Converter", "turndown + marked", "HTML→MD, MD→HTML, CSV→JSON")
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
System_Ext(google, "Google Drive API v3", "REST API")
|
|
858
|
+
System_Ext(tokenFile, "~/.config/mcp-google-gdrive/token.json", "Local file")
|
|
859
|
+
|
|
860
|
+
Rel(user, protocol, "stdio JSON-RPC")
|
|
861
|
+
Rel(protocol, registry, "Tool call dispatch")
|
|
862
|
+
Rel(registry, client, "API request")
|
|
863
|
+
Rel(registry, converter, "Format conversion")
|
|
864
|
+
Rel(client, auth, "Get access token")
|
|
865
|
+
Rel(auth, tokenFile, "Read/write tokens")
|
|
866
|
+
Rel(client, google, "HTTPS REST")
|
|
867
|
+
```
|
|
868
|
+
|
|
869
|
+
| Container | Type | Responsibilities | Tech |
|
|
870
|
+
|-----------|------|-----------------|------|
|
|
871
|
+
| MCP Protocol Handler | Process | Accept stdio input, parse JSON-RPC, return responses | @modelcontextprotocol/sdk |
|
|
872
|
+
| Tool Registry | Module | Define 14 tools with Zod schemas and annotations | zod |
|
|
873
|
+
| Auth Manager | Module | OAuth2 token lifecycle (load, refresh, save) | googleapis |
|
|
874
|
+
| Drive API Client | Module | HTTP calls to Drive API endpoints | googleapis |
|
|
875
|
+
| Format Converter | Module | Bidirectional format conversion for Workspace files | turndown, marked |
|
|
876
|
+
|
|
877
|
+
### 11.5 C4 Deployment Diagram
|
|
878
|
+
|
|
879
|
+
```mermaid
|
|
880
|
+
C4Deployment
|
|
881
|
+
title Deployment Diagram - mcp-google-gdrive
|
|
882
|
+
|
|
883
|
+
Deployment_Node(win, "Windows 11 Pro", "Host OS") {
|
|
884
|
+
Deployment_Node(vscode, "VSCode + Claude Code") {
|
|
885
|
+
Container(cc, "Claude Code Extension", "MCP Client")
|
|
886
|
+
}
|
|
887
|
+
Deployment_Node(wsl, "WSL2 - Fedora 43", "Linux VM") {
|
|
888
|
+
Deployment_Node(node, "Node.js v22", "JavaScript Runtime") {
|
|
889
|
+
Container(mcp, "mcp-google-gdrive", "MCP Server Process")
|
|
890
|
+
}
|
|
891
|
+
Deployment_Node(config, "~/.config/mcp-google-gdrive/") {
|
|
892
|
+
Container(creds, "credentials.json", "OAuth2 client credentials")
|
|
893
|
+
Container(token, "token.json", "OAuth2 access + refresh tokens")
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
Deployment_Node(gcloud, "Google Cloud", "External") {
|
|
899
|
+
Container(driveApi, "Drive API v3", "REST Service")
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
Rel(cc, mcp, "stdio (JSON-RPC)")
|
|
903
|
+
Rel(mcp, creds, "Read on startup")
|
|
904
|
+
Rel(mcp, token, "Read/write for auth")
|
|
905
|
+
Rel(mcp, driveApi, "HTTPS REST calls")
|
|
906
|
+
```
|
|
907
|
+
|
|
908
|
+
### 11.6 Risk Assessment
|
|
909
|
+
|
|
910
|
+
Critical process: OAuth2 token management. If tokens are compromised, attacker has full Drive access.
|
|
911
|
+
|
|
912
|
+
Data sensitivity:
|
|
913
|
+
- credentials.json: MEDIUM (contains client_id and client_secret — enables auth flow but not data access alone)
|
|
914
|
+
- token.json: HIGH (contains refresh_token — grants persistent Drive access)
|
|
915
|
+
- File content in transit: MEDIUM (encrypted via HTTPS to Google, plaintext via stdio locally)
|
|
916
|
+
|
|
917
|
+
Mitigations: File permissions (0600), .gitignore exclusion, WSL2 VM boundary, no network exposure.
|