Skip to content

Fin Operator MCP

'Fin Operator MCP' is currently in closed beta

Access is enabled per workspace. Please reach out to your accounts team to discuss access and tailored, hands-on support.

Operator is Fin's internal AI agent. The Fin Operator MCP server lets an AI client ask Operator to do work inside your Fin workspace and read the answers back, without you moving between the two products.

Availability
  • US-hosted workspaces only. EU-hosted workspaces are not supported yet.
  • Claude (claude.ai, Claude Desktop, Claude Code, and Claude Mobile once connected) is the only supported client at the moment.

What it does

Your client asks Operator something in plain language, Operator does the work, and hands back the answer plus any changes it suggests. Operator already knows your workspace, so you can:

  • Ask why Fin missed resolutions over a period
  • Investigate a specific conversation
  • Ask Operator to propose configuration changes

Proposed changes are reviewed and applied from the client, without leaving it.

Reviewing proposals

Proposals are not applied until apply_proposals is called. Review each one with get_proposal_details before you apply it — some changes cannot be undone.

How it works

Fin hosts a remote MCP server that follows the authenticated remote MCP specification (docs), with Dynamic Client Registration and PKCE.

Connection URL: https://fin-operator-mcp.intercom.workers.dev/mcp

Operator turns run asynchronously: a request returns as soon as Operator accepts the work, and the client collects the answer with a later call.

When a client calls a tool:

  1. The client connects to the Fin Operator MCP server and completes the OAuth flow
  2. We check if the workspace is enabled for the beta and that the teammate has permission to use Operator
  3. The tool runs as that teammate, inside that workspace
  4. Answers, and any proposed changes, are returned to the client

Setting things up

claude.ai and Claude Desktop

Who does which step

On Claude Team and Enterprise plans, only an Owner or Primary Owner can add a custom connector, and they only need to do it once for the organization. If you are not an owner, ask yours to run steps 1–3 below, then start from step 4 yourself. On individual plans you do all the steps.

Adding the connector — an organization owner on Team and Enterprise plans, or you on an individual plan:

  1. Open Claude's Connectors settings and choose Add custom connector.
  2. Give the connector a name, e.g. Fin Operator.
  3. Paste the connection URL: https://fin-operator-mcp.intercom.workers.dev/mcp

Connecting to it — every person who wants to use Operator does this for themselves:

  1. Choose Connect on the connector. Claude registers itself with the server and sends you to an authentication page.
  2. Sign in to your Fin workspace if you are not already, and approve the consent screen. It names the workspace you are connecting and the two permissions being granted (see OAuth scopes).
  3. You are returned to Claude and the connector shows as connected, listing the six Operator tools.

Each person authorizes as their own teammate profile, so the connector being shared does not mean the access is.

The same connection then works from Claude Mobile — connectors are attached to your Claude account, not to one device, so there is nothing to set up again there.

Claude Code

claude mcp add --transport http fin-operator https://fin-operator-mcp.intercom.workers.dev/mcp

Then run /mcp, select fin-operator, choose Authenticate, and approve the Intercom consent screen.

By default the server is added in the local scope: available to you throughout the project you ran the command in, but not in your other projects. To make it available in every project, add it with the user scope instead:

claude mcp add --scope user --transport http fin-operator https://fin-operator-mcp.intercom.workers.dev/mcp
Corporate allowlists

If your organization restricts which connectors Claude may use, ask whoever administers it to allow https://fin-operator-mcp.intercom.workers.dev/mcp. On Claude Team and Enterprise plans this is an organization owner action.

Available tools

The Fin Operator MCP server provides 6 tools.


send_operator_message

Send a message to Operator.

Returns as soon as Operator accepts the turn — it does not wait for the answer. The turn keeps running in Intercom; collect the answer with get_operator_response using the chat_id from the response. Once a turn has been accepted, never re-send the same message to retry.

