How to integrate Elastic Email MCP with Vercel AI SDK v6

This guide walks you through connecting Elastic Email to Vercel AI SDK v6 using the Composio tool router. By the end, you'll have a working Elastic Email agent that can add your contacts, create contact lists, build campaigns, make templates, and set up domains through natural language commands. This guide will help you understand how to give your Vercel AI SDK agent real control over a Elastic Email account through Composio's Elastic Email MCP server. Before we dive in, let's take a quick look at the key ideas and tools involved.

Elastic Email logoElastic Email
Api Key

Elastic Email is an email delivery and marketing platform for transactional emails, campaigns, contacts, and reporting. Use it to send reliable emails, manage audiences, verify addresses, and track performance.

91 Tools

Introduction

This guide walks you through connecting Elastic Email to Vercel AI SDK v6 using the Composio tool router. By the end, you'll have a working Elastic Email agent that can add your contacts, create contact lists, build campaigns, make templates, and set up domains through natural language commands.

This guide will help you understand how to give your Vercel AI SDK agent real control over a Elastic Email account through Composio's Elastic Email MCP server.

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

Also integrate Elastic Email with

TL;DR

Here's what you'll learn:
  • How to set up and configure a Vercel AI SDK agent with Elastic Email integration
  • Using Composio's Tool Router to dynamically load and access Elastic Email tools
  • Creating an MCP client connection using HTTP transport
  • Building an interactive CLI chat interface with conversation history management
  • Handling tool calls and results within the Vercel AI SDK framework

What is Vercel AI SDK?

The Vercel AI SDK is a TypeScript library for building AI-powered applications. It provides tools for creating agents that can use external services and maintain conversation state.

Key features include:

  • streamText: Core function for streaming responses with real-time tool support
  • MCP Client: Built-in support for Model Context Protocol via @ai-sdk/mcp
  • Step Counting: Control multi-step tool execution with stopWhen: stepCountIs()
  • OpenAI Provider: Native integration with OpenAI models

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

The Elastic Email MCP server is an implementation of the Model Context Protocol that connects your AI agent and assistants like Claude, Cursor, etc directly to your Elastic Email account. It provides structured and secure access to your contacts, campaigns, templates, domains, delivery records, and account settings, so your agent can organize audiences, create campaigns, build templates, check delivery status, and manage sending domains on your behalf.

  • Contact and audience management: Have your agent add or remove contacts, create contact lists, assign existing contacts to lists, and build dynamic segments using defined rules.
  • Campaign and template creation: Direct your agent to create campaigns, prepare reusable email templates, retrieve campaign details, or remove campaigns and templates you no longer need.
  • Delivery tracking and message review: Let the agent check email job status, review recipient delivery details, and retrieve rendered message previews with attachment information.
  • Domain and inbound email setup: Instruct your agent to add sending or tracking domains, review their DNS and certificate state, check domain restrictions, and configure inbound email routes.
  • Suppression, verification, and event management: Have your agent maintain suppression records, retrieve saved email verification results, monitor export jobs, and create or remove webhooks for selected email events.

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

What is Composio SDK?

Composio's Composio SDK 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 Composio SDK

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

How the Composio SDK works

The Composio SDK 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

Step by step09 STEPS
1

Prerequisites

Before you begin, make sure you have:
  • Node.js and npm installed
  • A Composio account with API key
  • An OpenAI API key
2

Getting API Keys for OpenAI and Composio

OpenAI API Key
  • Go to the OpenAI dashboard and create an API key. You'll need credits to use the models, or you can connect to another model provider.
  • 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.
3

Install required dependencies

bash
npm install @ai-sdk/openai @ai-sdk/mcp @composio/core ai dotenv

First, install the necessary packages for your project.

What you're installing:

  • @ai-sdk/openai: Vercel AI SDK's OpenAI provider
  • @ai-sdk/mcp: MCP client for Vercel AI SDK
  • @composio/core: Composio SDK for tool integration
  • ai: Core Vercel AI SDK
  • dotenv: Environment variable management
4

Set up environment variables

