How to integrate Agent mail MCP with LlamaIndex

Connect LlamaIndex to Agent mail MCP. Show me unread emails from today, send a status update to your team, and more using natural language, with authentication handled for you.

Agent mail logoAgent mail
Api Key

Agent mail provides AI agents with dedicated email inboxes for sending, receiving, and managing emails. It empowers agents to communicate autonomously with people, services, and other agents—no human intervention needed.

93 Tools1 Triggers

Introduction

This guide walks you through connecting Agent mail to LlamaIndex using the Composio tool router. By the end, you'll have a working Agent mail agent that can create inboxes, send and reply to emails, manage drafts and threads, schedule calendar events, and set up webhooks through natural language commands.

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

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

Also integrate Agent mail with

TL;DR

Here's what you'll learn:
  • Set your OpenAI and Composio API keys
  • Install LlamaIndex and Composio packages
  • Create a Composio Tool Router session for Agent mail
  • Connect LlamaIndex to the Agent mail MCP server
  • Build a Agent mail-powered agent using LlamaIndex
  • Interact with Agent mail through natural language

What is LlamaIndex?

LlamaIndex is a data framework for building LLM applications. It provides tools for connecting LLMs to external data sources and services through agents and tools.

Key features include:

  • ReAct Agent: Reasoning and acting pattern for tool-using agents
  • MCP Tools: Native support for Model Context Protocol
  • Context Management: Maintain conversation context across interactions
  • Async Support: Built for async/await patterns

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

The Agent mail MCP server is an implementation of the Model Context Protocol that connects your AI agent and assistants like Claude, Cursor, etc directly to your Agent mail account. It provides structured and secure access to your agent's dedicated inbox, so your agent can send emails, receive incoming messages, fetch specific conversations, and automate email-based workflows on your behalf.

  • Automated email sending: Instruct your agent to compose and send emails to any recipient, perfect for status updates, notifications, or outreach.
  • Message listing and inbox scanning: Let your agent quickly list all recent messages in the inbox to summarize, monitor, or trigger follow-up actions.
  • Targeted message retrieval: Have your agent fetch a specific message by ID, making it easy to pull full email content for context-aware decisions or replies.
  • Streamlined agent-to-agent communication: Enable your AI to directly interact with other agents or services via email, automating routine communication flows.

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 step10 STEPS
1

Prerequisites

Before you begin, make sure you have:
  • Python 3.8/Node 16 or higher installed
  • A Composio account with the API key
  • An OpenAI API key
  • A Agent mail account and project
  • Basic familiarity with async Python/Typescript
2

Getting API Keys for OpenAI, Composio, and Agent mail

OpenAI API key (OPENAI_API_KEY)
  • Go to the OpenAI dashboard
  • Create an API key if you don't have one
  • Assign it to OPENAI_API_KEY in .env
Composio API key and user ID
  • Log into the Composio dashboard
  • Copy your API key from Settings
    • Use this as COMPOSIO_API_KEY
  • Pick a stable user identifier (email or ID)
    • Use this as COMPOSIO_USER_ID
3

Installing dependencies

npm install @composio/llamaindex @llamaindex/openai @llamaindex/tools @llamaindex/workflow dotenv

Create a new Typescript project and install the necessary dependencies:

  • @composio/llamaindex: Composio's LlamaIndex integration
  • @llamaindex/openai: OpenAI LLM integration
  • @llamaindex/tools: MCP client for LlamaIndex
  • @llamaindex/workflow: Workflow framework for LlamaIndex
  • dotenv: Environment variable management
4

Set environment variables

bash
OPENAI_API_KEY=your-openai-api-key
COMPOSIO_API_KEY=your-composio-api-key
COMPOSIO_USER_ID=your-user-id

Create a .env file in your project root:

These credentials will be used to:

  • Authenticate with OpenAI's GPT-5 model
  • Connect to Composio's Tool Router
  • Identify your Composio user session for Agent mail access