Parameters:

  • message (required): the message to send to Operator
  • chat_id: continue an existing conversation. Omit to start a new chat. Use one chat per topic.

Status in the response envelope:

  • working: Operator accepted the turn and is running it. Turns normally take one to three minutes.
  • error: the error text opens with a code (rate_limited, chat_busy, usage_limit, …) when the turn definitively never started. A bare error: means the turn may have started anyway — check the chat in Intercom via chat_url before retrying.

get_operator_response

Read the latest response from an Operator chat. Never starts new work and never waits — it returns the chat's current state immediately.

Parameters:

  • chat_id (required): the chat to read, which is the UUID at the end of an Operator chat URL

Status in the response envelope:

  • complete: the latest turn finished; answer_text and tool_outputs are final
  • working: the turn is still running — check again shortly
  • needs_approval_in_ui: Operator is waiting for teammate input or confirmation in Intercom (open chat_url to respond)
  • error: the turn failed — check the chat in Intercom via chat_url rather than calling again

Proposals are returned only once the turn is known to have stopped writing. Until then proposals is empty and proposals_withheld is true: an empty array does not mean the turn proposed nothing.


get_proposal_details

Show what a pending proposal would change, as a diff, plus anything blocking it. Read-only, and costs no Operator credits.

Parameters:

  • chat_id (required): the chat whose proposals to describe
  • proposal_ids: proposals to describe. Omit to describe every pending proposal on the chat.
  • detail: summary, diff, or full. Omit to get diff for a single proposal and summary for several.

A chat with more than 20 pending proposals is described 20 at a time.


apply_proposals

Apply Operator proposals to the workspace's live configuration. This creates, updates or deletes real objects, and some of it cannot be undone. It runs the same code path as the Apply button in Intercom.

Parameters:

  • chat_id (required): the chat whose proposals to apply
  • proposals (required): up to 5 proposals per call, each with:
    • proposal_id (required): from the response envelope's proposals array
    • apply_mode: one of apply, draft, release, publish, destroy. Omit to apply in the proposal's default_apply_mode — a new entity lands as a draft, and an edit keeps the entity's publication state. Set it only when a human explicitly chose a mode, and only to a mode listed in that proposal's supported_apply_modes.

reject_proposals

Discard proposals. Nothing in the workspace changes.

Parameters:

  • chat_id (required): the chat whose proposals to reject
  • proposal_ids (required): up to 20 proposal IDs per call

ping

Connectivity check. Returns pong with the authenticated workspace and teammate.

Parameters:

  • message: optional message to echo back

Tool annotations

The five tools that do work are published with MCP tool annotations — hints that tell the client how careful it should be with a tool, before it ever calls it. Claude uses them to decide what it can run freely, what it should confirm with you, and what to show you first. ping carries none: it only reports who you are connected as.

Tool Read‑onlyDestructiveIdempotentOpen‑world
send_operator_messagefalsetruefalsetrue
get_operator_responsetruefalsetruefalse
get_proposal_detailstruefalsetruefalse
apply_proposalsfalsetruefalsetrue
reject_proposalsfalsefalsefalsefalse

The columns are the readOnlyHint, destructiveHint, idempotentHint and openWorldHint fields of each tool's annotations.

What the hints are saying:

  • get_operator_response and get_proposal_details are read-only and idempotent. Calling them again has no additional effect, so Claude can reach for them without asking you. This is deliberate: it makes showing you a diff cheaper than applying a change. Idempotent does not mean the answer is fixed — get_operator_response reports the chat's current state, so the status and proposals do change as a turn progresses.
  • apply_proposals is destructive and open-world. It writes to live workspace configuration and some of it cannot be undone, so clients that gate on destructiveHint will ask you to confirm before it runs. Treat a client that applies without asking as misconfigured.
  • send_operator_message is also marked destructive and open-world. It does not write configuration itself, but it starts an Operator turn that acts on your workspace and consumes Operator usage, so it is not a free retry. The openWorldHint is what tells the client the effect reaches outside its own state.
  • reject_proposals is neither read-only nor destructive. Discarding a suggestion changes nothing in the workspace, so it needs no confirmation, but it is not read-only either — the proposal is gone afterwards.

