gmail-multi-mcp
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| GOOGLE_CLIENT_ID | No | Google OAuth client ID. Required unless credentials are already stored in ~/.gmail-multi-mcp/config.json. | |
| GOOGLE_CLIENT_SECRET | No | Google OAuth client secret. Required unless credentials are already stored in ~/.gmail-multi-mcp/config.json. |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": true
} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| list_accountsA | List every configured Gmail account and whether it is usable. Call this first when you do not know which accounts exist, or when another tool reports an unknown account. |
| search_emailsA | Search with Gmail query syntax (e.g. "from:ana@x.com is:unread newer_than:7d"). Omit "account" to search EVERY configured mailbox in parallel and get one merged, date-sorted list. If one account fails the others still return, and the failure is reported in "failures". |
| read_threadA | Read a full conversation, every message in order. Prefer this over read_message when you need the context of an exchange rather than a single email. |
| read_messageA | Read one message in full, including its decoded body and attachment metadata. Attachment contents are not downloaded. |
| create_draftA | Save a draft without sending it. Use this whenever the user has not explicitly asked for the message to go out. |
| replyA | Send a reply that stays in the original thread. Handles the subject prefix and the In-Reply-To/References headers, which is what makes it appear as a reply rather than a new conversation. This SENDS immediately. |
| send_messageA | Compose and SEND a new email immediately. There is no undo. If the user has not clearly asked for it to be sent, use create_draft instead. |
| list_labelsA | List the labels of an account, system and user-created, with their ids. Call this before label_message if you are unsure a label exists. |
| label_messageA | Apply and/or remove labels on a message. Accepts label names or ids — names are resolved case-insensitively. Useful system labels: UNREAD, STARRED, IMPORTANT, SPAM, TRASH. Removing UNREAD marks a message as read. |
| trash_emailA | Move a message to the bin. This is NOT a permanent delete: the message keeps existing and untrash_email brings it back. Gmail does empty the bin by itself after 30 days, so it becomes permanent eventually — treat it as reversible for a month, not for ever. This server has no permanent-delete tool at all. The answer names the message that moved, so a wrong id is visible immediately. |
| untrash_emailA | Take a message back out of the bin and restore the labels it had. Only works while the message is still there — once Gmail has emptied the bin, after about 30 days, there is nothing left to recover. Use search_emails with "in:trash" to find what is in there. |
| drive_searchA | Find files in Google Drive. Omit "account" to search EVERY connected Drive in parallel and get one merged list, most recently modified first; if one account fails the others still return and the failure is reported in "failures". Use "query" for plain words (matched against filename and file contents) and "drive_query" only when you need raw Drive query syntax, e.g. "mimeType = 'application/pdf' and modifiedTime > '2026-01-01T00:00:00'". |
| drive_readA | Read a file as text. Google Docs are exported to plain text, Sheets to CSV and Slides to plain text; ordinary text files are downloaded as they are. Binary files (PDF, images, archives) are refused with a link instead — this tool does not download them. Long content is truncated and says so. |
| drive_listA | List what is inside a folder, sub-folders first. Omit "folder_id" for the root of My Drive. Use drive_search when you know what you are looking for but not where it lives. |
| drive_shared_drivesA | List the shared drives an account can reach, with their ids. A shared drive is NOT a file: it never appears in drive_search, not even searched by its exact name, so this is the only way to turn a drive name into the id that drive_list, drive_upload and drive_share need. Without "account", asks every configured account. "canAddChildren" tells you whether that account may write to it. |
| drive_uploadA | Put a file in Drive. Give either "content" for text you composed, or "local_path" for a file that already exists on the machine running this server — exactly one of the two. The file is private to the account until something shares it. |
| drive_create_docA | Create a real Google Doc — not a text file — from plain text. Line breaks are kept; formatting is not, because the content is converted from plain text on the way in. Returns the document id and a link to open it. |
| drive_shareA | Grant someone access to a file. This GIVES AWAY ACCESS to real data and cannot be undone from here. type "user" or "group" needs "email_address"; "domain" needs "domain"; type "anyone" makes the file readable by ANYONE WITH THE LINK, so only use it when the user asked for a public link in so many words. No notification email is sent unless "notify" is true. |
| calendar_list_eventsA | List events in a time range. Omit "account" to look at EVERY connected calendar at once, merged and sorted by start time. Repeating events are expanded into their real occurrences. Times must carry an explicit UTC offset. |
| calendar_get_eventA | Read one event in full: description, location, attendees and their responses, and the link to open it. |
| calendar_create_eventA | Create an event. For a timed event, "start" and "end" are ISO 8601 WITH an offset. For an all-day event set "all_day" and give plain dates (YYYY-MM-DD) — note that Google treats the end date as EXCLUSIVE, so a one-day event ends on the following day. Listing attendees puts the event on their calendars; they are only emailed when "send_updates" says so. |
| calendar_update_eventA | Change an existing event. Only the fields you give are touched — except "start" and "end", which must be given together or not at all, because moving one end alone reshapes the meeting. Passing "attendees" REPLACES the guest list rather than adding to it. |
| calendar_delete_eventA | Delete an event. This is IRREVERSIBLE from here — there is no undo and no bin. The event is read before deletion so the answer says what was removed. Only do this when the user has clearly asked for it. |
| calendar_find_free_timeA | Find gaps that are free on EVERY account asked about, within working hours. "time_min" and "time_max" must carry an explicit UTC offset. Working hours are interpreted in "timezone" (IANA), which defaults to the zone this server runs in and is always echoed back. IMPORTANT: if any calendar cannot be read, NO slots are returned and "incomplete" is set — a gap computed without one person's calendar is a double-booking, not an answer. |
| contacts_searchA | Find people in the account address book. The query matches names, nicknames, email addresses, phone numbers and organisations. Omit "account" to search EVERY connected address book at once. The same person in two accounts is returned TWICE on purpose — each copy has its own id and belongs to a different address book, so merging them would make contacts_update edit the wrong one. |
| contacts_getA | Read one contact in full: every email and phone with its label, organisation, job title, postal addresses, links and notes. |
| contacts_listA | Page through an account address book, most recently changed first. Returns "nextPageToken" when there is more; pass it back as "page_token" for the next page. Use contacts_search when you are looking for someone in particular. |
| contacts_createA | Add a person to the account address book. At least one field is required. Google does not check for duplicates — search first if the person might already be there. |
| contacts_updateA | Change an existing contact. ⚠️ Each field you name is REPLACED, not merged: passing "emails" with one address removes every other address that contact had. Fields you do not name are left alone. Read the contact first with contacts_get and send back the full list of whichever field you are editing. The current version is re-read before writing, so a change made elsewhere in the meantime cannot be silently overwritten. |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
TDQS
Scored across 29 tools
Every tool maps to a distinct resource and action: search/read/draft/send/reply/label/trash for email, search/read/list/upload/share for Drive, CRUD plus free-time for Calendar, and search/get/list/create/update for Contacts. read_thread vs read_message and create_draft vs send_message are explicitly scoped to avoid confusion.
Most tools follow a clear verb_noun pattern, and drive_*, calendar_*, and contacts_* prefixes make domains predictable. Minor deviations like the bare verb "reply", the unprefixed list_labels/label_message, and the noun-phrase drive_shared_drives keep it from being perfectly consistent.
29 tools is high in absolute terms, but the server covers four distinct Google services plus multi-account handling, giving each domain a reasonable 5-8 tool surface. It is slightly heavy but every tool serves a distinct purpose and none feel redundant.
Core workflows are well covered: Gmail has search/read/draft/send/reply/label/trash, Calendar has full CRUD and free-time search, Contacts has create/read/update/search, and Drive has search/read/upload/share/create. Minor gaps exist such as no contacts_delete, no Drive delete or folder creation, and no attachment downloading, but agents can complete most real tasks.