> ## Documentation Index
> Fetch the complete documentation index at: https://docs.zapier.com/llms.txt
> Use this file to discover all available pages before exploring further.

# AI agent connections & automations

> Connect user accounts via White Label and call Zapier-hosted MCP tools with Streamable HTTP.

# AI agent connections & automations

This guide covers using Zapier MCP so your product (or an AI agent inside it) can discover and call tools exposed from connected apps. It complements the generic [Token exchange](../implementation/token-exchange) page: for MCP you usually exchange a partner-signed JWT directly for a connect token, then complete a standard OAuth authorization code flow to obtain an MCP access token for the MCP server.

For embedding pre-built UI or running Actions API without MCP, see [Embedded triggers](./embedded-triggers) and [Embedded actions](./embedded-actions), and the [Zapier SDK](https://docs.zapier.com/) documentation as applicable.

## Flow overview

```mermaid theme={null}
sequenceDiagram
  actor User
  participant P as Partner
  participant ZAPI as Zapier API
  participant Z as zapier.com
  participant A as App
  participant AAPI as App API

  User->>P: Clicks "Connect"
  P-->>ZAPI: Exchange JWT for Connect token
  Note over P,ZAPI: POST zapier.com/oauth/token
  alt User not found
      ZAPI->>ZAPI: Provision user
  end
  ZAPI-->>P: connect token
  P->>Z: Redirect user to app's authorize URL
  Note over P,Z: connect.zapier.com/oauth/authorize?token=...&resource=...&state=...&redirect_uri=...
  Z->>A: Redirect to app's authorize URL
  User->>A: Grants Zapier access
  A->>Z: Redirect back with app code
  Z-->>AAPI: Exchange app code for tokens
  AAPI-->>Z: App access + refresh tokens
  Z-->>Z: Create app connection
  Z-->>Z: Create MCP server connection
  Z->>P: Redirect back with authorization code
  Note over P,Z: your-domain.com/callback?code=...&state=...
  P-->>ZAPI: Exchange authorization code for tokens
  Note over P,ZAPI: POST zapier.com/oauth/token
  ZAPI-->>P: MCP access + refresh tokens
  P-->>P: Store tokens, connect MCP server
```

## When to use Zapier MCP

Use MCP when you want a protocol-native integration (tool listing, `callTool`, streaming HTTP transport) against Zapier-hosted MCP servers. Use Action Runs (and related APIs) when you already orchestrate HTTP yourself or need fine-grained run/poll control outside MCP.

## Prerequisites

* White Label onboarding complete ([Partner onboarding](../implementation/partner-onboarding)): JWKS, callback URLs, JWT expectations, client credentials.
* Backend can sign partner JWTs and perform server-side calls to `POST https://zapier.com/oauth/token`.
* A registered redirect URI for the OAuth authorization-code step (same host/path you use when sending users to the MCP authorize URL).

## 1) Discover apps (`GET /v2/whitelabel/apps`)

Search the catalog for apps your users can connect (server-side). Example:

```http theme={null}
GET https://api.zapier.com/v2/whitelabel/apps?search=Slack
```

This catalog endpoint does not require authentication. Call it from your backend without an `Authorization` header.

Responses always use the same shape: an envelope with `data`, `links`, and `meta`, and each object in `data` has the same set of app fields. For MCP, the important ones are:

* `id` — app implementation id (used in URLs and MCP paths).
* `is_oauth` — if `true`, the third-party app uses an OAuth-style authorization step for the user.
* `has_fields` — if `true`, the user may need to enter extra identifiers (subdomain, instance URL, etc.) before or instead of OAuth.
* `links.mcp_authorize_url` — start of the MCP OAuth authorize flow.
* `links.mcp_server_url` — MCP server base URL for that app.

Example response:

```json theme={null}
{
  "data": [{
    "type": "app",
    "id": "SlackCLIAPI",
    "title": "Slack",
    "is_oauth": true,
    "has_fields": false,
    "links": {
      "mcp_authorize_url": "https://connect.zapier.com/oauth/authorize",
      "mcp_server_url": "https://mcp.zapier.com/api/v1/connect/SlackCLIAPI"
    }
  }],
  "links": { "next": null, "previous": null },
  "meta": { "count": 1, "limit": 10, "offset": 0 }
}
```

### Custom Connect domain

If Zapier provisions a custom subdomain for ConnectApp, replace the origin of `mcp_authorize_url` with that host before sending users to authorize. Keep the path unchanged.

## 2) JWT → connect token

Follow [Token exchange](../implementation/token-exchange), pattern B (MCP): exchange the partner-signed JWT for a connect token (`requested_token_type=urn:ietf:params:oauth:token-type:connect-token`, `scope=connection:write`). You must send `resource=<mcp_server_url>` on that `POST /oauth/token` request. Use the exact same URL as the `resource` query parameter in step 3. The connect token is returned in the JSON `access_token` field.

## 3) Send the user to `mcp_authorize_url`

Redirect the browser (or open a popup / new tab) to `mcp_authorize_url`. All of the parameters in the list below are required for this flow. You must also send every standard OAuth authorize parameter your client registration requires, typically `client_id` and `response_type=code` at minimum, plus any others indicated by Discovery via OAuth metadata below.

* `token` — the connect token from step 2 (Zapier-specific; in addition to standard OAuth parameters).
* `resource` — the app’s `mcp_server_url`.
* `redirect_uri` — your registered callback.
* `state` — random value you verify on return (CSRF protection).
* `scope` — must be `mcp:run`.

Example query shape:

```
https://connect.zapier.com/oauth/authorize?
  token=<CONNECT_TOKEN>
  &resource=<MCP_SERVER_URL>
  &redirect_uri=https://your-app.com/callback
  &state=<RANDOM_STATE>
  &scope=mcp:run
  &client_id=...
  &response_type=code
```

After the user completes consent, Zapier redirects to `redirect_uri` with `code`, `state`, and `connection_id`.

* `code` — OAuth authorization code. Exchange it for the MCP access token in step 4.
* `state` — the value you sent in step 3. Verify it matches (CSRF protection).
* `connection_id` — UUID for the underlying Zapier connection just created. This is the same auth as `authentication_id` in the [Embedded Actions Connection Flow](../implementation/connection-flow), exposed here as the public UUID so you can reuse a single connection across MCP and Embedded Actions without re-auth.

### Popup or new tab

If you open authorize in a secondary window, Zapier still redirects **that window** to `redirect_uri`. Use `postMessage` from your callback page to notify the opener, then close the window, if you want to avoid a full-page navigation in your primary app.

## 4) Exchange `code` for MCP access token

`POST https://zapier.com/oauth/token` with `grant_type=authorization_code`, the `code`, `client_id`, `client_secret`, and the same `redirect_uri` as step 3.

The response includes `access_token` (MCP bearer), `refresh_token`, and `expires_in`. Use the MCP access token (not the connect token) as `Authorization: Bearer` when talking to the MCP server.

## 5) Refresh the MCP access token

When MCP requests return HTTP `401`, refresh:

```bash theme={null}
curl -X POST https://zapier.com/oauth/token \
  -d grant_type=refresh_token \
  -d refresh_token=<REFRESH_TOKEN> \
  -d client_id=<ZAPIER_CLIENT_ID> \
  -d client_secret=<ZAPIER_CLIENT_SECRET>
```

## 6) Call the MCP server (Streamable HTTP)

The MCP server at `mcp_server_url` supports Streamable HTTP. Pass the MCP access token as the Bearer token.

Example using the official MCP TypeScript SDK:

```typescript theme={null}
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";

const transport = new StreamableHTTPClientTransport(new URL(app.links.mcp_server_url), {
  requestInit: {
    headers: { Authorization: `Bearer ${mcpAccessToken}` },
  },
});

const client = new Client({ name: "my-app", version: "1.0.0" });
await client.connect(transport);

const { tools } = await client.listTools();
const result = await client.callTool({
  name: "example_tool_name",
  arguments: { example_key: "example_value" },
});

await client.close();
```

## Discovery via OAuth metadata (optional)

Clients can discover authorization configuration without hardcoding `mcp_authorize_url`:

1. **Protected Resource Metadata** ([RFC 9728](https://www.rfc-editor.org/rfc/rfc9728)): insert `/.well-known/oauth-protected-resource` between the host and path of `mcp_server_url`.

   Example:

   ```http theme={null}
   GET https://mcp.zapier.com/.well-known/oauth-protected-resource/api/v1/connect/SlackCLIAPI
   ```

   Example JSON body (illustrative):

   ```json theme={null}
   {
     "resource": "https://mcp.zapier.com/api/v1/connect/SlackCLIAPI",
     "authorization_servers": ["https://connect.zapier.com"],
     "scopes_supported": ["mcp:run"]
   }
   ```

2. **Authorization Server Metadata** ([RFC 8414](https://www.rfc-editor.org/rfc/rfc8414)) for `https://connect.zapier.com`:

   ```http theme={null}
   GET https://connect.zapier.com/.well-known/oauth-authorization-server
   ```

<Note>
  **Non-standard authorize parameter:** The authorization endpoint requires `token=<connect_token>` (the connect token from the JWT exchange) in addition to normal OAuth query parameters for your client. Plan your authorize URLs accordingly.
</Note>

## Removing an MCP server and connection

To delete a user's MCP server and the connection that was created during the authorization flow, revoke the MCP refresh token by calling the standard OAuth revocation endpoint:

```bash theme={null}
curl -X POST https://zapier.com/oauth/revoke \
  -d token=<MCP_REFRESH_TOKEN> \
  -d client_id=<ZAPIER_CLIENT_ID> \
  -d client_secret=<ZAPIER_CLIENT_SECRET>
```

Both the MCP server and the underlying connection are removed immediately. The user will need to complete the full connection and authorization flow again to restore access.

## Security notes

* Keep `client_secret`, user access tokens, connect tokens, and MCP refresh tokens on the server. Only the short-lived browser steps should touch the connect token and authorization `code`.
* Validate `state` on callback. Reject mismatches.
* Prefer short-lived partner JWTs and rotate signing keys using JWKS.

## Reference implementation

Download a minimal CLI chat that demonstrates the full flow above — JWT exchange, browser-based authorization, and an AI-powered chat using MCP tools — built with the [Vercel AI SDK](https://sdk.vercel.ai/) and the official [MCP TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk):

<Card title="wl-mcp-demo.zip" icon="download" href="/assets/wl-mcp-demo.zip">
  Single-file TypeScript demo with `package.json`, `.env.example`, and README.
</Card>

The demo uses any OpenAI-compatible LLM provider and handles token persistence so subsequent runs skip browser authorization. See the included README for setup and configuration.

## Related guides

* [Token exchange](../implementation/token-exchange)
* [Connection flow](../implementation/connection-flow)
* [Error handling](../implementation/error-handling)
* [Embedded triggers](./embedded-triggers)
* [Embedded actions](./embedded-actions)
