How to integrate Klaviyo MCP with Claude Agent SDK

Framework Integration Gradient
Klaviyo Logo
Claude Agent SDK Logo
divider

Introduction

This guide walks you through connecting Klaviyo to the Claude Agent SDK using the Composio tool router. By the end, you'll have a working Klaviyo agent that can add new subscribers to main email list, clone last week's campaign for reuse, estimate recipients for upcoming product launch, create back-in-stock alerts for a product through natural language commands.

This guide will help you understand how to give your Claude Agent SDK agent real control over a Klaviyo account through Composio's Klaviyo MCP server.

Before we dive in, let's take a quick look at the key ideas and tools involved.

TL;DR

Here's what you'll learn:
  • Get and set up your Claude/Anthropic and Composio API keys
  • Install the necessary dependencies
  • Initialize Composio and create a Tool Router session for Klaviyo
  • Configure an AI agent that can use Klaviyo as a tool
  • Run a live chat session where you can ask the agent to perform Klaviyo operations

What is Claude Agent SDK?

The Claude Agent SDK is Anthropic's official framework for building AI agents powered by Claude. It provides a streamlined interface for creating agents with MCP tool support and conversation management.

Key features include:

  • Native MCP Support: Built-in support for Model Context Protocol servers
  • Permission Modes: Control tool execution permissions
  • Streaming Responses: Real-time response streaming for interactive applications
  • Context Manager: Clean async context management for sessions

What is the Klaviyo MCP server, and what's possible with it?

The Klaviyo MCP server is an implementation of the Model Context Protocol that connects your AI agent and assistants like Claude, Cursor, etc directly to your Klaviyo account. It provides structured and secure access to your marketing campaigns, contact lists, and automation features, so your agent can perform actions like creating campaigns, managing subscribers, sending messages, and analyzing engagement—all on your behalf.

  • Automated campaign creation and sending: Instantly have your agent create new marketing campaigns, clone existing ones, and trigger campaign sends to targeted audiences.
  • Subscriber and list management: Add or update profiles in specific Klaviyo lists, subscribe contacts to marketing lists, and ensure your audience is always up to date.
  • Event and engagement tracking: Automatically record customer activities or bulk-create profile events to power segmentation and analytics.
  • Catalog and back-in-stock automation: Let your agent create product catalog categories, manage restock alerts, and help drive timely customer notifications about inventory.
  • Campaign recipient estimation and analytics: Start background jobs to estimate campaign reach and analyze how many recipients meet your targeting criteria before a send.

Supported Tools & Triggers

