google-accounts-mcp
Provides tools for searching, reading, sending, and drafting emails, managing labels, and handling attachments via the Gmail API.
Provides tools for managing Google Calendar events and calendar settings, including per-account calendar management.
Provides access to a shared Google Drive folder for file handoff, including uploading, downloading, and listing files.
Provides tools for managing tasks via the Google Tasks API.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@google-accounts-mcpsearch for unread emails from alice@example.com"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
google-accounts-mcp
One MCP server for all your Google
accounts — multi-account by design. 51 tools across six surfaces:
Gmail, a shared Google Drive folder for file handoff, a cross-MCP shared
filesystem, per-account Google Calendar (incl. calendar management),
Google Tasks, and Google Contacts (read/write on saved contacts). Every
tool takes an account parameter; authorize as many Google accounts as
you like and address them by name or unique substring. Built on the
Python MCP SDK
(FastMCP); runs as a local stdio server or a containerized Streamable
HTTP service with bearer auth. Works with any MCP client.
Unofficial project, not affiliated with or endorsed by Google.
Table of Contents
Related MCP server: mcp-gsuite
Quick Start
One-time Google Cloud setup: create (or pick) a GCP project, enable the
Gmail, Google Drive, Google Calendar, Google Tasks, and People APIs,
and create an OAuth client ID of type Desktop app (APIs & Services →
Credentials). That client ID/secret is what authorize.py uses for the
local browser consent flow.
# Prerequisites: Python 3.12+, uv
uv sync
export GOOGLE_CLIENT_ID=...
export GOOGLE_CLIENT_SECRET=...
export TOKEN_DB_PATH=~/.local/share/google-accounts-mcp/tokens.db
# Authorize one or more Google accounts (opens a browser per account;
# stores refresh tokens in the SQLite DB, chmod 600)
uv run scripts/authorize.py you@example.com second@gmail.com
# Run over stdio (what most MCP clients spawn)
uv run google-accounts-mcp --stdio
# ...or as an HTTP server (requires MCP_BEARER_TOKEN)
MCP_BEARER_TOKEN=... uv run google-accounts-mcp
# Streamable HTTP at http://0.0.0.0:8321/mcpTool Reference
Every tool accepts an optional account parameter. When omitted it falls
back to DEFAULT_ACCOUNT (configured via env var). Partial account matches
are resolved automatically if unambiguous.
Account Management
Tool | Parameters | Description |
|
| List all authorized Gmail accounts. Optional substring filter. |
|
| List system and user labels for an account. |
Search & Read
Tool | Parameters | Description |
|
| Search with Gmail query syntax (e.g. |
|
| Fetch a full message: headers + text/plain body (falls back to stripped HTML). |
|
| Fetch every message in a thread. |
Drafts & Sending
Both draft_email and send_email take the same parameters:
Parameter | Type | Description |
|
| Recipient addresses. |
|
| Subject line. |
|
| Plain-text body. |
|
| Sending account. Defaults to |
|
| CC recipients. |
|
| BCC recipients. |
|
| Turns the message into a reply — stamps |
|
| Unified source references — see below. |
Each attachments entry is a scheme:value string:
local:<path>— file underATTACHMENTS_DIR. Path may be relative (e.g.local:uploads/report.pdfafterupload_file) or reference a previously downloaded attachment (local:<message_id>/<filename>). Paths outsideATTACHMENTS_DIRare rejected.shared:<filename>— file on the cross-MCP shared mount (/shared), e.g. staged there by notion-mcp'snotion_download_file(destination='shared'). Bare filenames only; verify staging withlist_shared_files.drive:<name-or-id>— file in the shared Drive folder. Tries name lookup first, falls back to treating the value as a Drive file ID; in either case the file must live inside the shared folder.
# Example
send_email(
to=["alice@example.com"],
subject="Q2 report",
body="See attached.",
attachments=["local:uploads/q2.pdf", "drive:charts.xlsx"],
)draft_email writes to the Drafts folder; send_email dispatches immediately
(use with care).
Shared-Store Semantics
The shared mount at /shared (host path
~/.local/share/containers/data/mcp-shared/) is read/write from both
MCP servers and has two invariants worth knowing:
Filename clashes auto-rename, atomically. If
download_attachmentis asked to writeinvoice.pdfinto shared storage and a file with that name already exists, the new one lands atinvoice-2.pdf(invoice-3.pdf, etc.). The create usesO_CREAT | O_EXCLso two concurrent writers never clobber each other, even without a prefix. The return value always reports the actual saved filename and thesource='shared:<actual-name>'string to pass to notion-mcp, so the agent never has to guess.Explicit namespacing via
prefix. In batch workflows where multiple messages may legitimately carry the same filename (e.g. 20 different senders whose attachment isinvoice.pdf), the auto-rename is safe but ugly. Passprefix=f"{message_id}_"todownload_attachmentand the files land asm1_invoice.pdf,m2_invoice.pdf, ... instead ofinvoice.pdf,invoice-2.pdf,invoice-3.pdf, which is much easier to reason about when correlating back to the source message.24h TTL. Files in shared storage are purged 24 hours after their last modification by the
mcp-shared-purge.timeruser unit on the host. This is a safety net for forgotten handoffs, not a backup — stage to Notion (or rename out of the shared dir) within that window. Agents that want immediate cleanup after a workflow can call thepurge_shared_filestool (see below).
Cross-MCP File Handoff to notion-mcp
google-accounts-mcp and notion-mcp share a volume (/shared in both
containers, host path ~/.local/share/containers/data/mcp-shared/) so
files move between servers without base64-through-MCP — in both
directions. Every transfer tool reports the sha256 of the bytes it
moved, so an agent can verify integrity end-to-end without shell
access. The canonical pipeline for attaching a Gmail attachment to a
Notion row:
download_attachment(
message_id="19a1b2...",
filename="invoice.pdf",
destination="shared", # writes SHARED_DIR/invoice.pdf
)
# Then from notion-mcp:
notion_add_file_to_row(
page_id="...",
source="shared:invoice.pdf", # reads the same bytes
files_property="Attachments",
)And the reverse — emailing a file stored in Notion:
# From notion-mcp:
notion_download_file(
block_id="...", # from notion_list_files_on_page
destination="shared", # writes SHARED_DIR/<name>
)
# Then from this server:
draft_email(
to=["alice@example.com"],
subject="Contract",
body="Attached.",
attachments=["shared:contract.pdf"],
)No size limit — the file bytes never traverse MCP parameters. For
cases where Drive persistence is also wanted, use
drive_upload(local_filename=...) instead of passing content_base64
so the bytes stay on disk end-to-end.
Labels & Lifecycle
Tool | Parameters | Description |
|
| Add/remove label IDs. |
|
| Removes |
|
| Removes |
|
| Adds |
modify_labels("msg-id", add_labels=["STARRED"], remove_labels=["INBOX", "UNREAD"])Attachments
Outgoing attachments must live under ATTACHMENTS_DIR — the server refuses
paths outside it to prevent exfiltration. Use upload_file to stage a new
file or reference a previously downloaded attachment path.
Reading PDF attachments from a sandboxed agent. An MCP client running
in a sandbox VM typically cannot see ATTACHMENTS_DIR or SHARED_DIR on
this server, and return_base64=True on a multi-MB PDF blows past most
MCP clients' parameter-size ceilings. Use extract_attachment_text to
pull structured text (with a 200 KB response ceiling and a pages= range
selector for anything bigger) and render_attachment_page for one-page
bitmaps when text extraction isn't enough.
Tool | Parameters | Description |
|
| Stages a file under |
|
| Enumerate attachments on a message. Every entry carries a |
|
| Batch variant of |
|
|
|
|
| Extract text from a PDF attachment server-side — returns JSON with |
|
| Render a single PDF page via |
|
| List files currently staged in the cross-MCP shared mount, with size and |
|
| Delete a single bare-filename file from |
PDF OCR
Scanned / image-only PDFs have no text layer, so native extraction returns
nothing. extract_attachment_text handles this with three reading tiers
(implemented in src/google_accounts_mcp/pdf_read.py, duplicated verbatim
in the sibling notion-mcp project — edit both copies together). OCR is
delegated to an xberg server — pages are
rasterised locally (pypdfium2) and uploaded as PNGs in one multipart
POST /extract:
Tier | Engine | When |
A — native text | pdfplumber (local) | Always first (except |
B — OCR | xberg |
|
C — VLM OCR | xberg |
|
In ocr='auto', an OCR failure (xberg down, extraction error) never breaks
extraction — the native-text result is returned with an ocr_error field
instead. ocr='force'/'llm' propagate the error.
Env (set per deployment):
Var | Meaning | Default |
| xberg endpoint |
|
| Request timeout (s) |
|
| Classical backend for tier B |
|
| Gateway model alias, passed verbatim |
|
| Vision endpoint, resolved by the xberg server |
|
| Vision-endpoint API key, sent in the per-request | (unset — |
The vlm key rides per-request because xberg 1.0.8 skips provider-env key
resolution whenever vlm_config.base_url is overridden (verified
2026-08-03) — revisit server-side key placement if upstream fixes that.
For one-off visual questions, skip OCR entirely: render_attachment_page
returns a real MCP image content block by default, so the calling model
just looks at the page.
Drive File Store
A shared Google Drive folder (DRIVE_FOLDER_NAME on DRIVE_ACCOUNT) acts as
a persistent file store for attachments that outlive a single server restart.
Files uploaded via drive_upload can be passed to draft_email /
send_email via the drive_attachments parameter — even from mailboxes
other than the Drive-owning account.
Tool | Parameters | Description |
|
| Upload to the shared folder. Returns file ID + webViewLink. Provide exactly one of |
|
| Delete files from |
|
| List files in the folder. Filter matches filename substrings. |
|
| Save to |
Calendar
Per-account Google Calendar read/write via the full calendar OAuth
scope (since 2026-07-04; events + calendarList + calendar management). Every Gmail account has
its own calendar surface — the same account parameter used by Gmail
tools also selects which calendar you operate on. Existing accounts
must re-run authorize.py after a scope change, since the OAuth consent
is fixed at grant time (old refresh tokens return insufficientPermissions
on calendar calls).
Why two scopes: calendar.events covers every events/* endpoint
(list / get / insert / patch / delete / move / quickAdd / instances /
freebusy), but calendarList is a separate surface with its own scope.
Adding calendar.calendarlist.readonly is the narrowest way to give
the list_calendars tool what it needs — still strictly less permissive
than the full calendar scope (no ACL changes, no calendar
create/delete, no settings).
Time-value model: a bare YYYY-MM-DD string makes an all-day event;
anything else is treated as an RFC3339 dateTime (2026-04-14T15:00:00+10:00
or 2026-04-14T15:00:00 + an explicit timezone IANA name). The
timezone parameter is silently dropped for date-only values because
Google Calendar rejects timeZone on all-day events. When your dateTime
already carries an offset, timezone is optional.
Tool | Parameters | Description |
|
| List calendars visible to the account (own + subscribed). Shows summary, access role, primary flag, and calendar ID. |
|
| List events on a calendar. |
|
| Read one event's full detail — attendees + response status, description, recurrence rules, conference link (if any), organizer. |
|
| Create a new event. |
|
| PATCH semantics — only fields explicitly set to a non-None value are sent. |
|
| Delete an event. |
|
| Create an event from a natural-language phrase using Google's own parser (e.g. |
|
| Move an event from one calendar to another (both owned by the account). |
|
| Set the account's RSVP. |
|
| Expand a recurring event into its individual instances. Window with |
|
| Create a secondary calendar (e.g. 'Family'). Returns its ID for use as |
|
| Rename a calendar / change metadata. PATCH semantics; |
|
| Permanently delete a SECONDARY calendar and all its events. The primary calendar is refused. |
|
| Query opaque busy-block intervals across one or more calendars (defaults to |
# Create a timed event with attendees and a popup reminder
create_event(
summary="Architecture review",
start="2026-04-15T10:00:00+10:00",
end="2026-04-15T11:00:00+10:00",
account="alice@example.com",
attendees=["alice@example.com", "bob@example.com"],
reminders_minutes=[10],
send_updates="all",
)
# Window query
list_events(
account="alice@example.com",
time_min="2026-04-14T00:00:00+10:00",
time_max="2026-04-15T00:00:00+10:00",
query="standup",
)
# RSVP to an invite
respond_to_event(
event_id="abc123",
response="yes",
account="alice@example.com",
comment="Running 5 min late",
)Tasks
Per-account Google Tasks read/write via the tasks OAuth scope (the only
write scope Google offers for Tasks — there is no narrower option).
task_list defaults to @default, the API alias for the account's default
list, so single-list users never need list_task_lists.
Due-date model: the Tasks API stores only a DATE — any time component
in an RFC3339 value is discarded server-side. Tools accept a bare
YYYY-MM-DD and expand it to midnight UTC for the API.
Tool | Parameters | Description |
|
| List the account's task lists (title + ID). Optional substring filter. |
|
| List tasks. Completed tasks the user has cleared from the UI additionally need |
|
| One task's full detail — title, status, due, notes, parent, completion time. |
|
| Create a task. |
|
| PATCH semantics — only non-None fields are sent. |
|
| Mark completed — sugar for the most common mutation. |
|
| Permanently delete (vs. |
Contacts
People API lookup + read/write on saved contacts (contacts +
contacts.other.readonly scopes; write support added 2026-07-04). The
second scope covers Google's "Other contacts" pool (people the account
has emailed but never saved — the Gmail autocomplete list), searched by
default and tagged [other] in results. That pool is read-only at the
API level; the supported write path is save_other_contact, which
copies an entry into My Contacts where it becomes editable.
Search-cache warmup: Google's contact search reads from a lazily-populated cache; the first search per account per process issues a warmup request and pauses ~2 s (per Google's documented guidance) before the real query. Subsequent searches are immediate.
Tool | Parameters | Description |
|
| Prefix-match search over names, emails, phone numbers, and organizations, across saved + other contacts. The go-to tool for "what's Alice's address?". |
|
| Browse saved contacts. |
|
| Full detail (all emails, phones, org, addresses, birthday, notes) by |
# Resolve a name before drafting
search_contacts(query="alice", account="alice@example.com")
# Capture a follow-up from an email thread
create_task(
title="Reply to Alice re: contract",
due="2026-07-07",
notes="thread: <message-id>",
account="alice@example.com",
)Authentication
Bearer auth (HTTP mode only): the HTTP server refuses to start without
MCP_BEARER_TOKEN. Every request (except /.well-known/* discovery
probes) must carry an Authorization: Bearer <token> header. Local stdio
mode (--stdio) has no network surface and skips bearer auth entirely.
Google OAuth 2.0: each Gmail account is authorized once via
scripts/authorize.py, which runs the installed-app OAuth flow and stores
the resulting refresh token in a SQLite DB (tokens.db). Access tokens are
refreshed on demand by the google-auth library — no background refresher.
If you run both a container deployment and local stdio copies, remember
the DB is a per-machine file: re-authorizing means copying the refreshed
tokens.db to each deployment (and restarting the container so cached
service objects drop stale credentials).
Scopes (authorize.py requests the full set on every account — a scope
addition therefore requires a one-time re-auth of each existing account,
since consent is fixed at grant time):
https://www.googleapis.com/auth/gmail.modify— read/write/label on all authorized mailboxes.https://www.googleapis.com/auth/drive.file— only files the app creates (i.e. the sharedDRIVE_FOLDER_NAMEfolder). Although granted everywhere, the drive tools only ever operate againstDRIVE_ACCOUNT.https://www.googleapis.com/auth/calendar— full calendar scope (2026-07-04; replaced the narrowercalendar.events+calendar.calendarlist.readonlypair when calendar management — create/update/delete calendar — was added; see Calendar).https://www.googleapis.com/auth/tasks— Google Tasks read/write (no narrower write scope exists).https://www.googleapis.com/auth/contacts+https://www.googleapis.com/auth/contacts.other.readonly— read/write on saved contacts (2026-07-04; wascontacts.readonly) plus read-only access to the "Other contacts" autocomplete pool (Google offers no write scope for that pool — promote entries withsave_other_contact).
Multi-Account Model
All tools accept account as an optional parameter. Resolution:
Empty →
DEFAULT_ACCOUNTif set, else the sole authorized account (a clear error lists the options when several exist).Exact match against stored accounts.
Case-insensitive substring match — if unique, used; if ambiguous, raises.
After scripts/authorize.py completes you must restart the container so the
in-memory service objects pick up the new credentials.
Configuration
All env vars are optional unless noted. Path defaults assume the
container layout (/data); set them explicitly for local runs.
Variable | Default | Description |
| (required in HTTP mode) | Bearer token clients must present. The HTTP server refuses to start if unset; stdio mode doesn't use it. |
| (required) | OAuth 2.0 client ID. |
| (required) | OAuth 2.0 client secret. |
|
| SQLite DB holding per-account refresh tokens. |
|
| Root for staged attachments and downloaded files. |
| (empty) | Account used when a tool's |
| (empty) | Account hosting the shared Drive folder. Required only for the |
|
| Name of the shared Drive folder. |
|
| HTTP port the server listens on. |
Architecture
┌─────────────────┐ HTTP + Bearer ┌──────────────────┐
│ Claude Code / │ ─────────────────▶ │ google-accounts- │
│ VS Code / etc │ │ mcp (FastMCP) │
└─────────────────┘ └────────┬─────────┘
│
┌─────────────────┼─────────────────┐
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌───────────────┐
│ Gmail API │ │ Drive API │ │ tokens.db │
│ (per acct) │ │ (1 acct) │ │ (SQLite) │
└─────────────┘ └─────────────┘ └───────────────┘Key design points:
SQLite token store (
auth.py) — one row per account keyed by email, holding the OAuth refresh token. Opened fresh per query; no long-lived sqlite connection.Lazy service cache — googleapiclient
Resourceobjects are built on first use per account and cached in-memory for the life of the process. Credentials auto-refresh viaAuthorizedHttp.Threadpool tool offload (
server.py) — the MCP SDK runs synchronous@mcp.tool()handlers inline on the event loop, so a single blockinghttplib2call would freeze every other request (the cause of the 4-minute "server unresponsive" stalls).mcp.toolis wrapped so each sync tool is registered as an async wrapper that runs the body in a worker thread (anyio.to_thread.run_sync); the loop stays free for concurrent and cheap calls. The wrapper preserves the tool signature (so client schemas are unchanged — no restart needed) and returns the original sync function as the module name (so tool-to-tool calls and tests still work). Cachedhttplib2objects aren't thread-safe, so_RetryingHttpserialises one account's socket with a per-instanceRLockwhile letting other accounts run in parallel. Each call logstool=… outcome=… duration_ms=…to stderr for your log pipeline.Container healthcheck —
python -m google_accounts_mcp.healthcheckdoes a full HTTP round-trip to/mcp; a wedged event loop fails the probe so a restart-on-unhealthy policy self-heals the container.PDF resource management —
render_attachment_pageand the OCR branch ofextract_attachment_textclose theirpypdfium2document/page/bitmap handles intry/finally(PDFium native memory isn't reclaimed deterministically by Python's GC). Athreading.Semaphorecaps concurrent rasterisation/parse — setPDF_MAX_CONCURRENCY(default4) to tune. Run the container withMALLOC_ARENA_MAX=2so glibc returns freed memory to the OS instead of retaining it in per-thread arenas. A 108-call mixed extract+render stress run across three accounts holds RSS flat (~320 MiB, well under the 1 GB cap) with zero restarts.Pure ASGI bearer middleware — wraps the Streamable HTTP app (
/mcp, stateless) and short-circuits unauthenticated requests with a 401, usinghmac.compare_digestfor constant-time comparison./.well-known/*paths pass through so MCP clients don't confuse 401 for an OAuth-protected server.Path-traversal guards —
_resolve_attachmentsrejects any path that resolves outsideATTACHMENTS_DIR, andupload_file/drive_uploadrequire bare filenames with no path components.
Development
# Syntax check before building
python3 -c "import py_compile; py_compile.compile('src/google_accounts_mcp/server.py', doraise=True)"
# Build the container image
podman build -t google-accounts-mcp . # or: docker buildThe Streamable HTTP transport is stateless, so a rebuild never breaks client sessions. If tool signatures changed, restart your MCP client so it re-fetches the schemas.
Testing
Three tiers:
# Tier 1 — pure helpers (no API, no mocking)
uv run --extra test pytest tests/test_gmail_helpers.py -v
# Tier 2 — Gmail client logic with mocked googleapiclient
uv run --extra test pytest tests/test_gmail_client.py -v
# Tier 1 + 2 — Calendar client (pure helpers + mocked calendar service)
uv run --extra test pytest tests/test_calendar_client.py -v
# Tier 1 + 2 — Tasks / Contacts clients (pure helpers + mocked services)
uv run --extra test pytest tests/test_tasks_client.py tests/test_contacts_client.py -v
# PDF reading / OCR tiers (pdf_read module + tool plumbing; the xberg
# HTTP calls are mocked — no network)
uv run --extra test pytest tests/test_pdf_read.py -v
# All unit tests together (fast, safe, run after every code change)
uv run --extra test pytest tests/test_gmail_helpers.py tests/test_gmail_client.py tests/test_calendar_client.py tests/test_tasks_client.py tests/test_contacts_client.py tests/test_pdf_read.py tests/test_retrying_http.py
# Tier 3 Gmail — live Gmail + Drive round-trip (gated)
GMAIL_TEST_ACCOUNT=you@example.com \
TOKEN_DB_PATH=~/.local/share/google-accounts-mcp/tokens.db \
ATTACHMENTS_DIR=~/.local/share/google-accounts-mcp/attachments \
GOOGLE_CLIENT_ID=... GOOGLE_CLIENT_SECRET=... \
uv run --extra test pytest tests/test_integration.py -v
# Tier 3 Calendar — live Google Calendar round-trip (gated by the same
# env var). Every test creates its own event and deletes it in a finally
# block; nothing is left on the calendar on success. Events are scheduled
# 24+ hours out to stay off the visible week.
GMAIL_TEST_ACCOUNT=you@example.com \
TOKEN_DB_PATH=~/.local/share/google-accounts-mcp/tokens.db \
GOOGLE_CLIENT_ID=... GOOGLE_CLIENT_SECRET=... \
uv run --extra test pytest tests/test_calendar_integration.py -v
# Tier 3 Tasks — live Google Tasks round-trip in a dedicated scratch task
# list (created and deleted by the module). Tier 3 Contacts — read-only
# live smoke of search/list/get (nothing to clean up by construction).
GMAIL_TEST_ACCOUNT=you@example.com \
TOKEN_DB_PATH=~/.local/share/google-accounts-mcp/tokens.db \
GOOGLE_CLIENT_ID=... GOOGLE_CLIENT_SECRET=... \
uv run --extra test pytest tests/test_tasks_integration.py tests/test_contacts_integration.py -vIntegration tests create their own artifacts and clean up after themselves — drafts (never sent) and Drive files for the Gmail suite, test events for the Calendar suite, a scratch task list for the Tasks suite. Nothing is left behind on success.
Local stdio Mode
--stdio starts FastMCP's stdio transport: no uvicorn, no bearer token
(the client owns the spawned process; there is no network surface). This
is what most interactive MCP clients should use:
// e.g. Claude Desktop claude_desktop_config.json / Claude Code .mcp.json
{
"mcpServers": {
"google": {
"command": "uv",
"args": ["run", "--project", "/path/to/google-accounts-mcp",
"google-accounts-mcp", "--stdio"],
"env": {
"GOOGLE_CLIENT_ID": "...",
"GOOGLE_CLIENT_SECRET": "...",
"TOKEN_DB_PATH": "/home/you/.local/share/google-accounts-mcp/tokens.db",
"ATTACHMENTS_DIR": "/home/you/.local/share/google-accounts-mcp/attachments"
}
}
}
}Prefer an env file over inline values where your client supports it
(uv run --env-file ...).
Container Deployment (HTTP)
podman build -t google-accounts-mcp .
podman run -d --name google-accounts-mcp -p 8321:8321 -v google-data:/data \
-e GOOGLE_CLIENT_ID=... -e GOOGLE_CLIENT_SECRET=... \
-e MCP_BEARER_TOKEN=some-long-random-token \
google-accounts-mcpThe /data volume persists tokens.db and staged attachments across
restarts. Authorize accounts by running scripts/authorize.py on a
machine with a browser and copying tokens.db into the volume (restart
the container afterwards). HTTP clients register the server as:
{
"mcpServers": {
"google": {
"url": "https://your-host:8321/mcp",
"headers": {"Authorization": "Bearer <MCP_BEARER_TOKEN>"}
}
}
}Terminate TLS at a reverse proxy — the server itself speaks plain HTTP.
Treat tokens.db like a password vault: whoever reads it controls every
connected Google account across all granted scopes (it is created with
mode 0600; keep the volume private).
License
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- Alicense-qualityDmaintenanceMCP server that seamlessly interacts with your Google Calendar, Gmail, Drive and so on.Last updated30MIT
- Alicense-qualityDmaintenanceMCP server to interact with Google Gmail and Calendar APIs. Supports multiple accounts, email search and drafting, and calendar event management.Last updatedMIT
- AlicenseBqualityBmaintenanceA multi-account Google Workspace MCP server that drives Gmail, Google Calendar, and Google Drive across any number of Google accounts in parallel from one server.Last updated402MIT
- AlicenseBqualityDmaintenanceMCP server for interacting with Google Gmail and Calendar via natural language, supporting multiple accounts.Last updated359MIT
Related MCP Connectors
Streamable HTTP MCP server for Google Calendar and Sheets with OAuth login.
Hosted Google Calendar MCP server for AI agents. No self-hosting or Google Cloud setup.
Read, search, send, organize, draft and schedule email across your inboxes from any MCP client.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/snickery/google-accounts-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server