mcp-google-contacts
by boonkgim
README.md
# mcp-google-contacts
[](https://github.com/boonkgim/mcp-google-contacts/actions/workflows/ci.yml)
[](LICENSE)
A remote MCP server for Google Contacts, deployed on Cloudflare Workers, for
use as a **custom connector in claude.ai** (web/desktop/mobile). Each user
who connects authorizes their own Google account via OAuth — the server
proxies that OAuth flow and never sees your Google password, just the tokens
it needs to call the People API on your behalf.
Built for a specific workflow: send Claude a photo of a namecard/business
card and have it extract the details and save a new contact for you.
## Architecture
- **`@cloudflare/workers-oauth-provider`** — implements the OAuth 2.1 server
that claude.ai talks to (authorize/token/dynamic client registration), and
hands your Worker an encrypted `props` bag per authorized user.
- **`google-handler.ts`** — a small Hono app that owns `/authorize` and
`/callback`: shows the consent screen, redirects to Google, exchanges the
code for tokens, and stores the Google refresh token in `props`.
- **`agents`' `McpAgent`** — a Durable Object-backed MCP server. Tool calls
read `this.props.googleRefreshToken` and mint a fresh Google access token
on demand (cached in-memory per Worker isolate) before calling the People
API.
- **`workers-oauth-utils.ts`** — CSRF/session/approval-dialog plumbing,
copied near-verbatim from Cloudflare's reference OAuth demo (provider-agnostic).
## Tools
- `create_contact` — create a contact (name, company, title, emails, phones, address, notes)
- `search_contacts` — search existing contacts by name/email/phone/company (use before creating, to avoid duplicates)
- `list_contacts` — list contacts, most recently modified first
- `get_contact` — fetch full details for one contact
- `update_contact` — update fields on an existing contact
## 1. Google Cloud setup
1. Go to the [Google Cloud Console](https://console.cloud.google.com/) and create (or pick) a project.
2. Enable the **Google People API**.
3. Go to **APIs & Services → Credentials → Create Credentials → OAuth client ID**.
- Application type: **Web application**
- Authorized redirect URI: `https://<your-worker-subdomain>.workers.dev/callback`
(you'll know your Worker's URL after the first `wrangler deploy` — you can
add/edit this redirect URI afterward in the Cloud Console).
- Save the **Client ID** and **Client Secret**.
4. If your OAuth consent screen is in "Testing" mode, add your own Google account as a test user.
## 2. Cloudflare setup
```bash
npm install
npx wrangler login
npx wrangler kv namespace create OAUTH_KV
```
Copy the `id` printed by the last command into `wrangler.jsonc` under both
`kv_namespaces[0].id` and `env.development.kv_namespaces[0].id`.
If `npx wrangler whoami` lists more than one Cloudflare account, add
`"account_id"` to `wrangler.jsonc` (see the comment there) or set the
`CLOUDFLARE_ACCOUNT_ID` env var — otherwise `wrangler` can't tell which
account to deploy to.
Set secrets (you'll be prompted to paste each value):
```bash
npx wrangler secret put GOOGLE_CLIENT_ID
npx wrangler secret put GOOGLE_CLIENT_SECRET
npx wrangler secret put COOKIE_ENCRYPTION_KEY # e.g. output of: openssl rand -hex 32
```
## 3. Deploy
```bash
npm run deploy
```
This prints your Worker's URL, e.g. `https://mcp-google-contacts.<your-subdomain>.workers.dev`.
Go back to the Google Cloud Console and make sure the OAuth client's redirect
URI is exactly `<that-url>/callback`.
## 4. Connect it to claude.ai
In claude.ai: **Settings → Connectors → Add custom connector**, and enter:
```
https://mcp-google-contacts.<your-subdomain>.workers.dev/mcp
```
Claude will walk you through authorizing — you'll see the consent screen
from `google-handler.ts`, then Google's own OAuth screen. Once approved, the
Google Contacts tools are available in your conversations.
## Local development
```bash
cp .env.development.example .env.development # fill in the same three values as the secrets above
npm run dev
```
`wrangler dev` runs the Worker locally; note that Google's OAuth redirect
must match what you're actually running against (add `http://localhost:8788/callback`
as an additional authorized redirect URI in Google Cloud Console for local testing).
## Notes
- Uses the `https://www.googleapis.com/auth/contacts` OAuth scope (read/write access to your contacts) plus `email profile` to identify who's connecting.
- Google access tokens expire in ~1 hour; this server refreshes them on demand from the stored refresh token rather than syncing to this Worker's own OAuth token lifetime — simpler and correct regardless of how long a Claude session goes between its own token refreshes.
- `search_contacts`/`list_contacts` page through all of `people/me`'s connections client-side rather than using the People API's `searchContacts` endpoint, which requires a separate index warm-up and can lag behind recent edits.
- A previous local-only version of this server (stdio transport, for Claude Desktop) is available in this repo's git history if you'd rather run it locally instead of deploying.
## Contributing
See [CONTRIBUTING.md](CONTRIBUTING.md) for local setup and the quality
checks (`npm run check`) to run before opening a PR.
## License
[MIT](LICENSE)
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues