Skip to main content
Glama
rohinigowdaiah1111

Gmail + Google Docs MCP Server

Gmail + Google Docs MCP Server

An MCP server that gives an AI agent tools to:

  • Draft and send Gmail emails

  • Create Google Docs and append content to them

Built with the official @modelcontextprotocol/sdk and Google's googleapis client, using a one-time OAuth 2.0 browser login (no Google Workspace admin setup required — works with a normal personal or Workspace Gmail account).

Tools exposed

Tool

Description

gmail_create_draft

Creates a draft email (not sent)

gmail_send_email

Sends an email immediately

gmail_send_draft

Sends a previously created draft by ID

gmail_list_drafts

Lists existing drafts

docs_create

Creates a new Google Doc, optionally with initial text

docs_append_text

Appends text to the end of an existing Google Doc (safe under concurrent edits — see below)

server_metrics

Returns per-tool call counts, error rates, and latency for this running server

gmail_create_draft and gmail_send_email also accept an optional attachments array (up to 10 files, 20MB each): { filename, contentBase64, mimeType }.

Related MCP server: Gmail MCP Server

1. Set up Google Cloud credentials

  1. Go to the Google Cloud Console and create (or select) a project.

  2. Enable these two APIs (APIs & Services > Library):

    • Gmail API

    • Google Docs API

  3. Configure the OAuth consent screen (APIs & Services > OAuth consent screen):

    • User type: "External" is fine for personal use (add yourself as a test user), or "Internal" if using a Workspace account.

  4. Create credentials (APIs & Services > Credentials > Create Credentials > OAuth client ID):

    • Application type: Desktop app (accepts any loopback redirect URI, so GOOGLE_REDIRECT_URI below doesn't need to be pre-registered).

  5. Copy .env.example to .env and fill in GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET from that OAuth client (adjust GOOGLE_REDIRECT_URI too if you want a different local port/path).

2. Install dependencies and build

npm install
npm run build

3. Authorize (one-time)

npm run authorize

This opens your browser to sign in to Google and grant access to Gmail (compose/send) and Docs. After you approve, tokens are saved to the path in GOOGLE_TOKEN_STORAGE_PATH (default tokens.json in the project root). Re-run this if you ever revoke access or delete that file.

.env and the token storage file contain secrets — they're already excluded via .gitignore and should never be committed.

4. Run the server

npm start

By default (MCP_TRANSPORT=stdio) the server communicates over stdio, so normally you won't run it directly — instead point your MCP client (e.g. Cursor) at it. To host it remotely instead (e.g. on Railway), see deployment-plan.md and the "Remote (HTTP) hosting" section below.

5. Connect it to Cursor

Add this to your mcp.json (Cursor Settings > MCP, or .cursor/mcp.json in a project):

{
  "mcpServers": {
    "gmail-docs": {
      "command": "node",
      "args": ["C:\\Users\\thriv\\OneDrive\\Documents\\BuildMCP\\dist\\index.js"]
    }
  }
}

Restart Cursor (or reload MCP servers) and the tools above will become available to the agent.

Configuration

Required (see .env.example):

Variable

Default

Purpose

GOOGLE_CLIENT_ID

(required)

OAuth client ID from Google Cloud Console

GOOGLE_CLIENT_SECRET

(required)

OAuth client secret from Google Cloud Console

GOOGLE_REDIRECT_URI

http://localhost:3000/oauth2callback

Redirect URI used for the one-time npm run authorize flow; npm run authorize listens on whatever host/port/path this specifies

GOOGLE_TOKEN_STORAGE_PATH

./tokens.json

Where the access/refresh token is stored (encrypted at rest); relative paths resolve from the project root

MCP_SERVER_NAME

google-workspace-mcp-server

Name this server reports over MCP

LOG_LEVEL

info

Structured (JSON) log verbosity written to stderr: trace|debug|info|warn|error|fatal

Remote (HTTP) transport — only relevant when hosting this server remotely instead of running it locally via stdio (see deployment-plan.md):

Variable

Default

Purpose

MCP_TRANSPORT

stdio

"stdio" for local Cursor usage, or "http" to bind an HTTP server instead (for remote hosting)

PORT

8080

Port the HTTP transport binds to (0.0.0.0). Railway injects this automatically — don't set it yourself there.

MCP_AUTH_TOKEN

(required if MCP_TRANSPORT=http)

Shared secret remote clients must send as Authorization: Bearer <token> to /mcp, and ?token=<token> to /authorize. The server refuses to start in http mode without it.

Optional:

Variable

Default

Purpose

GOOGLE_APPLICATION_CREDENTIALS

(unset)

Path to a service-account key file. Not yet used — reserved for a future service-account auth mode; see the NOTE comment in src/auth.ts.

ALLOWED_GOOGLE_ACCOUNTS

(unset, i.e. any account)

Comma-separated email allowlist. Not yet enforced — see the NOTE comment in src/auth.ts for what's needed to wire it up (requires the openid/userinfo.email scopes).

ENABLE_HTML_EMAIL

true

If false, gmail_create_draft/gmail_send_email reject isHtml: true with an INVALID_INPUT error

ENABLE_DOCS_APPEND

true

If false, the docs_append_text tool is not registered at all

Additional hardening (kept from the previous .env layout — see .env.example):

Variable

Default

Purpose

RATE_LIMIT_PER_MINUTE

60

Max calls allowed per tool per rolling 60s window before returning a RATE_LIMITED error

MAX_CONFLICT_RETRIES

3

Retry attempts for docs_append_text when a concurrent edit is detected

MAX_ATTACHMENT_BYTES

20971520 (20MB)

Max size per email attachment

TOKEN_ENCRYPTION_KEY

(auto-generated)

Base64, 32-byte key used to encrypt the token storage file at rest; if unset, a random key is generated once into .token.key

Notes & safety

  • gmail_send_email sends immediately with no human review — if you want a safety net, have the agent use gmail_create_draft and then a human sends it from Gmail (or call gmail_send_draft explicitly).

  • The Gmail scope used is gmail.compose, which allows creating/sending drafts and sending messages, but does not grant read access to the mailbox.

  • The Docs scope used is documents, which allows creating and editing docs but does not touch other Drive files.

  • Access tokens refresh automatically and are persisted back to the token storage file, which is encrypted at rest (AES-256-GCM). Existing plaintext token files are migrated transparently on first read.

Reliability & observability (Phase 5 hardening)

  • Structured errors: every tool failure is normalized to Error [CODE]: message, where CODE is one of INVALID_INPUT, REAUTH_REQUIRED, RATE_LIMITED, UPSTREAM_ERROR, CONFLICT, or INTERNAL_ERROR, plus a retryable hint and a requestId for correlating with logs.

  • Rate limiting: each tool is capped at RATE_LIMIT_PER_MINUTE calls/minute (in-process, sliding window) to protect your Google API quota from a runaway agent loop.

  • Conflict-safe Docs writes: docs_append_text reads the document's current revision and writes with writeControl.requiredRevisionId; if another edit races it, the request is retried with exponential backoff (MAX_CONFLICT_RETRIES attempts) instead of silently overwriting.

  • Structured logs: JSON logs go to stderr (never stdout, which is reserved for the MCP protocol channel) with a requestId per tool call. Only non-sensitive metadata is logged (e.g. recipient counts, string lengths) — email bodies, document text, attachment bytes, and tokens are never written to logs.

  • Metrics: call the server_metrics tool at any time to see call counts, error rates, and average latency per tool for the running process.

Remote (HTTP) hosting

Setting MCP_TRANSPORT=http switches the entrypoint to bind an HTTP server (instead of stdio) exposing:

  • GET /health — unauthenticated; returns 200 { status: "ok" } for platform health checks.

  • POST/GET/DELETE /mcp — the actual MCP endpoint (Streamable HTTP transport), gated by Authorization: Bearer <MCP_AUTH_TOKEN>.

  • GET /authorize — starts the Google consent flow remotely (gated by ?token=<MCP_AUTH_TOKEN> since it's opened in a browser). Needed because a headless remote server has no browser for npm run authorize to open.

  • GET <path from GOOGLE_REDIRECT_URI> — Google's OAuth callback; exchanges the code and persists the token, no restart required.

This mode is stateless: each /mcp request gets its own short-lived MCP server + transport pair (per the SDK's guidance for stateless HTTP hosting), so a single process can serve concurrent requests without cross-talk. The in-memory rate limiter and metrics are still per-process, so run a single instance (see deployment-plan.md, Phase 11).

Full step-by-step Railway deployment instructions (Volumes for token persistence, environment variables, redirect URI updates, CI, etc.) are in deployment-plan.md.

Project structure

src/
  config.ts       - env-driven settings: OAuth client, token path, server name, scopes, transport, feature toggles, hardening limits
  errors.ts        - AppError type + Google API error -> standardized error code mapping
  logging.ts       - structured pino logger (stderr-only) + per-request correlation IDs
  metrics.ts       - in-memory per-tool call/error/latency counters
  rateLimiter.ts   - per-tool sliding-window rate limiting
  tokenCrypto.ts   - AES-256-GCM encryption at rest for token.json
  auth.ts          - OAuth2 client creation + encrypted token load/save (stdio: eager/fail-fast; HTTP: lazy/non-throwing)
  authorize.ts     - one-time interactive `npm run authorize` script (local/stdio setup)
  gmail.ts         - GmailClient: createDraft, sendEmail (with attachments), sendDraft, listDrafts
  docs.ts          - DocsClient: createDocument, appendText (conflict-safe with retries)
  mcpServer.ts     - createMcpServer(): tool registry + shared logging/rate-limit/error middleware (used by both transports)
  httpServer.ts    - Streamable HTTP transport: /health, /mcp (bearer-token gated), /authorize, OAuth callback
  index.ts         - entrypoint; picks stdio or HTTP transport based on MCP_TRANSPORT
F
license - not found
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

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/rohinigowdaiah1111/MCP-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server