Google Workspace MCP — gsuite

Lokaler MCP-Server fuer beide Gmail-Accounts parallel: hello@marvinkuehlmann.com (Business) und marvinkuehlmann@gmail.com (Privat). Plus Google Calendar und YouTube Data/Analytics.

Eigener Fork seit 2026-04-17, Basis: MarkusPfundstein/mcp-gsuite. Source: mcp-gsuite~/source/mcps/mcp-gsuite/.

Stand

  • Version: 0.4.1+marvin.5 (Fork-Suffix)
  • Installation: uv tool install --force --editable ~/source/mcps/mcp-gsuite
  • Binary: ~/.local/bin/mcp-gsuite
  • Config-Ordner: ~/.config/mcp-gsuite/
  • Wrapper: start.sh (cd in Config-Ordner, dann mcp-gsuite — sucht accounts.json im CWD)

Architektur

~/.config/mcp-gsuite/
├── .gauth.json                                  OAuth-Client-Config (Google Cloud Console)
├── .accounts.json                               Liste der Accounts mit Metadata
├── .oauth2.hello@marvinkuehlmann.com.json       Token Business-Account
├── .oauth2.marvinkuehlmann@gmail.com.json       Token Privat-Account
└── start.sh                                     Wrapper mit cd

.accounts.json muss {"accounts": [...]} sein (Objekt, nicht nacktes Array — sonst keine sprechende Fehlermeldung).

Aktive Scopes

  • gmail.modify — lesen, draften, archivieren, trashen, labeln, unsubscriben
  • calendar — Events lesen + erstellen + loeschen + Recurrence (RRULE)
  • youtube.readonly — Channel/Video/Playlist-Metadata
  • yt-analytics.readonly — Analytics-Reports
  • (Monetary-Scope fuer YouTube-Revenue nicht aktiviert)

Tools nach Reload

Gmail Read/Drafts: query_gmail_emails, get_gmail_email, bulk_get_gmail_emails, reply_gmail_email, create_gmail_draft, delete_gmail_draft, get_gmail_attachment, bulk_save_gmail_attachments

Gmail Cleanup (Fork-Erweiterung): archive_gmail_email, trash_gmail_email, modify_gmail_labels, bulk_archive_gmail_by_query, bulk_trash_gmail_by_query, get_gmail_list_unsubscribe, one_click_unsubscribe_gmail

Calendar: list_calendars, get_calendar_events, create_calendar_event (mit recurrence), delete_calendar_event, update_calendar_event

YouTube Read: youtube_list_my_channels, youtube_list_my_videos, youtube_get_video_stats, youtube_list_my_playlists, youtube_analytics_query

YouTube Write: youtube_update_video_metadata (mit tags_mode=replace|merge|append, description_mode=replace|prepend|append), youtube_set_thumbnail, youtube_create_playlist, youtube_add_video_to_playlist, youtube_post_comment

Account-Switch

Jedes Tool braucht __user_id__ Parameter:

__user_id__: "hello@marvinkuehlmann.com"   → Business
__user_id__: "marvinkuehlmann@gmail.com"   → Privat

Default-Regel: Geschaeftliches/Kunden/Termine immer hello@, Privat (Familie, Banking) auf privat@. Im Zweifel fragen, nicht raten.

Quirks

  • Bulk-Tools mit dry_run=true als Default. Ohne explizites dry_run=false kommt nur Preview-Liste zurueck. Bewusst — erst schauen was matcht.
  • OAuth-Consent-Screen muss „Published” sein (nicht „Testing”) — sonst sterben Refresh-Tokens nach 7 Tagen mit invalid_grant. Single-User reicht ohne Google-Review.
  • YouTube-Tag-Update ueberschreibt API-seitig immer alles. Fork-Mode merge dedupliziert + sortiert, append haengt an. Bei Outperformer-Audits immer merge.
  • YouTube-Kommentar-Pinning geht NICHT via API — UI-only (drei Punkte → „Anheften”).
  • End-Screens / Info-Cards nicht in Data API v3.
  • IPv6-Probleme falls API-Calls haengen: alternative run.py mit IPv4-Force vorhanden (derzeit nicht aktiv).

Re-Auth (bei Scope-Aenderung)

cd ~/.config/mcp-gsuite
cp .oauth2.<email>.json .oauth2.<email>.json.bak-$(date +%Y-%m-%d)
rm .oauth2.<email>.json
# Claude Code neu starten -> beim ersten Tool-Call oeffnet sich Browser-Consent

Sicherheits-Hygiene

  • .oauth2.*.json enthalten Refresh-Tokens — niemals committen, niemals in Backups die das Repo enthalten
  • .gauth.json enthaelt OAuth-Client-Secret — gleiches gilt
  • Bei Token-Leak: in Google Account → „Drittanbieter mit Zugriff” widerrufen + neu auth