5

Import modules

import "dotenv/config";
import readline from "node:readline/promises";
import { stdin as input, stdout as output } from "node:process";

import { Composio } from "@composio/core";

import { mcp } from "@llamaindex/tools";
import { agent as createAgent } from "@llamaindex/workflow";
import { openai } from "@llamaindex/openai";

dotenv.config();

Create a new file called agent mail_llamaindex_agent.ts and import the required modules:

Key imports:

  • dotenv.config loads .env at runtime
  • readline gives us a simple CLI chat loop
  • Composio is the main Composio SDK client
  • mcp connects to an MCP endpoint
  • createAgent builds a LlamaIndex agent
  • openai configures the LLM backend
6

Load environment variables and initialize Composio

const OPENAI_API_KEY = process.env.OPENAI_API_KEY;
const COMPOSIO_API_KEY = process.env.COMPOSIO_API_KEY;
const COMPOSIO_USER_ID = process.env.COMPOSIO_USER_ID;

if (!OPENAI_API_KEY) throw new Error("OPENAI_API_KEY is not set");
if (!COMPOSIO_API_KEY) throw new Error("COMPOSIO_API_KEY is not set");
if (!COMPOSIO_USER_ID) throw new Error("COMPOSIO_USER_ID is not set");

What's happening:

This ensures missing credentials cause early, clear errors before the agent attempts to initialise.

7

Create a Tool Router session and build the agent function

async function buildAgent() {

  console.log(`Initializing Composio client...${COMPOSIO_USER_ID!}...`);
  console.log(`COMPOSIO_USER_ID: ${COMPOSIO_USER_ID!}...`);

  const composio = new Composio({
    apiKey: COMPOSIO_API_KEY,
    provider: new LlamaindexProvider(),
  });

  const session = await composio.create(
    COMPOSIO_USER_ID!,
    {
      toolkits: ["agent_mail"],
    },
  );

  const mcpUrl = session.mcp.url;
  console.log(`Composio Tool Router MCP URL: ${mcpUrl}`);

  const server = mcp({
    url: mcpUrl,
    clientName: "composio_tool_router_with_llamaindex",
    requestInit: {
      headers: {
        "x-api-key": COMPOSIO_API_KEY!,
      },
    },
    // verbose: true,
  });

  const tools = await server.tools();

  const llm = openai({ apiKey: OPENAI_API_KEY, model: "gpt-5" });

  const agent = createAgent({
    name: "composio_tool_router_with_llamaindex",
        description : "An agent that uses Composio Tool Router MCP tools to perform actions.",
    systemPrompt:
      "You are a helpful assistant connected to Composio Tool Router."+
"Use the available tools to answer user queries and perform Agent mail actions." ,
    llm,
    tools,
  });

  return agent;
}

What's happening here:

  • We create a Composio client using your API key and configure it with the LlamaIndex provider
  • We then create a tool router MCP session for your user, specifying the toolkits we want to use (in this case, agent mail)
  • The session returns an MCP HTTP endpoint URL that acts as a gateway to all your configured tools
  • LlamaIndex will connect to this endpoint to dynamically discover and use the available Agent mail tools.
  • The MCP tools are mapped to LlamaIndex-compatible tools and plug them into the Agent.
8

Create an interactive chat loop

