Skip to content

Restore gdrive server with search file ID fix and download tool#3302

Open
aaronpolhamus wants to merge 5 commits intomodelcontextprotocol:mainfrom
aaronpolhamus:restore-gdrive-server
Open

Restore gdrive server with search file ID fix and download tool#3302
aaronpolhamus wants to merge 5 commits intomodelcontextprotocol:mainfrom
aaronpolhamus:restore-gdrive-server

Conversation

@aaronpolhamus
Copy link

@aaronpolhamus aaronpolhamus commented Feb 8, 2026

Summary

  • Restores the archived src/gdrive/ server (removed in May 2025)
  • Fixes search results to include file IDs — the Drive API fetches files(id, name, mimeType, ...) but the output only included name and MIME type, making results unusable for downstream operations
  • Adds a download tool that saves files to a local temp directory instead of returning base64 blobs via the resource handler, which overflow LLM context windows
  • Fixes OAuth token auto-refresh — the server was creating new google.auth.OAuth2() without client credentials, so the refresh_token was unusable once the access_token expired (~1 hour). Now reads client_id/secret from the OAuth keys file.
  • Makes MCP resources opt-in via GDRIVE_ENABLE_RESOURCES env var — some MCP clients (e.g., Gemini CLI) call resources/list during initialization, which triggers drive.files.list() and can hang. Default is tools-only mode (search + download) for cross-client compatibility.

Motivation

The gdrive server is essential for LLM workflows that need to search and read Drive files (especially PDFs, images, and other binary formats). Two prior community PRs attempted similar improvements:

Both were closed when the server was archived. The underlying issues remain: without file IDs in search output, clients can't act on results; without a download tool, binary files either overflow context (base64 blobs) or are inaccessible.

Changes

1. Search output includes file IDs

// Before:
`${file.name} (${file.mimeType})`

// After:
`${file.name} (${file.mimeType}) [id:${file.id}]`

2. New download tool

  • Takes a fileId (from search results) and saves the file to a local directory
  • Google Workspace files are auto-exported: Docs → Markdown, Sheets → CSV, Presentations → Plain text, Drawings → PNG
  • Binary files (PDFs, images, etc.) saved as-is
  • Download directory configurable via GDRIVE_DOWNLOAD_DIR env var (default: /tmp/gdrive-downloads)
  • Filenames are sanitized for filesystem safety

3. OAuth token auto-refresh fix

The original server created new google.auth.OAuth2() without client_id or client_secret. This meant the refresh_token in the stored credentials was unusable — when the access token expired (~1 hour), Google's token endpoint returned invalid_request because the refresh grant requires client credentials. Now reads client_id/client_secret from the same OAuth keys file used during the initial auth flow (GDRIVE_OAUTH_PATH) and passes them to the OAuth2 constructor.

4. MCP resources opt-in (GDRIVE_ENABLE_RESOURCES)

Some MCP clients invoke resources/list during initialization, which triggers drive.files.list() and can hang or timeout. Resources are now disabled by default — the server advertises only tools capability. Set GDRIVE_ENABLE_RESOURCES=true to re-enable ListResources and ReadResource handlers.

This is a clean capability negotiation: the server honestly advertises what it supports based on the env var, and the MCP SDK validates that handlers match declared capabilities.

5. Standalone build

  • tsconfig.json is self-contained (no longer extends root tsconfig)
  • Version bumped from 0.6.2 → 0.7.0

Test plan

  • TypeScript compiles cleanly with npm run build
  • search returns file IDs in output format [id:...]
  • download saves binary files (PDFs) to local temp directory
  • download exports Google Docs as markdown
  • Filename sanitization handles special characters
  • OAuth auto-refresh works after access token expiry (tested with expired token + valid refresh_token)
  • Server starts in tools-only mode (default, no GDRIVE_ENABLE_RESOURCES)
  • Server starts with resources enabled (GDRIVE_ENABLE_RESOURCES=true)
  • Tested with Claude Code and Gemini CLI — both connect and use search/download tools successfully

Notes

We've been running these fixes in production for Claude Code and Gemini CLI MCP workflows (searching and reading ~300 signed compliance PDFs on Google Drive). Happy to maintain this server going forward.

Contact: aaron@mivest.io

🤖 Generated with Claude Code

aaronpolhamus and others added 5 commits February 8, 2026 01:15
The gdrive server was archived in May 2025, but it has two critical issues
for LLM workflows:

1. Search results discard file IDs — the Drive API returns them but the
   output only includes file name and MIME type, making it impossible to
   act on search results programmatically.

2. Binary files (PDFs, images) can only be read via the resource handler,
   which returns base64 blobs that overflow LLM context windows.

This commit restores the server from the pre-archive state and applies:

- Search output now includes file IDs as `[id:...]` in results
- New `download` tool that saves files to a local temp directory
  (configurable via GDRIVE_DOWNLOAD_DIR env var) instead of returning
  base64 blobs, enabling LLMs to read files with native tools
- Google Workspace files are auto-exported (Docs→MD, Sheets→CSV, etc.)
- Standalone tsconfig.json (no longer depends on root tsconfig)
- Version bump to 0.7.0

Prior community PRs modelcontextprotocol#1092 and modelcontextprotocol#1353 attempted similar improvements but
were closed when the server was archived.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Google Drive timestamps use U+202F (narrow no-break space) and other
Unicode whitespace in file names (e.g., "11:59 AM"). The previous regex
only stripped ASCII special characters, causing filenames with invisible
Unicode characters that break path resolution in LLM tools.

Extend the sanitization regex to also replace:
- U+00A0 (no-break space)
- U+202F (narrow no-break space)
- U+2000-U+200A (typographic spaces)
- U+2028-U+2029 (line/paragraph separators)
- U+205F (medium mathematical space)
- U+3000 (ideographic space)
- U+FEFF (BOM / zero-width no-break space)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…constructor

The server was creating `new google.auth.OAuth2()` without client_id or
client_secret, which meant the refresh_token was unusable once the
access_token expired. Google's token endpoint returned `invalid_request`
because the refresh grant requires client credentials.

Now reads client_id/client_secret from the OAuth keys file (same file used
for the initial auth flow) and passes them to the OAuth2 constructor,
enabling automatic token refresh.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Some MCP clients (e.g., Gemini CLI) call resources/list during
initialization, which triggers drive.files.list() and can hang or
timeout. Default to tools-only mode (search + download) for
cross-client compatibility. Set GDRIVE_ENABLE_RESOURCES=true to
re-enable the ListResources/ReadResource handlers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant