Google Workspace MCP Server
Allows creating Gmail drafts and sending email through the Gmail API, with support for composing messages and triggering external email sends.
Allows appending text to the end of a Google Doc's body by document ID using the Google Docs API.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Google Workspace MCP Servercreate a Gmail draft to my manager about the project timeline"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
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 effectAppend 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 install2. Google Cloud
Create a project in Google Cloud Console.
Enable Gmail API and Google Docs API.
Configure the OAuth consent screen (add your Google account as a test user if the app is in testing).
Create OAuth client credentials (Desktop app is simplest for local use).
Add authorized redirect URI:
http://localhost:3000/oauth2callback(or matchGOOGLE_REDIRECT_URI).
3. Environment
cp .env.example .envFill in:
GOOGLE_CLIENT_ID=...
GOOGLE_CLIENT_SECRET=...
GOOGLE_REDIRECT_URI=http://localhost:3000/oauth2callback
GOOGLE_TOKEN_STORAGE=.tokens/google-token.json
LOG_LEVEL=info4. Authorize once
npm run authThis opens a browser for Google consent and writes tokens to GOOGLE_TOKEN_STORAGE.
Default scopes:
https://www.googleapis.com/auth/gmail.composehttps://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 startDevelopment (TypeScript directly):
npm run devCursor / 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 |
| Create a draft (does not send) |
| Send email immediately (not idempotent in v1) |
| Append text at end of doc body by |
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:
Build/start:
npm run buildthennpm run start:http(Railway Start Command).Set Railway variables:
GOOGLE_CLIENT_ID,GOOGLE_CLIENT_SECRET,GOOGLE_REDIRECT_URI(https://<domain>/oauth2callback),MCP_API_KEY, and eitherGOOGLE_REFRESH_TOKENor a Volume +GOOGLE_TOKEN_STORAGE=/data/token.json.Health check path:
/health.First Google login: temporarily set
ENABLE_OAUTH_SETUP=true, visit/oauth/start, then disable setup and prefer storing the refresh token inGOOGLE_REFRESH_TOKEN.Point MCP clients at
https://<domain>/mcpwithAuthorization: Bearer <MCP_API_KEY>.
Local HTTP smoke test:
MCP_API_KEY=dev-secret npm run dev:http
curl http://127.0.0.1:3000/healthScripts
Command | Description |
| OAuth browser login + token save |
| Run stdio server via tsx |
| Run Streamable HTTP server via tsx |
| Compile to |
| Run compiled stdio server |
| Run compiled HTTP server (Railway) |
| Unit tests (mocked Google APIs) |
| 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 testsSecurity notes
Never commit
.envor token files.Logs go to stderr (stdout is reserved for MCP) and redact tokens/secrets/bodies.
gmail_send_emailis an external side effect; clients should confirm with the user when appropriate.
Available Tools
3 toolsgmail_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.
| Name | Required | Description | Default |
|---|---|---|---|
| cc | No | Optional CC recipient email addresses. | |
| to | Yes | Required. One or more recipient email addresses. | |
| bcc | No | Optional BCC recipient email addresses. | |
| body | Yes | Required. Email body content. | |
| is_html | No | When true, body is treated as HTML. Defaults to false (plain text). | |
| subject | Yes | Required. Email subject line. | |
| idempotency_key | No | Optional unique key reserved for future send idempotency. Not enforced in v1. |
TDQS
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.
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.
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.
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.
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.
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 emailADestructive
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.
| Name | Required | Description | Default |
|---|---|---|---|
| cc | No | Optional CC recipient email addresses. | |
| to | Yes | Required. One or more recipient email addresses. | |
| bcc | No | Optional BCC recipient email addresses. | |
| body | Yes | Required. Email body content. | |
| is_html | No | When true, body is treated as HTML. Defaults to false (plain text). | |
| subject | Yes | Required. Email subject line. | |
| idempotency_key | No | Optional unique key reserved for future send idempotency. Not enforced in v1. |
TDQS
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.
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.
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.
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.
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.
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).
| Name | Required | Description | Default |
|---|---|---|---|
| content | Yes | Required. Non-empty text to append to the document body. | |
| document_id | Yes | Required. Google Docs document ID (not the full URL). | |
| add_newline_after | No | When true, ensure appended content ends with a newline. Defaults to false. | |
| add_newline_before | No | When true, ensure appended content starts on a new line. Defaults to true. |
TDQS
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.
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.
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.
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.
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.
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.
3 tool updates
v1.0.0- First observed
gmail_create_draft - First observed
gmail_send_email - First observed
google_docs_append_content
TDQS
Scored across 3 tools
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.
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.
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.
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
Related MCP Connectors
MCP server connecting AI agents to 100+ apps (Gmail, Slack, Notion, GitHub) via one-click OAuth.
Email infrastructure for AI agents — send, receive, search, and reply to email over MCP.
Multiple Gmail accounts, editable Google Sheets & Docs for AI agents. Deny-by-default access rules.
Permissioned access to Gmail, Drive and Calendar via the user's own Google account
Related MCP Servers
- AlicenseBqualityCmaintenanceExposes Gmail (send/draft) and Google Docs (append) capabilities as tools for any MCP-compliant agent.370ISC
- AlicenseNot gradedqualityBmaintenanceEnables AI agents to send Gmail emails, create drafts, and append content to Google Docs through MCP tools. Provides secure OAuth-based integration with Google Workspace.205MIT
- AlicenseNot gradedqualityCmaintenanceEnables AI agents to send and draft Gmail emails and append content to Google Docs through standardized MCP tools.6MIT
- AlicenseNot gradedqualityBmaintenanceEnables MCP-compatible AI agents to create Gmail drafts, send emails, and append content to Google Docs with OAuth-secured authentication.19MIT