Skip to main content

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 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/actions and the Zapier SDK documentation as applicable.

Flow overview

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): 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:
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:
{
  "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 (sub)domain 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, 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 and state. 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:
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:
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): insert /.well-known/oauth-protected-resource between the host and path of mcp_server_url. Example:
    GET https://mcp.zapier.com/.well-known/oauth-protected-resource/api/v1/connect/SlackCLIAPI
    
    Example JSON body (illustrative):
    {
      "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) for https://connect.zapier.com:
    GET https://connect.zapier.com/.well-known/oauth-authorization-server
    
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.

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:
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 and the official MCP TypeScript SDK:

wl-mcp-demo.zip

Single-file TypeScript demo with package.json, .env.example, and README.
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.