Announcing CIMD support for MCP Client registration
Learn more

Gmail MCP vs Gmail API for AI Agents (2026)

TL;DR

  • The official Gmail MCP server is in Developer Preview, not GA. It exposes 10 tools covering search, thread retrieval, draft creation, and label management. It cannot send email; it can only create a draft for a human to send from Gmail.
  • MCP auth is interactive OAuth 2.0 only, using the gmail.readonly and gmail.compose scopes. There is no service account path, so a background agent with no user present cannot complete the flow.
  • The Gmail REST API exposes the full surface: send, modify, trash, delete, settings, history-based sync, and users.watch push via Pub/Sub. It supports OAuth, service account with domain-wide delegation for Workspace orgs, and JWT Bearer for headless execution.
  • Both paths use the same restricted Gmail scopes, so both require OAuth app verification and, for stored restricted-scope data, a CASA security assessment before production. The token type differs; the credential infrastructure does not.
  • Scalekit's Gmail connector handles the per-user OAuth flow, token storage, and refresh for both paths, so the MCP vs API decision does not change your auth infrastructure.

Your agent needs to read and write Gmail. Google now ships two distinct paths: an official remote MCP server at gmailmcp.googleapis.com/mcp/v1, and the Gmail REST API your code has probably been calling for years. They cover overlapping but not identical territory. They put you on different auth paths. They make different operational demands in production. One of those differences is a hard ceiling for any agent that needs to send mail on its own. Here is the decision framework.

What Gmail MCP and Gmail API actually are

The Gmail MCP server

Google's Gmail MCP server is a remote, Google-managed endpoint at https://gmailmcp.googleapis.com/mcp/v1, built so AI clients like Claude and Antigravity can act in Gmail. It is currently in the Google Workspace Developer Preview Program, not general availability. Transport is HTTP. Auth is OAuth 2.0, configured through a Google Cloud project where you enable the Gmail API and the Gmail MCP API, then set up an OAuth consent screen with the gmail.readonly and gmail.compose scopes.

Official docs: the Gmail MCP server configuration guide and the Gmail MCP tool reference.

The Gmail REST API

The Gmail REST API is a versioned interface at gmail.googleapis.com/gmail/v1. It exposes the full mailbox surface: messages, drafts, threads, labels, history, attachments, and settings such as filters, forwarding, send-as aliases, vacation responders, and delegates. It also exposes users.watch for push notifications via Cloud Pub/Sub.

Auth runs on a scope-based model and supports several patterns: OAuth Authorization Code for user delegation, service account with domain-wide delegation for Workspace organizations, and JWT Bearer for server-to-server execution. There are no LLM-specific affordances; schemas, pagination, errors, retries, and rate limits are yours to manage.

Official docs: the Gmail API guides and REST reference.

Comparing them where it matters for agents

What your agent can actually do

The MCP server covers reading and drafting well. The API owns everything operational and everything that writes the mailbox without a human in the loop.

Capability
Gmail MCP (preview)
Gmail REST API
Search threads
Yes (search_threads)
Yes (users.threads.list)
Read a thread and its messages
Yes (get_thread)
Yes (users.threads.get)
Create a draft
Yes (create_draft)
Yes (users.drafts.create)
List drafts
Yes (list_drafts)
Yes (users.drafts.list)
Send a message
No
Yes (users.messages.send)
Send an existing draft
No
Yes (users.drafts.send)
List and manage labels
Yes (list_labels, create_label)
Yes (full label CRUD)
Apply or remove labels
Yes (label_thread, unlabel_message)
Yes (users.messages.modify)
Trash or delete messages
No
Yes (users.messages.trash, delete)
Read attachments
No
Yes (users.messages.attachments.get)
Incremental sync since last change
No
Yes (users.history.list)
Push notifications on mailbox change
No
Yes (users.watch via Pub/Sub)
Settings (filters, forwarding, send-as, delegates)
No
Yes (users.settings.*)

Where the gap bites

The MCP server is built for a user-present, review-before-send workflow. Its 10 tools are create_draft, list_drafts, get_thread, search_threads, label_thread, unlabel_thread, list_labels, label_message, unlabel_message, and create_label. Anything that mutates the mailbox without human review, sends mail, syncs incrementally, or reacts to inbound events lives only in the REST API. These are architectural properties of the API, not MCP tools that will ship next month.

