e2a MCP tool for ADK¶
The e2a MCP Server connects your ADK agent to e2a, an authenticated email gateway built for AI agents. Inbound mail is SPF/DKIM-verified before it reaches your agent. Outbound mail can be held for human approval before it ships.
Use cases¶
-
Give agents their own inboxes: Provision dedicated email addresses (e.g.
support-bot@your-domain.com) and let agents send and receive mail just like a teammate. -
Authenticated inbound: Every incoming message arrives with SPF and DKIM verification results so your agent knows whether the sender is who they claim to be.
-
Human-in-the-loop approval: Configure HITL on any agent and outbound messages are held in a pending queue until a reviewer approves them — optionally with edits to subject, body, or recipients before sending.
-
Automate threaded conversations: Reply to received emails with proper In-Reply-To and References headers preserved, so threads stay intact across multiple turns.
Prerequisites¶
- A free e2a account and an API key from the dashboard.
- Node.js 18+ on the machine running the agent (the MCP server is
distributed via
npx -y @e2a/mcp-server).
Use with agent¶
from google.adk.agents import Agent
from google.adk.tools.mcp_tool import McpToolset
from google.adk.tools.mcp_tool.mcp_session_manager import StdioConnectionParams
from mcp import StdioServerParameters
E2A_API_KEY = "YOUR_E2A_API_KEY"
E2A_AGENT_EMAIL = "your-bot@your-domain.com" # optional default inbox
root_agent = Agent(
model="gemini-flash-latest",
name="e2a_agent",
instruction=(
"You manage email through the e2a tools. Call whoami once "
"to find your inbox address. Use list_messages and "
"get_message to read; use reply_to_message (not "
"send_email) when replying to an existing thread so "
"threading headers are preserved."
),
tools=[
McpToolset(
connection_params=StdioConnectionParams(
server_params=StdioServerParameters(
command="npx",
args=["-y", "@e2a/mcp-server"],
env={
"E2A_API_KEY": E2A_API_KEY,
"E2A_AGENT_EMAIL": E2A_AGENT_EMAIL,
},
),
timeout=30,
),
)
],
)
import { LlmAgent, MCPToolset } from "@google/adk";
const E2A_API_KEY = "YOUR_E2A_API_KEY";
const E2A_AGENT_EMAIL = "your-bot@your-domain.com"; // optional default inbox
const rootAgent = new LlmAgent({
model: "gemini-flash-latest",
name: "e2a_agent",
instruction:
"You manage email through the e2a tools. Call whoami once " +
"to find your inbox address. Use list_messages and " +
"get_message to read; use reply_to_message (not " +
"send_email) when replying to an existing thread so " +
"threading headers are preserved.",
tools: [
new MCPToolset({
type: "StdioConnectionParams",
serverParams: {
command: "npx",
args: ["-y", "@e2a/mcp-server"],
env: {
E2A_API_KEY: E2A_API_KEY,
E2A_AGENT_EMAIL: E2A_AGENT_EMAIL,
},
},
}),
],
});
export { rootAgent };
Available tools¶
Identity¶
| Tool | Description |
|---|---|
whoami |
Return the default agent's full record (requires E2A_AGENT_EMAIL) |
list_agents |
List every agent inbox owned by the authenticated user |
create_agent |
Register a new inbox using a slug on the shared domain; defaults to local mode so the agent receives mail by polling — no webhook required |
Cloud-mode agents must verify webhook signatures
When you create an agent with agent_mode: "cloud", e2a HMAC-signs every
webhook delivery against your account's webhook signing secret
(E2A_WEBHOOK_SECRET, shown in the e2a dashboard).
Your webhook handler must verify the signature on every request —
the e2a SDK exposes parseWebhook(body, secret) which parses and
verifies in one call. Local-mode agents (the default) avoid this
entirely by polling via list_messages. A complete runnable
cloud-mode + ADK example with proper signature verification lives
at github.com/Mnexa-AI/e2a/tree/main/examples/adk-cloud-webhook.
Messages¶
| Tool | Description |
|---|---|
send_email |
Send a new email; returns status: pending_approval instead of sent when HITL is enabled |
reply_to_message |
Reply to an inbound message; preserves In-Reply-To and References headers |
list_messages |
List inbound mail with status filter (unread / read / all) and pagination |
get_message |
Fetch full body, headers, and attachment metadata for one message |
Human-in-the-loop approval¶
| Tool | Description |
|---|---|
list_pending_messages |
List outbound mail awaiting human approval, soonest-expiring first |
get_pending_message |
Get the full draft (subject, recipients, body) of a pending message |
approve_pending_message |
Send a held message, optionally with reviewer edits (subject / body / recipients) |
reject_pending_message |
Discard a held message; optional reason stored for audit |
Configuration¶
| Variable | Required | Default | Description |
|---|---|---|---|
E2A_API_KEY |
Yes | — | Your e2a API key |
E2A_AGENT_EMAIL |
No | — | Default agent inbox; scopes tools so the LLM doesn't repeat the address on every call |
E2A_BASE_URL |
No | https://e2a.dev |
Self-hosted deployment URL |