Skip to main content
Glama
devinxiong97

gdrive-mcp-server

by devinxiong97
README.md
# Personal Google Drive — Remote MCP Server

A production-style **remote [Model Context Protocol](https://modelcontextprotocol.io) (MCP) server** that connects an MCP-compatible AI assistant to a **Google Drive** account. It runs serverlessly on **Cloudflare Workers**, authenticates users with **Google OAuth 2.0**, and exposes Drive as a small set of safe, well-typed tools the assistant can call.

The interesting part is the auth: this single Worker is **both an OAuth server and an OAuth client at the same time**. It issues tokens to the AI client *and* logs the user into Google — a pattern that shows up in almost every real "connect my app to a third-party API on the user's behalf" integration.

> **New here?** Read the two guides in [`docs/`](docs/):
> - [`docs/SETUP_GUIDE.md`](docs/SETUP_GUIDE.md) — build and deploy it yourself, step by step.
> - [`docs/HOW_IT_WORKS.md`](docs/HOW_IT_WORKS.md) — the concepts (MCP, OAuth, serverless) explained from scratch.

---

## What it does

Once connected, the assistant gains these tools:

| Tool | What it does |
|------|--------------|
| `whoami` | Reports which Google account is connected (a quick sanity check). |
| `list_files` | Lists the most recently modified files. |
| `search_files` | Searches by file name or full-text content. |
| `read_file` | Reads a file by id. Google Docs/Sheets/Slides are exported to text/CSV. |
| `create_file` | Creates a new file from text — including native Google Docs. |
| `update_file` | Replaces a file's contents and/or renames it. |
| `delete_file` | Moves a file to the Drive trash (recoverable, not a hard delete). |

Each tool is a thin, validated wrapper over the Google Drive REST API, called with the signed-in user's access token.

## Architecture at a glance

```
                  OAuth server                          OAuth client
   ┌───────────┐  (issues tokens)   ┌──────────────┐   (logs you in)   ┌─────────┐
   │ AI client │ ◀────────────────▶ │  This Worker │ ◀───────────────▶ │ Google  │
   └───────────┘   MCP over /sse    └──────────────┘    Drive API      └─────────┘
                                           │
                                    ┌──────┴───────┐
                                    │ Durable Obj  │  holds the live MCP session
                                    │ + KV (grants)│  stores OAuth grants/tokens
                                    └──────────────┘
```

1. The AI client connects to `/sse`, finds it protected, and runs an OAuth flow **against this Worker**.
2. The Worker shows a one-time approval screen, then redirects the user to **Google** to sign in and consent.
3. Google redirects back to `/callback`; the Worker exchanges the code for a Google access token and stores it (with the user's name/email) as **encrypted session state**.
4. The MCP tools call the Google Drive API using that token, on the user's behalf.

## Tech stack

- **[Cloudflare Workers](https://developers.cloudflare.com/workers/)** — serverless runtime (deploys globally, scales to zero, free tier).
- **[Durable Objects](https://developers.cloudflare.com/durable-objects/)** — host the stateful MCP session.
- **[Workers KV](https://developers.cloudflare.com/kv/)** — stores OAuth grants.
- **[`@cloudflare/workers-oauth-provider`](https://github.com/cloudflare/workers-oauth-provider)** — turns the Worker into a spec-compliant OAuth server.
- **[`agents` / `McpAgent`](https://www.npmjs.com/package/agents)** — the MCP server framework.
- **[`@modelcontextprotocol/sdk`](https://github.com/modelcontextprotocol)** — the MCP types and server.
- **[Hono](https://hono.dev/)** — tiny router for the `/authorize` and `/callback` endpoints.
- **[Zod](https://zod.dev/)** — runtime validation of every tool's inputs.
- **TypeScript** throughout.

## Repository map

| File | Responsibility |
|------|----------------|
| `src/index.ts` | The MCP server, all Drive tools, and the `OAuthProvider` wiring. |
| `src/google-handler.ts` | The `/authorize` + `/callback` routes that talk to Google. |
| `src/utils.ts` | Google authorize-URL builder and authorization-code → token exchange. |
| `src/workers-oauth-utils.ts` | Signed-cookie approval dialog (reference helper). |
| `wrangler.jsonc` | Worker config: bindings, Durable Object, KV namespace. |

## Quick start

Full instructions live in [`docs/SETUP_GUIDE.md`](docs/SETUP_GUIDE.md). The short version:

```bash
npm install
npx wrangler login
npx wrangler kv namespace create OAUTH_KV     # paste the id into wrangler.jsonc

npx wrangler secret put GOOGLE_CLIENT_ID
npx wrangler secret put GOOGLE_CLIENT_SECRET
npx wrangler secret put COOKIE_ENCRYPTION_KEY # value: openssl rand -hex 32

npm run deploy
```

Then add the printed `https://<your-worker>.workers.dev/sse` URL as a custom connector in any MCP-compatible client and sign in with Google.

## Local development

```bash
cp .dev.vars.example .dev.vars   # fill in the three values
npm run dev                       # http://localhost:8788
npx @modelcontextprotocol/inspector@latest   # point it at http://localhost:8788/sse
```

## Design notes & limitations

- **Scope is configurable.** The default requests the full `drive` scope so the write tools work. Narrow it to `drive.file` (only files this app creates) or `drive.readonly` in `src/google-handler.ts` to reduce risk.
- **Token lifetime.** Uses Google's short-lived access token (no refresh token yet), so a periodic re-connect is needed. Adding offline/refresh-token support is the natural next enhancement.
- **`read_file` handles text.** Plain-text files and exportable Google formats (Docs/Sheets/Slides) work; arbitrary binary files are out of scope.
- **`delete_file` trashes, it doesn't purge.** Files go to Drive trash and remain recoverable.

## License

MIT