Skip to main content

Multi-account Google Workspace MCP server — Gmail, Drive, Sheets, Calendar

Project description

Google Workspace MCP Server

A MCP server built with FastMCP for Google Workspace with multi-account support. Works with Claude Desktop, Claude Code, or any MCP client to interact with Gmail, Google Drive, Sheets, and Calendar across multiple Google accounts.

Features

  • Multi-account profiles — Named profiles (e.g. business, personal) to switch between accounts
  • Two transports — local STDIO (per-profile desktop OAuth) and remote HTTP + per-user OAuth, selected via GW_MCP_TRANSPORT (see Transports)
  • Zero-friction setup — OAuth flows triggered from within Claude, no CLI needed
  • Gmail — Search, read, send, threads, attachments, labels (create/list/update/delete), a full set of organizing tools (archive/unarchive, mark read/unread, star/unstar, trash/untrash, per-message & per-thread label modify, batch modify, gmail_apply_to_search), and filters (rules): list/create/delete the auto-label/auto-archive rules — 25 tools
  • Google Drive — Upload, download, list, search, folders, move, trash (7 tools)
  • Google Sheets — Read, write, append, create, metadata (5 tools)
  • Google Calendar — Events, create/update/delete, free/busy, calendars (6 tools)
  • 51 tools total including auth/setup + profile tools
  • Clean architecture — Services layer (Google API) separated from tools layer (MCP)

Prerequisites

A Google Cloud Project with OAuth 2.0 credentials:

  1. Go to Google Cloud Console → Credentials
  2. Create an OAuth 2.0 Client ID (type: Desktop app)
  3. Enable these APIs in API Library: Gmail API, Google Drive API, Google Sheets API, Google Calendar API

That's it. No redirect URIs to configure — the server handles it.

Quick Start (Claude Desktop)

Add to your Claude Desktop config:

macOS: ~/Library/Application Support/Claude/claude_desktop_config.json Windows: %APPDATA%\Claude\claude_desktop_config.json

{
  "mcpServers": {
    "google-workspace": {
      "command": "uvx",
      "args": ["--from", "/path/to/google-workspace-mcp-py", "google-workspace-mcp"]
    }
  }
}

Restart Claude Desktop. That's it — no pip install, no venv. uvx handles everything.

Requires uv — install with curl -LsSf https://astral.sh/uv/install.sh | sh (Mac/Linux) or powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" (Windows)

Install from PyPI

Each release is published to PyPI as multi-gw-mcp, so you can also install/run it by name instead of a local path:

pip install multi-gw-mcp          # or: uvx --from multi-gw-mcp google-workspace-mcp

Quick Start (Claude Code)

claude mcp add google-workspace -- uvx --from /path/to/google-workspace-mcp-py google-workspace-mcp

Setup Flow (happens inside Claude)

Once the server is running, Claude handles everything:

  1. Claude calls check_setup_status → sees "not configured"
  2. You provide your Google Cloud Client ID and Secret
  3. Claude calls setup_google_workspace → config saved automatically
  4. Claude calls authenticate_account("business") → your browser opens to Google sign-in → you click Allow → token saved
  5. Claude calls authenticate_account("personal") → same for second account
  6. Done. All tools work. Tokens auto-refresh.

No terminal commands. No config files to hand-edit. No copy-pasting tokens.

Transports

The server runs in one of two modes, chosen by the GW_MCP_TRANSPORT env var (main() in server.py):

GW_MCP_TRANSPORT Mode Auth
stdio (default) Local STDIO Per-profile desktop OAuth; tokens on disk under GW_MCP_CONFIG_DIR. Use the in-chat setup flow above.
http (or sse) Remote HTTP server Per-user OAuth via FastMCP's built-in GoogleProvider. Each connecting user signs in with their own Google account through the MCP protocol; additional accounts are added at runtime with add_gw_account. Requires GW_MCP_PUBLIC_URL, GW_MCP_WEB_CLIENT_ID, GW_MCP_WEB_CLIENT_SECRET.

In HTTP mode the server binds GW_MCP_HOST/GW_MCP_PORT and exposes a /health check plus an OAuth callback for adding profiles. Both transports share the same 51 tools and the same OAuth scopes.

If Published to PyPI

Once published, the config simplifies to:

{
  "mcpServers": {
    "google-workspace": {
      "command": "uvx",
      "args": ["google-workspace-mcp"]
    }
  }
}

Usage

Every tool accepts an optional profile parameter. If omitted, the first profile is used.

# Search business Gmail
gmail_search(query="from:aws subject:invoice after:2025/04/01", profile="business")

# Search personal Gmail
gmail_search(query="from:billing@example.com invoice", profile="personal")