async function chatLoop(agent: ReturnType<typeof createAgent>) {
  const rl = readline.createInterface({ input, output });

  console.log("Type 'quit' or 'exit' to stop.");

  while (true) {
    let userInput: string;

    try {
      userInput = (await rl.question("\nYou: ")).trim();
    } catch {
      console.log("\nAgent: Bye!");
      break;
    }

    if (!userInput) {
      continue;
    }

    const lower = userInput.toLowerCase();
    if (lower === "quit" || lower === "exit") {
      console.log("Agent: Bye!");
      break;
    }

    try {
      process.stdout.write("Agent: ");

      const stream = agent.runStream(userInput);
      let finalResult: any = null;

      for await (const event of stream) {
        // The event.data contains the streamed content
        const data: any = event.data;

        // Check for streaming delta content
        if (data?.delta) {
          process.stdout.write(data.delta);
        }

        // Store final result for fallback
        if (data?.result || data?.message) {
          finalResult = data;
        }
      }

      // If no streaming happened, show the final result
      if (finalResult) {
        const answer =
          finalResult.result ??
          finalResult.message?.content ??
          finalResult.message ??
          "";
        if (answer && typeof answer === "string" && !answer.includes("[object")) {
          process.stdout.write(answer);
        }
      }

      console.log(); // New line after streaming completes
    } catch (err: any) {
      console.error("\nAgent error:", err?.message ?? err);
    }
  }

  rl.close();
}

What's happening:

  • We're creating a direct terminal interface to chat with Agent mail
  • The LLM's responses are streamed to the CLI for faster interaction.
  • The agent uses context to maintain conversation history
  • The agent processes the request, selects appropriate Agent mail tools, and returns a result
  • We extract the answer from the result data structure and display it to the user
  • You can type 'quit' or 'exit' to stop the chat loop gracefully
  • Agent responses and any errors are streamed in a clear, readable format
9

Define the main entry point

async function main() {
  try {
    const agent = await buildAgent();
    await chatLoop(agent);
  } catch (err) {
    console.error("Failed to start agent:", err);
    process.exit(1);
  }
}

main();

What's happening here:

  • We're orchestrating the entire application flow
  • The agent gets built with proper error handling
  • Then we kick off the interactive chat loop so you can start talking to Agent mail
10

Run the agent

npx ts-node llamaindex-agent.ts

When prompted, authenticate and authorise your agent with Agent mail, then start asking questions.

Complete Code

Here's the complete code to get you started with Agent mail and LlamaIndex:

import "dotenv/config";
import readline from "node:readline/promises";
import { stdin as input, stdout as output } from "node:process";

import { Composio } from "@composio/core";
import { LlamaindexProvider } from "@composio/llamaindex";

import { mcp } from "@llamaindex/tools";
import { agent as createAgent } from "@llamaindex/workflow";
import { openai } from "@llamaindex/openai";

dotenv.config();

const OPENAI_API_KEY = process.env.OPENAI_API_KEY;
const COMPOSIO_API_KEY = process.env.COMPOSIO_API_KEY;
const COMPOSIO_USER_ID = process.env.COMPOSIO_USER_ID;

if (!OPENAI_API_KEY) {
    throw new Error("OPENAI_API_KEY is not set in the environment");
  }
if (!COMPOSIO_API_KEY) {
    throw new Error("COMPOSIO_API_KEY is not set in the environment");
  }
if (!COMPOSIO_USER_ID) {
    throw new Error("COMPOSIO_USER_ID is not set in the environment");
  }

async function buildAgent() {

  console.log(`Initializing Composio client...${COMPOSIO_USER_ID!}...`);
  console.log(`COMPOSIO_USER_ID: ${COMPOSIO_USER_ID!}...`);

  const composio = new Composio({
    apiKey: COMPOSIO_API_KEY,
    provider: new LlamaindexProvider(),
  });

  const session = await composio.create(
    COMPOSIO_USER_ID!,
    {
      toolkits: ["agent_mail"],
    },
  );

  const mcpUrl = session.mcp.url;
  console.log(`Composio Tool Router MCP URL: ${mcpUrl}`);

  const server = mcp({
    url: mcpUrl,
    clientName: "composio_tool_router_with_llamaindex",
    requestInit: {
      headers: {
        "x-api-key": COMPOSIO_API_KEY!,
      },
    },
    // verbose: true,
  });

  const tools = await server.tools();

  const llm = openai({ apiKey: OPENAI_API_KEY, model: "gpt-5" });

  const agent = createAgent({
    name: "composio_tool_router_with_llamaindex",
    description:
      "An agent that uses Composio Tool Router MCP tools to perform actions.",
    systemPrompt:
      "You are a helpful assistant connected to Composio Tool Router."+
"Use the available tools to answer user queries and perform Agent mail actions." ,
    llm,
    tools,
  });

  return agent;
}