readOnlyHint and destructiveHint are separate on purpose: applying a change and discarding one are different decisions, which is why the two are separate tools rather than one tool with a flag.

Annotations are hints, not enforcement. The authorization described in How permissions work is what actually decides whether a call is allowed.

A typical workflow

1. Ask Operator something

{
  "name": "send_operator_message",
  "arguments": {
    "message": "Why did Fin's resolution rate drop last week?"
  }
}

The response carries status: "working" and a chat_id.

2. Collect the answer

{
  "name": "get_operator_response",
  "arguments": { "chat_id": "b0c1d2e3-..." }
}

Turns normally take one to three minutes, so do not call this back-to-back. While the status is working, do something else and check again — repeated immediate calls are rate limited.

3. Review anything Operator proposed

{
  "name": "get_proposal_details",
  "arguments": { "chat_id": "b0c1d2e3-...", "detail": "diff" }
}

4. Apply or reject

Once a human has reviewed a specific proposal and confirmed it:

{
  "name": "apply_proposals",
  "arguments": {
    "chat_id": "b0c1d2e3-...",
    "proposals": [{ "proposal_id": "p_123" }]
  }
}

Quote numbers and data from tool_outputs verbatim rather than re-deriving them.

How permissions work

Once a workspace is enabled for the beta, teammate-level permissions apply through the MCP in exactly the same way they do for Operator in the product. Any teammate who can use Operator in Intercom can use it through the MCP too: there is nothing extra to grant them and no seat upgrade involved. A refused call names the specific permission required.

Concretely, every tool call is authorized on:

  • The workspace having Operator, and being enabled for the Fin Operator MCP beta on top of it — this gate is per workspace, not per teammate, and a teammate with Operator access in a workspace that is not enabled for the beta is still refused
  • A teammate-scoped token — the OAuth flow must be completed by a teammate
  • The teammate's Operator access permission in that workspace

Completing the OAuth flow on its own grants nothing. A teammate in a workspace that is not in the beta can hold a valid connection and still get nothing back.

OAuth scopes

The consent screen asks for two scopes:

  • Use Fin Operator — permission to send work to Operator. Every tool call is authorized on this scope; a connection without it is refused before anything runs.
  • Read one admin — lets the server read your teammate record once, while you are connecting, to record who authorized. Tool calls are attributed to you by the connection itself, not by this scope.

Neither scope grants direct access to conversation or contact data. Operator reads what it needs inside Intercom under the connecting teammate's own permissions.

Use Fin Operator is a private scope: it is only available to the app packages Intercom ships for Operator and cannot be requested by an app you build in the Developer Hub.

Rate limits

Requests are limited to 60 per minute per token, shared across all six tools: polling get_operator_response spends the same budget as reading proposal details. Ordinary interactive use sits well below this.

A throttled call is returned as a rate limit, telling the client to slow down rather than failing opaquely. The usual cause is polling get_operator_response in a tight loop.

Operator's own usage limits also apply, and are reported as a usage_limit error code from send_operator_message.

Debugging and troubleshooting

Check the connection works

Call ping. It returns the workspace and teammate the connection is authenticated as, which is the quickest way to confirm you are connected to the workspace you expect.

Common problems

  • "Operator MCP is not enabled for this workspace" — the workspace is not in the beta. Contact your accounts team.
  • Missing permission errors — the teammate needs Operator access in that workspace, granted the same way as for Operator in the Intercom UI.
  • A turn seems stuck — open chat_url from the response and look at the chat in Intercom. Do not re-send the message.
  • Empty proposals array — check proposals_withheld. If it is true, the turn is still writing; call get_operator_response again.
  • Authentication problems in Claude Code — re-run /mcp, select fin-operator, and authenticate again.