# Organize: archive + mark read + label everything from a newsletter in one call
# (label args accept NAMES or IDs — names are resolved automatically)
gmail_apply_to_search(
    query="from:newsletter@example.com older_than:30d",
    add_label_ids=["Archive/Newsletters"],
    archive=True, mark_read=True, max_results=200, profile="business"
)

# Star / archive a single message, or archive a whole conversation
gmail_star(message_id="...")
gmail_archive(message_id="...")
gmail_modify_thread(thread_id="...", remove_labels=["INBOX"], add_labels=["STARRED"])

# Trash is recoverable (not a permanent delete)
gmail_trash(message_id="...")
gmail_untrash(message_id="...")

# Filters (rules): auto-label + skip-inbox every future newsletter
# (label NAMES are resolved to IDs; the label must already exist)
gmail_create_filter(
    from_address="newsletter@example.com",
    add_labels=["Newsletters"], archive=True, mark_read=True, profile="business"
)
gmail_list_filters(profile="business")
gmail_delete_filter(filter_id="ANe1...", profile="business")

# Upload to Drive
drive_upload(local_path="/tmp/report.xlsx", folder_id="abc123", profile="business")

# Read a Google Sheet
sheets_read(spreadsheet_id="abc123", range="Sheet1!A1:D10")

# Check calendar
calendar_list_events(time_min="2025-04-01T00:00:00Z", time_max="2025-04-02T00:00:00Z")

All Tools (51)

Category Tool Description
Setup check_setup_status Check config & auth status (STDIO)
Setup setup_google_workspace Save OAuth credentials + profiles (STDIO)
Setup authenticate_account Open browser OAuth for a profile (STDIO)
Setup add_google_profile Add another account to config (STDIO)
Profiles list_google_profiles List accounts & auth status (STDIO)
Profiles whoami Show the authenticated user (HTTP)
Profiles add_gw_account Add another Google account at runtime (HTTP)
Profiles list_gw_accounts List connected accounts (HTTP)
Gmail gmail_search Search with Gmail query syntax
Gmail gmail_read Read a message by ID
Gmail gmail_read_thread Read entire thread
Gmail gmail_send Send email or reply
Gmail gmail_list_labels List system + user labels
Gmail gmail_create_label Create a user label
Gmail gmail_update_label Rename a user label
Gmail gmail_delete_label Delete a user label
Gmail gmail_modify_message Add/remove labels on a message
Gmail gmail_batch_modify Add/remove labels on many messages
Gmail gmail_modify_thread Add/remove labels on a whole thread
Gmail gmail_archive / gmail_unarchive Remove/add INBOX
Gmail gmail_mark_read / gmail_mark_unread Remove/add UNREAD
Gmail gmail_star / gmail_unstar Add/remove STARRED
Gmail gmail_trash / gmail_untrash Move to / restore from Trash (recoverable; not permanent delete)
Gmail gmail_apply_to_search Run a search and bulk archive/label/mark-read all matches
Gmail gmail_list_filters List all filters (auto-label/auto-archive rules)
Gmail gmail_create_filter Create a filter — match by from/to/subject/query/etc., act via labels + flags (archive/mark_read/star/forward)
Gmail gmail_delete_filter Delete a filter by ID
Gmail gmail_get_attachment_data Get attachment as base64 (or save server-side)
Gmail gmail_save_attachment_to_server Save attachment to the server filesystem
Drive drive_list List/search files
Drive drive_upload Upload local file
Drive drive_upload_base64 Upload from base64 data
Drive drive_download Download file
Drive drive_create_folder Create folder
Drive drive_move Move between folders
Drive drive_trash Trash a file
Sheets sheets_read Read data from range
Sheets sheets_write Write data to range
Sheets sheets_append Append rows
Sheets sheets_create Create spreadsheet
Sheets sheets_info Get metadata
Calendar calendar_list_events List events
Calendar calendar_create_event Create event
Calendar calendar_update_event Update event
Calendar calendar_delete_event Delete event
Calendar calendar_free_busy Check availability
Calendar calendar_list_calendars List calendars

Architecture

src/google_workspace_mcp/
├── server.py          # FastMCP composition + middleware
├── auth/
│   ├── oauth.py       # OAuth2 + profiles + auto-setup + browser auth flow
│   └── setup.py       # Optional CLI fallback (gw-mcp-auth)
├── services/          # Google API wrappers (reusable, testable)
│   ├── gmail.py
│   ├── drive.py
│   ├── sheets.py
│   └── calendar.py
├── tools/             # FastMCP @mcp.tool decorated functions
│   ├── profiles.py    # Setup + auth + profile tools
│   ├── gmail.py
│   ├── drive.py
│   ├── sheets.py
│   └── calendar.py
└── middleware/
    └── error_handler.py   # Google API errors → friendly messages

Environment Variables

