Skip to main content
Glama
FallenOne1701

Google Workspace MCP Server

Google Workspace MCP Server

Generic Model Context Protocol server that lets any MCP-compatible AI agent:

  • Create Gmail drafts (gmail_create_draft)

  • Send Gmail email (gmail_send_email) — external side effect

  • Append text to a Google Doc (google_docs_append_content)

Google OAuth tokens stay inside this server. Agents never see client secrets or access tokens.

See Docs/architecture.md and Docs/problemStatement.md.

Requirements

  • Node.js 20+

  • A Google Cloud project with Gmail API and Google Docs API enabled

  • OAuth 2.0 Desktop or Web client credentials

Related MCP server: Gmail & Google Docs MCP Server

Setup

1. Install

npm install

2. Google Cloud

  1. Create a project in Google Cloud Console.

  2. Enable Gmail API and Google Docs API.

  3. Configure the OAuth consent screen (add your Google account as a test user if the app is in testing).

  4. Create OAuth client credentials (Desktop app is simplest for local use).

  5. Add authorized redirect URI: http://localhost:3000/oauth2callback (or match GOOGLE_REDIRECT_URI).

3. Environment

cp .env.example .env

Fill in:

GOOGLE_CLIENT_ID=...
GOOGLE_CLIENT_SECRET=...
GOOGLE_REDIRECT_URI=http://localhost:3000/oauth2callback
GOOGLE_TOKEN_STORAGE=.tokens/google-token.json
LOG_LEVEL=info

4. Authorize once

npm run auth

This opens a browser for Google consent and writes tokens to GOOGLE_TOKEN_STORAGE.

Default scopes:

  • https://www.googleapis.com/auth/gmail.compose

  • https://www.googleapis.com/auth/documents

(documents is used so agents can append by document ID. Override with GOOGLE_SCOPES if needed.)

5. Run

npm run build
npm start

Development (TypeScript directly):

npm run dev

Cursor / MCP client config

Example Cursor MCP settings (stdio):

{
  "mcpServers": {
    "google-workspace": {
      "command": "node",
      "args": ["C:/Users/dhruv/MCP Server 1/dist/server.js"],
      "env": {
        "GOOGLE_CLIENT_ID": "your-client-id",
        "GOOGLE_CLIENT_SECRET": "your-client-secret",
        "GOOGLE_REDIRECT_URI": "http://localhost:3000/oauth2callback",
        "GOOGLE_TOKEN_STORAGE": "C:/Users/dhruv/MCP Server 1/.tokens/google-token.json",
        "LOG_LEVEL": "info"
      }
    }
  }
}

Or point command at npx tsx and args at src/server.ts during development.

Tools

Tool

Purpose

gmail_create_draft

Create a draft (does not send)

gmail_send_email

Send email immediately (not idempotent in v1)

google_docs_append_content

Append text at end of doc body by document_id

Structured responses look like:

{ "success": true, "draft_id": "...", "message_id": "...", "thread_id": "...", "provider": "gmail" }

or:

{ "success": false, "error": { "code": "VALIDATION_ERROR", "message": "..." } }

Deploy on Railway

Remote hosting uses Streamable HTTP (not stdio). Full checklist: Docs/deployment-plan.md.

