Hal Google MCP Integration¶
Connect Hal (opencode) to Gmail + Google Calendar via Google's official remote MCP servers.
Architecture¶
opencode (Hal) ──MCP──> gmailmcp.googleapis.com/mcp/v1 (official Google)
└──> calendarmcp.googleapis.com/mcp/v1
▲
OAuth 2.0 (Desktop app client, one-time consent)
tokens cached in ~/.local/share/opencode/mcp-auth.json
- No daemon, no cron, no new processes — pure config + one-time OAuth.
- Works exactly like existing
memory,desktop,shopifyMCP servers in opencode. - Session memory persists via Memory MCP — context survives across sessions.
Google Cloud Setup (one-time, ~10 min, in browser — your account)¶
1. Google Cloud Project¶
- Go to https://console.cloud.google.com
- Create a new project or select an existing one.
2. Enable 4 APIs¶
In APIs & Services → Library, enable:
gmail.googleapis.com
gmailmcp.googleapis.com
calendarmcp.googleapis.com
calendar.googleapis.com
gcloud services enable gmail.googleapis.com gmailmcp.googleapis.com calendarmcp.googleapis.com calendar.googleapis.com --project=YOUR_PROJECT_ID
3. OAuth Consent Screen¶
- APIs & Services → OAuth consent screen
- User Type: External (personal Gmail)
- App name:
Hal(or whatever) - Scopes (add manually under "Data access"):
https://www.googleapis.com/auth/gmail.readonlyhttps://www.googleapis.com/auth/gmail.composehttps://www.googleapis.com/auth/calendar.calendarlist.readonlyhttps://www.googleapis.com/auth/calendar.events.freebusyhttps://www.googleapis.com/auth/calendar.events.readonly- Publish the app: after saving, click Publish App → status becomes In production. No formal Google verification is required for personal single-user use — the consent screen will just show an "unverified app" warning once, which is harmless.
-
Why publish: In Testing mode Google expires refresh tokens after ~7 days (forces weekly re-auth). Publishing makes the refresh token effectively indefinite. No test-user setup needed.
- Save.
4. OAuth Client ID (Desktop App)¶
- APIs & Services → Credentials → Create Credentials → OAuth client ID
- Application type: Desktop app
- Name:
Hal opencode - Create → copy Client ID and Client Secret.
Important: Do NOT commit these to the config. Use environment variables.
opencode.json Configuration¶
Backup the existing config first (per your version-vs-in-place rule), then add two type: "remote" entries:
{
"mcp": {
"gmail": {
"type": "remote",
"url": "https://gmailmcp.googleapis.com/mcp/v1",
"enabled": true,
"oauth": {
"clientId": "{env:GOOGLE_MCP_CLIENT_ID}",
"clientSecret": "{env:GOOGLE_MCP_CLIENT_SECRET}"
}
},
"calendar": {
"type": "remote",
"url": "https://calendarmcp.googleapis.com/mcp/v1",
"enabled": true,
"oauth": {
"clientId": "{env:GOOGLE_MCP_CLIENT_ID}",
"clientSecret": "{env:GOOGLE_MCP_CLIENT_SECRET}"
}
}
}
}
Store credentials in a .env file (sourced in your shell profile) or export them:
# ~/.profile or ~/.config/fish/conf.d/hal-google.fish
export GOOGLE_MCP_CLIENT_ID="your-client-id"
export GOOGLE_MCP_CLIENT_SECRET="your-client-secret"
Restart opencode to pick up env vars.
Authenticate (once, then tokens auto-cached)¶
opencode mcp auth gmail
opencode mcp auth calendar
Each opens a browser consent screen. Approve. Tokens stored in ~/.local/share/opencode/mcp-auth.json (0o600).
Verify¶
# List available tools on each server
opencode mcp list
# Quick smoke tests (in an opencode session)
# "what's in my inbox today?"
# "what's on my calendar this week?"
# "draft a reply to the latest email from X"
# "create a calendar event for tomorrow 2pm: 'Review PRs'"
Caveats & Trade-offs¶
| Aspect | Detail |
|---|---|
| Token lifetime | Access token ~1 hour (auto-refreshed silently by opencode). Refresh token indefinite once the app is published — only invalidated by 6 months inactivity, a Gmail password change, or manual revocation. Re-auth only if one of those happens. |
| Scope limits | Official servers: Gmail = read + compose/send (gmail.readonly, gmail.compose). Calendar = read + create events. Full delete/archive or deeper write = custom server needed later. |
| Developer Preview | Both MCP servers are Google "Developer Preview" — fine for personal use, APIs may change. |
| No daemon | Nothing runs when opencode is closed → no reminders/scheduling (per your preference). |
| Security | Tokens in mcp-auth.json (0o600). Credentials via env vars. Your own Google Cloud project = your data stays in your Google account. The one-time "unverified app" warning is expected until/unless you go through formal Google verification. |
Alternatives (if needed later)¶
| Option | When |
|---|---|
Custom Python MCP (like desktop-mcp) |
Want full scopes, shared single OAuth client, stdlib-only, max control. More code + maintenance. |
| klodr/gmail-mcp (hardened) | Want recipient pairing, audit log, whitelisted send destinations. Still same weekly re-auth. |
| Google Workspace (paid) | Only needed if you ever want an Internal-only app (no consent screen at all). For personal Gmail, publishing the External app already removes the 7-day expiry — Workspace is optional. |
Related Pages¶
- [[OpenCode Desktop MCP]]
- [[OpenCode Canva Design Skill]]
- [[OpenCode MCP Node Requirement]]
- [[JBS LEMO Shopify Storefront]]
- [[OpenCode Voice Input]]