Variable Default Description
GW_MCP_TRANSPORT stdio stdio (local) or http/sse (remote server)
GW_MCP_HOST 127.0.0.1 Bind host (HTTP mode)
GW_MCP_PORT 8000 Bind port (HTTP mode)
GW_MCP_PUBLIC_URL (unset) Public base URL — set to enable HTTP per-user OAuth
GW_MCP_WEB_CLIENT_ID / GW_MCP_WEB_CLIENT_SECRET (unset) Web OAuth client for HTTP mode
GW_MCP_CONFIG_DIR ~/.config/google-workspace-mcp Config & token directory
GW_MCP_OAUTH_PORT 3456 Local port for OAuth callback (STDIO mode)
GW_MCP_ALLOWED_CLIENT_REDIRECTS (built-in default) Comma-separated allow-list of MCP-client redirect URI patterns. Defaults already cover Claude Code/Desktop loopback and Claude Web. Override only to extend.

OAuth scopes

Both transports request the same scopes:

  • gmail.readonly, gmail.send, gmail.modify, gmail.settings.basic
  • drive.file (HTTP) / drive (STDIO), spreadsheets, calendar

gmail.modify covers label changes and messages.trash/untrash. gmail.settings.basic is required for the filter (rule) tools (gmail_list_filters / gmail_create_filter / gmail_delete_filter). Permanent deletion is intentionally not supported (it would require the broader full-mailbox scope).

⚠️ Re-consent required. Adding gmail.settings.basic changes the requested scope set, so every existing user must re-authenticate on their next use — existing tokens lack the new scope and the filter tools will return an insufficient-scope error until the account is re-authed. This is a one-time consent screen; no data is lost.

Remote / HTTP mode OAuth (Claude Code, Desktop & Web)

When GW_MCP_PUBLIC_URL is set the server becomes its own OAuth authorization server and proxies upstream to Google. There are two distinct redirect layers — do not conflate them:

  1. MCP client → this server (handled in code). Claude clients register via Dynamic Client Registration with their own redirect URI:

    • Claude Code (CLI) and Claude Desktop use an RFC 8252 loopback on a dynamic port: http://localhost:<port>/... / http://127.0.0.1:<port>/....
    • Claude Web (claude.ai) uses the fixed callback https://claude.ai/api/mcp/auth_callback.

    All three are accepted by the built-in GW_MCP_ALLOWED_CLIENT_REDIRECTS allow-list — no configuration needed.

  2. This server → Google (one human step). The server always sends Google a single fixed redirect: <GW_MCP_PUBLIC_URL>/auth/callback. This exact URI must be registered in the Google Cloud Console:

    APIs & Services → Credentials → your Web OAuth 2.0 Client (GW_MCP_WEB_CLIENT_ID) → Authorized redirect URIs → add https://<your-public-host>/auth/callback (e.g. https://mcp.example.com/auth/callback).

    If this is missing, every client fails with Google redirect_uri_mismatch — it is not a per-client problem.

Optional CLI

If you prefer terminal setup over in-chat setup:

uvx --from /path/to/project gw-mcp-auth --init       # Create config interactively
uvx --from /path/to/project gw-mcp-auth --profile biz # Auth one profile
uvx --from /path/to/project gw-mcp-auth --status      # Check status

Built With

Contributing

Contributions are welcome — see CONTRIBUTING.md for the dev setup and workflow. For security issues, please follow SECURITY.md rather than opening a public issue.

License

MIT © 3J Technologies

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

multi_gw_mcp-1.0.2.tar.gz (165.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

multi_gw_mcp-1.0.2-py3-none-any.whl (45.9 kB view details)

Uploaded Python 3

File details

Details for the file multi_gw_mcp-1.0.2.tar.gz.

File metadata

  • Download URL: multi_gw_mcp-1.0.2.tar.gz
  • Upload date:
  • Size: 165.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for multi_gw_mcp-1.0.2.tar.gz
Algorithm Hash digest
SHA256 bce2e52e458412c0035c373e1e8baabd39a8f55bfd09974b44c376923f837bcf
MD5 3c17bb3bd6a18c46e101f21f5617c9c3
BLAKE2b-256 b08b90264c8fa535e6b10674df07d1279d7a212e2fedfb21a3fa3f098df37c7c

See more details on using hashes here.

File details

Details for the file multi_gw_mcp-1.0.2-py3-none-any.whl.

File metadata

  • Download URL: multi_gw_mcp-1.0.2-py3-none-any.whl
  • Upload date:
  • Size: 45.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for multi_gw_mcp-1.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 60e61e1f88ae644edc835969aeaba0368df171f220f1a4cf8f08fb2f2b098bdd
MD5 7ed61091a07bcbac1cf7f58c5d58e242
BLAKE2b-256 6a40419ddc9293cb31d5999cb1b464e9ee104db47cf747bbf37d5a7867a2b2d1

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page