bash
OPENAI_API_KEY=your_openai_api_key_here
COMPOSIO_API_KEY=your_composio_api_key_here
COMPOSIO_USER_ID=your_user_id_here

Create a .env file in your project root.

What's needed:

  • OPENAI_API_KEY: Your OpenAI API key for GPT model access
  • COMPOSIO_API_KEY: Your Composio API key for tool access
  • COMPOSIO_USER_ID: A unique identifier for the user session
5

Import required modules and validate environment

typescript
import "dotenv/config";
import { openai } from "@ai-sdk/openai";
import { Composio } from "@composio/core";
import * as readline from "readline";
import { streamText, type ModelMessage, stepCountIs } from "ai";
import { createMCPClient } from "@ai-sdk/mcp";

const composioAPIKey = process.env.COMPOSIO_API_KEY;
const composioUserID = process.env.COMPOSIO_USER_ID;

if (!process.env.OPENAI_API_KEY) throw new Error("OPENAI_API_KEY is not set");
if (!composioAPIKey) throw new Error("COMPOSIO_API_KEY is not set");
if (!composioUserID) throw new Error("COMPOSIO_USER_ID is not set");

const composio = new Composio({
  apiKey: composioAPIKey,
});
What's happening:
  • We're importing all necessary libraries including Vercel AI SDK's OpenAI provider and Composio
  • The dotenv/config import automatically loads environment variables
  • The MCP client import enables connection to Composio's tool server
6

Create Tool Router session and initialize MCP client

typescript
async function main() {
  // Create a tool router session for the user
  const session = await composio.create(composioUserID!, {
    toolkits: ["elastic_email"],
  });

  const mcpUrl = session.mcp.url;
What's happening:
  • We're creating a Tool Router session that gives your agent access to Elastic Email tools
  • The create method takes the user ID and specifies which toolkits should be available
  • The returned mcp object contains the URL and authentication headers needed to connect to the MCP server
  • This session provides access to all Elastic Email-related tools through the MCP protocol
7

Connect to MCP server and retrieve tools

typescript
const mcpClient = await createMCPClient({
  transport: {
    type: "http",
    url: mcpUrl,
    headers: session.mcp.headers, // Authentication headers for the Composio MCP server
  },
});

const tools = await mcpClient.tools();
What's happening:
  • We're creating an MCP client that connects to our Composio Tool Router session via HTTP
  • The mcp.url provides the endpoint, and mcp.headers contains authentication credentials
  • The type: "http" is important - Composio requires HTTP transport
  • tools() retrieves all available Elastic Email tools that the agent can use
8

Initialize conversation and CLI interface

typescript
let messages: ModelMessage[] = [];

console.log("Chat started! Type 'exit' or 'quit' to end the conversation.\n");
console.log(
  "Ask any questions related to elastic_email, like summarize my last 5 emails, send an email, etc... :)))\n",
);

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
  prompt: "> ",
});

rl.prompt();
What's happening:
  • We initialize an empty messages array to maintain conversation history
  • A readline interface is created to accept user input from the command line
  • Instructions are displayed to guide the user on how to interact with the agent
9

Handle user input and stream responses with real-time tool feedback

typescript
rl.on("line", async (userInput: string) => {
  const trimmedInput = userInput.trim();

  if (["exit", "quit", "bye"].includes(trimmedInput.toLowerCase())) {
    console.log("\nGoodbye!");
    rl.close();
    process.exit(0);
  }

  if (!trimmedInput) {
    rl.prompt();
    return;
  }

  messages.push({ role: "user", content: trimmedInput });
  console.log("\nAgent is thinking...\n");

  try {
    const stream = streamText({
      model: openai("gpt-5"),
      messages,
      tools,
      toolChoice: "auto",
      stopWhen: stepCountIs(10),
      onStepFinish: (step) => {
        for (const toolCall of step.toolCalls) {
          console.log(`[Using tool: ${toolCall.toolName}]`);
          }
          if (step.toolCalls.length > 0) {
            console.log(""); // Add space after tool calls
          }
        },
      });

      for await (const chunk of stream.textStream) {
        process.stdout.write(chunk);
      }

      console.log("\n\n---\n");

      // Get final result for message history
      const response = await stream.response;
      if (response?.messages?.length) {
        messages.push(...response.messages);
      }
    } catch (error) {
      console.error("\nAn error occurred while talking to the agent:");
      console.error(error);
      console.log(
        "\nYou can try again or restart the app if it keeps happening.\n",
      );
    } finally {
      rl.prompt();
    }
  });

  rl.on("close", async () => {
    await mcpClient.close();
    console.log("\n👋 Session ended.");
    process.exit(0);
  });
}

