Google is the one connector most portfolios need per entity: each company has its own mailbox, its own calendar, its own Drive. That makes it a brain-layer connector, which is the only layer that gives real isolation.
What it gives Plexward
- Gmail. Inbox triage into the entity's brain, thread reading for context, and drafts staged for your review. Sending is a human decision.
- Calendar. The shared calendar on the dashboard, meeting preparation briefs, and the weekly page that is built from next week's meetings.
- Drive. Documents read into the knowledge index, document-freshness audits that flag a stale contract or an out-of-date memo, and generated deliverables written back into the right folder.
- Sheets and Docs, optionally, when an entity's operating model lives in a spreadsheet. Editing happens in place, with no download and re-upload round trip.
Layer
brain. Each entity runs its own local MCP server process, over stdio, with its own credential directory. This is the layer where isolation is real rather than doctrinal.
There is also an account layer alternative: the claude.ai Gmail, Google Calendar and Google Drive connectors. They reach exactly one Google account for your whole machine. Use them only if you run a single entity, or for a genuinely personal account. If you run a per-entity server, name the account-layer Google connectors in every brain's NOT This Company block, or an agent will reach for the wrong mailbox and you will not find out until the draft goes to the wrong person.
Declare it as:
{ "name": "acme-google", "layer": "local MCP", "svc": "Gmail · Drive · Calendar", "account": "ops@acme.example" }
Prerequisites
- A Google Cloud project you control, with an OAuth client of type Desktop app. One project can serve several entities; one OAuth client per entity is cleaner.
- The APIs the entity actually needs, enabled in that Cloud project: Gmail, Calendar, Drive, and Docs and Sheets if you want them. Enabling an API and requesting a scope are two different things and both are required.
- A local Google Workspace MCP server binary. It runs as a stdio process launched by the brain.
- A free localhost port per entity for the OAuth callback.
Setup steps
1. Create the OAuth client. In the Cloud console, create a Desktop app OAuth client. Add the callback as an authorized redirect URI:
http://localhost:8010/oauth2callback
Pick a distinct port per entity (8010, 8011, 8012, ...) and write the assignment down. This single line causes more failed setups than everything else on this page combined.
2. Put the secret outside the repo.
mkdir -p ~/.config/secrets
cat > ~/.config/secrets/acme-google.env <<'ENV'
GOOGLE_OAUTH_CLIENT_ID=<client-id>
GOOGLE_OAUTH_CLIENT_SECRET=<client-secret>
ENV
chmod 600 ~/.config/secrets/acme-google.env
Or, with a secrets backend, put the values in the entity's vault and reference them from the brain's committed .env.tpl. Either way the value never enters the repo.
3. Write the server block. Copy .mcp.json.example to .mcp.json in the brain (it is gitignored) and adjust:
{
"mcpServers": {
"acme-google": {
"command": "/absolute/path/to/workspace-mcp",
"args": ["--tools", "gmail", "drive", "calendar", "--single-user", "--transport", "stdio"],
"env": {
"GOOGLE_OAUTH_CLIENT_ID": "${GOOGLE_OAUTH_CLIENT_ID}",
"GOOGLE_OAUTH_CLIENT_SECRET": "${GOOGLE_OAUTH_CLIENT_SECRET}",
"WORKSPACE_MCP_CREDENTIALS_DIR": "~/.google_workspace_mcp/credentials/acme",
"WORKSPACE_MCP_PORT": "8010"
}
}
}
}
Name the server <slug>-google. The probe matches on the name, the routing doc refers to it by name, and a generic name like google makes it impossible to tell two entities apart in a connector list.
Use absolute paths for the command. If the binary comes from a version manager such as fnm or nvm, pin the full versioned path. A bare npx or node works in your interactive shell and dies on reboot under a process manager.
4. Choose the permission level deliberately. Two different mechanisms are easy to confuse:
--tools gmail drive calendarselects which tool groups are loaded.--permissions gmail:readonly drive:full docs:full sheets:fullselects the OAuth scopes requested.
A common and good default is Gmail read-only with Drive and Docs read-write: the agent can read the thread and draft a reply, but sending stays a human action through a reviewed draft.
5. Run the OAuth consent once, per entity. Start a session in the brain and call any tool from the server. It prints an authorization URL, you open it in a browser, sign in as the entity's Google user, and approve. The token lands in the credentials directory you set. This is a browser step and it is yours.
6. Map the entity for the calendar view. The dashboard needs to know which credential directory belongs to which entity:
cp control-center/config/calendar-creds.example.json control-center/config/calendar-creds.json
{
"acme": "acme",
"bravo": "acme"
}
Two entities may deliberately point at the same directory when they share one Google Workspace. Make that a recorded decision, not an accident.
Gmail
Read-only is the right default. Attachment download works, sending and label changes do not. Drafting happens in the brain and a human sends. If an entity genuinely needs the agent to label or archive, widen the scope for that entity only, and say so in the routing doc.
When you do draft mail, draft it as HTML rather than plain text: plain text renders as a narrow fixed-width column in Gmail's reading pane. Wrap paragraphs in block elements, separate them with a spacer, and use real links.
Calendar
Calendar is the input to two things: the dashboard's shared calendar strip, and any skill that builds a weekly page from next week's meetings. Read access is enough for both. Write access is only needed if you want the agent to create events, which is rarely worth the scope.
Drive
Drive powers document-freshness audits: the agent lists a folder with modification dates, applies per-type rules (a status doc goes stale in two weeks, a company overview in two months, a compliance document is flagged hardest), and reports a risk-ranked list of what to refresh. That needs read access plus metadata. Writing deliverables back needs drive.file at minimum, and full drive if the agent must move or reshare files.
Per-entity routing
## Owned Integrations
| MCP Tool | Service | Account / Workspace | Notes |
|---|---|---|---|
| acme-google | Gmail, Drive, Calendar | ops@acme.example | Local server, stdio. Credential dir `~/.google_workspace_mcp/credentials/acme`. OAuth callback on port 8010: that redirect URI must stay registered on the OAuth client. |
## NOT This Company
- claude.ai Gmail / Google Calendar / Google Drive. Those reach a different
account. Use `acme-google` instead.
- Any other entity's `<slug>-google` server.
Credential isolation is a directory convention. WORKSPACE_MCP_CREDENTIALS_DIR pointing at ~/.google_workspace_mcp/credentials/<slug> is the only thing keeping two Google-connected entities apart. Two entities that share a directory share one consent and one refresh token, which means re-authorizing or revoking either one does the same to the other. That is sometimes exactly what you want (two brands, one mailbox) and sometimes a nasty surprise. Write the decision into the routing doc.
Verify
cd ~/brains/acme-brain && claude mcp list | grep '^acme-google'
ls -la ~/.google_workspace_mcp/credentials/acme/
bin/mc-connectors --company acme --dry-run | grep -i google
Expected: acme-google: /path/to/workspace-mcp ... - ✔ Connected, a token file in the credentials directory with a recent modification time, and an active row from the probe.
Then a real read, because Connected only proves the process started: ask a session in the brain to list the last three calendar events, or the newest file in a known Drive folder, and confirm it is the right account's data.
Common failures
redirect_uri_mismatch. The port inWORKSPACE_MCP_PORTdoes not match a registered redirect URI on the OAuth client. This is the number one failure. If you recreate the client or change the port, update both sides in the same sitting.- "Editing does not work" has three separate causes that look identical. (1) The tool group was not loaded (
--toolsis missingdocs). (2) The stored token predates the write scope and needs a one-time re-consent. (3) The API itself was never enabled in the Cloud project. Check all three before concluding the connector is broken. - Widening scopes does not re-consent by itself. Adding a permission to the args changes what is requested; the token on disk still carries the old grant. Delete the token or force a re-auth, then verify with a write-read-clear cycle against a throwaway document.
- Two entities quietly sharing a token. Setting up entity B by copying entity A's block and forgetting to change
WORKSPACE_MCP_CREDENTIALS_DIRmakes B silently read A's mail, with no error anywhere. Always verify with a real read against known data, not with the health check. - A version-manager path that dies on reboot. The server works all day and is
disconnectedafter a restart. Pin the absolute versioned binary path. - Consent expiry on an unverified Cloud app. A testing-mode OAuth app issues refresh tokens that expire in days. Publish the app, or expect to re-consent constantly.
- Token files are secrets.
~/.google_workspace_mcp/credentials/holds live refresh tokens. It belongs outside every repo, at mode 600, and it belongs in your backups only if your backups are encrypted.
What Plexward does with it once connected
Calendar feeds the dashboard's shared calendar and the meeting-brief skills. Gmail feeds inbox triage, which folds thread summaries into the entity's brain and stages replies as drafts for review. Drive feeds the knowledge index and the document-freshness audit, which writes a dated risk-ranked report into the brain and pings the entity's Telegram topic with a four-line summary.
Cross-platform weekly digests read all three at once: what changed in Drive, which threads went quiet, which meetings happened, and what that implies for next week.