The Customer.io MCP connector routes your AI agent's tool calls to Customer.io's own MCP server through Scalekit. Each user signs in to Customer.io once, and Scalekit stores and refreshes their tokens, so your agent never handles credentials. It comes with 8 tools.
- Tools
- 8
- What they doRead · write · destructive
- 6 · 0 · 26 read0 write2 destructive
- Users sign in with
- OAuth
- OAuth app
- Scalekit's or your own
Setup
Install the SDK
Terminal window npm install @scalekit-sdk/node dotenvTerminal window pip install scalekit-sdk-python python-dotenvSet your credentials
Add your Scalekit credentials to your
.envfile. Find values in app.scalekit.com > Developers > API Credentials..env SCALEKIT_ENVIRONMENT_URL=<your-environment-url>SCALEKIT_CLIENT_ID=<your-client-id>SCALEKIT_CLIENT_SECRET=<your-client-secret>Create the Customer.io MCP connection
In AgentKit > Connections, create a Customer.io MCP connection. The name you give it is the
connection_nameyour code passes. See Configure connections.Scalekit credentials are available for Customer.io MCP server, so you don't need to register an OAuth app. To show your own app on the consent screen, use your own credentials instead.
Use your own OAuth app
Customer.io MCP uses Dynamic Client Registration (DCR) — no client ID or secret is required. The only step is creating a connection in Scalekit and authorizing your Customer.io account.
-
Create a connection in Scalekit
- In the Scalekit dashboard, go to AgentKit → Connections → Create Connection.
- Search for Customer.io MCP and click Create.
- Note the Connection name — use this as
connection_namein your code (e.g.,customeriomcp).
-
Authorize your Customer.io account
Generate an authorization link and open it in a browser to complete the Customer.io OAuth flow.
The user is redirected to Customer.io to sign in and grant access. Scalekit stores the token and injects it automatically into every tool call — no further configuration is needed.
-
Authorize a user and make your first call
quickstart.mts import { ScalekitClient } from '@scalekit-sdk/node'import 'dotenv/config'import { createInterface } from 'node:readline/promises'const scalekit = new ScalekitClient(process.env.SCALEKIT_ENVIRONMENT_URL,process.env.SCALEKIT_CLIENT_ID,process.env.SCALEKIT_CLIENT_SECRET,)const actions = scalekit.actionsconst connector = 'customeriomcp'const identifier = 'user_123'// Generate an authorization link for the userconst { link } = await actions.getAuthorizationLink({ connectionName: connector, identifier })console.log('Authorize Customer.io MCP:', link)const rl = createInterface({ input: process.stdin, output: process.stdout })await rl.question('Press Enter after authorizing...')rl.close()// Make your first callconst result = await actions.executeTool({connector,identifier,toolName: 'customeriomcp_cio_auth_status',toolInput: {},})console.log(result)Terminal window npx tsx quickstart.mtsquickstart.py import osfrom scalekit import ScalekitClientfrom dotenv import load_dotenvload_dotenv()scalekit_client = ScalekitClient(env_url=os.getenv("SCALEKIT_ENVIRONMENT_URL"),client_id=os.getenv("SCALEKIT_CLIENT_ID"),client_secret=os.getenv("SCALEKIT_CLIENT_SECRET"),)actions = scalekit_client.actionsconnection_name = "customeriomcp"identifier = "user_123"# Generate an authorization link for the userlink_response = actions.get_authorization_link(connection_name=connection_name,identifier=identifier,)print("Authorize Customer.io MCP:", link_response.link)input("Press Enter after authorizing...")# Make your first callresult = actions.execute_tool(tool_input={},tool_name="customeriomcp_cio_auth_status",connection_name=connection_name,identifier=identifier,)print(result)Terminal window python quickstart.pyEach user signs in once. See Authorize a user for the full flow and statuses.
Tools
Pass the exact name toexecute_toolcustomeriomcp_cio_auth_statusShow the active authentication state — authenticated user, account, and accessible workspaces.Read-onlyCio Auth Status
Show the active authentication state — authenticated user, account, and accessible workspaces. Call this to verify which Customer.io account is connected.
Inputs
This tool takes no inputs.
customeriomcp_cio_primePrint LLM-ready instructions for using the Customer.io API.Read-onlyCio Prime
Print LLM-ready instructions for using the Customer.io API. Call this first in a new task to load context about available endpoints and best practices.
Inputs
This tool takes no inputs.
customeriomcp_cio_read_apiRead from the Customer.io API (GET only).Read-onlyCio Read Api
Read from the Customer.io API (GET only). Use cio_schema first to find the correct path. Supports pagination, jq filtering, and dry_run preview.
Inputs
pathstringrequired- API path including placeholders, e.g. '/v1/environments/{environment_id}/campaigns'. Placeholders are substituted from params.
dry_runboolean- Validate and return the request without executing it.
jqstring- gojq expression to filter the response before returning. Use to trim large responses.
limitnumber- Page size.
pagenumber- Page number (1-indexed).
page_allboolean- Auto-paginate and return NDJSON for the full dataset.
paramsobject- Parameters object. Keys matching path placeholders are substituted; remaining keys become the query string.
customeriomcp_cio_schemaIntrospect the Customer.io API schema to discover endpoints, parameters, and response shapes.Read-onlyCio Schema
Introspect the Customer.io API schema to discover endpoints, parameters, and response shapes. Use this before calling cio_read_api or cio_write_api to find the correct path and placeholders.
Inputs
querystring- One of: '' (list resources), 'campaigns' (resource), 'campaigns.list' (resource.method), 'GET /v1/...' (method + path), or '/v1/...' (all methods for a path).
refreshboolean- Force re-download of API specs.
customeriomcp_cio_skills_listList available Customer.io agent skills — task-specific instruction manuals covering campaigns, segments, deliveries, analytics, and more.Read-onlyCio Skills List
List available Customer.io agent skills — task-specific instruction manuals covering campaigns, segments, deliveries, analytics, and more.
Inputs
refreshboolean- Force re-download of skills.
customeriomcp_cio_skills_readRead the full content of a specific Customer.io agent skill by path.Read-onlyCio Skills Read
Read the full content of a specific Customer.io agent skill by path. Use cio_skills_list to find available paths (e.g. 'campaigns', 'fly-api/campaigns.md').
Inputs
pathstringrequired- Skill path, e.g. 'campaigns' or 'campaigns/examples'. See cio_skills_list for available paths.
customeriomcp_cio_delete_apiDelete a resource via the Customer.io API (DELETE only).DestructiveCio Delete Api
Delete a resource via the Customer.io API (DELETE only). Always run with dry_run=true first to preview before executing.
Inputs
pathstringrequired- API path including placeholders, e.g. '/v1/environments/{environment_id}/campaigns/{campaign_id}'. Placeholders are substituted from params.
dry_runboolean- Validate and return the request without executing it.
jqstring- gojq expression to filter the response before returning.
paramsobject- Parameters object. Keys matching path placeholders are substituted; remaining keys become the query string.
customeriomcp_cio_write_apiWrite to the Customer.io API (POST, PUT, or PATCH).DestructiveCio Write Api
Write to the Customer.io API (POST, PUT, or PATCH). Always run with dry_run=true first to preview the request before executing.
Inputs
pathstringrequired- API path including placeholders, e.g. '/v1/environments/{environment_id}/campaigns'. Placeholders are substituted from params.
bodyobject- JSON request body.
dry_runboolean- Validate and return the request without executing it.
jqstring- gojq expression to filter the response before returning.
methodstring- HTTP method: POST, PUT, or PATCH. Defaults to POST.
paramsobject- Parameters object. Keys matching path placeholders are substituted; remaining keys become the query string.
No tools match.
Workflows
Check authentication status
Use customeriomcp_cio_auth_status to verify the connection and see the authenticated user, account, and accessible workspaces.
const status = await actions.executeTool({ connector: 'customeriomcp', identifier: 'user_123', toolName: 'customeriomcp_cio_auth_status', toolInput: {},});console.log(status);status = actions.execute_tool( connection_name="customeriomcp", identifier="user_123", tool_name="customeriomcp_cio_auth_status", tool_input={},)print(status)Read campaign data
Use customeriomcp_cio_read_api to fetch campaigns from a Customer.io environment. Call customeriomcp_cio_schema first to discover the correct API path and available parameters.
const campaigns = await actions.executeTool({ connector: 'customeriomcp', identifier: 'user_123', toolName: 'customeriomcp_cio_read_api', toolInput: { path: '/v1/environments/{environment_id}/campaigns', params: { environment_id: 'env_abc123' }, limit: 10, },});console.log(campaigns);campaigns = actions.execute_tool( connection_name="customeriomcp", identifier="user_123", tool_name="customeriomcp_cio_read_api", tool_input={ "path": "/v1/environments/{environment_id}/campaigns", "params": {"environment_id": "env_abc123"}, "limit": 10, },)print(campaigns)Create a campaign
Use customeriomcp_cio_write_api to create a new campaign. Always set dry_run: true first to validate the request before executing.
// Step 1 — dry run to validateconst preview = await actions.executeTool({ connector: 'customeriomcp', identifier: 'user_123', toolName: 'customeriomcp_cio_write_api', toolInput: { path: '/v1/environments/{environment_id}/campaigns', params: { environment_id: 'env_abc123' }, body: { name: 'Welcome Series', type: 'triggered' }, dry_run: true, },});console.log(preview);
// Step 2 — execute after confirming dry run looks correctconst result = await actions.executeTool({ connector: 'customeriomcp', identifier: 'user_123', toolName: 'customeriomcp_cio_write_api', toolInput: { path: '/v1/environments/{environment_id}/campaigns', params: { environment_id: 'env_abc123' }, body: { name: 'Welcome Series', type: 'triggered' }, },});console.log(result);# Step 1 — dry run to validatepreview = actions.execute_tool( connection_name="customeriomcp", identifier="user_123", tool_name="customeriomcp_cio_write_api", tool_input={ "path": "/v1/environments/{environment_id}/campaigns", "params": {"environment_id": "env_abc123"}, "body": {"name": "Welcome Series", "type": "triggered"}, "dry_run": True, },)print(preview)
# Step 2 — execute after confirming dry run looks correctresult = actions.execute_tool( connection_name="customeriomcp", identifier="user_123", tool_name="customeriomcp_cio_write_api", tool_input={ "path": "/v1/environments/{environment_id}/campaigns", "params": {"environment_id": "env_abc123"}, "body": {"name": "Welcome Series", "type": "triggered"}, },)print(result)