main().catch((err) => {
  console.error("Fatal error:", err);
  process.exit(1);
});
What's happening:
  • We use streamText instead of generateText to stream responses in real-time
  • toolChoice: "auto" allows the model to decide when to use Elastic Email tools
  • stopWhen: stepCountIs(10) allows up to 10 steps for complex multi-tool operations
  • onStepFinish callback displays which tools are being used in real-time
  • We iterate through the text stream to create a typewriter effect as the agent responds
  • The complete response is added to conversation history to maintain context
  • Errors are caught and displayed with helpful retry suggestions

Complete Code

Here's the complete code to get you started with Elastic Email and Vercel AI SDK:

typescript
import "dotenv/config";
import { openai } from "@ai-sdk/openai";
import { Composio } from "@composio/core";
import * as readline from "readline";
import { streamText, type ModelMessage, stepCountIs } from "ai";
import { createMCPClient } from "@ai-sdk/mcp";

const composioAPIKey = process.env.COMPOSIO_API_KEY;
const composioUserID = process.env.COMPOSIO_USER_ID;

if (!process.env.OPENAI_API_KEY) throw new Error("OPENAI_API_KEY is not set");
if (!composioAPIKey) throw new Error("COMPOSIO_API_KEY is not set");
if (!composioUserID) throw new Error("COMPOSIO_USER_ID is not set");

const composio = new Composio({
  apiKey: composioAPIKey,
});

async function main() {
  // Create a tool router session for the user
  const session = await composio.create(composioUserID!, {
    toolkits: ["elastic_email"],
  });

  const mcpUrl = session.mcp.url;

  const mcpClient = await createMCPClient({
    transport: {
      type: "http",
      url: mcpUrl,
      headers: session.mcp.headers, // Authentication headers for the Composio MCP server
    },
  });

  const tools = await mcpClient.tools();

  let messages: ModelMessage[] = [];

  console.log("Chat started! Type 'exit' or 'quit' to end the conversation.\n");
  console.log(
    "Ask any questions related to elastic_email, like summarize my last 5 emails, send an email, etc... :)))\n",
  );

  const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
    prompt: "> ",
  });

  rl.prompt();

  rl.on("line", async (userInput: string) => {
    const trimmedInput = userInput.trim();

    if (["exit", "quit", "bye"].includes(trimmedInput.toLowerCase())) {
      console.log("\nGoodbye!");
      rl.close();
      process.exit(0);
    }

    if (!trimmedInput) {
      rl.prompt();
      return;
    }

    messages.push({ role: "user", content: trimmedInput });
    console.log("\nAgent is thinking...\n");

    try {
      const stream = streamText({
        model: openai("gpt-5"),
        messages,
        tools,
        toolChoice: "auto",
        stopWhen: stepCountIs(10),
        onStepFinish: (step) => {
          for (const toolCall of step.toolCalls) {
            console.log(`[Using tool: ${toolCall.toolName}]`);
          }
          if (step.toolCalls.length > 0) {
            console.log(""); // Add space after tool calls
          }
        },
      });

      for await (const chunk of stream.textStream) {
        process.stdout.write(chunk);
      }

      console.log("\n\n---\n");

      // Get final result for message history
      const response = await stream.response;
      if (response?.messages?.length) {
        messages.push(...response.messages);
      }
    } catch (error) {
      console.error("\nAn error occurred while talking to the agent:");
      console.error(error);
      console.log(
        "\nYou can try again or restart the app if it keeps happening.\n",
      );
    } finally {
      rl.prompt();
    }
  });

  rl.on("close", async () => {
    await mcpClient.close();
    console.log("\n👋 Session ended.");
    process.exit(0);
  });
}