async function chatLoop(agent: ReturnType<typeof createAgent>) {
  const rl = readline.createInterface({ input, output });

  console.log("Type 'quit' or 'exit' to stop.");

  while (true) {
    let userInput: string;

    try {
      userInput = (await rl.question("\nYou: ")).trim();
    } catch {
      console.log("\nAgent: Bye!");
      break;
    }

    if (!userInput) {
      continue;
    }

    const lower = userInput.toLowerCase();
    if (lower === "quit" || lower === "exit") {
      console.log("Agent: Bye!");
      break;
    }

    try {
      process.stdout.write("Agent: ");

      const stream = agent.runStream(userInput);
      let finalResult: any = null;

      for await (const event of stream) {
        // The event.data contains the streamed content
        const data: any = event.data;

        // Check for streaming delta content
        if (data?.delta) {
          process.stdout.write(data.delta);
        }

        // Store final result for fallback
        if (data?.result || data?.message) {
          finalResult = data;
        }
      }

      // If no streaming happened, show the final result
      if (finalResult) {
        const answer =
          finalResult.result ??
          finalResult.message?.content ??
          finalResult.message ??
          "";
        if (answer && typeof answer === "string" && !answer.includes("[object")) {
          process.stdout.write(answer);
        }
      }

      console.log(); // New line after streaming completes
    } catch (err: any) {
      console.error("\nAgent error:", err?.message ?? err);
    }
  }

  rl.close();
}

async function main() {
  try {
    const agent = await buildAgent();
    await chatLoop(agent);
  } catch (err: any) {
    console.error("Failed to start agent:", err?.message ?? err);
    process.exit(1);
  }
}

main();

Conclusion

You've successfully connected Agent mail to LlamaIndex through Composio's Tool Router MCP layer. Key takeaways:
  • Tool Router dynamically exposes Agent mail tools through an MCP endpoint
  • LlamaIndex's ReActAgent handles reasoning and orchestration; Composio handles integrations
  • The agent becomes more capable without increasing prompt size
  • Async Python provides clean, efficient execution of agent workflows
You can easily extend this to other toolkits like Gmail, Notion, Stripe, GitHub, and more by adding them to the toolkits parameter.
TOOLS & TRIGGERS

Supported Tools and Triggers

Every Agent mail action and event your agent gets out of the box.

Batch Get Messages

Return metadata for up to 500 messages from one inbox in a single request.

Batch Update Message Labels

Atomically add or remove the same labels on up to 50 messages in one inbox.

Complete File Upload

Mark a pending Agent Drive file ready after its bytes have been PUT to the presigned URL returned by CREATE_FILE.

Create Agent Armor Feedback

Record whether Agent Armor's completed verdict on a message was correct.

Create Calendar Event

Create a one-off or recurring event on a US-only inbox calendar.

Create Draft

Create a draft, optionally scheduling its automatic delivery with send_at.

Create File

Initialize a pending Agent Drive file and return instructions for a direct storage upload.

Create Inbox

Create a new AgentMail inbox via API.

Create Inbox API Key

Create an inbox-scoped bearer key and return its one-time secret.

Create Inbox in Pod

Create an inbox inside an explicitly selected AgentMail pod, optionally choosing its address, initial status, idempotency ID, and metadata.

Create Inbox Polling Webhook

Create or resume a polling webhook scoped to one inbox.

Create Inbox Webhook

Create a regular webhook scoped to one AgentMail inbox for a non-empty set of event types.