Summary:

  1. Build/start: npm run build then npm run start:http (Railway Start Command).

  2. Set Railway variables: GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, GOOGLE_REDIRECT_URI (https://<domain>/oauth2callback), MCP_API_KEY, and either GOOGLE_REFRESH_TOKEN or a Volume + GOOGLE_TOKEN_STORAGE=/data/token.json.

  3. Health check path: /health.

  4. First Google login: temporarily set ENABLE_OAUTH_SETUP=true, visit /oauth/start, then disable setup and prefer storing the refresh token in GOOGLE_REFRESH_TOKEN.

  5. Point MCP clients at https://<domain>/mcp with Authorization: Bearer <MCP_API_KEY>.

Local HTTP smoke test:

MCP_API_KEY=dev-secret npm run dev:http
curl http://127.0.0.1:3000/health

Scripts

Command

Description

npm run auth

OAuth browser login + token save

npm run dev

Run stdio server via tsx

npm run dev:http

Run Streamable HTTP server via tsx

npm run build

Compile to dist/

npm start

Run compiled stdio server

npm run start:http

Run compiled HTTP server (Railway)

npm test

Unit tests (mocked Google APIs)

npm run typecheck

TypeScript check

Project layout

src/
  server.ts                 # MCP stdio bootstrap
  http.ts                   # Streamable HTTP + /health + bearer auth
  app.ts                    # Shared createAppServer / providers
  config/                   # env-driven configuration
  mcp/tools/                # MCP tool handlers
  mcp/schemas/              # Zod input schemas for tools
  providers/google/         # OAuth, Gmail, Docs
  validation/               # email/doc validation
  errors/                   # normalized error codes
  logging/                  # structured stderr logging (redacted)
  scripts/auth.ts           # local OAuth helper
tests/unit/                 # vitest unit tests

Security notes

  • Never commit .env or token files.

  • Logs go to stderr (stdout is reserved for MCP) and redact tokens/secrets/bodies.

  • gmail_send_email is an external side effect; clients should confirm with the user when appropriate.

Available Tools

3 tools
gmail_create_draftCreate Gmail draftA

Create a draft email in the authenticated user's Gmail account without sending it.

When to use:

  • The agent should prepare an email for later review or sending.

  • Prefer this over gmail_send_email when the user has not confirmed sending.

Required parameters: to (non-empty array of valid emails), subject, body. Optional: cc, bcc, is_html (default false).

Side effects: Creates a Gmail draft only. Does not send the email.

Success: Returns draft_id, message_id, thread_id, and provider "gmail". Common failures: VALIDATION_ERROR (bad emails/missing fields), AUTHENTICATION_REQUIRED, AUTHORIZATION_DENIED, GOOGLE_API_ERROR.

ParametersJSON Schema
NameRequiredDescriptionDefault
ccNoOptional CC recipient email addresses.
toYesRequired. One or more recipient email addresses.
bccNoOptional BCC recipient email addresses.
bodyYesRequired. Email body content.
is_htmlNoWhen true, body is treated as HTML. Defaults to false (plain text).
subjectYesRequired. Email subject line.
idempotency_keyNoOptional unique key reserved for future send idempotency. Not enforced in v1.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare the safety profile (readOnlyHint=false, destructiveHint=false, idempotentHint=false, openWorldHint=true). The description goes further by stating the side effect boundary ('creates a draft only. Does not send'), the success payload shape (draft_id, message_id, thread_id, provider), and the concrete failure taxonomy (VALIDATION_ERROR, AUTHENTICATION_REQUIRED, AUTHORIZATION_DENIED, GOOGLE_API_ERROR). That is real added value beyond the structured fields.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The one-line purpose is front-loaded, followed by clearly labeled blocks for usage, parameters, side effects, returns, and failures. Efficient and scannable, though the parameter restatement and failure list add some redundancy with the schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description compensates by naming the returned identifiers and provider, and it covers the mutation's side-effect boundary and error surface. An agent has everything needed to call this correctly for a 7-parameter mutation tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so both schema and description document all seven parameters, setting the baseline at 3. The description restates required vs optional and the is_html default, which largely duplicates the schema rather than adding syntax or format meaning beyond it.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Create a draft email') and immediately scopes it as 'without sending it.' The 'Prefer this over gmail_send_email' line explicitly differentiates it from a named sibling, so an agent can disambiguate without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides an explicit when-to-use block plus a named alternative (gmail_send_email) and the exact condition that selects it (user has not confirmed sending). This is the full when/when-not/alternative triad.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

gmail_send_emailSend Gmail emailA
Destructive

Send an email through Gmail on behalf of the authenticated Google account.

IMPORTANT SIDE EFFECT: This tool actually sends an email. It is not a draft. MCP clients/agents should obtain user confirmation when appropriate before calling this tool. The server will not silently convert a send into a draft.

When to use:

  • The user explicitly wants the email delivered now.

  • Do not use this to "prepare" an email; use gmail_create_draft instead.

Required parameters: to (non-empty array of valid emails), subject, body. Optional: cc, bcc, is_html (default false), idempotency_key (reserved; not enforced in v1 — sends are not inherently idempotent).

Success: Returns message_id, thread_id, and provider "gmail". Common failures: VALIDATION_ERROR, AUTHENTICATION_REQUIRED, AUTHORIZATION_DENIED, RATE_LIMITED, GOOGLE_API_ERROR, NETWORK_ERROR.

Recipient addresses and content are not silently modified.

