
Download an attachment from a message by attachment ID. Returns readable extractedtext for PDF, DOCX, and text files (use this to read the contents, e.g. a resume), plus the raw base64url data, filename, MIME type, and size. Check extractionstatus for the outcome. Set returndownloadurl=true for a download URL instead of the content (no extracted_text), for binary or large attachments.
List draft messages, newest first, with pagination. Pass q to filter server-side with Gmail search syntax (e.g. 'subject:invoice'), and includespamtrash=true to also search spam and trash. Each result includes draft/message/thread IDs plus to, cc, subject, and snippet inline; set includemetadata=false for bare IDs. Use getdraft only when the full body or attachments are needed.
Retrieve complete details of a specific draft by ID including message content, headers, recipients, and metadata.
Create a draft with recipients, subject, and body. Supports HTML, CC/BCC, threading, inline attachments, and ONE large staged file via filereference plus filereferencefilename (files up to about 15 MB). Returns identifiers only -- subject, recipients and body are not echoed back; use getdraft to read it back. For fromaddress, call listsendasaddresses first.
Edit an existing draft. Only the fields you supply change; everything else (recipients, subject, body, attachments, thread) is preserved. Pass an empty list to clear recipients or attachments. The draft ID is stable but the underlying message ID changes on every update. Use listdrafts for draft IDs and listsendasaddresses for a valid from_address.
Permanently delete a draft. Cannot be undone. Draft and content are permanently removed.
Send an existing draft immediately. Draft is sent as email and automatically deleted from drafts. Returns sent message with ID.
Forward an email to new recipients and send it immediately. Keeps the original body, attachments and inline images, adds your comment on top, and stays in the original thread. Find messageid with listmessages. To review before sending, use createforwarddraft then send_draft.
Create a forward of an email as a draft without sending it. Keeps the original body, attachments and inline images, adds your comment on top, and stays in the original thread. Find messageid with listmessages. Returns the draft ID: send it with senddraft, edit with updatedraft, or discard with delete_draft.
List all labels, both system and custom. Returns id, name, type and visibility only. Use get_label for a single label's message and thread totals, which this endpoint does not return.
Retrieve detailed information about a specific label by ID including name, type, visibility, message counts, and colors.
Create a custom label. Nest it by putting slashes in the name, e.g. 'Clients/Acme' creates Acme under Clients. Visibility defaults to shown. Colors must come from Gmail's fixed palette. Returns the new label with its ID.
Update an existing label's properties including name, visibility, and colors. Cannot modify system labels, only custom labels.
Permanently delete a custom label. Removes label from all messages. Cannot delete system labels. Cannot be undone.
Read one email's body as plain text, with From/To/Subject/Date, Message-ID, labels, and an attachment list. Use this to read, summarize, or quote an email, and to get the Message-ID and threadid needed to reply via sendmessage. Far smaller than getmessage. Lossy: drops MIME structure and styling. Use getmessage for the raw tree or an uncommon header.
Search or list messages with Gmail query syntax (from:, subject:, is:unread, newerthan:, OR, -negation) and pagination. Results carry sender, to, cc, subject, date, snippet, labels, and Message-ID inline, so triage and replies need no follow-up call. An empty list with searchscope.complete means no such message exists; empty searches retry across spam/trash. Read bodies with getmessagetext.
Retrieve complete message details by ID including the raw MIME tree, all headers, base64-encoded body parts, attachments, and labels. Format options control detail level. To just read or summarize the body, use getmessagetext instead: it returns decoded text and is far smaller.
Send a new email with recipients, subject, and body. Supports HTML, CC/BCC, attachments, and threading. Returns sent message with ID and thread ID. To reply, pass threadid and use messageidheader from listmessages as inreplyto. To set fromaddress, first call listsendasaddresses: Gmail rewrites From: to the default address if the alias is not verified.
Add or remove labels from a message. Supports up to 100 label additions/removals per operation. Use system labels (INBOX, STARRED, IMPORTANT, UNREAD, TRASH) or custom label IDs from list_labels, which is the only way to resolve a label name to the per-account ID this takes.
Move a message to trash by adding the TRASH label. Gmail also removes INBOX, so the message leaves the inbox listing; SENT and custom labels stay, and untrash does not put INBOX back. Not a permanent delete: use untrashmessage to restore it, or find trashed mail with listmessages and q='in:trash'.
Restore a message from trash by removing the TRASH label. Its other labels are untouched, so it returns to the folders it was in. Use list_messages with q='in:trash' to find trashed message IDs. Safe to repeat: a message already out of trash is unchanged.
Move multiple messages to trash in one batch by adding the TRASH label to each. Other labels are left in place. Not a permanent delete: restore them one at a time with untrashmessage. Use listmessages to find message IDs.
Modify labels on multiple messages in one batch. Supports up to 100 label additions/removals. More efficient than modifying each message. Use system labels or custom label IDs from list_labels, which is the only way to resolve a label name to the per-account ID this takes.
Get the authenticated mailbox's own address plus its total message and thread counts. Use this to answer 'what account am I' or 'how big is this mailbox'. For the aliases this mailbox can send from, use listsendasaddresses instead. Also returns historyid, the marker for the mailbox's current state.
List the addresses this mailbox can send mail as, including aliases and delegated addresses. Call this before setting fromaddress on sendmessage, createdraft, or updatedraft: Gmail silently rewrites From: to the default address if the value is not a verified alias. Check verification_status is 'accepted'.
Search or list conversation threads with Gmail query syntax and pagination. Each result includes subject, latest sender/date, snippet, aggregated labels, and message count inline, so most triage needs no follow-up call. searchscope.complete with an empty list is a definitive 'no such conversation'; an empty search is retried once across spam and trash. Use getthread for the full messages.
Retrieve a complete conversation thread by ID including all messages in chronological order. Format options control detail level.
Add or remove labels from every message in a thread at once. Supports up to 100 label additions/removals. More efficient than modifying each message. Use system labels or custom label IDs from list_labels, which is the only way to resolve a label name to the per-account ID this takes.
Move every message in a thread to trash by adding the TRASH label. Other labels are left in place. Not a permanent delete: use untrashthread to restore the whole conversation. Use listthreads to find thread IDs.
Restore an entire conversation from trash by removing the TRASH label from its messages. Their other labels are untouched. Use list_threads with q='in:trash' to find trashed thread IDs. Safe to repeat: a thread already out of trash is unchanged.
Validate Gmail credentials. Verifies credentials during setup.

In an mcp.json file, add the configuration below, and restart Cursor.
Learn more in the official documentation ↗
1{
2 "mcpServers": {
3 "agent-handler": {
4 "url": "https://ah-api-develop.merge.dev/api/v1/tool-packs/{TOOL_PACK_ID}/registered-users/{REGISTERED_USER_ID}/mcp",
5 "headers": {
6 "Authorization": "Bearer yMt*****"
7 }
8 }
9 }
10}
11Open your Claude Desktop configuration file and add the server configuration below. You'll also need to restart the application for the changes to take effect.
Make sure Claude is using the Node v20+.
Learn more in the official documentation ↗
1{
2 "mcpServers": {
3 "agent-handler": {
4 "command": "npx",
5 "args": [
6 "-y",
7 "mcp-remote@latest",
8 "https://ah-api-develop.merge.dev/api/v1/tool-packs/{TOOL_PACK_ID}/registered-users/{REGISTERED_USER_ID}/mcp",
9 "--header",
10 "Authorization: Bearer ${AUTH_TOKEN}"
11 ],
12 "env": {
13 "AUTH_TOKEN": "yMt*****"
14 }
15 }
16 }
17}Open your Windsurf MCP configuration file and add the server configuration below.
Click on the refresh button in the top right of the Manage MCP server page or in the top right of the chat box in the box icon.
Learn more in the official documentation ↗
1{
2 "mcpServers": {
3 "agent-handler": {
4 "command": "npx",
5 "args": [
6 "-y",
7 "mcp-remote@latest",
8 "https://ah-api.merge.dev/api/v1/tool-packs/<tool-pack-id>/registered-users/<registered-user-id>/mcp",
9 "--header",
10 "Authorization: Bearer ${AUTH_TOKEN}"
11 ],
12 "env": {
13 "AUTH_TOKEN": "<ah-production-access-key>"
14 }
15 }
16 }
17 }In Command Palette (Cmd+Shift+P on macOS, Ctrl+Shift+P on Windows), run "MCP: Open User Configuration".
You can then add the configuration below and press "start" right under servers. Enter the auth token when prompted.
Learn more in the official documentation ↗
1{
2 "inputs": [
3 {
4 "type": "promptString",
5 "id": "agent-handler-auth",
6 "description": "Agent Handler AUTH_TOKEN", // "yMt*****" when prompt
7 "password": true
8 }
9 ],
10 "servers": {
11 "agent-handler": {
12 "type": "stdio",
13 "command": "npx",
14 "args": [
15 "-y",
16 "mcp-remote@latest",
17 "https://ah-api-develop.merge.dev/api/v1/tool-packs/{TOOL_PACK_ID}/registered-users/{REGISTERED_USER_ID}/mcp",
18 "--header",
19 "Authorization: Bearer ${input:agent-handler-auth}"
20 ]
21 }
22 }
23}The use cases naturally vary depending on your agent, but here are a few agentic workflows from using this email MCP server:
Here are some popular tools across data categories:
Here are just a few advantages of using Merge Agent Handler’s Gmail MCP server:
You can take the following steps:
1. Navigate to Tool Packs in the Agent Handler dashboard sidebar.
2. Create a new Tool Pack by clicking "Add New" or select an existing Tool Pack you want to modify.
3. Add the Gmail connector from the available connectors list. You can also choose the specific tools you want to enable.
4. Configure your agent’s authentication method by either selecting individual authentication (each user would provide their own Gmail credentials) or shared authentication: (organization-level access by using a single set of credentials)
5. Save your Tool Pack. From there, the Gmail tools are now available for your agents to use within the Tool Pack!
Yes, you can add any number of security rules in a matter of clicks in Merge Agent Handler.
For example, you can:
Yes, Agent Handler for Employees lets your employees connect Claude, ChatGPT, Microsoft Copilot, Cursor, and other MCP-compatible AI tools to Gmail without bypassing IT governance.
Instead of setting up direct connections with personal credentials that IT can't monitor or revoke, each employee authenticates through Agent Handler and gets individual credentials tied to their identity.
IT also provisions access by role or group via SCIM. A sales rep, for example, gets Gmail to manage outreach, Salesforce to track deals, and Google Calendar to schedule meetings; while a CS manager gets Gmail to handle account communications, Zendesk to track support tickets, and Salesforce to log account notes.
Every tool call an employee's AI makes to Gmail is also inspected against your DLP rules and logged to a searchable audit trail, giving security teams full visibility into what data was accessed and by whom.
Whether you're an engineer experimenting with agents or a product manager looking to add tools, you can get started for free now