# Choose MCP or REST for Your iMessage Integration

Canonical: https://figment.so/blog/imessage-mcp-vs-rest

## The one-sentence answer

Use REST when your application code decides what to do. Use MCP when a language model decides.

Both paths share the same Figment Apple Connect OAuth grant and the same two iMessage scopes: `messages:read` for history and search, and `messages:send` for outbound messages. The difference is the caller's reasoning model, not the underlying permission contract.

Figment issues these grants, not Apple. Apple's supported third-party account authorization covers Mail, Calendar, and Contacts; there is no Apple-issued iMessage OAuth scope.

## What Figment's REST interface gives you

Figment Apple Connect exposes iMessage through a conventional HTTP API at `https://figment.so/api/apple-connect`. After completing the PKCE authorization flow with your registered `client_id`, you receive a Figment access token (normally valid for 900 seconds) and a `connection_id` that identifies the connected Apple Account.

Three read endpoints cover the common patterns:

```
GET /v1/connections/{connection_id}/chats?limit=20&offset=0
GET /v1/connections/{connection_id}/messages?chatGuid=...&limit=20
GET /v1/connections/{connection_id}/messages/search?query=...&chatGuid=...&limit=20
```

Use `chatGuid` values returned by the chats endpoint. When constructing real requests, URL-encode all query parameter values with a URL builder; never paste raw `chatGuid` strings directly into a query string.

A fourth endpoint handles outbound messages:

```
POST /v1/connections/{connection_id}/messages/send
```

The body carries a `chatGuid` (taken from the chats response) and `text`. Every send request requires a stable `Idempotency-Key` header you generate and persist before the first attempt. Poll `GET /v1/connections/{connection_id}/messages/receipt` with the same key to check delivery state.

REST fits when your code owns the full decision path: a CRM logging a conversation, a support tool routing by keyword, or a scheduled alert pipeline. The logic is explicit and testable.

## How MCP changes the caller

> **Integration design:** Figment does not currently ship a hosted MCP server. This section describes building the MCP layer yourself, wrapping Figment's supplied REST endpoints as typed tools. No Figment MCP server endpoint contract has been issued; treat the architecture below as a design guide, not a tested integration.

The [Model Context Protocol](https://modelcontextprotocol.io/introduction) is an open-source standard for connecting AI applications to external systems. In this integration design, you build an MCP server that exposes Figment's REST operations as typed tools. An LLM running inside a host — Claude Desktop, VS Code, or a custom agentic framework — instantiates an MCP client, discovers the available tools, and calls them when it determines an action is warranted.

Your MCP server translates each `tools/call` request into the appropriate Figment REST call and returns the result as structured content. The host never touches Figment directly; your MCP server holds the access token and enforces idempotency.

MCP uses JSON-RPC 2.0 over two transports: stdio for local processes and Streamable HTTP for remote servers. The [MCP architecture specification](https://modelcontextprotocol.io/docs/2026-07-28/learn/architecture.md) recommends OAuth for remote server authentication — which fits naturally with the Figment token flow.

The practical effect: an agent can read recent messages, reason about their content, and decide whether and how to reply — without hardcoded routing logic in your application. This suits AI assistants, agentic task handlers, and CRM copilots where the LLM interprets context before acting.

**Two content-trust concerns apply specifically to this path.** First, message bodies are untrusted input. A received message can contain text designed to redirect the agent's behavior — a prompt-injection risk. Your MCP server should not forward raw message content as tool arguments or system instructions. Second, writes must be explicit. The send tool should require a resolved `chatGuid` and final `text` from the agent — it must not infer or construct those values from conversation context alone. Treat every invocation of the send tool as an explicit authorized write, not an automatic response.

## Agent versus application interaction and permission map

This map covers every significant decision axis across the two integration paths.

| Concern | REST — application-driven | MCP — agent-driven (design) |
|---|---|---|
| **Who calls the endpoint** | Your application code | LLM via `tools/call` through your MCP server |
| **Token holder** | Your backend | Your MCP server (same Figment access token) |
| **Scopes needed** | `messages:read`, `messages:send` | Same scopes; server holds the grant |
| **How `chatGuid` is selected** | Your code retrieves and passes it | Agent uses a prior tool result from the chats listing |
| **Idempotency key** | App generates one key per intended send before first request | MCP server generates one key per tool invocation; never shared across separate calls |
| **Read completeness** | Bounded by Mac sync state; check `hasMore` and `historyComplete` | Same Mac-sync limit applies; expose these fields in tool output |
| **Delivery certainty** | Poll `/receipt` with same key; `unknown` means poll again, never resend under a new key | Tool returns receipt; `unknown` means poll only — do not issue a new send |
| **Content trust** | App controls what text it reads and passes | Message text is untrusted; guard against prompt injection before using it in tool arguments |
| **Best for** | CRM pipelines, keyword routers, scheduled alerts | AI assistants, agentic task handlers, copilot features |

The grant, Mac dependency, and delivery uncertainty are identical across both paths. Only the decision-making layer differs.

## Scope and idempotency rules that apply to both paths

Two rules are non-negotiable regardless of which surface you use.

**Exactly two iMessage scopes.** `messages:read` covers both history retrieval and search — there is no separate search permission. `messages:send` is distinct. A conversation appearing in a read result is not automatically authorized for sends; the send grant must include that exact existing conversation. Request `messages:send` only when your use case requires outbound messages.

**Idempotency is about intent, not content.** Generate and persist one key per intended send action before its first request. Reusing a content hash to deduplicate silently merges two separately intended identical messages. A failed send with a given key returns its recorded failure on retry — the key does not trigger a new send attempt. An `unknown` receipt means poll the same receipt endpoint. It never means issue a new key.

Both paths also share the Mac-sync constraint: read history reflects what is available on the connected Mac. The `historyComplete` and `hasMore` fields indicate coverage. Data is bounded even when the connector status shows `ready`.

## Picking your path — or running both

**Choose REST** when your logic is deterministic: routing rules, response templates, or time-based triggers. It is straightforward to test, easy to reason about, and maps directly to any HTTP client or automation platform.

**Choose MCP** when the decision of when and what to send belongs to a language model. MCP gives the agent a typed tool contract it can discover and invoke. Your application code stays out of the routing logic entirely.

**Run both** when your product has deterministic and agentic surfaces. A support product might use REST for SLA-driven auto-replies while an MCP server powers the AI copilot that drafts contextual responses. The grant and scopes are shared; only the caller changes.

Sandbox access is free and uses synthetic data that cannot reach real recipients. Live connections are $29/month per active Apple connection; access starts after setup.

## Start your integration

Register your app and explore the sandbox at the [developer dashboard](/apple-connect/developers). When you're ready to connect a live Apple Account, the [Connect Apple Account](/apple-connect/developers) flow is there.

For a full walkthrough of the PKCE grant and token exchange, see [OAuth for iCloud: Connect Apple Data to Your App](/oauth-for-icloud). For head-to-head alternative comparisons, see [Figment vs BlueBubbles](/blog/figment-vs-bluebubbles), [Figment vs AirMessage](/blog/figment-vs-airmessage), and [Figment vs Claw Messenger](/blog/figment-vs-claw-messenger).