main().catch((err) => {
  console.error("Fatal error:", err);
  process.exit(1);
});

Conclusion

You've successfully built a Elastic Email agent using the Vercel AI SDK with streaming capabilities! This implementation provides a powerful foundation for building AI applications with natural language interfaces and real-time feedback.

Key features of this implementation:

  • Real-time streaming responses for a better user experience with typewriter effect
  • Live tool execution feedback showing which tools are being used as the agent works
  • Dynamic tool loading through Composio's Tool Router with secure authentication
  • Multi-step tool execution with configurable step limits (up to 10 steps)
  • Comprehensive error handling for robust agent execution
  • Conversation history maintenance for context-aware responses

You can extend this further by adding custom error handling, implementing specific business logic, or integrating additional Composio toolkits to create multi-app workflows.
TOOLS

Supported Tools

Every Elastic Email action and event your agent gets out of the box.

Add Contact List Members

Add selected existing contacts to a named Elastic Email contact list.

Add Contacts

Add up to 1000 Elastic Email contacts and optionally assign them to existing lists.

Add Suppressions

Add up to 1000 email addresses to Elastic Email's bounce, complaint, or unsubscribe suppression records.

Adjust Subaccount Credits

Add or remove email credits from a managed Elastic Email subaccount.

Check Domain Restriction

Check whether Elastic Email restricts a domain or identifies it as a free-provider domain.

Create Campaign

Create a campaign.

Create Contact List

Create a contact list, optionally with initial email members.

Create Domain

Create a sending or tracking domain in the connected Elastic Email account.

Create Inbound Route

Create a new inbound email route.

Create Segment

Create a dynamic contact segment from a name and SQL-like rule.

Create Subaccount

Create a managed subaccount with optional initial email settings.

Create Template

Create a new email template with its name, content, and scope.

Create Webhook

Create a webhook subscription for selected email events.

Delete Campaign

Delete one campaign by exact name.

Delete Contact

Delete one contact by exact email address.

Delete Contact List

Delete one contact list by exact name.

Delete Contacts

Permanently delete 1-10 contacts by exact email address.

Delete Domain

Delete one configured domain from the connected Elastic Email account.

Delete Email Verification

Delete one saved email verification result by exact email address.

Delete File

Permanently delete one stored file by its exact name.

Delete Inbound Route

Permanently delete one inbound email route by its public ID.

Delete Segment

Delete one Elastic Email dynamic contact segment by its exact name.

Delete Suppression

Remove one email address from Elastic Email suppression records.

Delete Template

Delete one Elastic Email template by its exact name.

Delete Verification File

Delete one uploaded verification file job by its VerificationID.

Delete Webhook

Delete one webhook subscription by its public WebhookID.

Download File

Download a stored Elastic Email file by its exact name.

Download Verification File Results

Download the ZIP result archive for a completed verification file job.

Get Campaign

Return one Elastic Email campaign by its exact name.

Get Contact

Return one Elastic Email contact by email address.

Get Contact Export Status

Get the current status of an asynchronous contact export job.

Get Contact List

Return one Elastic Email contact list by its exact name.

Get Credential Metadata

Get one Elastic Email API-key or SMTP credential's audit metadata without returning its secret token.

Get Domain

Return detailed DNS and certificate state for one Elastic Email domain.

Get Email Job Status

Return delivery status and optional recipient-level details for an Elastic Email transaction.

Get Email Preview

Return the rendered preview, attachment metadata, and delivery status for an Elastic Email message ID.

Get Email Verification

Return the saved Elastic Email verification result for one email address.

Get Event Export Status

Get the current status of an asynchronous global or channel event export.

Get File Info

Return metadata for a stored Elastic Email file without downloading it.

Get Inbound Route

Return one Elastic Email inbound route by its public ID.

Get Segment

Return one Elastic Email dynamic contact segment by its exact name.

Get Account Statistics

Return aggregate Elastic Email delivery statistics for a time interval.

Get Statistics Breakdown

Return one Elastic Email campaign or channel delivery summary by exact name.

Get Subaccount

Return one managed Elastic Email subaccount by its login email.