The draft-only ceiling

This is the single most consequential limit. The MCP server can compose a draft, but there is no send tool. Google's own walkthrough confirms the pattern: the client creates a draft in your drafts folder so you can review and send it from Gmail. An agent that must send a follow-up, a notification, or an autonomous reply cannot do it through the MCP server today. That work requires users.messages.send on the REST API.

The auth path each one puts you on

MCP: interactive OAuth, per user, every time

The Gmail MCP server uses OAuth 2.0 with a browser consent flow. Each user who connects authorizes the gmail.readonly and gmail.compose scopes, and the agent inherits exactly what that user can see and do. There is no bot identity and no service account option on this path.

The headless gap

Because consent requires a browser, a background agent with no user present cannot complete the MCP flow. A nightly triage job, a scheduled digest, or an event-driven pipeline has no way to authenticate against the MCP server autonomously. This is a hard constraint, not a configuration choice.

REST API: delegated, delegated-at-scale, or headless

The REST API gives you three patterns. OAuth Authorization Code is per-user delegation, the same identity model as MCP. Service account with domain-wide delegation lets a Workspace org authorize one client to impersonate its users without per-user prompts; this works for Workspace domains only, not consumer @gmail.com accounts. JWT Bearer gives clean server-to-server auth for headless execution. For background agents, that headless path is the deciding factor.

Verification applies to both paths

Both paths request restricted Gmail scopes such as gmail.readonly. Google requires restricted-scope OAuth app verification for production, and if you store restricted-scope data on your servers, a security assessment (CASA Tier 2 in practice). Choosing MCP does not exempt you from this; the scope, and therefore the review, is the same.

What each path cannot do (sourced from official docs)

This is the part most comparisons skip. Naming what is structurally absent on each side is what tells you whether a path can carry your use case.

What the MCP server cannot do that the API can

The MCP server has no send tool, no trash or delete, no attachment retrieval, no users.history.list for incremental sync, no users.watch for push notifications, and no settings management. It is also Developer Preview, so its tool schemas can change as Google iterates. If your agent sends mail, reacts to inbound events, or manages mailbox configuration, the MCP server is not the path.

What the API makes you own that the MCP server smooths

The API gives you no LLM-ready tool schemas, no normalized tool descriptions, and no managed connection. You construct requests, parse responses, handle pagination, and map errors yourself. The MCP server returns tool definitions an MCP client can consume directly, which is genuinely faster for an interactive, read-and-draft assistant.

The shared quota neither path removes

MCP tool calls consume the same Gmail API quota as direct calls. As of the May 1, 2026 update, new projects get 1,200,000 quota units per minute per project and 6,000 per minute per user per project, with a per-user moving-average limit near 250 units per second. Sends are expensive relative to reads, and consumer accounts cap at 500 sent emails per day. Quota planning is your responsibility on either path.

What you own in production

On the MCP path

Google manages hosting, scaling, and tool schemas. You own per-user token storage, refresh, and revocation; tenant isolation; and the operational reality that a preview server's schemas can shift. Indirect prompt injection is a first-class risk: Google warns that an MCP client with Gmail access can read and modify mailbox data, so untrusted email content can carry hidden instructions.

On the REST API path

You own the full stack: endpoint selection, request construction, error handling, retries, pagination, token lifecycle, and version migration. You also own push infrastructure. A users.watch registration expires after 7 days and must be renewed, typically daily, and notifications flow through Cloud Pub/Sub at roughly one event per second per user. The tradeoff is control: the API is v1 and versioned, so a deterministic pipeline is not exposed to surprise schema changes.

When to use MCP, when to use the API

Use Gmail MCP when

  • Your agent is interactive and user-present, such as a Claude or Antigravity assistant where OAuth consent is natural.
  • The job is read, search, summarize, and draft for human review, not autonomous send.
  • You want Google-managed tool schemas and a fast path to a working assistant without writing REST adapters.
  • The deployment is single-user or per-user, and a browser consent step is acceptable.

