draft-only-google
Provides access to a Gmail mailbox for reading threads and messages, downloading attachments, managing labels, and creating, updating, and listing drafts without sending email.
Enables interaction with Google Calendar to list calendars and events, retrieve event details, and create or update events while suppressing guest notifications by default.
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., "@draft-only-google Draft a reply to my last email from Sarah and label it follow-up"
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.
draft-only-google-mcp
This is a small MCP server that gives Claude access to one Gmail mailbox and its Google Calendar. Claude can read mail, manage labels, write drafts and work with calendar events. It has no way to send email, so you review every draft and send it yourself from Gmail.
It is about 560 lines of Python. It depends only on Anthropic's mcp SDK, Google's auth libraries and requests, and it talks only to the Gmail API, the Calendar API and Google OAuth.
macOS only. Tokens are stored in the macOS Keychain and nowhere else, and the server refuses to start a login or read a token on any other system. Linux and Windows are not supported today.
What the guarantee covers
There is no code path in this server that sends mail. It has no send tool, it never calls Gmail's send endpoints, and it does not speak SMTP. Every id goes through one check before it reaches a URL, so an id cannot steer a request to another endpoint. Calendar writes always pass sendUpdates=none, and no tool has a parameter that changes that.
tests/test_no_send.py enforces this. It fails if the source mentions a send endpoint, a send scope or SMTP, if the OAuth scopes or the tool list change from a fixed list, if a tool gains a parameter with send or notify in its name, if a calendar write asks Google to notify guests, or if the final URL of any tool call leaves the Gmail and Calendar read and draft endpoints.
Related MCP server: gmail-mcp-server
What the guarantee does not cover
The guarantee is about this server's code, not about the Google token, so these limits matter:
The token itself can send. Gmail has no scope that allows drafts without also allowing send, so this server uses
gmail.modify, which Google describes as read, compose and send. Other software holding this token could send mail.An agent with a shell can reach the token. The token is stored in the Keychain by the
securitycommand, so a process running as your user can read it back with that same command without a prompt. If you need the limit to hold, do not also give the agent unrestricted shell access.Calendar guests can still hear about events.
attendeesis refused unless you turn onDRAFT_ONLY_GOOGLE_ALLOW_ATTENDEES. Once it is on, an event with attendees can appear on their calendars even though no invite is requested, and Google's documentation says some emails might still be sent. Changing an event that already has guests can reach them the same way. Treat adding a guest as a visible action.Drafts can hold private content.
create_draftcan attach any regular file inside the allowed folders, and mail you ask Claude to read can contain instructions written by strangers. Read each draft and its recipients before you send it.
Tools
Gmail:
search_threads,get_thread,get_message,download_attachment,list_labels,modify_thread_labels,create_draft,update_draft,list_draftsCalendar:
list_calendars,list_events,get_event,create_event,update_event
Setup
You need macOS, uv and a Google account. You create your own Google OAuth client, so no third party is involved and your token only works with your client.
1. Create a Google OAuth client
Open the Google Cloud console and create a new project.
Under APIs & Services, open Library, then enable the Gmail API and the Google Calendar API.
Open Google Auth Platform and fill in the app name and your email address when asked. Choose the audience:
With a Google Workspace account, choose Internal. Only people in your organization can use the app, and no review is needed.
With a personal Gmail account, choose External, then add your own address as a test user under Audience.
Under Clients, create an OAuth client with the application type Desktop app, then download its JSON file.
An External app in Testing status gets a refresh token that expires after 7 days, so you would need to log in again each week. To avoid that, publish the app from the Audience page. Google will then show an unverified app warning at login, which you can click through because it is your own app.
2. Sign in
git clone https://github.com/elliothimmelfarb/draft-only-google-mcp.git
cd draft-only-google-mcp
uv run draft-only-google-mcp login /path/to/client_secret.jsonA browser opens for Google's consent screen. When you are signed in, the token is in the Keychain and you should delete the JSON file. Run uv run draft-only-google-mcp whoami to check which account is stored.
3. Add it to Claude Code
claude mcp add -s user draft-only-google -- uv run --directory "$PWD" draft-only-google-mcpConfiguration
All settings are optional environment variables. Set them for both the login command and the server, for example with claude mcp add -e NAME=value.
Variable | Default | Purpose |
| none | Makes |
|
| The Keychain service name. |
|
| The name the MCP server reports. |
|
| Where |
| the attachment folder | Folders |
|
| The default time zone for calendar events. |
| off | Set to |
To use two mailboxes, register the server twice with a different DRAFT_ONLY_GOOGLE_ACCOUNT for each and run login once for each.
Development
uv run pytestLicense
MIT. See LICENSE.
Available Tools
14 toolscreate_draftA
Create a draft in the mailbox (it is NOT sent). For a reply, pass reply_to_message_id and leave subject empty to get "Re: " threaded correctly. Write each paragraph as one line; lines wrapped by hand are joined so the email fills the reader's window. attachments: absolute paths of local files to attach. Each must be a regular file inside the attachment folder or DRAFT_ONLY_GOOGLE_ATTACHMENT_ROOTS, and together they must fit in 25 MB.
Inputs: to (required), body (required), cc, bcc, +3 more.
create_eventB
Create a calendar event. start/end are RFC 3339 datetimes or YYYY-MM-DD for all-day. attendees is refused unless DRAFT_ONLY_GOOGLE_ALLOW_ATTENDEES is on. This server asks Google not to notify guests, but the event may still appear on their calendars and Google may still email them, so treat adding a guest as a visible action.
Inputs: end (required), start (required), summary (required), location, +4 more.
download_attachmentB
Save an attachment to the attachment folder under a new unique name and return the local path.
Inputs: filename (required), message_id (required), attachment_id (required). Returns: result
get_eventC
Get one calendar event.
Inputs: event_id (required), calendar_id.
get_messageB
Get one Gmail message with headers, plain-text body and attachment list.
Inputs: message_id (required).
get_threadB
Get every message in a Gmail thread with headers, plain-text body and attachment list.
Inputs: thread_id (required).
list_calendarsB
List calendars visible to the account.
Inputs: no named parameters. Returns: result
list_draftsC
List drafts in the mailbox, including any Bcc recipients.
Inputs: max_results. Returns: result
list_eventsA
List calendar events between two RFC 3339 times (e.g. 2026-01-15T00:00:00+01:00). Recurring events are expanded into single instances, ordered by start time.
Inputs: time_max (required), time_min (required), query, calendar_id, +1 more. Returns: result
list_labelsA
List Gmail labels with their ids.
Inputs: no named parameters. Returns: result
modify_thread_labelsA
Add or remove label ids on a thread. Archive = remove INBOX. Mark read = remove UNREAD.
Inputs: thread_id (required), add_label_ids, remove_label_ids.
search_threadsA
Search Gmail threads with Gmail search syntax (from:, to:, subject:, newer_than:7d, is:unread, in:sent, label:...). Returns each thread's latest message summary. Use get_thread for full bodies.
Inputs: query, page_token, max_results.
update_draftC
Replace the contents of an existing draft.
Inputs: to (required), body (required), draft_id (required), cc, +3 more.
update_eventA
Change fields on a calendar event; omitted fields stay as they are. attendees replaces the whole list and is refused unless DRAFT_ONLY_GOOGLE_ALLOW_ATTENDEES is on. This server asks Google not to notify guests, but Google may still email them about a change.
Inputs: event_id (required), end, start, summary, +5 more.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 14 tools
Each tool targets a distinct resource+action pair (thread vs message vs draft vs event), and the descriptions explicitly cross-reference each other (search_threads points to get_thread for full bodies). The only borderline pair is get_thread vs get_message, which requires the agent to know Gmail's thread/message model, but the descriptions make the split workable.
All 14 tools follow a strict snake_case verb_noun pattern (list_/get_/search_/create_/update_/modify_/download_). No mixed conventions or vague verbs anywhere in the set.
14 tools is well within a comfortable range and each maps to a concrete Gmail or Calendar operation. The split across threads, messages, attachments, labels, drafts, events, and calendars is proportionate to the two-API scope.
Read/create/update lifecycle is covered for drafts and events, and send is intentionally excluded by design (draft-only). However, there is no delete_draft, no delete_event, no get_draft, and no way to modify labels on individual messages rather than threads, leaving dead ends for cleanup workflows.
Maintenance
Related MCP Connectors
Connect any IMAP/SMTP mailbox to Claude & ChatGPT: search, read, sort, draft. Sends only with OK.
Connect any mailbox to Claude, ChatGPT & AI: read, send, reply, schedule & search emails.
Permissioned access to Gmail, Drive and Calendar via the user's own Google account
Manage Gmail end-to-end: search, read, send, draft, label, and organize threads. Automate workflow…
Related MCP Servers
- AlicenseAqualityCmaintenanceEnables Claude to manage Gmail, Google Calendar, and Google Contacts through a safety-first interface with soft-delete protections and draft-only email capabilities. Supports multiple Google accounts with comprehensive mutation logging and mandatory manual confirmation for destructive actions.16MIT
- AlicenseNot gradedqualityDmaintenanceEnables reading, sending, searching, and managing Gmail through Claude using the official Google Gmail API.123 npm3MIT
- FlicenseBqualityDmaintenanceEnables Claude to read unread emails and create draft responses using the Gmail API.2-
- AlicenseNot gradedqualityDmaintenanceEnables Claude to read, search, send, and manage Gmail messages and threads through natural language.282 npmMIT