
Product
Introducing Socket Firewall Enterprise: Flexible, Configurable Protection for Modern Package Ecosystems
Socket Firewall Enterprise is now available with flexible deployment, configurable policies, and expanded language support.
@zapier/mcp-integration
Advanced tools
SDK for using remote Model Context Protocol (MCP) servers in/as Zapier integrations
SDK for integrating with Model Context Protocol (MCP) servers, designed for use in Zapier integrations.
Install the package via npm:
npm install @zapier/mcp-integration
zcache via https://admin.zapier.com/nexus/gargoyle/ for the CLI App: app_id found in your .zapierapprc file after running zapier register.Make sure your tsconfig.json includes .json files:
{
"include": ["src/**/*", "src/*.json"]
}
Make sure your .zapierapprc includes the .json files:
{
"includeInBuild": ["dist/.*.json"]
}
Here's a minimal working example:
Create src/mcp.ts:
import { Proxy } from '@zapier/mcp-integration';
import packageJson from '../package.json' with { type: 'json' };
export const mcp = new Proxy({
name: packageJson.name,
version: packageJson.version,
serverUrl: process.env.SERVER_URL,
transport: 'sse', // or 'streamable'
});
Update src/index.ts:
import { defineApp } from 'zapier-platform-core';
import { mcp } from './mcp.js';
export default defineApp({
...mcp.defineApp(),
triggers: {
my_trigger: {
noun: 'Item',
display: {
label: 'New Item',
description: 'Triggers when a new item is available.',
},
operation: {
perform: async (z, bundle) => {
// Call MCP tool
return await mcp.callTool({
name: 'list_items',
arguments: {},
});
},
},
},
},
});
Use the CLI to automatically generate actions from your MCP tools:
npx @zapier/mcp-integration generate
This creates complete Zapier actions from your MCP tools automatically.
You can use @zapier/mcp-integration in two ways:
Use MCP for authentication and all actions:
// src/mcp.ts
export const mcp = new Proxy({
name: packageJson.name,
version: packageJson.version,
serverUrl: process.env.SERVER_URL,
transport: process.env.TRANSPORT,
});
// src/index.ts
export default defineApp({
...mcp.defineApp(), // Includes auth + actions
});
Handle authentication yourself, use MCP for some actions:
// src/mcp.ts
export const mcp = new Proxy({
name: packageJson.name,
version: packageJson.version,
serverUrl: process.env.SERVER_URL,
transport: process.env.TRANSPORT,
auth: { type: 'oauth' },
});
// src/index.ts
export default defineApp({
...mcp.defineApp({ handleAuth: false }),
authentication: yourAuthConfig,
});
const perform = async (z: ZObject, bundle: Bundle) => {
const result = await mcp.callTool({
name: 'my_tool',
arguments: { hello: 'world' },
parse: true, // Parse JSON responses (default: true)
error: true, // Throw on MCP errors (default: true)
filter: 'data.items', // JSONata filter (optional)
});
return result;
};
Use z.request() normally - authentication is handled automatically:
const perform = async (z: ZObject, bundle: Bundle) => {
const response = await z.request({
method: 'GET',
url: 'https://api.example.com/data',
});
return response.json;
};
The package includes a CLI tool that automatically generates Zapier actions from your MCP tools.
npx @zapier/mcp-integration generate [options]
Options:
--mcpModule <path> - Path to your MCP module (default: dist/mcp.js)--writeToDir <path> - Output directory (default: .)--tool <name> - Generate only specific tool (preserves existing files)# Generate all actions
npx @zapier/mcp-integration generate
# Custom paths
npx @zapier/mcp-integration generate --mcpModule dist/my-mcp.js --writeToDir ./src
Generate only specific tools during development:
# Generate only one tool - faster and preserves other files
npx @zapier/mcp-integration generate --tool notion-create-comment
Benefits:
src/
βββ tools.json # Complete tool definitions
βββ creates/
β βββ index.generated.ts # Export index
β βββ create_tool_name.generated.ts
βββ searches/
β βββ index.generated.ts
β βββ search_tool_name.generated.ts
βββ triggers/
βββ index.generated.ts
βββ trigger_tool_name.generated.ts
Important: All .generated.ts files are auto-created and shouldn't be manually edited.
Use transformers to customize how MCP tools become Zapier actions:
import {
defineTransform,
extendAction,
withNamedImport,
} from '@zapier/mcp-integration';
export const transformer = defineTransform({
transformCreate: (action, tool) => {
if (tool.name === 'notion-create-page') {
return extendAction(action)
.prependFields({
key: 'workspace_id',
dynamic: 'list_workspaces.id.name',
})
.replacePerform(withNamedImport('../utils/customPerform.js', 'perform'))
.build();
}
return action;
},
});
// Use in your proxy
export const mcp = new Proxy({
// ... config
transformer,
});
// Add fields
extendAction(action)
.prependFields({ key: 'token', type: 'string', required: true })
.appendFields({ key: 'debug', type: 'boolean', default: false })
.build();
// Modify fields
extendAction(action)
.modifyField('page_id', (field) => ({
...field,
dynamic: 'list_pages.id.name',
}))
.build();
// Replace all fields
extendAction(action)
.replaceInputFields(
{ key: 'url', type: 'string', required: true },
{ key: 'method', type: 'string', choices: ['GET', 'POST', 'PUT'] },
)
.build();
Organize fields in the UI with groups:
// Define groups and fields
export const inputFieldGroups = [
{ key: 'content', label: 'Content', emphasize: true },
{ key: 'formatting', label: 'Formatting', emphasize: false },
];
export const inputFields = [
{ key: 'title', type: 'string', required: true, group: 'content' },
{ key: 'text', type: 'text', required: true, group: 'content' },
{
key: 'formatting',
type: 'string',
list: true,
choices: { bold: 'Bold', italic: 'Italic' },
group: 'formatting',
},
];
// Use in transformer
extendAction(action)
.replaceInputFields(withNamedImport('../utils/myAction.js', 'inputFields'))
.replaceInputFieldGroups(
withNamedImport('../utils/myAction.js', 'inputFieldGroups'),
)
.build();
// Add common dropdowns
const addDropdowns = addCommonDynamicDropdowns({
page_id: 'list_pages.id.name',
user_id: 'list_users.id.name',
});
extendAction(action).transformAllFields(addDropdowns).build();
transformTool: (tool) => {
// Make read-only tools generate search/trigger instead of create
if (tool.name === 'get-user') {
return {
...tool,
annotations: { ...tool.annotations, readOnlyHint: true },
};
}
return undefined; // unchanged
},
const mcp = new Proxy({
// ... basic config
auth: { type: 'oauth' }, // Auto-configured
});
const mcp = new Proxy({
// ... basic config
auth: { type: 'bearer', token: 'your-token' },
});
sse - Server-Sent Events (recommended)streamable - HTTP streamingconst mcp = new Proxy({
// ... config
transport: 'sse', // or 'streamable'
debug: true, // Enable debug logging (streamable only)
});
await mcp.callTool({
name: 'my_tool',
arguments: { param: 'value' },
parse: true, // Parse JSON (default: true)
error: true, // Throw on errors (default: true)
filter: 'data.items', // JSONata filter
});
Main class for MCP integration.
new Proxy(config: Config)
Config:
name: string - Integration nameversion: string - Integration versionserverUrl: string - MCP server URLtransport: 'sse' | 'streamable' - Transport protocolauth?: AuthConfig - Authentication (optional)transformer?: Transformer - Action customization (optional)delegateAuth?: boolean - Delegate auth handling (default: false)debug?: boolean - Enable debug logging (optional)defineApp(options?: AppOptions): AppReturns Zapier app configuration.
Options:
handleAuth?: boolean - Handle authentication (default: true)callTool(options: CallToolOptions): Promise<any>Call an MCP tool.
Options:
name: string - Tool namearguments: object - Tool argumentsparse?: boolean - Parse JSON (default: true)error?: boolean - Throw on errors (default: true)filter?: string - JSONata filterlistTools(params?) - List tools with paginationlistAllTools() - List all tools (auto-pagination)getTool(name) - Get specific toolgetServerVersion() - Get server versionauthorizeUrl(z, bundle) - Get authorization URLgetAccessToken(z, bundle) - Exchange code for tokensrefreshAccessToken(z, bundle) - Refresh expired tokensdefineTest() - Connection test functiondefineConnectionLabel() - Connection label generatorclose() - Close MCP clientconfigure(config) - Update configurationdefineTransform(transformer: Transformer): TransformerCreate action transformer.
Transformer:
transformTool?: (tool) => Tool | undefined - Transform tool before generationtransformCreate?: (action, tool) => Create | undefined - Customize createstransformSearch?: (action, tool) => Search | undefined - Customize searchestransformTrigger?: (action, tool) => Trigger | undefined - Customize triggersextendAction<T>(action: T): ActionExtender<T>Fluent API for modifying actions.
Methods:
prependFields(...fields) - Add fields at startappendFields(...fields) - Add fields at endinsertFieldsAfter(key, ...fields) - Insert fields after keyreplaceInputFields(...fields) - Replace all fieldsreplaceInputFieldGroups(groups) - Replace field groupsmodifyField(key, modifier) - Modify specific fieldtransformAllFields(transformer) - Transform all fieldsreplacePerform(namedImport) - Replace perform functionreplaceDescription(description) - Change descriptionbuild() - Return modified actionaddCommonDynamicDropdowns(mappings) - Add dropdowns to fieldswithNamedImport(path, name) - Create named import referenceconvertInputSchemaToFields(schema) - Convert MCP schema to Zapier fields// src/mcp.ts
import { Proxy, defineTransform, extendAction } from '@zapier/mcp-integration';
import packageJson from '../package.json' with { type: 'json' };
const transformer = defineTransform({
transformCreate: (action, tool) => {
// Add workspace selection to all creates
return extendAction(action)
.prependFields({
key: 'workspace_id',
dynamic: 'list_workspaces.id.name',
required: true,
})
.build();
},
});
export const mcp = new Proxy({
name: packageJson.name,
version: packageJson.version,
serverUrl: process.env.SERVER_URL,
transport: 'sse',
transformer,
});
// src/index.ts
import { defineApp } from 'zapier-platform-core';
import { mcp } from './mcp.js';
export default defineApp({
...mcp.defineApp(),
// Generated actions will be automatically included
// Custom triggers for dropdowns
triggers: {
list_workspaces: {
noun: 'Workspace',
display: { label: 'New Workspace', description: 'For dropdowns' },
operation: {
perform: async (z, bundle) => {
const workspaces = await mcp.callTool({
name: 'list-workspaces',
arguments: {},
filter: 'content[0].json.data',
});
return workspaces.map((w) => ({ id: w.id, name: w.name }));
},
},
},
},
});
// src/utils/createPagePerform.ts
export const perform = async (z: ZObject, bundle: Bundle) => {
const { workspace_id, title, content, template } = bundle.inputData;
try {
if (!workspace_id) throw new Error('Workspace required');
if (!title?.trim()) throw new Error('Title cannot be empty');
const result = await mcp.callTool({
name: 'notion-create-page',
arguments: {
workspace_id,
title: title.trim(),
content,
metadata: {
template_used: template || 'blank',
created_by: 'zapier',
},
},
filter: 'content[0].json',
});
return {
id: result.id,
title: result.properties?.title || title,
url: result.url,
created_at: new Date().toISOString(),
};
} catch (error) {
z.console.error('Page creation failed:', error);
throw new Error(`Failed to create page: ${error.message}`);
}
};
// src/utils/commentAction.ts
export const inputFieldGroups = [
{ key: 'content', label: 'Content', emphasize: true },
{ key: 'formatting', label: 'Text Formatting', emphasize: false },
];
export const inputFields = [
{
key: 'page_id',
label: 'Page',
dynamic: 'list_pages.id.name',
required: true,
group: 'content',
},
{
key: 'text_content',
label: 'Comment Text',
type: 'text',
required: true,
group: 'content',
},
{
key: 'formatting',
label: 'Text Formatting',
type: 'string',
list: true,
choices: {
bold: 'Bold',
italic: 'Italic',
underline: 'Underline',
},
group: 'formatting',
},
];
export const perform = async (z: ZObject, bundle: Bundle) => {
const formattingOptions = bundle.inputData.formatting || [];
const richTextObject = {
type: 'text',
text: { content: bundle.inputData.text_content },
annotations: {
bold: formattingOptions.includes('bold'),
italic: formattingOptions.includes('italic'),
underline: formattingOptions.includes('underline'),
},
};
return await mcp.callTool({
name: 'notion-create-comment',
arguments: {
parent: bundle.inputData.page_id,
rich_text: [richTextObject],
},
});
};
This package includes comprehensive TypeScript support:
import { Proxy, defineTransform, extendAction } from '@zapier/mcp-integration';
// All types are automatically inferred
const mcp = new Proxy({
name: 'my-integration',
version: '1.0.0',
serverUrl: process.env.SERVER_URL!,
transport: 'sse',
});
// Tool calls are properly typed
const result = await mcp.callTool({
name: 'my_tool',
arguments: { param: 'value' },
});
The package provides full TypeScript definitions for all exported functions and classes.
This package is part of the Zapier MCP integration project. For issues and contributions, please visit the GitLab repository.
MIT Β© Zapier
FAQs
SDK for using remote Model Context Protocol (MCP) servers in/as Zapier integrations
The npm package @zapier/mcp-integration receives a total of 61 weekly downloads. As such, @zapier/mcp-integration popularity was classified as not popular.
We found that @zapier/mcp-integration demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago.Β It has 306 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Product
Socket Firewall Enterprise is now available with flexible deployment, configurable policies, and expanded language support.

Security News
Open source dashboard CNAPulse tracks CVE Numbering Authoritiesβ publishing activity, highlighting trends and transparency across the CVE ecosystem.

Product
Detect malware, unsafe data flows, and license issues in GitHub Actions with Socketβs new workflow scanning support.