Skip to main content
Glama

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-mcp

It 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 connected

Tokens 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

Google

Browser sign-in, over your own OAuth client (make one).

GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET

Linear

Your own key (get one), entered once.

LINEAR_API_KEY

Stripe

Your own key (get one), entered once.

STRIPE_API_KEY

Granola

Your own key (get one), entered once. In the Granola app: Settings → Connectors → API keys. Business plan or above.

GRANOLA_API_KEY

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.

SLACK_BOT_TOKEN

Notion

Your own key (get one), entered once. Then share the pages it should see with the integration.

NOTION_API_KEY

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 support_email_to_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 fixed_to_reply_in_the_original_thread

Customers who reported a bug hear it's fixed in the same email thread.

Linear, Gmail

QBR account brief 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 churn_signal_to_save_call

A cancellation at period end triggers a call while there is still time.

Stripe, Granola, Slack, Google Calendar

New customer onboarding kickoff 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 customer_slack_channel_to_requests_and_bugs

Asks in shared channels get tracked and answered with a link.

Slack, Linear

Refund request handled end to end 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 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 help_center_gap_finder

Questions asked three times with no article get a draft article.

Gmail, Notion

Escalation runbook 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 internal_q_and_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 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 = 30

Name 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.langchain

Need 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_send

  • Linear: linear_search_issues, linear_issue_create, linear_issues_list, linear_attachments_list, linear_customer_needs_list, linear_customer_need_create, linear_issue_update

  • Stripe: stripe_customers_retrieve, stripe_invoices_list, stripe_subscriptions_list, stripe_customers_list, stripe_charges_list, stripe_refunds_create

  • Granola: granola_notes_list

  • Google Docs: gdocs_documents_create

  • Slack: slack_chat_post_message, slack_conversations_history

  • Google Calendar: gcalendar_events_insert

  • Google Drive: gdrive_files_copy, gdrive_permissions_create, gdrive_files_list

  • Google Forms: gforms_forms_responses_list

  • Notion: notion_search, notion_pages_create

  • Google Sheets: gsheets_spreadsheets_values_update

License

Apache 2.0.

Available Tools

32 tools
connectA

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_statusA
Read-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_listA
Read-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_listA
Read-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_getC
Read-onlyIdempotent

Read a Gmail thread.

Inputs: id (required), format, userId, metadataHeaders.

gmail_threads_listC
Read-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_listA
Read-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_listB
Read-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_listA
Read-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_listA
Read-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_issuesA
Read-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.

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_historyB
Read-onlyIdempotent

Fetch recent messages from a Slack channel.

Inputs: channel (required), limit, cursor, latest, +3 more.

stripe_charges_listB
Read-onlyIdempotent

List charges, most recently created first.

Inputs: limit, customer, endingBefore, paymentIntent, +1 more.

stripe_customers_listA
Read-onlyIdempotent

List customers, most recently created first. Filter by email to find one.

Inputs: email, limit, endingBefore, startingAfter.

stripe_customers_retrieveB
Read-onlyIdempotent

Retrieve a single customer by ID.

Inputs: customer (required).

stripe_invoices_listA
Read-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_listB
Read-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

    B3.2/5.0

    Scored across 32 tools

    Disambiguation4/5

    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.

    Naming Consistency4/5

    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.

    Tool Count2/5

    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.

    Completeness3/5

    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

    ActivitySlowing
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      D
      maintenance
      Connects 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 npm
      MIT
    • A
      license
      Not graded
      quality
      Not graded
      maintenance
      Enables 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.
      -
    • F
      license
      Not graded
      quality
      C
      maintenance
      Unified email orchestration server for Gmail and Outlook with agentic tools for sending, reading, searching, and managing emails, enabling assistant-driven email workflows.
      2
      -
    • F
      license
      Not graded
      quality
      D
      maintenance
      Enables AI-powered email management through Gmail, including search, send, drafts, labels, and an intelligent agent with human approval workflow and optional customer database integration.
      -