ParametersJSON Schema
NameRequiredDescriptionDefault
ccNoOptional CC recipient email addresses.
toYesRequired. One or more recipient email addresses.
bccNoOptional BCC recipient email addresses.
bodyYesRequired. Email body content.
is_htmlNoWhen true, body is treated as HTML. Defaults to false (plain text).
subjectYesRequired. Email subject line.
idempotency_keyNoOptional unique key reserved for future send idempotency. Not enforced in v1.

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already flag destructiveHint=true and idempotentHint=false, but the description goes well beyond them: it warns this actually sends (not a draft), recommends user confirmation, guarantees no silent send-to-draft conversion, discloses that idempotency_key is unenforced in v1, states recipients/content are not modified, and enumerates failure codes. This is rich behavioral context layered on top of structured hints.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the critical side-effect warning before details, which is the right priority order. It is somewhat long due to the full failure-code list, but each section (usage, params, success, failures) earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a send tool with no output schema, the description supplies the return shape (message_id, thread_id, provider) and the failure taxonomy, covering both success and error paths. An agent has everything needed to call it and interpret results.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema documents each parameter; baseline would be 3. The description adds real value by calling out required vs optional sets and, crucially, clarifying that idempotency_key is reserved and not enforced in v1 — a nuance the schema only hints at.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ('Send') plus resource ('email through Gmail') and the acting identity ('authenticated Google account'). It explicitly distinguishes itself from the sibling gmail_create_draft, so an agent can route correctly without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives an explicit 'When to use' section: only when the user wants delivery now, plus a negative condition ('do not use this to prepare') and the named alternative (gmail_create_draft). Nothing is left to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

google_docs_append_contentAppend to Google DocA

Append plain text to the end of an existing Google Doc.

When to use:

  • Add content to a known document without calculating Google Docs insertion indexes.

  • Pass the document ID only (not a full Docs URL).

Required parameters: document_id, content (non-empty). Optional: add_newline_before (default true), add_newline_after (default false).

Side effects: Mutates the document body by inserting text at the end of the body segment. Uses revision WriteControl so concurrent edits are detected rather than applied blindly.

Success: Returns document_id, appended_characters, and provider "google_docs". Common failures: VALIDATION_ERROR (empty content), RESOURCE_NOT_FOUND, AUTHENTICATION_REQUIRED, AUTHORIZATION_DENIED, GOOGLE_API_ERROR (including stale revision).

ParametersJSON Schema
NameRequiredDescriptionDefault
contentYesRequired. Non-empty text to append to the document body.
document_idYesRequired. Google Docs document ID (not the full URL).
add_newline_afterNoWhen true, ensure appended content ends with a newline. Defaults to false.
add_newline_beforeNoWhen true, ensure appended content starts on a new line. Defaults to true.

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already flag non-readOnly, non-idempotent, openWorld, non-destructive. Description adds valuable context beyond annotations: body mutation via end insertion, revision WriteControl for concurrency detection, and a concrete failure taxonomy with stale revision. Missing detail on exact return timing or rate limits, but strong coverage.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded first sentence states the action, followed by structured sections (When to use, Required, Optional, Side effects, Success, Failures). Every sentence adds value with no redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Covers purpose, usage, side effects, return fields, and failure modes, which is substantial for a 4-param mutation tool with no output schema. Slightly limited on edge cases like document size limits or content formatting constraints, but overall quite complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% with descriptions, defaults, and minLength constraints all present. Description restates required/optional params and defaults, adding little beyond the schema. Baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (Append), resource (plain text), and target (end of an existing Google Doc). Distinguishes the operation from siblings (gmail tools) by scope and clarifies 'plain text' specificity.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit 'When to use' section: adding content without calculating insertion indexes, and passing document ID only (not URL). No explicit when-not-to-use or named alternative, but context is clear enough to guide invocation.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 3 tool updatesv1.0.0
    • First observedgmail_create_draft
    • First observedgmail_send_email
    • First observedgoogle_docs_append_content

TDQS

A4.1/5.0

Scored across 3 tools

Disambiguation5/5

The three tools target clearly distinct actions: creating a Gmail draft, sending a Gmail email, and appending to a Google Doc. The descriptions explicitly contrast draft vs. send and provide strong guidance on when to use each, eliminating misselection risk.

Naming Consistency4/5

All tool names use consistent snake_case with a service prefix + verb + noun pattern: gmail_create_draft, gmail_send_email, google_docs_append_content. The only minor deviation is the prefix style (gmail vs google_docs), but this is still readable and predictable.

Tool Count2/5

Three tools is very thin for a server labeled 'Google Workspace,' which implies broad coverage of Gmail, Docs, Drive, Calendar, and more. While the individual tools are well-scoped, the count is mismatched to the apparent breadth of the stated purpose.

Completeness2/5

The surface covers only Gmail draft/send and Docs append, with no read, list, search, update, or delete operations for those services, and no other Workspace products at all. This leaves significant gaps that would cause agent dead ends for common Workspace tasks.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers