support-inbox-mcp
Provides tools for working with Gmail threads and messages (list and get threads, modify threads, create drafts, send messages), enabling support inbox workflows such as turning bug reports into tracked issues, drafting customer replies, and responding in the original thread.
Provides tools for Google Calendar, used to book customer calls such as churn save calls, onboarding kickoffs and escalation calls.
Provides tools for creating Google Docs documents, used to generate QBR account briefs and other written deliverables.
Provides tools for accessing Google Drive files, used to share onboarding plan docs and to answer internal questions from stored documentation.
Provides tools for reading Google Forms responses, used to pick up NPS survey scores and follow up with detractors.
Provides tools for writing to Google Sheets, used to build an account health sheet of billing status and open bugs per account.
Provides tools for Linear's API, including searching and listing issues, creating and updating issues, listing attachments, and managing customer needs, so agents can file and track bugs and requests.
Provides tools for Notion, allowing agents to read wiki pages for internal Q&A and to create draft help-center articles for recurring questions.
Provides tools for reading and posting in Slack channels with a bot token, used to track requests and bugs from shared customer channels and to post internal answers and escalations.
Provides tools for Stripe billing data: retrieving customers, listing invoices, subscriptions and charges, and creating refunds, supporting refund handling, churn detection and account health workflows.
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., "@support-inbox-mcp turn unread support emails into Linear bugs and draft replies"
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.
Support Inbox to Linear
Support email becomes Linear bugs, refunds get handled, and fixed bugs get a reply in-thread.
An MCP server with 12 workflows across Gmail, Linear, Stripe, Granola, Google Docs, Slack, Google Calendar, Google Drive, Google Forms, Notion and Google Sheets. Each workflow is a prompt your agent runs as a slash command, over the 30 tools it needs and no others.
uv tool install https://github.com/r28ai/support-inbox-mcp/releases/download/v0.1.0/support_inbox_mcp-0.1.0-py3-none-any.whl
claude mcp add support -- support-inbox-mcpIt installs with uv from this repository's release, with no git and nothing to build; nothing but Charter and the libraries it uses comes from PyPI. To update, run the install line from the latest release. If a desktop app cannot find support-inbox-mcp, give it the full path from which support-inbox-mcp (where support-inbox-mcp on Windows).
Then ask your agent to connect your apps, or run /mcp__support__setup.
Connect your apps
Ask the agent to connect one ("connect Linear"). It tells you where to get that app's key and the command that stores it, and the next call works, with no restart. The agent never asks for a key in the chat.
Or connect everything this server uses from a terminal:
support-inbox-mcp login # each app in turn
support-inbox-mcp login linear # just one
support-inbox-mcp status # what is connectedTokens and keys go to your operating system's keychain (macOS Keychain, Windows Credential Manager, the Secret Service on Linux), and are checked with one read-only call to the app's own API before they are kept. Every key, token and OAuth client is yours: we register no app with any of these services, and nothing passes through a server of ours, because there isn't one.
App | How it connects | Or set |
Browser sign-in, over your own OAuth client (make one). |
| |
Linear | Your own key (get one), entered once. |
|
Stripe | Your own key (get one), entered once. |
|
Granola | Your own key (get one), entered once. In the Granola app: Settings → Connectors → API keys. Business plan or above. |
|
Slack | Your own key (get one), entered once. A bot token from your own Slack app, which the guide sets up in about three minutes. |
|
Notion | Your own key (get one), entered once. Then share the pages it should see with the integration. |
|
A variable set in your client's config always wins over the keychain.
Related MCP server: Email Triage MCP
Workflows
Workflow | What you get | Apps |
Support email → Linear bug with a reply drafted | Bug reports leave the inbox as issues, and the customer gets a real acknowledgement. | Gmail, Linear |
Fixed → reply in the original thread | Customers who reported a bug hear it's fixed in the same email thread. | Linear, Gmail |
QBR account brief | Spend, payment issues, open requests and last calls, on one page before the QBR. | Stripe, Linear, Granola, Google Docs |
Churn signal → save call | A cancellation at period end triggers a call while there is still time. | Stripe, Granola, Slack, Google Calendar |
New customer onboarding kickoff | Plan doc shared, kickoff booked and welcome sent on day one. | Stripe, Google Drive, Google Calendar, Gmail |
Customer Slack channel → requests and bugs | Asks in shared channels get tracked and answered with a link. | Slack, Linear |
Refund request handled end to end | The charge is found, the refund issued and the reply drafted, with a human approving the refund. | Gmail, Stripe |
NPS detractor follow-up | Low scores from paying accounts get a personal reply and their complaint tracked. | Google Forms, Stripe, Gmail, Linear |
Help-center gap finder | Questions asked three times with no article get a draft article. | Gmail, Notion |
Escalation runbook | Priority raised, call booked, customer told: one command instead of four tabs. | Slack, Linear, Google Calendar, Gmail |
Internal Q&A from the docs | Questions in #ask get answered in-thread from the wiki and Drive, with links. | Slack, Notion, Google Drive |
Account health sheet | Billing state and open bugs per account in one sheet the CS team sorts by. | Stripe, Linear, Google Sheets |
Every prompt takes one optional argument, details: the repo, team, channel, customer or date range you mean, so the agent does not have to ask. In Claude Code, put it in quotes, or only its first word arrives:
/mcp__support__support_email_to_linear_bug_with_a_reply_drafted "the support@ inbox, Linear team SUP"Reads run without asking. Before anything that creates, sends, changes or deletes, the prompt tells the agent to show you the call and wait.
1 of the 12 workflows need no Google or Granola credential.
Other clients
Claude Desktop: install uv if you have not, since Claude Desktop starts the server with it, then open the .mcpb from the latest release. Claude asks for any keys in its own settings and keeps them in your keychain. The first start takes a few seconds longer, while uv installs it.
VS Code (.vscode/mcp.json): VS Code asks for each key the first time the server starts and stores it securely. Leave out any you stored with login.
{
"inputs": [
{
"type": "promptString",
"id": "google-client-secret",
"description": "Google: OAuth client secret",
"password": true
},
{
"type": "promptString",
"id": "linear-api-key",
"description": "Linear: Personal API key",
"password": true
},
{
"type": "promptString",
"id": "stripe-api-key",
"description": "Stripe: Secret or restricted key",
"password": true
},
{
"type": "promptString",
"id": "granola-api-key",
"description": "Granola: API key",
"password": true
},
{
"type": "promptString",
"id": "slack-bot-token",
"description": "Slack: Bot token (xoxb-\u2026)",
"password": true
},
{
"type": "promptString",
"id": "notion-api-key",
"description": "Notion: Integration secret (ntn_\u2026)",
"password": true
}
],
"servers": {
"support": {
"type": "stdio",
"command": "support-inbox-mcp",
"env": {
"GOOGLE_CLIENT_SECRET": "${input:google-client-secret}",
"LINEAR_API_KEY": "${input:linear-api-key}",
"STRIPE_API_KEY": "${input:stripe-api-key}",
"GRANOLA_API_KEY": "${input:granola-api-key}",
"SLACK_BOT_TOKEN": "${input:slack-bot-token}",
"NOTION_API_KEY": "${input:notion-api-key}",
"GOOGLE_CLIENT_ID": ""
}
}
}
}Cursor (.cursor/mcp.json) starts it the same way:
{
"mcpServers": {
"support": {
"command": "support-inbox-mcp"
}
}
}Codex (~/.codex/config.toml) starts a turn without waiting for a server unless it is required, and then the agent has none of its tools. required = true makes the session wait for it, and startup_readiness = "catalog" waits for its tool list rather than just its connection:
[mcp_servers.support]
command = "support-inbox-mcp"
required = true
startup_readiness = "catalog"
startup_timeout_sec = 30Name the server support. A host builds each tool's name from that key, and a longer one can push a tool past the 64 characters a function name allows.
Built with Charter
Every tool here is a Charter declaration: a Pydantic schema saying where each field goes on the wire. Charter's runtime builds the request, attaches and refreshes the credential, and trims the response before the model reads it. It runs in your process, with no proxy and no telemetry.
The 30 tool schemas come to 50,308 tokens.
The same tools work in your own agent, without MCP:
from charter.adapters.openai import to_openai_tools
from charter_packs_mcp import FAMILIES
tools = FAMILIES["support"].tools()
definitions = to_openai_tools(tools) # or charter.adapters.langchainNeed an API that isn't here? Write a pack: your coding agent writes the declarations, and Charter's conformance suite checks them.
Gmail:
gmail_threads_list,gmail_threads_get,gmail_drafts_create,gmail_threads_modify,gmail_messages_sendLinear:
linear_search_issues,linear_issue_create,linear_issues_list,linear_attachments_list,linear_customer_needs_list,linear_customer_need_create,linear_issue_updateStripe:
stripe_customers_retrieve,stripe_invoices_list,stripe_subscriptions_list,stripe_customers_list,stripe_charges_list,stripe_refunds_createGranola:
granola_notes_listGoogle Docs:
gdocs_documents_createSlack:
slack_chat_post_message,slack_conversations_historyGoogle Calendar:
gcalendar_events_insertGoogle Drive:
gdrive_files_copy,gdrive_permissions_create,gdrive_files_listGoogle Forms:
gforms_forms_responses_listNotion:
notion_search,notion_pages_createGoogle Sheets:
gsheets_spreadsheets_values_update
License
Apache 2.0.
Available Tools
32 toolsconnectA
Connect one app this server uses. For an app that issues keys, says where to get one and the terminal command that stores it. For Google, once the user's own OAuth client is set, starts the browser sign-in and returns at once: the user approves in the browser and the next call works. To see which apps are connected, call connection_status. Never ask the user for a key in the chat.
Inputs: app (required).
connection_statusARead-only
See which apps this server is connected to, and how to connect each one that is not. Changes nothing.
Inputs: no named parameters.
gcalendar_events_insertC
Create a calendar event; returns details of the event.
Inputs: event (required), calendarId (required), sendUpdates, maxAttendees, +3 more.
gdocs_documents_createA
Create a blank document with a title. Only the title is honoured — the document is created empty. To add content, call this and then documents_batch_update with the returned documentId.
Inputs: body.
gdrive_files_copyA
Create a copy of a file and apply any requested updates with patch semantics. Typically send a new name and optionally parents.
Inputs: file (required), fileId (required), ocrLanguage, copyComments, +5 more.
gdrive_files_listARead-onlyIdempotent
List the user's files. Returns all files by default, including trashed files; add trashed = false to q to hide them. q is Drive's search grammar — name contains 'Q3' and mimeType = 'application/vnd.google-apps.folder'.
Inputs: q, spaces, corpora, driveId, +7 more.
gdrive_permissions_createA
Create a permission for a file or shared drive. type is user, group, domain or anyone; role is owner, organizer, fileOrganizer, writer, commenter or reader. For user or group, send emailAddress. Concurrent permission writes on the same file are not supported.
Inputs: fileId (required), permission (required), emailMessage, supportsAllDrives, +4 more.
gforms_forms_responses_listARead-onlyIdempotent
List a form's submitted responses, newest page first, up to 5000 per page. The only supported filter is on submission time: pass filter='timestamp >= 2026-01-01T00:00:00Z' to read what has arrived since a point in time. Answers come back keyed by questionId.
Inputs: formId (required), filter, pageSize, pageToken.
gmail_drafts_createC
Save an email draft to Gmail.
Inputs: body (required), userId.
gmail_messages_sendC
Send an email via the Gmail API.
Inputs: body (required), userId.
gmail_threads_getCRead-onlyIdempotent
Read a Gmail thread.
Inputs: id (required), format, userId, metadataHeaders.
gmail_threads_listCRead-onlyIdempotent
List Gmail threads.
Inputs: q, userId, labelIds, pageToken, +2 more.
gmail_threads_modifyB
Modify the labels on a thread, and so on every message in it.
Inputs: id (required), body (required), userId.
granola_notes_listARead-onlyIdempotent
List meeting notes, filtered by when they were created or last updated and optionally narrowed to one folder and its subfolders. Returns each note's id, title, owner and timestamps, not its content. Fetch that with notes_get. Only notes that already have a generated AI summary appear here.
Inputs: cursor, folderId, pageSize, createdAfter, +2 more.
gsheets_spreadsheets_values_updateC
Sets values in a range of a spreadsheet.
Inputs: range (required), valueRange (required), spreadsheetId (required), valueInputOption (required), +3 more.
linear_attachments_listBRead-onlyIdempotent
List attachments — the links between Linear issues and things outside it.
Inputs: variables.
linear_customer_need_createA
Record a customer request, optionally attached to an issue or project. This is the one Linear mutation whose reply carries no object — it answers only with whether it worked.
Inputs: variables (required).
linear_customer_needs_listARead-onlyIdempotent
List customer requests. Filter by issue to see what a piece of work is wanted for, or by customer to see everything one company has asked for.
Inputs: variables.
linear_issue_createA
Create an issue. team_id and title are required; everything else is optional. The UUIDs for team, assignee, state and labels come from teams_list, users_list and workflow_states_list — Linear does not accept names here. Set parent_id to create a sub-issue.
Inputs: variables (required).
linear_issues_listARead-onlyIdempotent
List issues, optionally filtered. Conditions on one filter object combine with AND. To find a team's open work, filter on team.key and state.type.
Inputs: variables.
linear_issue_updateA
Update an issue. Only the fields provided are changed. To close an issue, set state_id to a state whose type is 'completed' or 'canceled' — Linear has no separate close operation. Use added_label_ids and removed_label_ids to adjust labels; label_ids replaces them outright.
Inputs: variables (required).
linear_search_issuesARead-onlyIdempotent
Search issues by text, across titles and descriptions. Set include_comments to search inside comments too. This is full-text search; to filter on fields such as state or assignee, use issues_list.
Inputs: variables (required).
notion_pages_createA
Create a page — as a subpage of another page, or as a row of a database by giving its data_source_id as the parent. Content comes as a markdown string Notion parses into blocks, or from a template: one or the other, never both.
Inputs: body (required), filterProperties.
notion_searchA
Search the titles of pages and data sources shared with this integration. Titles only — it does not search page content — and it returns nothing that has not been shared. With no query it lists everything visible, which is how you find the IDs to start from.
Inputs: body.
slack_chat_post_messageA
Send a message to a Slack channel, private group, or DM. Provide text for a plain message; set thread_ts to reply inside an existing thread.
Inputs: channel (required), text, parse, blocks, +13 more.
slack_conversations_historyBRead-onlyIdempotent
Fetch recent messages from a Slack channel.
Inputs: channel (required), limit, cursor, latest, +3 more.
stripe_charges_listBRead-onlyIdempotent
List charges, most recently created first.
Inputs: limit, customer, endingBefore, paymentIntent, +1 more.
stripe_customers_listARead-onlyIdempotent
List customers, most recently created first. Filter by email to find one.
Inputs: email, limit, endingBefore, startingAfter.
stripe_customers_retrieveBRead-onlyIdempotent
Retrieve a single customer by ID.
Inputs: customer (required).
stripe_invoices_listARead-onlyIdempotent
List invoices, most recently created first. Filter by customer, subscription, status or collection method.
Inputs: limit, status, created, customer, +4 more.
stripe_refunds_createA
Refund a charge. Provide either charge or payment_intent. Omit amount to refund the full sum.
Inputs: amount, charge, reason, metadata, +1 more.
stripe_subscriptions_listBRead-onlyIdempotent
List subscriptions. Filter by customer or status.
Inputs: limit, price, status, customer, +2 more.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 32 tools
Tools are namespaced by service and target distinct actions; descriptions actively disambiguate overlapping pairs like linear_search_issues vs linear_issues_list (full-text vs field filter) and connect vs connection_status (change vs read). A few pairs (gmail_threads_list/get, list vs retrieve) are close but clearly separated by descriptions.
Nearly all tools follow a {service}_{resource}_{verb} snake_case pattern (gdrive_files_copy, gmail_threads_list, stripe_invoices_list), and casing is uniformly lowercase snake_case. Minor deviations: verb position varies (linear_search_issues puts the verb first) and connect/connection_status lack a service prefix, but the convention is still readable.
32 tools spanning ~11 unrelated services (Drive, Gmail, Linear, Stripe, Granola, Docs, Slack, Calendar, Forms, Notion, Sheets) is heavy for a server named 'support-inbox'. The breadth exceeds a well-scoped surface and crosses into the 'too many' band.
Email, issue, and customer workflows get reasonable read/write coverage, but lifecycle operations are thin: little or no delete/archive, no Gmail label or search-by-content management, and limited Linear comment/label tooling. The multi-domain scope makes full coverage across every connected app unlikely.
Maintenance
Related MCP Connectors
Build and run agents and automations across hundreds of apps using natural language.
Stateful email for AI agents: read inboxes, reply in-thread, draft with approval.
Email OS for agents - real-inbox search, triage, commitments, and a verifiable BEC hard-stop.
Gmail, Outlook, Drive, OneDrive and calendars for AI agents. Many accounts, one endpoint, audit log.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceConnects AI assistants to over 30 business tools like Gmail, Slack, and Airtable through a single unified interface. It enables users to perform actions across multiple platforms using natural language without managing individual API integrations.23 npmMIT
- AlicenseNot gradedqualityNot gradedmaintenanceEnables AI agents to interact with Gmail for classifying messages, extracting action items, and performing batch inbox triage. It supports automated labeling, smart replies, and task creation for external platforms like Linear, Jira, and Todoist.-
- FlicenseNot gradedqualityCmaintenanceUnified email orchestration server for Gmail and Outlook with agentic tools for sending, reading, searching, and managing emails, enabling assistant-driven email workflows.2-
- FlicenseNot gradedqualityDmaintenanceEnables AI-powered email management through Gmail, including search, send, drafts, labels, and an intelligent agent with human approval workflow and optional customer database integration.-