# Gmail MCP Server > **Gmail MCP Server** is a hosted, multitenant Model Context Protocol (MCP) server run by **MewCP** (https://mewcp.com), giving AI agents managed access to Gmail. > > MewCP takes care of all MCP infrastructure for you — credential storage, OAuth flows, > token refresh, and production-grade auto-scaling — so your AI agents can connect to > third-party services and run freely without you managing any MCP server yourself. > > To connect your agent to this server you need a MewCP account and two values: > - MEWCP_KEY — your personal API key (dashboard → Developer) > - CREDENTIAL_ID — the stored credential MewCP securely injects per request > > Server page: https://mewcp.com/mcp/google-gmail > MewCP docs: https://docs.mewcp.com > Full catalog: https://mewcp.com/llms.txt ## About Manage Gmail end to end with tools for sending, reading, replying to and organizing emails. Work with threads, labels, drafts, attachments and inbox workflows while keeping communication and email automation in one place. ## How to connect Server Page URL: https://mewcp.com/mcp/google-gmail Gateway URL: https://gateway.mewcp.com/google-gmail/mcp Every request to this server requires two headers: Authorization: Bearer — your MewCP API key (dashboard → Developer) x-mewcp-credential-id: — the stored credential ID for this service All connection snippets and ready-to-use code examples are available on the server page and in this document below. --- ## Server documentation **Full programmatic control of Gmail — messages, threads, drafts, labels, filters, and settings** A Model Context Protocol (MCP) server that exposes Gmail's API for reading, sending, and organizing mail, and for managing the mailbox's labels, filters, drafts, and settings. ## Overview The mewcp-gmail MCP Server provides: - Full message and thread lifecycle management — list, get, send, modify labels, trash/untrash, and permanently delete - Label, filter, forwarding-address, and send-as alias management for organizing and routing mail - Draft creation, retrieval, updating, and sending - Vacation responder and auto-forwarding settings management - Incremental mailbox sync via the history API, so a client can track changes without re-listing everything Perfect for: - Building an AI email assistant that triages, drafts, and organizes a Gmail inbox - Automating label-based mail filtering and forwarding rules - Keeping an external system's copy of a mailbox in sync via incremental history polling ## Tools ### Profile
get_profile — Get the authenticated user's Gmail profile Gets the current user's Gmail profile, returning mailbox email address, message/thread totals, and current history ID. **Inputs:** ``` - `userId` (string, optional) — The user's email address. Defaults to `me`, which refers to the authenticated user and is correct for almost every call — set this only if the token has delegated access to another mailbox. ``` **Output `data` schema:** ```typescript { emailAddress: string | null; messagesTotal: number | null; threadsTotal: number | null; historyId: string | null; } ```
### Drafts
create_draft — Create a new draft Creates a draft with the DRAFT label. Give it content either with the plain to/subject/body fields (builds the RFC 2822/base64url encoding internally — use this for a normal draft) or with `message` (a raw Gmail Message resource with a hand-built `raw` blob — only needed for attachments, custom headers, or multipart bodies). If `message` is set, the plain fields below are ignored. **Inputs:** ``` - `userId` (string, optional) — The user's email address. Defaults to `me`, which refers to the authenticated user and is correct for almost every call — set this only if the token has delegated access to another mailbox. - `message` (object, optional) — The message content of the draft (object (Message)) as a raw Gmail Message resource — must include a base64url-encoded `raw` RFC 2822 blob. Only needed for attachments, custom headers, or multipart bodies; for a normal draft use the plain to/subject/body fields below instead and leave this unset. - `to` (string, optional) — Comma-separated recipient email address(es). Ignored if `message` is set. - `subject` (string, optional) — The draft's subject line. Ignored if `message` is set. - `body` (string, optional) — The draft's body text. Ignored if `message` is set. - `cc` (string, optional) — Comma-separated Cc recipient email address(es). Ignored if `message` is set. - `bcc` (string, optional) — Comma-separated Bcc recipient email address(es). Ignored if `message` is set. - `html` (boolean, optional) — If true, `body` is treated as HTML instead of plain text. Ignored if `message` is set. ``` **Output `data` schema:** ```typescript { id: string | null; message: object | null; } ```
delete_draft — Permanently delete a draft (destructive) DESTRUCTIVE — REQUIRES EXPLICIT USER CONFIRMATION BEFORE CALLING. Immediately and permanently deletes the specified draft (does not simply trash it). This action is irreversible — the draft and its message content cannot be recovered. NEVER call this tool autonomously or as part of an automated flow. You MUST stop, tell the user exactly what will be deleted and that it is permanent, and wait for their explicit written confirmation before proceeding. **Inputs:** ``` - `userId` (string, optional) — The user's email address. Defaults to `me`, which refers to the authenticated user and is correct for almost every call — set this only if the token has delegated access to another mailbox. - `id` (string, required) — The ID of the draft to delete. ``` **Output `data` schema:** ```typescript {} ```
get_draft — Retrieve a draft Gets the specified draft. **Inputs:** ``` - `userId` (string, optional) — The user's email address. Defaults to `me`, which refers to the authenticated user and is correct for almost every call — set this only if the token has delegated access to another mailbox. - `id` (string, required) — The ID of the draft to retrieve. - `format` (string, optional) — The format to return the draft's message in: `minimal` (ID and labels only), `full` (full data, parsed into `payload`), `raw` (full data as a base64url string in `raw`; `payload` unused), `metadata` (ID, labels, and headers only). `full`/`raw` are unavailable when using the `gmail.metadata` scope. ``` **Output `data` schema:** ```typescript { id: string | null; message: object | null; } ```
list_drafts — List drafts in the mailbox Lists the drafts in the user's mailbox. **Inputs:** ``` - `userId` (string, optional) — The user's email address. Defaults to `me`, which refers to the authenticated user and is correct for almost every call — set this only if the token has delegated access to another mailbox. - `maxResults` (integer, optional) — Maximum number of drafts to return. Defaults to 100, maximum allowed is 500. - `pageToken` (string, optional) — Page token to retrieve a specific page of results. - `q` (string, optional) — Only return drafts matching this query, in Gmail search-box syntax, e.g. `"from:someuser@example.com rfc822msgid: is:unread"`. - `includeSpamTrash` (boolean, optional) — Include drafts from `SPAM` and `TRASH` in the results. ``` **Output `data` schema:** ```typescript { drafts: { id: string | null; message: object | null; }[] | null; nextPageToken: string | null; resultSizeEstimate: number | null; } ```
send_draft — Send an existing draft Sends the specified, existing draft to the recipients in the To, Cc, and Bcc headers. **Inputs:** ``` - `userId` (string, optional) — The user's email address. Defaults to `me`, which refers to the authenticated user and is correct for almost every call — set this only if the token has delegated access to another mailbox. - `id` (string, required) — The ID of the existing draft to send. - `message` (object, optional) — Optional — the draft's message content (object (Message)). ``` **Output `data` schema:** ```typescript {} ```
update_draft — Replace a draft's content NOTE: this tool first fetches the draft's current state, then replaces it — the response includes both the `before` and `after` state so you have a full record of what changed. Replaces a draft's content entirely; since this is a full overwrite, any fields not included in `message` are lost. **Inputs:** ``` - `userId` (string, optional) — The user's email address. Defaults to `me`, which refers to the authenticated user and is correct for almost every call — set this only if the token has delegated access to another mailbox. - `id` (string, required) — The ID of the draft to update. - `message` (object, optional) — The replacement message content of the draft (object (Message)); since this is a full replace, send this to give the draft its new content. ``` **Output `data` schema:** ```typescript { before: { id: string | null; message: object | null; }; after: { id: string | null; message: object | null; }; } ```
### Labels
create_label — Create a label Creates a label. **Inputs:** ``` - `userId` (string, optional) — The user's email address. Defaults to `me`, which refers to the authenticated user and is correct for almost every call — set this only if the token has delegated access to another mailbox. - `name` (string, required) — The display name of the label. - `messageListVisibility` (enum: show, hide, optional) — Visibility of messages with this label in the Gmail web message list. - `labelListVisibility` (enum: labelShow, labelShowIfUnread, labelHide, optional) — Visibility of the label itself in the Gmail web label list. - `type` (enum: system, user, optional) — Owner type. `system` labels are internally created by Gmail and cannot be added/modified/deleted. `user` labels are created by the user/app. - `color_text_color` (string, optional) — Text color hex string for the label, chosen from Gmail's fixed color palette. Only available for `type: user` labels; must be set together with `color_background_color`. - `color_background_color` (string, optional) — Background color hex string for the label, chosen from Gmail's fixed color palette. Only available for `type: user` labels; must be set together with `color_text_color`. ``` **Output `data` schema:** ```typescript { id: string | null; name: string | null; messageListVisibility: string | null; labelListVisibility: string | null; type: string | null; messagesTotal: number | null; messagesUnread: number | null; threadsTotal: number | null; threadsUnread: number | null; color: { textColor: string | null; backgroundColor: string | null; } | null; } ```
delete_label — Permanently delete a label (destructive) DESTRUCTIVE — REQUIRES EXPLICIT USER CONFIRMATION BEFORE CALLING. Immediately and permanently deletes the specified label and removes it from any messages and threads it's applied to. This action is irreversible — the label and its associations with messages and threads cannot be recovered. NEVER call this tool autonomously or as part of an automated flow. You MUST stop, tell the user exactly what will be deleted and that it is permanent, and wait for their explicit written confirmation before proceeding. **Inputs:** ``` - `userId` (string, optional) — The user's email address. Defaults to `me`, which refers to the authenticated user and is correct for almost every call — set this only if the token has delegated access to another mailbox. - `id` (string, required) — The ID of the label to delete. ``` **Output `data` schema:** ```typescript {} ```
get_label — Retrieve a label Gets the specified label. **Inputs:** ``` - `userId` (string, optional) — The user's email address. Defaults to `me`, which refers to the authenticated user and is correct for almost every call — set this only if the token has delegated access to another mailbox. - `id` (string, required) — The ID of the label to retrieve. ``` **Output `data` schema:** ```typescript { id: string | null; name: string | null; messageListVisibility: string | null; labelListVisibility: string | null; type: string | null; messagesTotal: number | null; messagesUnread: number | null; threadsTotal: number | null; threadsUnread: number | null; color: { textColor: string | null; backgroundColor: string | null; } | null; } ```
list_labels — List all labels Lists all labels in the user's mailbox. **Inputs:** ``` - `userId` (string, optional) — The user's email address. Defaults to `me`, which refers to the authenticated user and is correct for almost every call — set this only if the token has delegated access to another mailbox. ``` **Output `data` schema:** ```typescript { labels: { id: string | null; name: string | null; messageListVisibility: string | null; labelListVisibility: string | null; type: string | null; messagesTotal: number | null; messagesUnread: number | null; threadsTotal: number | null; threadsUnread: number | null; color: { textColor: string | null; backgroundColor: string | null; } | null; }[] | null; } ```
update_label — Partially update a label NOTE: this overwrites the current field values — the original state is not stored after the call. The response includes both the before and after state so you have a full record of what changed. Partially updates the specified label (only the fields provided are changed). **Inputs:** ``` - `userId` (string, optional) — The user's email address. Defaults to `me`, which refers to the authenticated user and is correct for almost every call — set this only if the token has delegated access to another mailbox. - `id` (string, required) — The ID of the label to update. - `name` (string, optional) — The display name of the label. - `messageListVisibility` (enum: show, hide, optional) — Visibility of messages with this label in the Gmail web message list. - `labelListVisibility` (enum: labelShow, labelShowIfUnread, labelHide, optional) — Visibility of the label itself in the Gmail web label list. - `type` (enum: system, user, optional) — System labels cannot actually be renamed/recolored even though the field is present. - `color_text_color` (string, optional) — Text color hex string, chosen from Gmail's fixed color palette; must be set together with `color_background_color`. Only applies to `type: user` labels. - `color_background_color` (string, optional) — Background color hex string, chosen from Gmail's fixed color palette; must be set together with `color_text_color`. Only applies to `type: user` labels. ``` **Output `data` schema:** ```typescript { before: { id: string | null; name: string | null; messageListVisibility: string | null; labelListVisibility: string | null; type: string | null; messagesTotal: number | null; messagesUnread: number | null; threadsTotal: number | null; threadsUnread: number | null; color: { textColor: string | null; backgroundColor: string | null; } | null; }; after: { id: string | null; name: string | null; messageListVisibility: string | null; labelListVisibility: string | null; type: string | null; messagesTotal: number | null; messagesUnread: number | null; threadsTotal: number | null; threadsUnread: number | null; color: { textColor: string | null; backgroundColor: string | null; } | null; }; } ```
### Messages
batch_delete_messages — Permanently delete many messages (destructive) DESTRUCTIVE — REQUIRES EXPLICIT USER CONFIRMATION BEFORE CALLING. Permanently deletes many messages by message ID in one call; provides no guarantee that a message was not already deleted or ever existed. This action is irreversible — deleted messages cannot be recovered. NEVER call this tool autonomously or as part of an automated flow. You MUST stop, tell the user exactly how many messages (and their IDs, if the list is short) will be deleted and that it is permanent, and wait for their explicit written confirmation before proceeding. **Inputs:** ``` - `userId` (string, optional) — The user's email address. Defaults to `me`, which refers to the authenticated user and is correct for almost every call — set this only if the token has delegated access to another mailbox. - `ids` (string[], required) — The IDs of the messages to delete. No guarantee is given that a message wasn't already deleted or ever existed — this is a fire-and-forget bulk permanent delete, irreversible. ``` **Output `data` schema:** ```typescript {} ```
batch_modify_messages — Add/remove labels on many messages (destructive) DESTRUCTIVE — REQUIRES EXPLICIT USER CONFIRMATION BEFORE CALLING. Adds or removes labels on the specified messages in a single bulk call. This action affects many messages at once and can change their visibility (e.g. removing INBOX or adding TRASH/SPAM) or accessibility. NEVER call this tool autonomously or as part of an automated flow. You MUST stop, tell the user exactly which messages and labels will be affected, and wait for their explicit written confirmation before proceeding. **Inputs:** ``` - `userId` (string, optional) — The user's email address. Defaults to `me`, which refers to the authenticated user and is correct for almost every call — set this only if the token has delegated access to another mailbox. - `ids` (string[], required) — The IDs of the messages to modify. Limit of 1000 IDs per request. - `addLabelIds` (string[], optional) — Label IDs to add to all specified messages. - `removeLabelIds` (string[], optional) — Label IDs to remove from all specified messages. - `addClassificationLabels` (object[], optional) — Classification Label values to add (Google Workspace only). Limit of 20 per message. - `removeClassificationLabelIds` (string[], optional) — Classification Label values to remove from the messages. ``` **Output `data` schema:** ```typescript {} ```
delete_message — Permanently delete a message (destructive) DESTRUCTIVE — REQUIRES EXPLICIT USER CONFIRMATION BEFORE CALLING. Immediately and permanently deletes the specified message; this cannot be undone (prefer trashing instead). NEVER call this tool autonomously or as part of an automated flow. You MUST stop, tell the user exactly what will be deleted and that it is permanent, and wait for their explicit written confirmation before proceeding. **Inputs:** ``` - `userId` (string, optional) — The user's email address. Defaults to `me`, which refers to the authenticated user and is correct for almost every call — set this only if the token has delegated access to another mailbox. - `id` (string, required) — The ID of the message to delete. ``` **Output `data` schema:** ```typescript {} ```
get_message_attachment — Retrieve a message attachment Gets the specified message attachment. **Inputs:** ``` - `userId` (string, optional) — The user's email address. Defaults to `me`, which refers to the authenticated user and is correct for almost every call — set this only if the token has delegated access to another mailbox. - `messageId` (string, required) — The ID of the message containing the attachment. - `id` (string, required) — The ID of the attachment (from the message's `payload` — see get_message). ``` **Output `data` schema:** ```typescript { attachmentId: string | null; size: number | null; data: string | null; } ```
get_message — Retrieve a message Gets the specified message. **Inputs:** ``` - `userId` (string, optional) — The user's email address. Defaults to `me`, which refers to the authenticated user and is correct for almost every call — set this only if the token has delegated access to another mailbox. - `id` (string, required) — The ID of the message to retrieve. Usually obtained from list_messages. - `format` (string, optional) — `minimal` (ID and labels only), `full` (default; full data parsed into `payload`, `raw` unused), `raw` (full data as base64url in `raw`, `payload` unused), `metadata` (ID, labels, and headers only). `full`/`raw` are unavailable when using the `gmail.metadata` scope. - `metadataHeaders` (string[], optional) — When `format=METADATA`, restricts the returned headers to only those named here. ``` **Output `data` schema:** ```typescript { id: string | null; threadId: string | null; labelIds: string[] | null; snippet: string | null; historyId: string | null; internalDate: string | null; payload: object | null; sizeEstimate: number | null; raw: string | null; classificationLabelValues: object[] | null; } ```
list_messages — List messages in the mailbox Lists the messages in the user's mailbox. **Inputs:** ``` - `userId` (string, optional) — The user's email address. Defaults to `me`, which refers to the authenticated user and is correct for almost every call — set this only if the token has delegated access to another mailbox. - `maxResults` (integer, optional) — Maximum number of messages to return. Defaults to 100, maximum allowed is 500. - `pageToken` (string, optional) — Page token to retrieve a specific page of results. - `q` (string, optional) — Only return messages matching this query, in Gmail search-box syntax. Cannot be used with the `gmail.metadata` scope. - `labelIds` (string[], optional) — Only return messages with labels matching all of the given label IDs. - `includeSpamTrash` (boolean, optional) — Include messages from `SPAM` and `TRASH` in the results. ``` **Output `data` schema:** ```typescript { messages: { id: string | null; threadId: string | null; labelIds: string[] | null; snippet: string | null; historyId: string | null; internalDate: string | null; payload: object | null; sizeEstimate: number | null; raw: string | null; classificationLabelValues: object[] | null; }[] | null; nextPageToken: string | null; resultSizeEstimate: number | null; } ```
modify_message — Add/remove labels on a message Updates the specified message's labels. Only the label additions/removals you provide are applied — everything else about the message keeps its current value. NOTE: this overwrites the current label state — the original state is not stored after the call. The response includes both the before and after state of the message so you have a full record of what changed. Adds or removes labels on the specified message. **Inputs:** ``` - `userId` (string, optional) — The user's email address. Defaults to `me`, which refers to the authenticated user and is correct for almost every call — set this only if the token has delegated access to another mailbox. - `id` (string, required) — The ID of the message to modify. - `addLabelIds` (string[], optional) — Label IDs to add to this message. Up to 100 per update. - `removeLabelIds` (string[], optional) — Label IDs to remove from this message. Up to 100 per update. - `addClassificationLabels` (object[], optional) — Classification Label values to add (Google Workspace only). - `removeClassificationLabelIds` (string[], optional) — Classification Label values to remove from the message. ``` **Output `data` schema:** ```typescript { before: { id: string | null; threadId: string | null; labelIds: string[] | null; snippet: string | null; historyId: string | null; internalDate: string | null; payload: object | null; sizeEstimate: number | null; raw: string | null; classificationLabelValues: object[] | null; }; after: { id: string | null; threadId: string | null; labelIds: string[] | null; snippet: string | null; historyId: string | null; internalDate: string | null; payload: object | null; sizeEstimate: number | null; raw: string | null; classificationLabelValues: object[] | null; }; } ```
send_message — Send a raw RFC 2822 message Sends the specified message to the recipients in the To, Cc, and Bcc headers. Requires a hand-built, base64url-encoded RFC 2822 `raw` blob — for a plain email or reply, use send_email or reply_to_message instead; reach for this tool only when you need something those can't express (attachments, custom headers, multipart bodies). **Inputs:** ``` - `userId` (string, optional) — The user's email address. Defaults to `me`, which refers to the authenticated user and is correct for almost every call — set this only if the token has delegated access to another mailbox. - `raw` (string, optional) — The entire RFC 2822 message (headers + body, with `To`/`Cc`/`Bcc`/`Subject` etc. as headers), base64url-encoded. Not explicitly marked required by the provider docs but practically necessary to send anything. ``` **Output `data` schema:** ```typescript { id: string | null; threadId: string | null; labelIds: string[] | null; snippet: string | null; historyId: string | null; internalDate: string | null; payload: object | null; sizeEstimate: number | null; raw: string | null; classificationLabelValues: object[] | null; } ```
send_email — Send a plain email from to/subject/body Sends a plain email from ordinary fields (to, subject, body) — builds the RFC 2822 message and base64url encoding internally, so you don't need to hand-construct or encode it yourself. For attachments, custom headers, or multipart bodies, use send_message with a hand-built `raw` instead. **Inputs:** ``` - `to` (string, required) — Comma-separated recipient email address(es) for the To header. - `subject` (string, required) — The email subject line. - `body` (string, required) — The email body text. - `userId` (string, optional) — The user's email address. Defaults to `me`, which refers to the authenticated user and is correct for almost every call — set this only if the token has delegated access to another mailbox. - `cc` (string, optional) — Comma-separated Cc recipient email address(es). - `bcc` (string, optional) — Comma-separated Bcc recipient email address(es). - `html` (boolean, optional) — If true, `body` is sent as HTML instead of plain text. ``` **Output `data` schema:** ```typescript { id: string | null; threadId: string | null; labelIds: string[] | null; snippet: string | null; historyId: string | null; internalDate: string | null; payload: object | null; sizeEstimate: number | null; raw: string | null; classificationLabelValues: object[] | null; } ```
reply_to_message — Reply to an existing message with plain text Replies to an existing message with plain body text — looks up the original message to set the Subject, recipient, and threading headers (In-Reply-To, References) automatically, and builds the RFC 2822/base64url encoding internally, so you don't need to hand-construct or encode it yourself. For attachments, custom headers, or multipart bodies, use send_message with a hand-built `raw` instead. **Inputs:** ``` - `message_id` (string, required) — The ID of the message to reply to. - `body` (string, required) — The reply body text. - `userId` (string, optional) — The user's email address. Defaults to `me`, which refers to the authenticated user and is correct for almost every call — set this only if the token has delegated access to another mailbox. - `cc` (string, optional) — Comma-separated Cc recipient email address(es). - `bcc` (string, optional) — Comma-separated Bcc recipient email address(es). - `html` (boolean, optional) — If true, `body` is sent as HTML instead of plain text. ``` **Output `data` schema:** ```typescript { id: string | null; threadId: string | null; labelIds: string[] | null; snippet: string | null; historyId: string | null; internalDate: string | null; payload: object | null; sizeEstimate: number | null; raw: string | null; classificationLabelValues: object[] | null; } ```
trash_message — Move a message to trash Moves the specified message to the trash. This changes the message's labels (typically adding TRASH and removing INBOX) — everything else about the message keeps its current value. NOTE: this overwrites the current label state — the original state is not stored after the call. The response includes both the before and after state of the message so you have a full record of what changed. **Inputs:** ``` - `userId` (string, optional) — The user's email address. Defaults to `me`, which refers to the authenticated user and is correct for almost every call — set this only if the token has delegated access to another mailbox. - `id` (string, required) — The ID of the message to trash. ``` **Output `data` schema:** ```typescript { before: { id: string | null; threadId: string | null; labelIds: string[] | null; snippet: string | null; historyId: string | null; internalDate: string | null; payload: object | null; sizeEstimate: number | null; raw: string | null; classificationLabelValues: object[] | null; }; after: { id: string | null; threadId: string | null; labelIds: string[] | null; snippet: string | null; historyId: string | null; internalDate: string | null; payload: object | null; sizeEstimate: number | null; raw: string | null; classificationLabelValues: object[] | null; }; } ```
untrash_message — Remove a message from trash Removes the specified message from the trash. This changes the message's labels (typically removing TRASH) — everything else about the message keeps its current value. NOTE: this overwrites the current label state — the original state is not stored after the call. The response includes both the before and after state of the message so you have a full record of what changed. **Inputs:** ``` - `userId` (string, optional) — The user's email address. Defaults to `me`, which refers to the authenticated user and is correct for almost every call — set this only if the token has delegated access to another mailbox. - `id` (string, required) — The ID of the message to remove from trash. ``` **Output `data` schema:** ```typescript { before: { id: string | null; threadId: string | null; labelIds: string[] | null; snippet: string | null; historyId: string | null; internalDate: string | null; payload: object | null; sizeEstimate: number | null; raw: string | null; classificationLabelValues: object[] | null; }; after: { id: string | null; threadId: string | null; labelIds: string[] | null; snippet: string | null; historyId: string | null; internalDate: string | null; payload: object | null; sizeEstimate: number | null; raw: string | null; classificationLabelValues: object[] | null; }; } ```
### Threads
delete_thread — Permanently delete a thread (destructive) DESTRUCTIVE — REQUIRES EXPLICIT USER CONFIRMATION BEFORE CALLING. Immediately and permanently deletes the specified thread and all its messages; cannot be undone (prefer trashing instead). NEVER call this tool autonomously or as part of an automated flow. You MUST stop, tell the user exactly what will be deleted and that it is permanent, and wait for their explicit written confirmation before proceeding. **Inputs:** ``` - `userId` (string, optional) — The user's email address. Defaults to `me`, which refers to the authenticated user and is correct for almost every call — set this only if the token has delegated access to another mailbox. - `id` (string, required) — The ID of the thread to delete. ``` **Output `data` schema:** ```typescript {} ```
get_thread — Retrieve a thread Gets the specified thread. **Inputs:** ``` - `userId` (string, optional) — The user's email address. Defaults to `me`, which refers to the authenticated user and is correct for almost every call — set this only if the token has delegated access to another mailbox. - `id` (string, required) — The ID of the thread to retrieve. - `format` (string, optional) — The format to return the thread's messages in: `full` (full email data, `payload` parsed; unavailable with the `gmail.metadata` scope), `metadata` (IDs, labels, and headers only), `minimal` (IDs and labels only). - `metadataHeaders` (string[], optional) — When `format=METADATA`, restricts the returned headers to only those named here. ``` **Output `data` schema:** ```typescript { id: string | null; snippet: string | null; historyId: string | null; messages: object[] | null; } ```
list_threads — List threads in the mailbox Lists the threads in the user's mailbox. **Inputs:** ``` - `userId` (string, optional) — The user's email address. Defaults to `me`, which refers to the authenticated user and is correct for almost every call — set this only if the token has delegated access to another mailbox. - `maxResults` (integer, optional) — Maximum number of threads to return. Defaults to 100, maximum allowed is 500. - `pageToken` (string, optional) — Page token to retrieve a specific page of results. - `q` (string, optional) — Only return threads matching this query, in Gmail search-box syntax. Cannot be used with the `gmail.metadata` scope. - `labelIds` (string[], optional) — Only return threads with labels matching all of the given label IDs. - `includeSpamTrash` (boolean, optional) — Include threads from `SPAM` and `TRASH` in the results. ``` **Output `data` schema:** ```typescript { threads: { id: string | null; snippet: string | null; historyId: string | null; messages: object[] | null; }[] | null; nextPageToken: string | null; resultSizeEstimate: number | null; } ```
modify_thread — Add/remove labels on a thread NOTE: this changes label state on the thread (all its messages) immediately — the original label state is not stored after the call, so the response includes both the `before` and `after` thread state for a full record of what changed. Adds or removes labels applied to the thread; this affects all messages in the thread. **Inputs:** ``` - `userId` (string, optional) — The user's email address. Defaults to `me`, which refers to the authenticated user and is correct for almost every call — set this only if the token has delegated access to another mailbox. - `id` (string, required) — The ID of the thread to modify. - `addLabelIds` (string[], optional) — Label IDs to add to this thread (all its messages). Up to 100 per update. - `removeLabelIds` (string[], optional) — Label IDs to remove from this thread (all its messages). Up to 100 per update. ``` **Output `data` schema:** ```typescript { before: { id: string | null; snippet: string | null; historyId: string | null; messages: object[] | null; }; after: { id: string | null; snippet: string | null; historyId: string | null; messages: object[] | null; }; } ```
trash_thread — Move a thread to trash NOTE: this moves the thread (all its messages) to trash immediately — the original, non-trashed state is not stored after the call, so the response includes both the `before` and `after` thread state for a full record of what changed. Moves the specified thread, and all its messages, to the trash. **Inputs:** ``` - `userId` (string, optional) — The user's email address. Defaults to `me`, which refers to the authenticated user and is correct for almost every call — set this only if the token has delegated access to another mailbox. - `id` (string, required) — The ID of the thread to trash. ``` **Output `data` schema:** ```typescript { before: { id: string | null; snippet: string | null; historyId: string | null; messages: object[] | null; }; after: { id: string | null; snippet: string | null; historyId: string | null; messages: object[] | null; }; } ```
untrash_thread — Remove a thread from trash NOTE: this removes the thread (all its messages) from trash immediately — the prior, trashed state is not stored after the call, so the response includes both the `before` and `after` thread state for a full record of what changed. Removes the specified thread, and all its messages, from the trash. **Inputs:** ``` - `userId` (string, optional) — The user's email address. Defaults to `me`, which refers to the authenticated user and is correct for almost every call — set this only if the token has delegated access to another mailbox. - `id` (string, required) — The ID of the thread to remove from trash. ``` **Output `data` schema:** ```typescript { before: { id: string | null; snippet: string | null; historyId: string | null; messages: object[] | null; }; after: { id: string | null; snippet: string | null; historyId: string | null; messages: object[] | null; }; } ```
### History
list_history — List mailbox change history for sync Lists the history of all changes to the mailbox in chronological order (increasing historyId), for syncing local client state with the server. **Inputs:** ``` - `userId` (string, optional) — The user's email address. Defaults to `me`, which refers to the authenticated user and is correct for almost every call — set this only if the token has delegated access to another mailbox. - `startHistoryId` (string, required) — Return history records after this `historyId` (obtained from a message's/thread's `historyId`, or a previous `list` response). History IDs increase chronologically but are not contiguous. An invalid or stale `startHistoryId` typically returns `HTTP 404` — perform a full sync if that happens. A `historyId` is usually valid for at least a week (sometimes only a few hours). No `nextPageToken` in the response means there are no updates; store the returned `historyId` for the next request. - `maxResults` (integer, optional) — Maximum number of history records to return. Defaults to 100, maximum allowed is 500. - `pageToken` (string, optional) — Page token to retrieve a specific page of results. - `labelId` (string, optional) — Only return messages with a label matching this ID. - `historyTypes` (string[], optional) — Restrict to these history record types. Enum values (`HistoryType`): `messageAdded`, `messageDeleted`, `labelAdded`, `labelRemoved`. ``` **Output `data` schema:** ```typescript { history: { id: string | null; messages: object[] | null; messagesAdded: object[] | null; messagesDeleted: object[] | null; labelsAdded: object[] | null; labelsRemoved: object[] | null; }[] | null; nextPageToken: string | null; historyId: string | null; } ```
### Settings
get_auto_forwarding_settings — Get the auto-forwarding setting Gets the auto-forwarding setting for the account. **Inputs:** ``` - `userId` (string, optional) — The user's email address. Defaults to `me`, which refers to the authenticated user and is correct for almost every call — set this only if the token has delegated access to another mailbox. ``` **Output `data` schema:** ```typescript { enabled: boolean | null; emailAddress: string | null; disposition: string | null; } ```
get_vacation_settings — Get the vacation responder settings Gets the vacation responder settings. **Inputs:** ``` - `userId` (string, optional) — The user's email address. Defaults to `me`, which refers to the authenticated user and is correct for almost every call — set this only if the token has delegated access to another mailbox. ``` **Output `data` schema:** ```typescript { enableAutoReply: boolean | null; responseSubject: string | null; responseBodyPlainText: string | null; responseBodyHtml: string | null; restrictToContacts: boolean | null; restrictToDomain: boolean | null; startTime: string | null; endTime: string | null; } ```
update_vacation_settings — Update the vacation responder settings Updates the vacation responder settings. This first fetches the current settings so the response can report what changed. Only the fields you provide are changed — others keep their current value. NOTE: this overwrites the current field values — the original state is not stored after the call. The response includes both the before and after state (top-level fields are the post-update state, `data.before` holds the pre-update state) so you have a full record of what changed. **Inputs:** ``` - `userId` (string, optional) — The user's email address. Defaults to `me`, which refers to the authenticated user and is correct for almost every call — set this only if the token has delegated access to another mailbox. - `enableAutoReply` (boolean, optional) — Whether Gmail automatically replies to messages. - `responseSubject` (string, optional) — Text prepended to the subject line in vacation responses. Either this or the response body must be nonempty to enable auto-replies. - `responseBodyPlainText` (string, optional) — Response body in plain text. If both plain-text and HTML bodies are set, HTML is used. - `responseBodyHtml` (string, optional) — Response body in HTML (Gmail sanitizes it before storing). Used over plain text when both are set. - `restrictToContacts` (boolean, optional) — Whether responses are limited to senders in the user's contacts. - `restrictToDomain` (boolean, optional) — Whether responses are limited to senders in the user's domain. Google Workspace only. - `startTime` (string, optional) — Optional start time for auto-replies (epoch ms). Replies only to messages received after this time. Must precede endTime if both are set. - `endTime` (string, optional) — Optional end time for auto-replies (epoch ms). Replies only to messages received before this time. Must follow startTime if both are set. ``` **Output `data` schema:** ```typescript { before: { enableAutoReply: boolean | null; responseSubject: string | null; responseBodyPlainText: string | null; responseBodyHtml: string | null; restrictToContacts: boolean | null; restrictToDomain: boolean | null; startTime: string | null; endTime: string | null; }; after: { enableAutoReply: boolean | null; responseSubject: string | null; responseBodyPlainText: string | null; responseBodyHtml: string | null; restrictToContacts: boolean | null; restrictToDomain: boolean | null; startTime: string | null; endTime: string | null; }; } ```
### Filters
create_filter — Create a mail filter Creates a mail filter (an account can have a maximum of 1,000 filters). **Inputs:** ``` - `userId` (string, optional) — The user's email address. Defaults to `me`, which refers to the authenticated user and is correct for almost every call — set this only if the token has delegated access to another mailbox. - `from` (string, optional) — Sender's display name or email address. Maps to the filter's `criteria.from`. - `to` (string, optional) — Recipient's display name or email address (matches To/Cc/Bcc). Maps to the filter's `criteria.to`. - `subject` (string, optional) — Case-insensitive phrase in the subject; whitespace trimmed/collapsed. Maps to the filter's `criteria.subject`. - `query` (string, optional) — Only match messages matching this query, in Gmail search-box syntax. Maps to the filter's `criteria.query`. - `negatedQuery` (string, optional) — Only match messages NOT matching this query, same syntax. Maps to the filter's `criteria.negatedQuery`. - `hasAttachment` (boolean, optional) — Whether the message has any attachment. Maps to the filter's `criteria.hasAttachment`. - `excludeChats` (boolean, optional) — Whether to exclude chats from the match. Maps to the filter's `criteria.excludeChats`. - `size` (integer, optional) — Size of the entire RFC822 message in bytes (headers + attachments), compared per `sizeComparison`. Maps to the filter's `criteria.size`. - `sizeComparison` (string, optional) — How `size` should relate to the actual message size. Enum values (`SizeComparison`): `unspecified`, `smaller`, `larger`. Maps to the filter's `criteria.sizeComparison`. - `addLabelIds` (string[], optional) — Labels to add to matching messages. Maps to the filter's `action.addLabelIds`. - `removeLabelIds` (string[], optional) — Labels to remove from matching messages. Maps to the filter's `action.removeLabelIds`. - `forward` (string, optional) — Email address to forward matching messages to, keeping the original sender in From. Maps to the filter's `action.forward`. ``` **Output `data` schema:** ```typescript { id: string | null; criteria: { from: string | null; to: string | null; subject: string | null; query: string | null; negatedQuery: string | null; hasAttachment: boolean | null; excludeChats: boolean | null; size: number | null; sizeComparison: string | null; } | null; action: { addLabelIds: string[] | null; removeLabelIds: string[] | null; forward: string | null; } | null; } ```
delete_filter — Permanently delete a filter (destructive) DESTRUCTIVE — REQUIRES EXPLICIT USER CONFIRMATION BEFORE CALLING. Immediately and permanently deletes the specified filter. This action is irreversible — the filter's criteria and actions cannot be recovered once deleted. NEVER call this tool autonomously or as part of an automated flow. You MUST stop, tell the user exactly what will be deleted and that it is permanent, and wait for their explicit written confirmation before proceeding. **Inputs:** ``` - `userId` (string, optional) — The user's email address. Defaults to `me`, which refers to the authenticated user and is correct for almost every call — set this only if the token has delegated access to another mailbox. - `id` (string, required) — The ID of the filter to delete. ``` **Output `data` schema:** ```typescript {} ```
get_filter — Retrieve a filter Gets the specified filter. **Inputs:** ``` - `userId` (string, optional) — The user's email address. Defaults to `me`, which refers to the authenticated user and is correct for almost every call — set this only if the token has delegated access to another mailbox. - `id` (string, required) — The ID of the filter to fetch. ``` **Output `data` schema:** ```typescript { id: string | null; criteria: { from: string | null; to: string | null; subject: string | null; query: string | null; negatedQuery: string | null; hasAttachment: boolean | null; excludeChats: boolean | null; size: number | null; sizeComparison: string | null; } | null; action: { addLabelIds: string[] | null; removeLabelIds: string[] | null; forward: string | null; } | null; } ```
list_filters — List mail filters Lists the message filters of the Gmail user. **Inputs:** ``` - `userId` (string, optional) — The user's email address. Defaults to `me`, which refers to the authenticated user and is correct for almost every call — set this only if the token has delegated access to another mailbox. ``` **Output `data` schema:** ```typescript { // Note: the Gmail API's list response field is named `filter` (singular), not `filters`. filter: { id: string | null; criteria: { from: string | null; to: string | null; subject: string | null; query: string | null; negatedQuery: string | null; hasAttachment: boolean | null; excludeChats: boolean | null; size: number | null; sizeComparison: string | null; } | null; action: { addLabelIds: string[] | null; removeLabelIds: string[] | null; forward: string | null; } | null; }[] | null; } ```
### Forwarding Addresses
get_forwarding_address — Retrieve a forwarding address Gets the specified forwarding address. **Inputs:** ``` - `userId` (string, optional) — The user's email address. Defaults to `me`, which refers to the authenticated user and is correct for almost every call — set this only if the token has delegated access to another mailbox. - `forwardingEmail` (string, required) — The forwarding address to retrieve. ``` **Output `data` schema:** ```typescript { forwardingEmail: string | null; verificationStatus: string | null; } ```
list_forwarding_addresses — List forwarding addresses Lists the forwarding addresses for the specified account. **Inputs:** ``` - `userId` (string, optional) — The user's email address. Defaults to `me`, which refers to the authenticated user and is correct for almost every call — set this only if the token has delegated access to another mailbox. ``` **Output `data` schema:** ```typescript { forwardingAddresses: { forwardingEmail: string | null; verificationStatus: string | null; }[] | null; } ```
### Send-As
get_send_as_alias — Retrieve a send-as alias Gets the specified send-as alias. **Inputs:** ``` - `userId` (string, optional) — The user's email address. Defaults to `me`, which refers to the authenticated user and is correct for almost every call — set this only if the token has delegated access to another mailbox. - `sendAsEmail` (string, required) — The send-as alias to retrieve. ``` **Output `data` schema:** ```typescript { sendAsEmail: string | null; displayName: string | null; replyToAddress: string | null; signature: string | null; isPrimary: boolean | null; isDefault: boolean | null; treatAsAlias: boolean | null; smtpMsa: { host: string | null; port: number | null; username: string | null; password: string | null; securityMode: string | null; } | null; verificationStatus: string | null; } ```
list_send_as_aliases — List send-as aliases Lists the send-as aliases for the account, including the primary address and any custom "from" aliases. **Inputs:** ``` - `userId` (string, optional) — The user's email address. Defaults to `me`, which refers to the authenticated user and is correct for almost every call — set this only if the token has delegated access to another mailbox. ``` **Output `data` schema:** ```typescript { sendAs: { sendAsEmail: string | null; displayName: string | null; replyToAddress: string | null; signature: string | null; isPrimary: boolean | null; isDefault: boolean | null; treatAsAlias: boolean | null; smtpMsa: { host: string | null; port: number | null; username: string | null; password: string | null; securityMode: string | null; } | null; verificationStatus: string | null; }[] | null; } ```
update_send_as_alias — Partially update a send-as alias NOTE: this tool first fetches the alias's current state, then applies your changes — the response includes both the `before` and `after` state so you have a full record of what changed. Only the fields you provide are changed — others keep their current value. Partially updates the specified send-as alias. **Inputs:** ``` - `userId` (string, optional) — The user's email address. Defaults to `me`, which refers to the authenticated user and is correct for almost every call — set this only if the token has delegated access to another mailbox. - `sendAsEmail` (string, required) — The send-as alias to update. - `displayName` (string, optional) — Name shown in the From: header. - `replyToAddress` (string, optional) — Optional Reply-To: address. Empty means no Reply-To: header is generated. - `signature` (string, optional) — Optional HTML signature added to new messages composed with this alias in the Gmail web UI. - `isDefault` (boolean, optional) — Whether this is the default From: address for new messages/vacation replies. - `treatAsAlias` (boolean, optional) — Whether Gmail should treat this address as an alias of the primary address. Custom "from" aliases only. - `smtpMsa` (object, optional) — Optional outbound SMTP relay for mail sent with this alias (object (SmtpMsa)); custom aliases only. Keys: `host` (string, SMTP service hostname), `port` (integer, SMTP service port), `username` (string, write-only), `password` (string, write-only), `securityMode` (enum: `securityModeUnspecified`, `none`, `ssl`, `starttls`). ``` **Output `data` schema:** ```typescript { before: { sendAsEmail: string | null; displayName: string | null; replyToAddress: string | null; signature: string | null; isPrimary: boolean | null; isDefault: boolean | null; treatAsAlias: boolean | null; smtpMsa: { host: string | null; port: number | null; username: string | null; password: string | null; securityMode: string | null; } | null; verificationStatus: string | null; }; after: { sendAsEmail: string | null; displayName: string | null; replyToAddress: string | null; signature: string | null; isPrimary: boolean | null; isDefault: boolean | null; treatAsAlias: boolean | null; smtpMsa: { host: string | null; port: number | null; username: string | null; password: string | null; securityMode: string | null; } | null; verificationStatus: string | null; }; } ```
## API Parameters Reference
Response Envelope Every tool returns the same top-level envelope. Only `data` varies per tool. ```json // Success { "success": true, "statusCode": 200, "retriable": false, "retry_after_seconds": null, "error": null, "data": { ... } } // Error { "success": false, "statusCode": 400, "retriable": false, "retry_after_seconds": null, "error": { "code": "VALIDATION_ERROR", "message": "userId is required", "details": null }, "data": null } ``` - `retriable` — `true` when it is safe to retry (rate limit, network error, 503). `false` for validation and auth errors. - `retry_after_seconds` — seconds to wait before retrying; present only when `retriable` is `true` and the upstream specifies a delay. - `error.code` — machine-readable string: `VALIDATION_ERROR`, `AUTH_ERROR`, `UPSTREAM_ERROR`, `SERVER_ERROR`.
Common Parameters - `userId` — The user's email address. The special value `me` can be used to indicate the authenticated user. Required on nearly every tool. - `maxResults` — Maximum number of items to return on list-type tools (drafts, messages, threads, history). Defaults to 100, maximum allowed is 500. - `pageToken` — Page token to retrieve a specific page of results, taken from a previous list-type tool's `nextPageToken`. - `q` — Search-box query syntax (as used in the Gmail web UI) for filtering drafts, messages, and threads. Unavailable when only the `gmail.metadata` scope is granted. - `includeSpamTrash` — Include items from `SPAM` and `TRASH` in list results (drafts, messages, threads).
Resource Formats **User ID:** ``` me | {email address} Example: me ``` **Resource IDs (message, thread, draft, label, filter):** ``` Opaque, API-assigned string Example: 18abc2f3e4d5f678 ``` **History ID:** ``` Numeric string, increases chronologically but not contiguously Example: 1234567 ```
## Troubleshooting
Missing or Invalid Headers - **Cause:** API key not provided in request headers or incorrect format - **Solution:** 1. Verify `Authorization: Bearer YOUR_API_KEY` and `X-Mewcp-Credential-Id: CREDENTIAL-ID` headers are present 2. Check API key is active in your MewCP account
Insufficient Credits - **Cause:** API calls have exceeded your request limits - **Solution:** 1. Check credit usage in your Curious Layer dashboard 2. Upgrade to a paid plan or add credits for higher limits 3. Contact support for credit adjustments
Credential Not Connected - **Cause:** No Gmail credential linked to your account - **Solution:** 1. Go to **Credentials** in your MewCP dashboard 2. Connect your Gmail account (OAuth) 3. Retry the request with the correct `X-Mewcp-Credential-Id` header
Malformed Request Payload - **Cause:** JSON payload is invalid or missing required fields - **Solution:** 1. Validate JSON syntax before sending 2. Ensure all required tool parameters are included 3. Check parameter types match expected values
Server Not Found - **Cause:** Incorrect server name in the API endpoint - **Solution:** 1. Verify endpoint format: `mewcp-gmail/mcp/{tool-name}` 2. Use correct server name from documentation 3. Check available servers in your Curious Layer account
Gmail API Error - **Cause:** Upstream Gmail API returned an error - **Solution:** 1. Check Gmail/Google Workspace service status at [Google Workspace Status Dashboard](https://www.google.com/appsstatus/dashboard/) 2. Verify your credential has the required scopes (see `SCOPES` in `gmail_mcp/config.py`) 3. Review the error message for specific details
---
Resources - **[Gmail API Documentation](https://developers.google.com/gmail/api/guides)** — Official API reference - **[Gmail API Reference](https://developers.google.com/gmail/api/reference/rest)** — Complete endpoint reference - **[FastMCP Docs](https://gofastmcp.com/v2/getting-started/welcome)** — FastMCP specification - **[FastMCP Credentials](https://pypi.org/project/fastmcp-credentials/)** — FastMCP Credentials package for credential handling
--- ## Connection snippets ### Python (fastmcp) ```python import asyncio from fastmcp import Client from fastmcp.client.transports import StreamableHttpTransport SERVER_URL = "https://gateway.mewcp.com/google-gmail/mcp" MEWCP_KEY = "YOUR_MEWCP_KEY" CREDENTIAL_ID = "YOUR_CREDENTIAL_ID" transport = StreamableHttpTransport( url=SERVER_URL, headers={ "Authorization": f"Bearer {MEWCP_KEY}", "x-mewcp-credential-id": CREDENTIAL_ID, } ) async def main(): client = Client(transport) async with client: await client.ping() tools = await client.list_tools() resources = await client.list_resources() prompts = await client.list_prompts() # Change the tool name and arguments with actual tool and arguments available in server result = await client.call_tool("example_tool", {"param": "value"}) print(result) asyncio.run(main()) ``` ### TypeScript (MCP SDK) ```typescript import { Client } from "@modelcontextprotocol/sdk/client/index.js"; import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"; const SERVER_URL = "https://gateway.mewcp.com/google-gmail/mcp"; const MEWCP_KEY = "YOUR_MEWCP_KEY"; const CREDENTIAL_ID = "YOUR_CREDENTIAL_ID"; const transport = new StreamableHTTPClientTransport(new URL(SERVER_URL), { requestInit: { headers: { Authorization: `Bearer ${MEWCP_KEY}`, "x-mewcp-credential-id": CREDENTIAL_ID, }, }, }); const client = new Client({ name: "mewcp-client", version: "1.0.0", }); await client.connect(transport); const tools = await client.listTools(); console.log("Available tools:", tools.tools.map(t => t.name)); // Change the tool name and arguments to a tool available on your server const result = await client.callTool({ name: "example_tool", arguments: { param: "value" }, }); console.log("Tool result:", result); ``` ### VS Code (settings.json) ```json { "servers": { "mewcp-google-gmail": { "type": "http", "url": "https://gateway.mewcp.com/google-gmail/mcp", "headers": { "Authorization": "Bearer YOUR_MEWCP_KEY", "x-mewcp-credential-id": "YOUR_CREDENTIAL_ID" } } } } ``` ### Cursor (mcp.json) ```json { "mcpServers": { "google-gmail": { "url": "https://gateway.mewcp.com/google-gmail/mcp", "headers": { "Authorization": "Bearer YOUR_MEWCP_KEY", "x-mewcp-credential-id": "YOUR_CREDENTIAL_ID" } } } } ``` ### Claude Desktop (claude_desktop_config.json) ```json "mcpServers": { "google-gmail": { "command": "npx", "args": [ "-y", "mcp-remote@latest", "https://gateway.mewcp.com/google-gmail/mcp", "--transport", "http-only", "--header", "Authorization: Bearer YOUR_MEWCP_KEY", "--header", "x-mewcp-credential-id: YOUR_CREDENTIAL_ID" ] } } ```