Use the Gmail REST API when

  • Your agent must send mail, modify or delete messages, or manage settings such as filters and forwarding.
  • Your agent runs headless: scheduled digests, triage jobs, or event-driven pipelines with no user present.
  • You need incremental sync via users.history.list or real-time reaction via users.watch and Pub/Sub.
  • You are serving a Workspace org through service-account delegation, or you need deterministic, versioned behavior in a production pipeline.

The credential problem that exists on both paths

Both paths hand you a token, not a vault

Whether the token comes from the MCP OAuth flow or a direct API OAuth grant, it has to live somewhere: encrypted at rest, isolated per tenant, and revocable when a user disconnects. Gmail access tokens expire after one hour, and refresh tokens can be revoked by a password change, a scope change, or Google's security systems, after which only human re-authorization restores access.

The N-credential reality

In a multi-tenant B2B agent, every user has their own Gmail credential. Fifty customers means fifty OAuth tokens, fifty refresh lifecycles, and fifty revocation paths. Offboarding makes this concrete: an Okta account is disabled, but a Gmail refresh token granted months ago keeps working until something explicitly revokes it. The agent does not decide to keep using it. It just does.

Where Scalekit fits

Scalekit's Gmail connector resolves the per-user credential on every tool call and keeps tokens out of the agent runtime and the model context. The same token vault and refresh logic work whether you front the REST API through Scalekit tools or expose a scoped MCP endpoint. The path decision does not change what you need at the credential layer.

Building Gmail agents with Scalekit

The value proposition for a Gmail agent

A production Gmail agent fails on the same three things every time: per-user tokens, correct scope, and an audit trail that ties each action to the user who authorized it. Scalekit's connector handles the OAuth flow, stores tokens in a token vault, refreshes them proactively, and exposes Gmail as scoped tools. Your agent calls a tool, gets a result, and never sees a token. Browse the Scalekit Gmail connector and the connector docs.

Connect with the Node SDK

Create the connection in the dashboard first, then copy the exact Connection name; the string must match the dashboard value, which is the most common integration error.