Get Suppression

Return suppression details for one Elastic Email address.

Get Template

Return one Elastic Email template by its exact name.

Get Verification File Results

Return one page of detailed results and metadata for a verification file.

Get Webhook

Return one Elastic Email webhook subscription by its public ID.

Import Contacts

Start an asynchronous contact import using exactly one source: an uploaded CSV file or a provider-accessible CSV URL.

Import Suppressions

Upload CSV content containing bounced, complained, or unsubscribed email addresses for asynchronous suppression import.

List Campaigns

Find campaigns by optional name fragment and return one page.

List Contact List Members

Return one page of contacts in a named Elastic Email contact list.

List Contact Lists

Return one page of contact lists from the connected Elastic Email account.

List Contacts

Return one page of contacts from the connected Elastic Email account.

List Credential Metadata

List API-key or SMTP credential metadata without returning secret tokens.

List Domains

Return all sending and tracking domains configured for the account.

List Email Verifications

Return one page of individual email verification results.

List Files

Return one page of stored files and metadata.

List Inbound Routes

Return all inbound email routing rules in their current order.

List Segments

Return one page of dynamic contact segments.

List Statistics Breakdowns

Return one page of campaign or channel delivery summaries.

List Subaccounts

Return one page of managed subaccounts without credentials or passwords.

List Suppressions

Return one page of all suppressed addresses or only addresses suppressed for bounce, complaint, or unsubscribe reasons.

List Templates

Return one page of templates for the required visibility scopes.

List Verification Files

Return all uploaded verification file jobs and their current statuses.

List Webhooks

Return one page of webhook subscriptions.

Pause Campaign

Pause an active Elastic Email campaign by exact name, cancelling messages that are still waiting to be sent.

Remove Contact List Members

Remove selected contacts from a named Elastic Email contact list without deleting the contacts.

Reorder Inbound Routes

Set the processing order of Elastic Email inbound routing rules.

Search Delivery Events

Search all delivery events, one transaction's events, or one channel's events and return one page.

Send Email

Send an email to one or more recipients using inline content or a saved template.

Send Merge File Email

Send personalized email to recipients listed in a CSV merge-data file.

Send Transactional Email

Send one transactional message with To, CC, and BCC recipient groups.

Set Default Sender Domain

Set the domain of a verified sender email as the account default.

Start Contact Export

Start an asynchronous export of all contacts or contacts selected by one filter rule or a list of email addresses.

Start Event Export

Start an asynchronous export for all events or one channel.

Start Verification File

Start bulk verification for a previously uploaded CSV file.

Trigger Campaign Automation

Enter one contact email into an irreversible automation that may send email or execute later steps and cannot be undone.

Update Campaign

Update an existing active or paused campaign.

Update Contact

Update the first name, last name, or custom fields for one Elastic Email contact.

Update Contact List

Update an Elastic Email contact list by providing at least one change: rename it with NewListName or change whether contacts may unsubscribe with AllowUnsubscribe.

Update Domain

Update certificate, VERP, or custom bounce settings for an Elastic Email domain.

Update Inbound Route

Replace an existing inbound route definition by public ID.

Update Segment

Replace an existing dynamic contact segment's name and rule.

Update Subaccount Email Settings

Replace email limits and sender settings for a managed subaccount.

Update Template

Replace an existing email template's name, content, and scope.

Update Webhook

Update a webhook URL, event notification flags, name, or enabled state.

Upload File

Store a base64-encoded file in the connected Elastic Email account.

Upload Verification File

Upload a CSV containing an email column for a later bulk verification job.

Verify Domain

Ask Elastic Email to re-check a domain's DNS configuration.

Verify Email

Run verification for one email address and return its deliverability assessment.

FAQ

Frequently asked questions

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

Yes, you can. Vercel AI SDK v6 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 Elastic Email tools.

Yes, absolutely. You can configure which Elastic Email 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.

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 Elastic Email data and credentials are handled as safely as possible.

Start with Elastic Email.It takes 30 seconds.

Managed auth, hosted MCP servers, and every Elastic Email tool your agent needs.Free to start.

Start building