MCP Server
Connect AI assistants to Front via the MCP server (beta)
If you havenāt been granted access to the MCP server beta yet, please join our community group and:
- Request access via the form in the Welcome topic.
- Post feedback about what you want to see added or improved as a new post in the group.
Front's MCP server (mcp.frontapp.com/mcp) (currently in open beta) lets AI agents act on Front conversation data using a single OAuth-authenticated endpoint. Agents authenticate as a specific Front user, with permissions matching that user's role (user-scoped authorization).
This article covers how to connect any MCP-compatible client to Front using an OAuth app you create yourself in the Front developer settings. For the user-facing overview, official directory listings (Claude, and others coming), and use case inspirations for Front teammates, see the general Help Center article on the MCP server.
Looking for examples before you build?
The MCP space in the Front Community has workflow walkthroughs, sample prompts, video demos, and a feedback channel where the team responds directly. If you want to see what's possible before you set anything up, start there.
Overview
| Endpoint | https://mcp.frontapp.com/mcp |
| Transport | Streamable HTTP |
| MCP spec version | 2025-11-25 |
| Auth | OAuth 2.1 + PKCE with incremental scope consent |
| Identity model | Per-user tokens ā every tool call attributes to a specific Front teammate |
| Scopes | read, write, send |
The identity model is the part most worth internalizing: the agent's effective permissions are exactly the authorizing teammate's permissions. If the teammate can't see an inbox, the agent can't either.
Use cases
A few patterns this surface unlocks:
- Custom agent harnesses. Wire Front into Claude Code, Cursor, or an in-house orchestrator alongside your other tools (GitHub, Notion, Jira, Slack, Linear, your CRM) for cross-system workflows: customer reports a bug, agent reproduces it, identifies the suspect PR, and posts an internal comment with the diagnosis.
- Multi-tenant partner integrations. Publish an OAuth app that any Front admin can install. Each end user authorizes individually.
- Triage and routing agents. Scheduled or event-driven agents that search the inbox, classify by topic, assign to the right teammate, and draft a first-pass reply for human review.
- Conversation insights and enrichment. Pull conversation data into your own pipelines for analysis, KB extraction, or feedback ingestion. The conversation timeline includes messages, comments, tags, assignment history, and more in a single stream.
Set up the MCP server connection
Connecting an AI assistant to Front's MCP server has two general steps: create a Front developer app, configure its OAuth scopes, and then connect your AI client using the app's credentials.
After you complete these two steps, your teammates will be able to find the Front MCP server in your AI assistant and connect to it without having to create a developer app or configure the connection details on the AI client side.
1. Set up the Front developer app with an OAuth feature
- Create a developer app and give it an appropriate name (e.g. "Claude MCP Connector")
- Click Add feature in the Features tab.
- Add an OAuth feature to your developer app.
- Note the Client ID and Client secret.
- Add a redirect URL that corresponds to the AI assistant you're sending data to. For example, as of this writing, the Claude documentation instructs you to use
https://claude.ai/api/mcp/auth_callbackfor most versions of Claude. If you're using Claude Code or similar CLI, you should enterhttp://localhost/callback. This URL will allow you to connect to a randomly generated local port. - Enable MCP Server under Feature Access.
Only enable the MCP Server option. Enabling other types of feature access can lead to 403 errors when you authorize through your AI assistant.
- Under Resource permissions, select the resources available to the MCP server.
Request the narrowest set that covers your use case. A read-only research agent only needs
read. A drafting copilot needsread+writebut notsend. Only requestsendif your agent will actually send messages.Remember that despite the permissions selected in the OAuth client, agents connecting to the MCP server will be further limited by the subset of data and permissions that the user who connects the agent has access to.
2. Connect your AI assistant
Once the app is configured, connect from your MCP client so that you and your team can view the Front MCP server. Once it is set up for your company, individual teammates can find the MCP server in the list of connectors and authorize it for their individual accounts, but they will not need to configure the technical details involving the server URL and credentials, as explained in this section.
The exact configuration syntax for initial configuration varies by AI client, but every client will need:
- The MCP server URL:
https://mcp.frontapp.com/mcp - Your app's
client_idandclient_secret - The OAuth scopes the app should request
Use the UI or command line to connect the MCP server
We recommend using your AI assistants UI menus to connect the Front MCP server, or terminal commands for CLI assistants. Configuring JSON files is not recommended for most users because varying local paths and environment settings can cause issues. We've provided two recommended examples for Claude below, plus a general JSON shape if you have to modify your AI assistant's configuration file directly.
If you have issues connecting the MCP server, please reach out to your AI assistant's support team and share this documentation with them so they can recommend the correct steps.
Example for Claude (Web and Desktop)
- Open Settings and navigate to the Connectors tab (or the Customize page).
- Click + and then Add custom connector.
- Enter the server URL: https://mcp.frontapp.com/mcp
- Click Advanced settings and enter your OAuth Client ID and Client Secret.
- Click Add and complete the OAuth authentication flow.
You may have to close out Claude and re-open it before it sees the new MCP server and has you authorize permissions.
Example for Claude Code
- In Front, make sure your OAuth feature contains the
http://localhost/callbackredirect URL. - In your terminal, run the following command and enter your client secret when prompted:
Including
MCP_CLIENT_SECRETis optional. If you don't include it, Claude should prompt you for it after. If it fails to do so, then include it inline.You can name the MCP server something other than
frontif you desire.MCP_CLIENT_SECRET=<your-client-secret> claude mcp add --transport http --client-id <your-client-id> --client-secret front https://mcp.frontapp.com/mcp - Exit Claude and re-open it in your terminal so that it pulls the latest list of servers.
- Run /mcp to see a list of MCP servers.
- Select the server you added and choose to Authenticate it.
- Authorize in your browser.
Example for generic MCP server config (confirm with your client's docs on exactly how you structure and pass these properties) - Not recommended for most users
{
"mcpServers": {
"front": {
"url": "https://mcp.frontapp.com/mcp",
"transport": "streamable-http",
"oauth": {
"client_id": "<your-client-id>",
"client_secret": "<your-client-secret>",
"scopes": ["read", "write", "send"]
}
}
}
}Tips for authorization
Match your client's requested scopes to your OAuth app. By default, many AI assistants (including Claude) will request every scope the MCP server supports. If those scopes exceed what you enabled on the Front OAuth app, the authorization flow may return an error.
If you encounter this error, configure your client to only request the scopes your app is set up for. In Claude, for example, this is set in the client's JSON config ā see Claude's docs on restricting OAuth scopes for the exact syntax. Other clients have similar settings; check their documentation if you hit an authorization error.
When the client first connects, each user will be redirected to Front to log in and consent to the requested scopes. The resulting token is bound to that specific Front user and they can only act on data their Front role allows.
A note on enterprise deployment: If your AI assistant is centrally managed (e.g. Claude Enterprise, ChatGPT Enterprise), your IT team may need to allow the connection or distribute the app credentials. Each end user still completes the OAuth consent flow individually ā this is how Front guarantees that every tool call has a real, attributable user behind it.
Rate limits
The MCP server uses separate rate limits from the Core API and other Front platform features, so you don't need to worry about stability issues for your existing integrations. We will publish more specifics on rate limits once the MCP server exits beta.
Tool reference
Please note that the tools are still under development for the beta. The exact list, names, and descriptions are subject to change as we evolve them in response to feedback and further development.
The MCP server currently exposes 18 tools across five domains. All write tools that mutate state in user-visible ways carry destructiveHint: true, which prompts MCP clients to request per-call user confirmation.
Conversations
| Tool | Type | Description | Flags |
|---|---|---|---|
search_conversations | Read | Full-text and filter search across conversations. | query (required) ā Full-text search string. filters.inboxId ā Restrict to a single inbox (inb_xxx). filters.teammateId ā Restrict to conversations assigned to a teammate (tea_xxx). filters.teamId ā Restrict to conversations owned by a team (tim_xxx). filters.tags ā Array of tag IDs (tag_xxx); returns conversations matching all tags. filters.status ā One of open, archived, trashed, spam. filters.after / filters.before ā Date range filter (YYYY-MM-DD). cursor ā Pagination cursor from a previous call. |
read_conversation | Read | Full timeline of a conversation including messages, internal comments, tag/assignment changes, status transitions, rule actions, and SLA events. | conversationId (required) ā Public conversation ID (cnv_xxx). limit ā Max timeline entries to return (default 50, max 200). cursor ā Pagination cursor for timeline entries. |
create_draft | Write | Creates a draft reply on the conversation. Does not send. | conversationId (required) ā Public conversation ID (cnv_xxx). body (required) ā Draft body text. bodyFormat ā html (default), markdown, or plain. inReplyToMessageId ā Pin to a specific message; defaults to the latest. replyAll ā Reply to all original recipients (default true). shared ā Share draft with teammates (default true); set false to keep private. |
send_reply | Write (destructive) | Sends a reply on the conversation's native channel (email, SMS, chat, custom). | conversationId (required) ā Public conversation ID (cnv_xxx). body (required) ā Reply body text. bodyFormat ā html (default), markdown, or plain. inReplyToMessageId ā Reply to a specific message; defaults to the latest. channelOverride ā Channel public ID to override the default send channel. |
update_conversation_status | Write (destructive) | Archives or reopens a conversation. If the requester is the assignee (or it's their private inbox), the change is global; otherwise only their view is affected. | conversationId (required) ā Public conversation ID (cnv_xxx). status (required) ā open (return to inbox) or archived (remove from open inbox). |
assign_conversation | Write | Assigns a conversation to a teammate, or unassigns it. | conversationId (required) ā Public conversation ID (cnv_xxx). assigneeId (required) ā Teammate ID (tea_xxx) to assign to, or null to unassign. |
Comments
| Tool | Type | Description | Flags |
|---|---|---|---|
add_comment | Write | Posts an internal comment on a conversation. Not visible to customers. Supports @mentions which are auto-resolved to teammates. | conversationId (required) ā Public conversation ID (cnv_xxx). body (required) ā Comment body text. |
Tags
| Tool | Type | Description | Flags |
|---|---|---|---|
list_tags | Read | Lists all tags in the workspace, including hierarchy. | name_query ā Filter by tag name keywords. inbox_ids ā Filter by inbox IDs the tag applies to (inb_xxx). all_inboxes ā Filter to tags that apply to all inboxes (true/false). is_visible_in_conversation_lists ā Filter by list visibility. parent_tag_id ā Filter by parent tag (tag_xxx) for hierarchical tags. limit ā Max results (default 50, max 100). offset ā Pagination offset. |
tag_conversation | Write | Adds or removes tags on a conversation. Idempotent. | conversationId (required) ā Public conversation ID (cnv_xxx). addTags ā Array of tag IDs (tag_xxx) to add. removeTags ā Array of tag IDs (tag_xxx) to remove. |
Contacts
| Tool | Type | Description | Flags |
|---|---|---|---|
search_contacts | Read | Searches contacts by name, email, or handle. | query (required) ā Search string (name, email, or handle). cursor ā Pagination cursor from a previous call. |
read_contact | Read | Returns a full contact record including handles and linked accounts. | contactId (required) ā Public contact card ID (crd_xxx). |
read_account | Read | Returns the account (company) record linked to contacts. | account_id (required) ā Numeric account ID or public account ID (acc_xxx). |
update_contact | Write | Updates a contact's handles or custom fields. | contactId (required) ā Public contact card ID (crd_xxx). handles ā Array of handle operations, each with type (e.g. email, twitter), handle (the value), and action (add or remove). customFields ā Key-value object of custom field updates; pass null for a key to clear it. |
Organization
| Tool | Type | Description | Flags |
|---|---|---|---|
list_inboxes | Read | Lists inboxes visible to the authenticated user. | name_query ā Filter by inbox name keywords. access_mode ā everyone or restricted. ai_enabled ā Filter to AI-enabled inboxes (true/false). ticketing_enabled ā Filter to ticketing-enabled inboxes (true/false). business_hours_enabled ā Filter by business hours status. global_rules_enabled ā Filter by company rules status. teammate_ids ā Filter to inboxes accessible by specific teammates. circle_ids ā Filter to inboxes accessible by specific teammate groups. limit ā Max results (default 25, max 50). offset ā Pagination offset. |
list_teammates | Read | Lists all teammates and their roles in the workspace. | name_query ā Search by name or email keywords. limit ā Max results (default 10, max 25). offset ā Pagination offset. |
list_teams | Read | Lists all teams in the workspace. | (no parameters) |
list_drafts | Read | Lists in-flight draft messages authored by the authenticated teammate. | limit ā Max drafts to return (default 50, max 200). |
Human approval for destructive actions
The MCP server does not ship a dedicated request_approval tool. Instead, agents that need human sign-off for destructive actions should follow this convention:
- Call
add_commenton the conversation with a structured body summarizing the proposed action, plus@mentionsof the approver(s). Tag the comment with a recognizable label (e.g.agent-approval) so it's searchable in Front's UI. - Poll
read_conversationwithinclude: ["comment"]for the approver's reply. A recognized keyword likeapproveorrejectworks well; agents can also parse free-form rationale. - On approval, call the destructive tool (
send_reply,update_conversation_status, etc.). These tools carrydestructiveHint: true, so the MCP client will gate the action with its own per-call confirmation UI.
This pattern works well for refund flows, external communications, and other actions where a human should see the proposed action in context before it ships. Comments are auditable, attributable to the agent's authorizing user, and visible to all teammates in the conversation.
Troubleshooting
401 Unauthorized on every request
401 Unauthorized on every requestThe token is invalid, expired, or has been revoked. Common causes:
- The user revoked the app's access in Front's connected apps settings.
- A workspace admin uninstalled the OAuth app entirely.
- The access token expired and the refresh flow didn't fire. Re-authenticate to mint a new token.
403 Forbidden on a tool that worked before
403 Forbidden on a tool that worked beforeThe token has scopes for some tools but not the one being called. For example, a read-scoped token will get 403 on add_comment. Re-authorize the user and request the broader scope set on consent.
This also fires if the authenticated Front user lost access to the relevant inbox, team, or resource between authorization and the tool call. Permissions are enforced at call time against the user's current Front role.
429 Too Many Requests
429 Too Many RequestsRate limits are tiered per teammate per minute:
- Light reads (
list_*,get_*): 120/min - Heavy reads (
search_conversations,read_conversation): 30/min - Writes (drafts, comments, tags, assignment, status, contacts): 20/min
- Send (
send_reply): 20/min
Additional caps apply at the per-teammate (1,000/hour) and per-workspace (10,000/hour) level. The response includes a Retry-After header and an x-ratelimit-tier header indicating which tier was exceeded.
If you're seeing rate-limit errors during normal operation, the most common cause is a polling loop that's tighter than it needs to be. Approval-by-polling loops should generally poll on the order of seconds-to-minutes, not sub-second.
Conversation counts don't match what the user sees in Front
A known v1 limitation: search_conversations returns conversations matching global state, not per-inbox archival state. If a user archived a conversation from an inbox's view but the conversation is still globally open (e.g. it's open in another inbox), the API returns it but the Front sidebar hides it.
There's also no current way to fetch the union of a user's personal inbox plus conversations assigned or subscribed to them. The MCP server returns conversations from the queried inbox only.
If your agent needs to mirror a user's exact Front view, this is on the v1.1 roadmap. In the meantime, document the gap with users so they know the agent may see slightly more (or differently filtered) conversations than they do.
Message bodies come back as HTML and they're noisy
Conversation messages currently return as HTML. If your downstream model parses better against plain text, strip tags client-side before passing to the model, or use a small preprocessing step in your agent harness. A plain-text option is on the v1.1 roadmap.
Attachments aren't accessible
PDF and other attachment content isn't extractable through the MCP server in v1. If your workflow depends on attachment parsing, do it out-of-band ā fetch the attachment via Front's API and process it separately, then feed the extracted text back to the agent.
Agent can't start a new conversation
There's no send_new_message tool in v1. Agents can only act within existing conversations.
Feedback
To share feedback during this beta, please join our community group and create a new post.
Updated 2 days ago