Create Allowlist or Blocklist Entry

Add an email address or domain to an organization-wide send, receive, or reply allowlist or blocklist.

Create Pod

Create an AgentMail pod for grouping inboxes and related resources.

Create Polling Webhook

Create or resume an organization-level polling webhook for a non-empty set of event types, optionally filtered to at most 10 inboxes and pods combined.

Create Webhook

Create an organization-level webhook for a non-empty set of event types, optionally filtered to at most 10 inboxes and pods combined.

Delete Calendar Event

Accept asynchronous deletion of a US-only calendar event or cancel recurring dates.

Delete Draft

Permanently delete one unsent draft from an inbox.

Delete File

Permanently delete a pending or ready Agent Drive file and free its path.

Delete Inbox

Permanently delete one inbox by ID.

Delete Inbox Polling Webhook

Permanently delete an inbox-scoped polling webhook by webhook_id or client_id, invalidate its polling token, and free its subscription slot.

Delete Inbox Webhook

Permanently delete a regular webhook created for a selected AgentMail inbox and stop future deliveries.

Delete Allowlist or Blocklist Entry

Remove one email address or domain from an organization-wide send, receive, or reply allowlist or blocklist.

Delete Message

Permanently delete one message from an inbox.

Delete Pod

Permanently delete one AgentMail pod by its unique ID.

Delete Pod Inbox

Permanently delete an inbox through its explicitly selected AgentMail pod, preserving the pod tenant boundary.

Delete Polling Webhook

Permanently delete an organization-level polling webhook by webhook_id or client_id, invalidate its polling token, and free its subscription slot.

Delete Thread

Permanently delete one AgentMail thread and all of its messages.

Delete Webhook

Permanently delete an organization-level webhook and stop future deliveries.

Forward Message

Immediately forward an existing message to new recipients with optional added content and attachments.

Get Agenda

Get one page of non-cancelled calendar dates in a UTC window, expanding recurring events and ordering dates by start time.

Get API Key

Retrieve API-key metadata without exposing bearer secret values.

Get Calendar

Get an inbox's US-only calendar settings, event count, and ETag.

Get Calendar Event

Get the full current form of a US-only calendar event or recurring-event date, including its opaque ETag for conditional mutations.

Get Current Identity

Return the connected AgentMail identity and its organization, pod, or inbox access boundary without exposing the credential itself.

Get Domain

Return an AgentMail custom domain, its domain and tracking verification statuses, and all required DNS records.

Get Domain Setup Link

Build a one-click Domain Connect DNS setup link when supported.

Get Domain Zone File

Download the AgentMail-generated DNS zone file for a custom domain as a bounded binary file reference.

Get Draft

Retrieve the complete contents and scheduling details of one draft.

Get Draft Attachment

Get a temporary download reference for one draft attachment.

Get File

Get Agent Drive file metadata.

Get Inbox

Retrieve one AgentMail inbox and its metadata by ID or email address.

Get Inbox Polling Webhook

Get one inbox-scoped polling webhook by webhook_id or client_id.

Get Inbox Webhook

Get one regular webhook created for a selected AgentMail inbox.

Get Inbox Webhook Headers

List only the names of custom delivery headers on an inbox-scoped regular webhook.

Get Message

Retrieve an email message from an AgentMail inbox, including sender, recipients, labels, and available subject, body and attachment metadata.

Get Message Attachment

Get a temporary download reference for one message attachment.

Get Organization

Return the connected AgentMail organization's identifiers, current inbox and domain counts, configured resource limits, and timestamps.

Get Pod

Retrieve one AgentMail pod by its unique ID.

Get Pod Inbox

Get an AgentMail inbox through an explicitly selected pod, preserving the pod tenant boundary.

Get Polling Webhook

Get one organization-level polling webhook by webhook_id or client_id.

Get Raw Message

Get a temporary download reference for one message's raw RFC 5322 source, including its original headers and MIME structure.

