Google MCP Hub
Use all your Google accounts with Claude at once. Gmail, Drive and Calendar for your personal, work and side-project accounts, in one conversation.
flowchart LR
you(["🧑 You"]) -- "ask" --> claude["Claude<br/>claude.ai · Desktop · Code"]
claude -- "one connector,<br/>signed in as you" --> hub
subgraph gcp ["☁️ Your own Google Cloud project"]
hub["Google MCP Hub"]
vault[("🔐 Secret Manager<br/>account keys")]
hub --- vault
end
hub --> a["personal@gmail.com<br/>Gmail · Drive · Calendar"]
hub --> b["you@work.com<br/>Gmail · Drive · Calendar"]
hub --> c["side-project@gmail.com<br/>Gmail · Drive · Calendar"]
What you can do
- 📬 Search every inbox at once. "Find the latest invoice in any of my accounts."
- 🔀 Work across accounts. "Read the contract email in my work account and save a summary as a Google Doc in my personal Drive."
- 📅 See all your calendars together. "What's on my calendars this week?" or "Find a free hour on Tuesday across all accounts."
- 🏷️ Group accounts with tags. Tag two accounts
work, then ask "Check my work inboxes." - ✍️ Draft, don't send. Claude writes Gmail drafts and creates files and events. Nothing goes out without you.
Your data stays yours. You run your own copy in your own Google Cloud account. Nobody else holds your keys or sees your email, not even the people who wrote this code.
⭐ Leave a star if you find this useful
Contents
- What you need
- Setup at a glance
- Let your AI agent set it up: hand the work to Claude Code or a similar agent
- Deploy: the commands, for people comfortable with a terminal
- Connect your accounts and Claude
- Tools Claude gets
- How it stays private
- What it costs
- Run it locally
- Reference: settings, project layout, notes for AI agents, troubleshooting
🆕 New to Google Cloud? Follow the step-by-step setup guide. It assumes no experience and takes about 30 minutes.
What you need
| You need | Why | Cost |
|---|---|---|
| A Google account | To sign in to Google Cloud | Free |
| A Google Cloud account with billing turned on | The hub runs there. Google asks for a card even for free-tier use | About $0 a month for one person (details) |
| A Claude account on a plan with custom connectors | Claude talks to the hub as a connector | Your existing plan |
A terminal with gcloud |
To run the deploy script | Free. Cloud Shell has everything in your browser |
The Google accounts you connect can be any mix: personal Gmail, Google Workspace (work or school), or several of each.
Setup at a glance
| Step | What you do | Time |
|---|---|---|
| 1 | Create a Google Cloud project with billing | 5 min |
| 2 | Get the code and fill in deploy.env (project, region, your email) |
2 min |
| 3 | Run ./scripts/deploy.sh once; it tells you what to set up next |
1 min |
| 4 | Create a Google sign-in client in the Cloud Console (the only manual step) | 5 min |
| 5 | Run ./scripts/deploy.sh again; it deploys and prints your hub's address |
5 min |
| 6 | Open your hub, sign in, connect your Google accounts | 2 min |
| 7 | Add the hub to Claude as a custom connector | 1 min |
👉 Every click is spelled out in the step-by-step guide.
Let your AI agent set it up
An AI coding agent that can run terminal commands, such as Claude Code, can do most of the setup for you. You only do the parts that need your browser.
What your computer needs
| Tool | What it's for | Check it's installed | Get it |
|---|---|---|---|
| Claude Code (or another agent with a terminal) | Runs the setup for you | claude --version |
claude.com/claude-code |
| Git | Downloads the code | git --version |
git-scm.com/downloads |
Google Cloud CLI (gcloud) |
Talks to your Google Cloud account | gcloud --version |
cloud.google.com/sdk/docs/install |
| Bash | Runs the deploy script | bash --version |
Built into macOS and Linux. On Windows it comes with Git ("Git Bash") |
You don't need Docker or Node.js. Google Cloud builds the hub for you. Node.js 22+ is only needed to run it locally.
Your agent can check these and install what's missing.
What only you can do
The agent will stop and ask you for these, because each one needs your browser or your approval:
| When | What you do |
|---|---|
| Start | Sign gcloud in to your Google account: type ! gcloud auth login in Claude Code, or run gcloud auth login in a terminal |
| Start | Make sure your Google Cloud account has billing turned on (step 2 of the guide) |
| Middle | Create the Google sign-in client in the Cloud Console. Google has no command for this (step 7 of the guide) |
| Middle | Allow steps that create cloud resources or make the hub reachable from the internet, when your agent asks permission |
| End | Open your hub, sign in and connect your Google accounts |
| End | Add the hub to Claude as a custom connector and press Approve |
What to ask
Copy this into Claude Code, filling in the blanks:
Set up Google MCP Hub for me from https://github.com/rescueahero4/google-mcp-hub.
Follow its README ("Notes for AI agents") and guides/getting-started.md.
My owner email is: ____________
My region is: ____________ (for example us-central1 or asia-northeast1)
Use a new Google Cloud project called: ____________ (or reuse one I name)
Check what I need installed first, and tell me exactly what to click whenever you need me.
🔒 Stay in control. The agent works in your own Google Cloud account with your permission. It never needs your Google password, and your client secret stays in
deploy.envon your computer, which git ignores.
Deploy
For people who already use gcloud. You need a project with billing enabled.
Step 1 — Get the code and set your details
git clone https://github.com/rescueahero4/google-mcp-hub.git
cd google-mcp-hub
cp deploy.env.example deploy.env
Edit deploy.env:
PROJECT_ID=my-mcp-hub # project IDs cannot contain the word "google"
REGION=us-central1 # pick one near you
OWNER_EMAILS=you@gmail.com # the only Google account(s) allowed to use the hub
Step 2 — First run
./scripts/deploy.sh
It enables the APIs, then stops and prints your hub's redirect URI with what to do next.
Step 3 — Create the OAuth client
- Google Auth Platform → Get started. Audience: External.
- Audience → Publish app, so connected accounts don't expire after 7 days. See Testing vs. In production.
- Clients → Create client → Web application. Add the redirect URI the script printed.
- Put the client ID and secret in
deploy.env:
GOOGLE_CLIENT_ID=1234-abc.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=GOCSPX-...
Step 4 — Deploy
./scripts/deploy.sh
It creates two service accounts and three secrets, builds the image on Cloud Build and deploys to Cloud Run. Then it prints:
Hub: https://google-mcp-hub-123456789.us-central1.run.app/
Claude connector: https://google-mcp-hub-123456789.us-central1.run.app/mcp
What the script creates
| Resource | Purpose | Permissions |
|---|---|---|
Cloud Run service google-mcp-hub |
The hub. Scales to zero, max 1 instance | Public URL; the hub checks every request itself |
Service account hub-runtime |
Runs the hub | Read its 3 secrets; add versions to hub-accounts. Nothing project-wide |
Service account hub-builder |
Builds the image from source | roles/run.builder |
Secret hub-accounts |
Connected accounts and their Google refresh tokens | Old versions destroyed on every write |
Secret hub-signing-key |
Signs the hub's own tokens and sessions | Rotate to sign everyone out |
Secret hub-google-client-secret |
Your OAuth client secret |
Updating to a new version
git pull
./scripts/deploy.sh --yes
Connected accounts and Claude connections survive updates.
Signing every Claude connection out
./scripts/deploy.sh --yes --rotate-signing-key
Every Claude app has to sign in and press Approve again. Connected Google accounts stay connected.
Removing everything
Delete the project if it only holds the hub:
gcloud projects delete my-mcp-hub
Or remove just the hub's parts:
gcloud run services delete google-mcp-hub --region us-central1
gcloud secrets delete hub-accounts
gcloud secrets delete hub-signing-key
gcloud secrets delete hub-google-client-secret
gcloud iam service-accounts delete hub-runtime@my-mcp-hub.iam.gserviceaccount.com
gcloud iam service-accounts delete hub-builder@my-mcp-hub.iam.gserviceaccount.com
Disconnect your accounts on the hub page first, so their access is also revoked at Google.
Connect your accounts and Claude
Connect Google accounts
- Open your hub's address and sign in with your owner email.
- Under Connect an account, pick an access level and click Connect with Google.
- Choose the account in Google's chooser. You'll see "Google hasn't verified this app". That's expected for your own private app: click Advanced → Go to … (unsafe).
- Repeat for each account.
| Field | Required | What it's for |
|---|---|---|
| Access | Yes | read-write (default) or read-only |
| Name | No | A short name Claude can use. Defaults to the part of the email before @ |
| Tags | No | Groups like work or family. Several accounts can share a tag |
You can rename, re-tag, reconnect or disconnect any account later from the same page.
Connect Claude
| App | How |
|---|---|
| claude.ai, Desktop, mobile | Settings → Connectors → Add custom connector → paste https://<your hub>/mcp → sign in with Google → Approve |
| Claude Code | claude mcp add --transport http google-hub https://<your hub>/mcp, then /mcp to sign in |
Then try: "List my connected Google accounts, then show the 3 latest emails in each."
Tools Claude gets
Every tool takes an account: the account's name or email.
| Area | Tool | What it does |
|---|---|---|
| Accounts | list_accounts |
Connected accounts with names, emails, tags and access |
| Gmail | gmail_search |
Search with Gmail syntax, like from:boss newer_than:7d |
gmail_read_message |
Read one message: headers, text and attachment list | |
gmail_create_draft |
Create a draft. Never sends | |
| Drive | drive_search |
Search file names and contents |
drive_read |
Read a file as text. Docs come back as Markdown, Sheets as CSV | |
drive_create |
Create a file from text, optionally as a Google Doc or Sheet | |
| Calendar | calendar_list_calendars |
Calendars the account can see |
calendar_list_events |
Events in a time range (default: next 7 days) | |
calendar_find_busy |
Busy times only, for finding a free slot across accounts | |
calendar_create_event |
Create an event. Guests are only emailed if you ask |
Working across accounts is Claude reading with one account's tool and writing with another's. The hub never moves data between accounts on its own, and every step shows up in Claude.
How it stays private
sequenceDiagram
participant C as Claude
participant H as Your hub
participant G as Google sign-in
C->>H: Connect
H->>G: Who is this?
G-->>H: you@gmail.com (verified)
H->>H: Is this an owner email?
H->>H: Did they press Approve?
H-->>C: Access token (1 hour)
C->>H: gmail_search(account: "work")
H->>H: Check token and owner, every request
- 🔑 Only you get in. Signing in, connecting accounts and approving Claude all need a Google account listed in
OWNER_EMAILS. Everyone else is refused. - ✋ You approve each Claude app. After Google sign-in, the hub asks you to press Approve before Claude gets a token.
- 🧾 Only Claude can register. The hub accepts sign-in requests only from Claude's addresses (claude.ai, claude.com, and localhost for Claude Code).
- 🔐 Keys live in Secret Manager. Google refresh tokens are stored encrypted in one secret. The hub's runtime account can read only its own three secrets.
- 📝 Logs without content. Each tool call logs who, which account, which tool, how long and whether it worked. Never message text, search terms or tokens.
- ⚠️ Email can contain tricks. Text from emails and files is treated as untrusted, and Claude is told not to follow instructions inside it. For a hard guarantee, connect inbox-heavy accounts as
read-only.
Testing vs. In production
Google's Publish app button does not make your hub public or list it anywhere. It changes two things:
| Testing | In production | |
|---|---|---|
| Who can pass Google's sign-in for your app | Only test users you add | Any Google account, after a warning |
| Connected accounts | Expire every 7 days | Stay connected |
Either way, the hub itself still refuses anyone who isn't an owner. Pick In production to avoid weekly reconnects, or stay in Testing (adding your own accounts as test users) for an extra layer from Google.
What it costs
For one person, expect $0 to about $1 a month.
| Part | Why it's cheap |
|---|---|
| Cloud Run | Scales to zero; you pay only while a request runs |
| Secret Manager | Three small secrets, well inside the free tier |
| Cloud Build, Artifact Registry | A few minutes of build time and a small image per deploy |
Set a budget alert (for example $5) so nothing surprises you. The first call after a quiet spell takes 1–3 seconds while the hub wakes up.
Run it locally
For trying changes without deploying.
npm install
cp .env.example .env # fill in an OAuth client and a 32+ character HUB_SIGNING_KEY
npm run dev # http://localhost:8080
- Add
http://localhost:8080/oauth/google/callbackto your OAuth client's redirect URIs. - Accounts are stored in
.data/accounts.json(git-ignored). - Test with MCP Inspector or
claude mcp add --transport http hub-dev http://localhost:8080/mcp. npm run typecheckchecks types.npm run buildcompiles todist/.
Reference
Settings (environment variables)
The deploy script sets these for you. You only set them yourself for local runs.
| Variable | Required | Meaning |
|---|---|---|
BASE_URL |
Yes | The hub's public address |
OWNER_EMAILS |
Yes | Comma-separated Google emails allowed to use the hub |
GOOGLE_CLIENT_ID |
Yes | Your OAuth client ID |
GOOGLE_CLIENT_SECRET |
Yes | Your OAuth client secret |
HUB_SIGNING_KEY |
Yes | Random string, 32+ characters. Changing it signs everyone out |
STORE |
No | file (default, local) or gcp (Secret Manager) |
DATA_FILE |
No | Local account file. Default .data/accounts.json |
GCP_PROJECT |
With gcp |
Project that holds the accounts secret |
ACCOUNTS_SECRET |
No | Secret name. Default hub-accounts |
ALLOWED_REDIRECT_URIS |
No | Comma-separated OAuth redirect URIs allowed to register. Default: claude.ai and claude.com |
ALLOW_LOOPBACK_REDIRECTS |
No | false blocks localhost clients such as Claude Code. Default true |
PORT |
No | Default 8080 |
Project layout
src/
server.ts routes (plain node:http, no framework)
oauth.ts sign-in for Claude: Google-gated, owner-only, stateless
web.ts the hub page: sign in, connect, rename, tag, disconnect
accounts.ts per-account Google access and friendly errors
store.ts account list: a JSON file locally, one secret on Google Cloud
mcp.ts builds the MCP server for each request
tools/ one file per Google service
scopes.ts the two access levels
scripts/deploy.sh one-command deploy
guides/ step-by-step setup guide
Two runtime dependencies: @modelcontextprotocol/sdk and zod. Google APIs are called with plain fetch.
Adding a Google service
- Create
src/tools/<service>.tsexportingregister<Service>Tools(ctx). - Register each tool with
ctx.tool(name, { title, description, input, readOnly }, handler). - In the handler,
await googleFor(ctx.user, account)gives you afetchsigned in as that account. - Call it from
src/mcp.ts, and add any new scopes tosrc/scopes.ts.
Notes for AI agents
Follow these when a user asks you to set up or update the hub.
- Check the tools:
git --version,gcloud --version,bash --version. Help the user install anything missing. Docker and Node.js are not needed to deploy. - Check sign-in:
gcloud auth list. If no account is active, ask the user to rungcloud auth loginthemselves. It opens a browser, so you can't do it. - Pick the project: create one with
gcloud projects create <id>(the ID must not contain "google") and link billing withgcloud billing projects link <id> --billing-account <account>, or use one the user names. If creation fails on quota, offer to reuse an existing project. - Write
deploy.envfromdeploy.env.example:PROJECT_ID,REGION,OWNER_EMAILS. Never commit it, print the client secret, or paste it into chat. - First run:
./scripts/deploy.sh --yes. With no OAuth client set, it enables APIs, prints the redirect URI and exits. - Hand over the OAuth client step: walk the user through guide step 7 with the printed redirect URI. Ask them to put the client ID and secret into
deploy.envthemselves, or to give you the downloaded JSON file so you can copy the values without showing them. - Deploy:
./scripts/deploy.sh --yes. The build takes 3–5 minutes, so run it in the background if you can. The script grants a project IAM role and deploys a public Cloud Run service, so expect to need the user's permission. - If the build fails reading sources (
storage.objects.get), re-run the script; it sets up thehub-builderservice account. - Hand over the browser steps: opening the hub URL, connecting accounts, and adding
<hub URL>/mcpas a custom connector in Claude, then pressing Approve. - Verify:
curl <hub URL>/healthreturns{"ok":true}. For errors, read the logs:gcloud logging read 'resource.type="cloud_run_revision" AND resource.labels.service_name="google-mcp-hub" AND severity>=ERROR' --project <id> --limit 20 --freshness 1h.
To update an existing hub: git pull, then ./scripts/deploy.sh --yes.
Troubleshooting
| Problem | Fix |
|---|---|
| Accounts need reconnecting every 7 days | Your OAuth app is in Testing. Publish it, or reconnect weekly |
| "Google hasn't verified this app" | Expected for a private app. Advanced → Go to … (unsafe) |
redirect_uri_mismatch |
The OAuth client's redirect URI must exactly match the one the script prints |
| Project ID rejected | Project IDs can't contain "google" |
| "You have exceeded your project quota" | Reuse an existing project, or request more |
Build fails reading sources (storage.objects.get) |
Re-run the script; it sets up the hub-builder account that fixes this |
allUsers / domain-restricted sharing error |
Your organization blocks public services. Use a project outside the organization, or ask your admin |
| Work account can't connect | Your Workspace admin blocks outside apps. Ask them to trust your OAuth client ID |
| Claude doesn't see new tools | Start a new chat, or turn the connector off and on |
| Something else | Check the logs: Cloud Console → Cloud Run → google-mcp-hub → Logs |
License
MIT. Free to use, change and share.