Skip to Content
TwinsGmail

Gmail

Twin of the Gmail API v1 and hosted Gmail MCP.

Twin of the Gmail API v1 and hosted Gmail MCP.

Coversgmail.googleapis.com, gmailmcp.googleapis.com
AuthGoogle OAuth access tokens
WebhooksNo
MCP tools23
Operations91

Coverage

Messages, threads, drafts, labels and attachments, incremental change sync through users.history, the settings surface including filters, forwarding and send-as, and the media upload host on the same origin. The hosted MCP server answers on /mcp/v1 and shares the same mailbox state as the REST API.

Credentials

This twin issues no tokens of its own. It verifies the ones Google Identity mints, so any well-formed ya29.… token from there authenticates by default and your existing credentials need no change. The auth.mode switch that restricts it to credentials the world knows lives on Google Identity rather than here. See Credentials.

The same Google access token authenticates the REST and hosted MCP surfaces.

Gmail’s scopes are enforced and they are narrow. A readonly token cannot insert, a permanent delete needs the full mail scope, and the metadata scope serves metadata but refuses message content and search. Settings scopes are not interchangeable with each other.

Vendor specific details

  • A query that matches nothing returns {"resultSizeEstimate": 0} with no messages key at all. Code that does for m in body["messages"] raises here, exactly as it does in production.
  • An unknown value in labelIds is a 400 Invalid label, not an empty result. labelIds is a repeated parameter, so a comma-joined pair counts as one bad name.
  • users.watch stores the registration and answers normally, but nothing is ever delivered. Real Gmail publishes changes to Cloud Pub/Sub rather than posting to a URL, so there is no callback to wait for.
  • A startHistoryId that is too old is a plain 404 with no fullSyncRequired hint. You have to treat the 404 itself as the signal to resync.
  • An attachment token resolves against its own message, so the message id in the path is ignored entirely. A token that does not decode is a 400, and a token whose message was deleted is a 403 even though messages.get on the same id is a 404.

Its own notes

Once a sandbox is running, this twin serves its own operating notes at {control_url}/veris/manual: the credentials it accepts, the API versions it serves, and the fault statuses you can arm against it. They are generated from the same source as its behaviour, so they cannot drift.