Get Thread

Retrieve one AgentMail thread and a paginated page of its messages.

Get Thread Attachment

Get a temporary download reference for an attachment using its thread and attachment IDs.

Get Webhook

Get one organization-level webhook configuration by ID.

Get Webhook Headers

List only the names of custom delivery headers on an organization-level webhook.

List Calendar Event Instances

List one page of non-cancelled dates computed for a recurring US-only calendar event in a UTC window, including dates beyond the agenda horizon.

List Calendar Events

List one US-only calendar page of stored one-off events, recurring series, and edited series dates, including cancelled events, by most recent update.

List Domains

List one page of AgentMail custom domains and return the continuation token for the next page.

List Drafts

List unsent drafts in an AgentMail inbox with filters and pagination.

List Files

List one page of an inbox's Agent Drive files in path order, including pending files.

List Inbox API Keys

List API-key metadata scoped to an inbox without exposing secret values.

List Inboxes

List a page of inboxes available to the authenticated AgentMail account.

List Inbox Events

List label-change events from an AgentMail inbox.

List Inbox Polling Webhooks

List polling webhooks created through one inbox route.

List Inbox Webhooks

List one page of regular webhooks created for a selected AgentMail inbox.

List Allowlist or Blocklist Entries

List one page of organization-wide send, receive, or reply allowlist or blocklist entries.

List Messages

List messages from an AgentMail inbox.

List Pod Inboxes

List one page of inboxes inside an explicitly selected AgentMail pod, or supply query to search addresses and display names.

List Pods

Return one page of AgentMail pods and its continuation token.

List Polling Webhooks

List organization-level polling webhooks created through the organization route.

List Threads

List conversation threads in an AgentMail inbox with filters.

List Webhooks

List AgentMail webhook configurations.

Query Inbox Event Metrics

Query timestamped email-event counts for an AgentMail inbox.

Query Metrics

Query organization-wide email event counts or cumulative resource-usage time series over a bounded time range.

Query Rate Metrics

Query organization-wide rolling bounce and complaint rates.

Release Held Message

Release a message that Agent Armor held for review, emit its delivery and security override events, and remove the agent-armor-held label.

Reply To Message

Reply to a selected message while preserving its AgentMail thread.

Respond to Calendar Event

Accept, decline, or tentatively accept an email invitation on a US-only inbox calendar.

Send Draft

Immediately send and consume a draft, optionally changing message labels.

Send Email

Send an email using AgentMail API

Send Message

Immediately send a new email from an AgentMail inbox with optional HTML, attachments, custom headers, labels, and open tracking.

Update Calendar

Change an inbox calendar's default time zone in US production.

Update Calendar Event

Patch a US-only calendar event, one recurring date, or that date and future dates.

Update Draft

Edit a draft, reschedule delivery, or cancel a scheduled send with null.

Update Inbox

Update an inbox's display name, status, or custom metadata.

Update Inbox Webhook

Update an inbox-scoped regular webhook's enabled state or replace its event types.

Update Inbox Webhook Headers

Atomically set, replace, or remove custom delivery headers on an inbox-scoped regular webhook.

Update Message Labels

Add or remove labels from one message in an inbox.

Update Pod Inbox

Update the display name, active or paused status, or metadata of an inbox inside an explicitly selected AgentMail pod.

Update Thread Labels

Add or remove custom labels from every message in one thread.

Update Webhook

Update an organization-level webhook's enabled state, event types, or inbox and pod subscriptions.

Update Webhook Headers

Atomically set, replace, or remove custom delivery headers on an organization-level webhook.

FAQ

Frequently asked questions

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

Yes, you can. LlamaIndex 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 Agent mail tools.

Yes, absolutely. You can configure which Agent mail 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 Agent mail data and credentials are handled as safely as possible.

Start with Agent mail.It takes 30 seconds.

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

Start building