Tools
Add Profile to ListAdd profiles to a klaviyo list by profile ids or email addresses.
Assign campaign message templateCreates a non-reusable version of the template and assigns it to the message.
Bulk create client eventsUse the client-side endpoint with a public api key to track profile activity.
Bulk create eventsThis api endpoint creates or updates profiles by batching up to 1,000 events, with a 5mb payload limit.
Create back in stock subscriptionUse the server-side endpoint to subscribe to restock alerts, following the back in stock api guide.
Create campaignCreates a campaign given a set of parameters, then returns it.
Create campaign cloneClones an existing campaign, returning a new campaign based on the original with a new id and name.
Create Campaign Recipient Estimation JobStart an asynchronous task to estimate the number of recipients for a campaign.
Create campaign send jobTrigger a campaign to send asynchronously*rate limits*:burst: `10/s`steady: `150/m` **scopes:** `campaigns:write`
Create catalog categoryCreate a new catalog category.
Create catalog category relationships itemsCreate a new item relationship for the given category id.
Create catalog itemCreate a new catalog item.
Create catalog item relationships categoriesCreate a new catalog category relationship for the given item id.
Create catalog variantCreate a new variant for a related catalog item.
Create client back in stock subscriptionUse the endpoint for client-side back in stock notifications with a public api key.
Create client eventCreate client-side events to track profiles using a public api key, not for updating identifiers (server-side only).
Create client subscriptionEndpoint manages email/sms opt-ins using consent and requires public api key for client use.
Create couponCreates a new coupon.
Create coupon codeSynchronously creates a coupon code for the given coupon.
Create eventCreate or update a profile event with minimum identifiers and metric name.
Create listCreate a new list.
Create or update client profileUpdate user profiles without tracking using a public client-side api; use a private server-side api for identifier changes.
Create or update client push tokenThis endpoint for mobile sdks (ios & android) creates/updates push tokens using a public api key.
Create or Update ProfileCreate or update a profile in klaviyo with the given attributes.
Create or update push tokenMigrate or create push tokens with klaviyo's endpoint, utilizing their mobile sdks for ios & android.
Create profileCreate a new profile.
Create segmentCreate a segment.
Create tagSummary: instructions on creating a tag within an account's designated tag group with a maximum of 500 tags, with optional tag group specification.
Create tag groupCreate tag groups up to 50 per account, defaulting to non-exclusive unless specified.
Create tag relationships campaignsSummary: link a tag to campaigns, ensuring a limit of 100 tags per campaign.
Create tag relationships flowsAssign tags to flows using their ids in the request body, ensuring a flow is not linked to over 100 tags.
Create tag relationships listsSummary: a tag can be added to one or more lists, with a max of 100 tags per list.
Create tag relationships segmentsSummary: set tag associations with segments using the request body, limited to one tag per segment and up to 100 tags per segment.
Create templateSummary: custom html templates can be created unless an account reaches 1,000 template limit.
Create template cloneClone a template by its id, but cloning fails if account has 1,000+ templates.
Create template renderRender an email template with specific context and sparse fieldsets, then get html/plain text.
Create webhookCreate a new webhook*rate limits*:burst: `1/s`steady: `15/m` **scopes:** `webhooks:write`
Delete campaignDelete a campaign with the given campaign id.
Delete catalog categoryDelete a catalog category using the given category id.
Delete catalog category relationships itemsDelete item relationships for the given category id.
Delete catalog itemDelete a catalog item with the given item id.
Delete catalog item relationships categoriesDelete catalog category relationships for the given item id.
Delete catalog variantDelete a catalog item variant with the given variant id.
Delete couponDelete the coupon with the given coupon id.
Delete coupon codeDeletes a coupon code specified by the given identifier synchronously.
Delete flowDelete a flow with the given flow id.
Delete listDelete a list with the given list id.
Delete segmentDelete a segment with the given segment id.
Delete tagDelete the tag with the given tag id.
Delete tag groupDelete a specified tag group and its contents; associated resource links will be removed.
Delete tag relationships campaignsDisconnect a tag from campaigns using the campaign id(s) in the request body.
Delete tag relationships flowsRemove a tag's association with one or more flows.
Delete tag relationships listsRemove a tag's association with one or more lists.
Delete tag relationships segmentsUse the request body to de-associate a tag from specified segment ids.
Delete templateDelete a template with the given template id.
Delete webhookDelete a webhook with the given id.
Get accountRetrieve a single account object by its account id.
Get accountsUse a private api key to fetch an associated account's details like contact info, timezone, and currency, as well as validate the key.
Get bulk profile import jobGet a bulk profile import job with the given job id.
Get bulk profile import job errorsGet import errors for the bulk profile import job with the given id.
Get bulk profile import job listsGet list for the bulk profile import job with the given id.
Get bulk profile import job profilesGet profiles for the bulk profile import job with the given id.
Get bulk profile import job relationships listsGet list relationship for the bulk profile import job with the given id.
Get bulk profile import job relationships profilesGet profile relationships for the bulk profile import job with the given id.
Get bulk profile import jobsGet all bulk profile import jobs.
Get CampaignRetrieve a specific campaign by its id from klaviyo.
Get campaign campaign messagesReturn all messages that belong to the given campaign.
Get campaign messageReturns a specific message based on a required id.
Get campaign message campaignReturn the related campaign*rate limits*:burst: `10/s`steady: `150/m` **scopes:** `campaigns:read`
Get campaign message relationships campaignReturns the id of the related campaign*rate limits*:burst: `10/s`steady: `150/m` **scopes:** `campaigns:read`
Get campaign message relationships templateReturns the id of the related template*rate limits*:burst: `10/s`steady: `150/m` **scopes:** `campaigns:read` `templates:read`
Get campaign message templateReturn the related template*rate limits*:burst: `10/s`steady: `150/m` **scopes:** `campaigns:read` `templates:read`
Get campaign recipient estimationGet estimated recipients for a given campaign id using `create campaign recipient estimation job`.
Get campaign recipient estimation jobRetrieve the status of a recipient estimation job triggered with the `create campaign recipient estimation job` endpoint.
Get campaign relationships campaign messagesReturns the ids of all messages associated with the given campaign.
Get campaign relationships tagsReturns the ids of all tags associated with the given campaign.
Get CampaignsRetrieve campaigns from your klaviyo account.
Get campaign send jobGet a campaign send job*rate limits*:burst: `10/s`steady: `150/m` **scopes:** `campaigns:read`
Get campaign tagsReturn all tags that belong to the given campaign.
Get catalog categoriesRetrieve up to 100 account catalog categories, sortable by creation date.
Get catalog categoryGet a catalog category with the given category id.
Get catalog category itemsRetrieve up to 100 sorted items per request from a category using the category id.
Get catalog category relationships itemsGet all items in the given category id.
Get catalog itemGet a specific catalog item with the given item id.
Get catalog item categoriesRetrieve the catalog categories for an item by id, sorted by 'created' date, with a 100-category maximum per request.
Get catalog item relationships categoriesGet all catalog categories that a particular item is in.
Get catalog itemsRetrieve up to 100 sorted catalog items per account, with `$custom` integration and `$default` type.
Get catalog item variantsRetrieve up to 100 variants per request for a specific item id, sortable by creation date.
Get catalog variantGet a catalog item variant with the given variant id.
Get catalog variantsRetrieve up to 100 account variants per request, sortable by creation date.
Get couponGet a specific coupon with the given coupon id.
Get coupon codeReturns a coupon code specified by the given identifier.
Get coupon code bulk create jobGet a coupon code bulk create job with the given job id.
Get coupon code bulk create jobsGet all coupon code bulk create jobs.
Get coupon code relationships couponGets a list of coupon code relationships associated with the given coupon id*rate limits*:burst: `75/s`steady: `700/m` **scopes:** `coupon-codes:read`
Get coupon codesObtains coupon codes using necessary coupon or profile filters.
Get coupon codes for couponGets a list of coupon codes associated with the given coupon id*rate limits*:burst: `75/s`steady: `700/m` **scopes:** `coupon-codes:read`
Get coupon for coupon codeGet the coupon associated with a given coupon code id.
Get coupon relationships coupon codesGets the coupon relationship associated with the given coupon code id*rate limits*:burst: `75/s`steady: `700/m` **scopes:** `coupons:read`
Get couponsGet all coupons in an account.
Get create categories jobGet a catalog category bulk create job with the given job id.
Get create categories jobsGet all catalog category bulk create jobs.
Get create items jobGet a catalog item bulk create job with the given job id.
Get create items jobsGet all catalog item bulk create jobs.
Get create variants jobGet a catalog variant bulk create job with the given job id.
Get create variants jobsGet all catalog variant bulk create jobs.
Get delete categories jobGet a catalog category bulk delete job with the given job id.
Get delete categories jobsGet all catalog category bulk delete jobs.
Get delete items jobGet a catalog item bulk delete job with the given job id.
Get delete items jobsGet all catalog item bulk delete jobs.
Get delete variants jobGet a catalog variant bulk delete job with the given job id.
Get delete variants jobsGet all catalog variant bulk delete jobs.
Get eventGet an event with the given event id.
Get event metricGet the metric for an event with the given event id.
Get event profileGet the profile associated with an event with the given event id.
Get event relationships metricGet a list of related metrics for an event*rate limits*:burst: `350/s`steady: `3500/m` **scopes:** `events:read` `metrics:read`
Get event relationships profileGet profile [relationships](https://developers.
Get eventsGet all events in an account requests can be sorted by the following fields: `datetime`, `timestamp` returns a maximum of 200 events per page.
Get flowGet a flow with the given flow id.
Get flow actionGet a flow action from a flow with the given flow action id.
Get flow action for messageGet the flow action for a flow message with the given message id.
Get flow action messagesRetrieve up to 50 flow messages per request by action id, sortable by various fields, with ascending/descending options, and paginated using `page[size]` and `page[number]`.
Get flow action relationships flowGet the flow associated with the given action id.
Get flow action relationships messagesRetrieves up to 50 flow message relationships per request for a specified flow action id, with cursor pagination.
Get flow flow actionsGet all flow actions associated with the given flow id.
Get flow for flow actionGet the flow associated with the given action id.
Get flow messageGet the flow message of a flow with the given message id.
Get flow message relationships actionGet the [relationship](https://developers.
Get flow message relationships templateReturns the id of the related template*rate limits*:burst: `3/s`steady: `60/m` **scopes:** `templates:read`
Get flow message templateReturn the related template*rate limits*:burst: `3/s`steady: `60/m` **scopes:** `templates:read`
Get flow relationships flow actionsRetrieve all flow action relationships for a specific flow id, sortable by `id`, `status`, `created`, `updated`.
Get flow relationships tagsReturn the tag ids of all tags associated with the given flow.
Get flowsGet all flows in an account.
Get flow tagsReturn all tags associated with the given flow id.
Get formGet the form with the given id.
Get form for form versionGet the form associated with the given form version.
Get form id for form versionGet the id of the form associated with the given form version.
Get formsGet all forms in an account.
Get form versionGet the form version with the given id.
Get imageGet the image with the given image id.
Get imagesGet all images in an account.
Get listApi allows 75 req/sec and 700 req/min, but with 'profile count' param, it's 1 req/sec and 15 req/min.
Get list profilesRetrieve profiles in a list by id, filterable by email/phone/push token/join date, sortable by join date.
Get list relationships profilesGet profile membership [relationships](https://developers.
Get list relationships tagsReturns the tag ids of all tags associated with the given list.
Get ListsRetrieve marketing lists from your klaviyo account.
Get list tagsReturn all tags associated with the given list id.
Get metricGet a metric with the given metric id.
Get metricsGet all metrics in an account.
Get profileGet the profile with the given profile id.
Get profile listsGet list memberships for a profile with the given profile id.
Get profile relationships listsGet list memberships for a profile with the given profile id.
Get profile relationships segmentsGet segment membership relationships for a profile with the given profile id.
Get ProfilesRetrieve profiles from your klaviyo account.
Get profile segmentsGet segment memberships for a profile with the given profile id.
Get segmentFetch a segment by id with default rates of 75/s and 700/m, or with `additional-fields` at 1/s and 15/m.
Get segment profilesRetrieve profiles in a segment by id, filtering by email, phone, token, or join date, and sorting by join date.
Get segment relationships profilesGet all profile membership [relationships](https://developers.
Get segment relationships tagsIf `related resource` is `tags`, returns the tag ids of all tags associated with the given segment id.
Get segmentsFetch segments from an account with filters like `name`, `created`, and `updated`.
Get segment tagsReturn all tags associated with the given segment id.
Get tagRetrieve the tag with the given tag id.
Get tag groupRetrieve the tag group with the given tag group id.
Get tag group relationships tagsReturns the tag ids of all tags inside the given tag group.
Get tag groupsRetrieve up to 25 tag groups per account, sortable/filterable by specific attributes.
Get tag group tagsReturn the tags for a given tag group id.
Get tag relationships campaignsReturns the ids of all campaigns associated with the given tag.
Get tag relationships flowsReturns the ids of all flows associated with the given tag.
Get tag relationships listsReturns the ids of all lists associated with the given tag.
Get tag relationships segmentsReturns the ids of all segments associated with the given tag.
Get tag relationships tag groupReturns the id of the tag group related to the given tag.
Get tagsRetrieve up to 50 account tags at once, filterable/sortable by name or id, with cursor pagination.
Get tag tag groupReturns the tag group resource for a given tag id.
Get templateGet a template with the given template id.
Get templatesRetrieve account templates with sorting options (`id`, `name`, `created`, `updated`).
Get update categories jobGet a catalog category bulk update job with the given job id.
Get update categories jobsGet all catalog category bulk update jobs.
Get update items jobGet a catalog item bulk update job with the given job id.
Get update items jobsGet all catalog item bulk update jobs.
Get update variants jobGet a catalog variate bulk update job with the given job id.
Get update variants jobsGet all catalog variant bulk update jobs.
Get version ids for formGet the ids of the form versions for the given form.
Get versions for formGet the form versions for the given form.
Get webhookGet the webhook with the given id.
Get webhooksGet all webhooks in an account.
Get webhook topicGet the webhook topic with the given id.
Get webhook topicsGet all webhook topics in a klaviyo account.
Merge profilesQueue a task to merge one source profile into a destination profile using their ids.
Query campaign valuesReturns the requested campaign analytics values data*rate limits*:burst: `1/s`steady: `2/m`daily: `225/d` **scopes:** `campaigns:read`
Query flow seriesReturns the requested flow analytics series data*rate limits*:burst: `1/s`steady: `2/m`daily: `225/d` **scopes:** `flows:read`
Query flow valuesReturns the requested flow analytics values data*rate limits*:burst: `1/s`steady: `2/m`daily: `225/d` **scopes:** `flows:read`
Query metric aggregatesThe klaviyo endpoint fetches metric events, handling json requests for custom data queries, sorting, and filtering; offers grouping and time-based filters; requires adherence to rate limits (3 requests per second, 60 per minute) under 'metrics:read'.
Remove Profile from ListRemove profiles from a klaviyo list by profile ids or email addresses.
Request profile deletionTo delete a profile, use only one identifier: email, phone number, or id.
Spawn bulk profile import jobInitiate a job to create/update a batch of profiles, up to 10,000 with a max size of 5mb per request.
Spawn coupon code bulk create jobCreate a coupon-code-bulk-create-job to bulk create a list of coupon codes.
Spawn create categories jobCreate bulk job for up to 100 catalog categories with a 5mb size limit and a max of 500 concurrent jobs.
Spawn create items jobCreate batches of up to 100 catalog items with a 5mb size limit using the bulk job, which allows 500 concurrent jobs.
Spawn create variants jobInitiate a job to bulk create up to 100 catalog variants, with a 5mb payload size limit.
Spawn delete categories jobDelete multiple catalog categories in bulk, with a limit of 100 per request and a 5mb payload size.
Spawn delete items jobDelete batches of catalog items with a bulk job, max 100 items/request, 5mb size limit, and up to 500 concurrent jobs.
Spawn delete variants jobDelete multiple catalog variants with a bulk job, max 100 per request, 5mb size limit.
Spawn update categories jobCreate a job to bulk update up to 100 categories, with a 5mb size limit and a maximum of 500 concurrent jobs.
Spawn update items jobYou can bulk update up to 100 catalog items with a 5mb payload limit.
Spawn update variants jobCreate a job to bulk update up to 100 catalog variants with a 5mb payload limit.
Subscribe profilesThe api supports double opt-in for marketing, with 'historical import' bypassing consent.
Suppress profilesSuppress profiles by email, segment, or list id to stop email marketing, regardless of consent.
Unregister client push tokenThis endpoint unsubscribes a push token, for use with klaviyo's mobile sdks and a public api key.
Unsubscribe profilesOpt-out profiles from email or sms marketing.
Unsuppress profilesRemove 'user suppressed' blocks on profiles manually via email, segment, or list id.
Update CampaignUpdate a campaign with the specified attributes.
Update campaign messageUpdate a campaign message*rate limits*:burst: `10/s`steady: `150/m` **scopes:** `campaigns:write`
Update campaign send jobPermanently cancel the campaign, setting the status to canceled or revert the campaign, setting the status back to draft*rate limits*:burst: `10/s`steady: `150/m` **scopes:** `campaigns:write`
Update catalog categoryUpdate a catalog category with the given category id.
Update catalog category relationships itemsUpdate item relationships for the given category id.
Update catalog itemUpdate a catalog item with the given item id.
Update catalog item relationships categoriesUpdate catalog category relationships for the given item id.
Update catalog variantUpdate a catalog item variant with the given variant id.
Update coupon*rate limits*:burst: `3/s`steady: `60/m` **scopes:** `coupons:write`
Update coupon codeUpdates a coupon code specified by the given identifier synchronously.
Update flow statusUpdate the status of a flow with the given flow id, and all actions in that flow.
Update imageUpdate the image with the given image id.
Update listUpdate the name of a list with the given list id.
Update profileUpdate profiles with the provided id.
Update segmentUpdate a segment with the given segment id.
Update tagUpdate the tag with the given tag id.
Update tag groupUpdate the tag group with the given tag group id.
Update templateUpdate a template with the given template id.
Update webhookUpdate the webhook with the given id.
Upload image from fileUpload an image from a file.
Upload image from urlImport an image from a url or data uri.

What is the Composio tool router, and how does it fit here?

What is Tool Router?

Composio's Tool Router helps agents find the right tools for a task at runtime. You can plug in multiple toolkits (like Gmail, HubSpot, and GitHub), and the agent will identify the relevant app and action to complete multi-step workflows. This can reduce token usage and improve the reliability of tool calls. Read more here: Getting started with Tool Router

The tool router generates a secure MCP URL that your agents can access to perform actions.

How the Tool Router works

The Tool Router follows a three-phase workflow:

  1. Discovery: Searches for tools matching your task and returns relevant toolkits with their details.
  2. Authentication: Checks for active connections. If missing, creates an auth config and returns a connection URL via Auth Link.
  3. Execution: Executes the action using the authenticated connection.

Step-by-step Guide

Prerequisites

Before starting, make sure you have:
  • Composio API Key and Claude/Anthropic API Key
  • Primary know-how of Claude Agents SDK
  • A Klaviyo account
  • Some knowledge of Python

Getting API Keys for Claude/Anthropic and Composio

Claude/Anthropic API Key
  • Go to the Anthropic Console and create an API key. You'll need credits to use the models.
  • Keep the API key safe.
Composio API Key
  • Log in to the Composio dashboard.
  • Navigate to your API settings and generate a new API key.
  • Store this key securely as you'll need it for authentication.

Install dependencies

pip install composio-anthropic claude-agent-sdk python-dotenv

Install the Composio SDK and the Claude Agents SDK.

What's happening:

  • composio-anthropic provides Composio integration for Anthropic
  • claude-agent-sdk is the core agent framework
  • python-dotenv loads environment variables

Set up environment variables

bash
COMPOSIO_API_KEY=your_composio_api_key_here
USER_ID=your_user_id_here
ANTHROPIC_API_KEY=your_anthropic_api_key_here

Create a .env file in your project root.

What's happening:

  • COMPOSIO_API_KEY authenticates with Composio
  • USER_ID identifies the user for session management
  • ANTHROPIC_API_KEY authenticates with Anthropic/Claude

Import dependencies

import asyncio
from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions
import os
from composio import Composio
from dotenv import load_dotenv

load_dotenv()
What's happening:
  • We're importing all necessary libraries including the Claude Agent SDK and Composio
  • The load_dotenv() function loads environment variables from your .env file
  • This setup prepares the foundation for connecting Claude with Klaviyo functionality

Create a Composio instance and Tool Router session

async def chat_with_remote_mcp():
    api_key = os.getenv("COMPOSIO_API_KEY")
    if not api_key:
        raise RuntimeError("COMPOSIO_API_KEY is not set")

    composio = Composio(api_key=api_key)

    # Create Tool Router session for Klaviyo
    mcp_server = composio.create(
        user_id=os.getenv("USER_ID"),
        toolkits=["klaviyo"]
    )

    url = mcp_server.mcp.url

    if not url:
        raise ValueError("Session URL not found")
What's happening:
  • The function checks for the required COMPOSIO_API_KEY environment variable
  • We're creating a Composio instance using our API key
  • The create method creates a Tool Router session for Klaviyo
  • The returned url is the MCP server URL that your agent will use

Configure Claude Agent with MCP

# Configure remote MCP server for Claude
options = ClaudeAgentOptions(
    permission_mode="bypassPermissions",
    mcp_servers={
        "composio": {
            "type": "http",
            "url": url,
            "headers": {
                "x-api-key": os.getenv("COMPOSIO_API_KEY")
            }
        }
    },
    system_prompt="You are a helpful assistant with access to Klaviyo tools via Composio.",
    max_turns=10
)
What's happening:
  • We're configuring the Claude Agent options with the MCP server URL
  • permission_mode="bypassPermissions" allows the agent to execute operations without asking for permission each time
  • The system prompt instructs the agent that it has access to Klaviyo
  • max_turns=10 limits the conversation length to prevent excessive API usage

Create client and start chat loop

# Create client with context manager
async with ClaudeSDKClient(options=options) as client:
    print("\nChat started. Type 'exit' or 'quit' to end.\n")

    # Main chat loop
    while True:
        user_input = input("You: ").strip()
        if user_input.lower() in {"exit", "quit"}:
            print("Goodbye!")
            break

        # Send query
        await client.query(user_input)

        # Receive and print response
        print("Claude: ", end="", flush=True)
        async for message in client.receive_response():
            if hasattr(message, "content"):
                for block in message.content:
                    if hasattr(block, "text"):
                        print(block.text, end="", flush=True)
        print()
What's happening:
  • The Claude SDK client is created using the async context manager pattern
  • The agent processes each query and streams the response back in real-time
  • The chat loop continues until the user types 'exit' or 'quit'

Run the application

if __name__ == "__main__":
    asyncio.run(chat_with_remote_mcp())
What's happening:
  • This entry point runs the async chat_with_remote_mcp() function using asyncio.run()
  • The application will start, create the MCP connection, and begin the interactive chat session

Complete Code

Here's the complete code to get you started with Klaviyo and Claude Agent SDK:

import asyncio
from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions
import os
from composio import Composio
from dotenv import load_dotenv

load_dotenv()

async def chat_with_remote_mcp():
    api_key = os.getenv("COMPOSIO_API_KEY")
    if not api_key:
        raise RuntimeError("COMPOSIO_API_KEY is not set")

    composio = Composio(api_key=api_key)

    # Create Tool Router session for Klaviyo
    mcp_server = composio.create(
        user_id=os.getenv("USER_ID"),
        toolkits=["klaviyo"]
    )

    url = mcp_server.mcp.url

    if not url:
        raise ValueError("Session URL not found")

    # Configure remote MCP server for Claude
    options = ClaudeAgentOptions(
        permission_mode="bypassPermissions",
        mcp_servers={
            "composio": {
                "type": "http",
                "url": url,
                "headers": {
                    "x-api-key": os.getenv("COMPOSIO_API_KEY")
                }
            }
        },
        system_prompt="You are a helpful assistant with access to Klaviyo tools via Composio.",
        max_turns=10
    )

    # Create client with context manager
    async with ClaudeSDKClient(options=options) as client:
        print("\nChat started. Type 'exit' or 'quit' to end.\n")

        # Main chat loop
        while True:
            user_input = input("You: ").strip()
            if user_input.lower() in {"exit", "quit"}:
                print("Goodbye!")
                break

            # Send query
            await client.query(user_input)

            # Receive and print response
            print("Claude: ", end="", flush=True)
            async for message in client.receive_response():
                if hasattr(message, "content"):
                    for block in message.content:
                        if hasattr(block, "text"):
                            print(block.text, end="", flush=True)
            print()

if __name__ == "__main__":
    asyncio.run(chat_with_remote_mcp())

Conclusion

You've successfully built a Claude Agent SDK agent that can interact with Klaviyo through Composio's Tool Router.

Key features:

  • Native MCP support through Claude's agent framework
  • Streaming responses for real-time interaction
  • Permission bypass for smooth automated workflows
You can extend this by adding more toolkits, implementing custom business logic, or building a web interface around the agent.

How to build Klaviyo MCP Agent with another framework

FAQ

What are the differences in Tool Router MCP and Klaviyo MCP?

With a standalone Klaviyo MCP server, the agents and LLMs can only access a fixed set of Klaviyo tools tied to that server. However, with the Composio Tool Router, agents can dynamically load tools from Klaviyo and many other apps based on the task at hand, all through a single MCP endpoint.

Can I use Tool Router MCP with Claude Agent SDK?

Yes, you can. Claude Agent SDK fully supports MCP integration. You get structured tool calling, message history handling, and model orchestration while Tool Router takes care of discovering and serving the right Klaviyo tools.

Can I manage the permissions and scopes for Klaviyo while using Tool Router?

Yes, absolutely. You can configure which Klaviyo scopes and actions are allowed when connecting your account to Composio. You can also bring your own OAuth credentials or API configuration so you keep full control over what the agent can do.

How safe is my data with Composio Tool Router?

All sensitive data such as tokens, keys, and configuration is fully encrypted at rest and in transit. Composio is SOC 2 Type 2 compliant and follows strict security practices so your Klaviyo data and credentials are handled as safely as possible.

Used by agents from

Context
ASU
Letta
glean
HubSpot
Agent.ai
Altera
DataStax
Entelligence
Rolai
Context
ASU
Letta
glean
HubSpot
Agent.ai
Altera
DataStax
Entelligence
Rolai
Context
ASU
Letta
glean
HubSpot
Agent.ai
Altera
DataStax
Entelligence
Rolai

Never worry about agent reliability

We handle tool reliability, observability, and security so you never have to second-guess an agent action.