master-zapier-plan-draft/research/zapier/MCP-REFERENCE.md
George Lambert b4150c8250 Milestone 0: import zappier billing, Verae middleware, and Zapier research
Compose-ready workspace: packages/zappier (rate card, portal, Stripe),
packages/verae-zapier-middleware (timestamp + NATS), packages/verae-zapier
(CLI app), vendor/zapier-platform, and research/zapier vendor corpus.

Gate 0 structure checks pass. Product code and research are not yet wired.
2026-09-09 02:37:36 -04:00

362 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Zapier MCP function reference
**Grok start:** `db.platform_reference.findOne({ kind: "guide", key: "build-new-connector" })`
or [PLATFORM-REFERENCE.md](PLATFORM-REFERENCE.md). This file is the MCP branch.
Mongo: `db.platform_reference.find({ kind: "mcp_function" })` — one document per tool, with JSON Schema, typed inputs, outputs, internals, related tools, and code.
Hosted server: `https://mcp.zapier.com/api/v1/connect` (closed source, Streamable HTTP).
Plugin repo only: `repos/zapier-mcp` (skills + manifests).
Live input schemas captured in `raw/site-extras/zapier-mcp-tools-gumloop.json`.
Official docs still list **14** meta-tools. Live servers expose **17**: the 14 plus `list_zapier_connections`, `manage_zapier_connections`, and rolling-out `write_code_action`.
---
## Call graph
```
auto_provision_mcp (also runs on OAuth connect)
discover_zapier_actions ──► enable_zapier_action ──► manage_zapier_connections
│ │
└──────────────► inspect_zapier_actions ◄── list_zapier_connections
(repeat for enums / dynamic fields)
┌───────────────┴───────────────┐
▼ ▼
execute_zapier_read_action execute_zapier_write_action
│ │
└──────── write_code_action ────┘
Skills: list_zapier_skills → get_zapier_skill("zapier:onboarding")
create_zapier_skill / update_zapier_skill / delete_zapier_skill
Config UI: get_configuration_url
Feedback: send_feedback
```
Safety: reads run free; writes need explicit user approval after you show the payload.
Billing: each **successful** execute costs **2 Zapier tasks**. Meta-tools do not. Failures are free.
Never invent `selected_api` (Gmail is `GoogleMailV2CLIAPI`, not `GmailCLIAPI`) or action keys. Always `inspect_zapier_actions` first.
---
## Action management
### `discover_zapier_actions`
Search the 9,000+ app catalog for actions this server *could* enable. Call before saying an app is unavailable.
**Internals:** Catalog lookup (same directory as SDK `listApps` / `listActions`). No OAuth, no mutation. Returns `selected_api` that later tools require verbatim.
**Input**
```ts
type Input = {
app?: string; // Search by name. Omit for popular apps.
};
```
**Output (documented):** `{ apps: [{ app, selected_api, actions[] }] }`
**Related:** `enable_zapier_action`, `inspect_zapier_actions`, `manage_zapier_connections`
**SDK twin:** `zapier.listApps({ search })`, `zapier-sdk list-apps --search`
```ts
await client.callTool({
name: "discover_zapier_actions",
arguments: { app: "gmail" },
});
```
---
### `enable_zapier_action`
Add one action (or `*` / omit for all) for a catalog app to this server.
**Internals:** Writes mcp.zapier.com server config. If the user has no connection, returns `auth_url`. Does not call the partner API.
**Input**
```ts
type Input = {
selected_api: string; // e.g. "GoogleMailV2CLIAPI" from discover
app_display_name?: string; // "Gmail" — for friendly confirmations
action?: string; // key, or "*" / omit for all
};
```
**Output:** enabled action list, which execute tool to use (read vs write), optional `auth_url`.
**Related:** `discover_zapier_actions`, `inspect_zapier_actions`, `disable_zapier_action`, `manage_zapier_connections`
```ts
await client.callTool({
name: "enable_zapier_action",
arguments: {
selected_api: "GoogleMailV2CLIAPI",
app_display_name: "Gmail",
action: "find_email",
},
});
```
---
### `disable_zapier_action`
Remove one action, or every action for `selected_api`. Does not revoke the Zapier connection.
**Input**
```ts
type Input = {
selected_api: string;
app_display_name?: string;
action?: string; // omit = disable the whole app on this server
};
```
**Related:** `inspect_zapier_actions`, `enable_zapier_action`
---
### `inspect_zapier_actions`
**Call this first before every execute.** Lists enabled apps/actions and resolves dynamic fields.
**Internals:** Reads this server's enabled-action table. With `tool_name` + `enum_property` it hits the same Platform dynamic-dropdown endpoint as the visual builder. With parent `params` it returns `dynamic_properties_schema` for fields that depend on earlier answers (spreadsheet → worksheet). Does not run the partner action.
**Input**
```ts
type Input = {
selected_api?: string;
action?: string;
tool_name?: string; // collision-safe id from a prior inspect
connection_id?: number | string; // only if not using the default account
enum_property?: string; // field with is_dynamic_enum: true
enum_search?: string;
enum_cursor?: string;
params?: Record<string, unknown>; // parent values for dependent fields
};
```
**Output (documented):** apps → actions with `action`, `tool_name`, execute tool name, parameter schema (`is_dynamic_enum`, `dynamic_properties_depends_on`), `connections.default`, plus `dynamic_enum_values` / `dynamic_properties_schema` on follow-up calls.
**Related:** both `execute_*`, `discover_zapier_actions`, `list_zapier_connections`
**SDK twin:** `getActionInputFieldsSchema`, `list-action-input-field-choices`
```ts
await client.callTool({ name: "inspect_zapier_actions", arguments: {} });
await client.callTool({
name: "inspect_zapier_actions",
arguments: {
tool_name: "SlackCLIAPI.send_channel_message",
enum_property: "channel",
enum_search: "launches",
},
});
```
---
### `auto_provision_mcp`
One-shot setup from the user's **own** existing Zapier connections (not shared teammates'). Also runs automatically after OAuth connect. Returns enabled apps plus top Zap titles (skill ideas). No inputs.
**Related:** `inspect_zapier_actions`, `enable_zapier_action`
---
## Execution
### `execute_zapier_read_action`
Run a search / lookup / get. No confirmation required. **2 tasks** on success.
**Internals:** Maps to Zapier Platform search/read `perform` (`runAction({ actionType: "search"|"read" })`) using the user's default connection (or `connection_id`). `params``bundle.inputData`. Empty results = not found, not an error.
**Input**
```ts
type Input = {
selected_api: string;
action: string; // exact key from inspect — never guess
tool_name?: string; // preferred when keys collide across apps
connection_id?: number | string;
params?: Record<string, unknown>; // nest dynamic fields under dynamic_properties
};
```
**Output:** action-specific records (`results[]` or `data[]`). 401 → `manage_zapier_connections`.
**Related:** `inspect_zapier_actions`, `discover_zapier_actions`, `enable_zapier_action`
**SDK twin:** `repos/sdk/examples/by-app/*/find-*.ts`
```ts
await client.callTool({
name: "execute_zapier_read_action",
arguments: {
selected_api: "GoogleMailV2CLIAPI",
action: "find_email",
tool_name: "GoogleMailV2CLIAPI.find_email",
params: { query: "from:sarah@acme.com newer_than:7d" },
},
});
```
If the user said only a first name, do **not** take the first hit — list candidates.
---
### `execute_zapier_write_action`
Create / update / send. **Show the payload and wait for explicit approval.** **2 tasks** on success. Not rolled back.
**Input:** same shape as the read execute.
**Related:** `inspect_zapier_actions`, `execute_zapier_read_action`
**SDK twin:** `repos/sdk/examples/by-app/gmail/send-email.ts`
```ts
// 1) inspect + resolve channel enum 2) confirm with user 3) write
await client.callTool({
name: "execute_zapier_write_action",
arguments: {
selected_api: "SlackCLIAPI",
action: "send_channel_message",
tool_name: "SlackCLIAPI.send_channel_message",
params: { channel: "C01234567", text: "Release shipped, monitoring now" },
},
});
```
---
### `write_code_action` (rolling out)
Generate a sandboxed custom action when the catalog has no match. Auth is injected from the connected account — **never put secrets in `requirements`**. Same-name call overwrites.
**Internals:** Zapier generates code and runs later invokes in a sandbox with the app connection. Closest SDK analog is `zapier.fetch(url, { connection, method })`.
**Input**
```ts
type Input = {
selected_api: string;
code_action_name: string; // e.g. "list_channel_users"
requirements: string; // natural language; endpoint, filters, pagination
};
```
**Related:** `discover_zapier_actions`, `inspect_zapier_actions`
---
## Connections
### `list_zapier_connections`
List OAuth grants for one app. Default = the user's own accounts. Set `include_shared: true` only if they asked.
**Input**
```ts
type Input = {
selected_api: string;
include_shared?: boolean;
limit?: number; // 1100, default 20
cursor?: string;
};
```
**Output (documented):** `{ connections: [{ connection_id, title, owner, is_default, expired }], next_cursor? }`
**SDK twin:** `zapier.findFirstConnection`, `zapier-sdk find-first-connection`
---
### `manage_zapier_connections`
Mint an `auth_url` and/or set `default_connection_id`. An app **cannot execute** until it has a default connection. After the user finishes OAuth, list then optionally set default.
**Input**
```ts
type Input = {
selected_api: string; // verbatim from discover/inspect
app_display_name?: string;
default_connection_id?: number | string;
};
```
**SDK twin:** `zapier-sdk create-connection` / `get-connection-start-url`
---
## Skills, config, feedback
| Tool | Input | What it does |
|------|--------|----------------|
| `list_zapier_skills` | `{}` | Names + one-line descriptions. Catalog is dynamic. |
| `get_zapier_skill` | `{ name }` | Full Markdown. Packaged: `zapier:onboarding`. |
| `create_zapier_skill` | `{ name, description, skillDefinition }` | Persist Markdown. Lock IDs with `ZapierAction[app:action](param: "id", runtime)`. Resolve schemas via `inspect_zapier_actions` (tool text still says `list_enabled_zapier_actions`). |
| `update_zapier_skill` | `{ name, description?, skillDefinition? }` | Patch. |
| `delete_zapier_skill` | `{ name }` | Permanent. |
| `get_configuration_url` | `{}` | Dashboard URL for this server. |
| `send_feedback` | `{ feedback: string(12000), feedback_positive: boolean }` | Product inbox. |
Official first-run prompt:
```text
Run the Zapier onboarding skill using get_zapier_skill with name "zapier:onboarding" and follow its instructions.
```
---
## Client connection (TypeScript)
```ts
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
const transport = new StreamableHTTPClientTransport(
new URL("https://mcp.zapier.com/api/v1/connect"),
{ requestInit: { headers: { Authorization: `Bearer ${token}` } } },
);
const client = new Client({ name: "app", version: "1.0.0" });
await client.connect(transport);
const tools = await client.listTools();
```
Listed clients use OAuth to that same URL and never see the token.
---
## Plugin skills (not server tools)
In `repos/zapier-mcp/plugins/zapier/skills/`:
| Skill | When |
|-------|------|
| `zapier-onboard` | First connect / “what is Zapier MCP” |
| `zapier-demo` | One read action, live |
| `zapier-explore` | Role-tailored toolkit |
| `zapier-status` | Health / audit / diagnose |
Lifecycle rules (`zapier-lifecycle.mdc`): prefer native app MCP over Zapier when both exist; never call both.
---
## Reload
```bash
# refresh live schemas (optional)
# then:
source ~/.mcp-env
.venv/bin/python scripts/ingest-mcp-reference.py
```