import { ScalekitClient } from '@scalekit-sdk/node'; import { ConnectorStatus } from '@scalekit-sdk/node/lib/pkg/grpc/scalekit/v1/connected_accounts/connected_accounts_pb'; import 'dotenv/config'; const scalekit = new ScalekitClient( process.env.SCALEKIT_ENV_URL, process.env.SCALEKIT_CLIENT_ID, process.env.SCALEKIT_CLIENT_SECRET, ); const { connectedAccount } = await scalekit.actions.getOrCreateConnectedAccount({ connectionName: 'gmail', // must match the Connection name in the dashboard exactly identifier: 'user_123', }); if (connectedAccount?.status !== ConnectorStatus.ACTIVE) { const { link } = await scalekit.actions.getAuthorizationLink({ connectionName: 'gmail', identifier: 'user_123', }); console.log('Authorize Gmail:', link); }

Connect with the Python SDK

import os import scalekit.client scalekit_client = scalekit.client.ScalekitClient( client_id=os.getenv("SCALEKIT_CLIENT_ID"), client_secret=os.getenv("SCALEKIT_CLIENT_SECRET"), env_url=os.getenv("SCALEKIT_ENV_URL"), ) actions = scalekit_client.actions response = actions.get_or_create_connected_account( connection_name="gmail", # must match the Connection name in the dashboard exactly identifier="user_123", ) if response.connected_account.status != "ACTIVE": link = actions.get_authorization_link(connection_name="gmail", identifier="user_123") print("Authorize Gmail:", link.link) input("Press Enter after authorizing...") # Fetch the user's last 5 unread emails through a scoped tool call result = actions.execute_tool( tool_name="gmail_fetch_mails", identifier="user_123", tool_input={"query": "is:unread", "max_results": 5}, ) print(result)

Scope tools, then run the Claude loop

list_scoped_tools returns only the tools the current user's connected account is authorized to call, not the full catalog. Discovery comes first, then scope, then execution.

import anthropic from google.protobuf.json_format import MessageToDict client = anthropic.Anthropic() # Discovery and scope: only this user's authorized Gmail tools scoped_response, _ = actions.tools.list_scoped_tools( identifier="user_123", filter={"connection_names": ["gmail"]}, page_size=100, # fetch beyond the default page so no connector tools are missed ) llm_tools = [ { "name": MessageToDict(t.tool).get("definition", {}).get("name"), "description": MessageToDict(t.tool).get("definition", {}).get("description", ""), "input_schema": MessageToDict(t.tool).get("definition", {}).get("input_schema", {}), } for t in scoped_response.tools ] messages = [{"role": "user", "content": "Fetch my last 5 unread emails and summarize them"}] while True: response = client.messages.create( model="claude-sonnet-4-6", max_tokens=1024, tools=llm_tools, messages=messages, ) if response.stop_reason == "end_turn": print(response.content[0].text) break tool_results = [] for block in response.content: if block.type == "tool_use": # Execution: Scalekit resolves the per-user token and calls Gmail result = actions.execute_tool( tool_name=block.name, identifier="user_123", tool_input=block.input, ) tool_results.append({ "type": "tool_result", "tool_use_id": block.id, "content": str(result.data), }) messages.append({"role": "assistant", "content": response.content}) messages.append({"role": "user", "content": tool_results})

Run it on LangChain

actions.langchain.get_tools() returns native StructuredTool objects, so there is no schema reshaping.

from langchain_openai import ChatOpenAI from langchain_core.messages import HumanMessage, ToolMessage tools = actions.langchain.get_tools( identifier="user_123", connection_names=["gmail"], page_size=100, # avoid missing tools when a connector has more than the default page ) tool_map = {t.name: t for t in tools} llm = ChatOpenAI(model="gpt-4o").bind_tools(tools) messages = [HumanMessage("Fetch my last 5 unread emails and summarize them")] while True: response = llm.invoke(messages) messages.append(response) if not response.tool_calls: print(response.content) break for tc in response.tool_calls: result = tool_map[tc["name"]].invoke(tc["args"]) messages.append(ToolMessage(content=str(result), tool_call_id=tc["id"]))

A note on other runtimes

Scalekit ships native adapters for LangChain, Anthropic, OpenAI, Google ADK, Vercel AI, and Mastra, and any MCP-compatible host can connect to a Scalekit-generated MCP URL. If you are running a different stack, for example a Hermes-model agent or another framework without a first-class adapter, the MCP route covers it, and you can request a dedicated adapter or capability through the channels below.

Observability and multi-tenant scale

Why scoped surfaces matter

A shared credential gives every user the same tool surface and the same access, which is both a security failure and an accuracy failure once a second user exists. Scoping tools per user keeps the surface small, which also improves tool selection: a model choosing from 5 to 10 relevant tools picks more reliably than one choosing from a full catalog. What the user cannot do, the agent cannot do.

Audit logs for agent actions

Standard logs capture a user ID and a timestamp. An agent action touches several principals: the triggering user, the agent process, and the credential owner. Scalekit's auth logs tie each Gmail tool call to the connected account that authorized it, which is what a SOC 2 or GDPR reviewer needs when they ask who authorized a given send or read.

When Scalekit does not have what you need

If a Gmail capability or a framework adapter you need is missing, ask for it directly. Join the Scalekit Slack community, use the Talk to us page, or talk to Scalekit's engineers.

Which one to build against

If your agent is interactive and its job is to search, read, summarize, and draft for human review, the Gmail MCP server is the faster route, with the caveat that it is preview software and cannot send. If your agent must send mail, run headless, sync incrementally, react to inbound events, or manage settings, build against the REST API directly, using service-account delegation for Workspace orgs and JWT Bearer for background execution. Most production Gmail agents will use both: MCP or scoped tools for the interactive surface, the API for everything autonomous. The credential management problem is the same either way, and that is what needs production-grade infrastructure.

Browse the Scalekit Gmail connector: scalekit.com/agent-connector/gmail

No items found.
Agent Auth Quickstart
On this page
Share this article
Agent Auth Quickstart

Acquire enterprise customers with zero upfront cost

Every feature unlocked. No hidden fees.
Start Free
$0
/ month
1 million Monthly Active Users
100 Monthly Active Organizations
1 SSO connection
1 SCIM connection
10K Connected Accounts
Unlimited Dev & Prod environments