Connect an AI agent
AI agents, such as a sales agent, a support bot or a coding assistant, can use a simmail universe as their mailbox over the Model Context Protocol (MCP). They send email, wait for replies, read inboxes, add people and move the clock, as tools.
The people they write to are simulated, and nothing reaches the real internet. So you can let an agent loose on a hundred prospects and read every conversation afterwards.
The endpoint
Section titled “The endpoint”Each universe’s MCP address is on your account page, next to its API address:
https://c1.simmail.dev/mcpIt uses MCP’s Streamable HTTP transport: one JSON-RPC request per POST, answered with JSON. There is no event stream; a GET answers 405.
Authentication
Section titled “Authentication”Send an API key as a bearer token:
Authorization: Bearer smk_your_keyThe key decides the universe. The key needs at least the member role, and your organization’s plan needs the MCP feature; otherwise the endpoint answers 403 or 402.
Make a key just for the agent (name it “AI agent”), so you can revoke it on its own.
Connect your client
Section titled “Connect your client”Every client below talks to the same address with the same key. Create a key on your account page, put it in an environment variable where the client supports one, and paste the matching setup:
export SIMMAIL_API_KEY=smk_your_keyclaude mcp add --transport http simmail https://c1.simmail.dev/mcp \ --header "Authorization: Bearer $SIMMAIL_API_KEY"Add --scope user to have it in every project, or --scope project to share it with your team. In that case Claude Code writes .mcp.json at the project root, and you can keep the key out of the file:
{ "mcpServers": { "simmail": { "type": "http", "url": "https://c1.simmail.dev/mcp", "headers": { "Authorization": "Bearer ${SIMMAIL_API_KEY}" } } }}Add simmail as a custom connector: Settings → Connectors → Add custom connector.
- Name:
simmail. URL:https://c1.simmail.dev/mcp. - For sign-in, choose No sign in.
- Under Request headers, add
Authorizationwith the valueBearer smk_your_key.
The connector works in Claude Desktop and on claude.ai. On Team and Enterprise plans, owners add connectors, and everyone who uses it shares that one key: make a key just for it.
~/.cursor/mcp.json (all projects) or .cursor/mcp.json (this project):
{ "mcpServers": { "simmail": { "url": "https://c1.simmail.dev/mcp", "headers": { "Authorization": "Bearer ${env:SIMMAIL_API_KEY}" } } }}The variable must be set in the environment Cursor starts in.
.vscode/mcp.json, or your user configuration (MCP: Open User Configuration). VS Code asks for the key the first time and stores it securely:
{ "inputs": [ { "type": "promptString", "id": "simmail-key", "description": "simmail API key", "password": true } ], "servers": { "simmail": { "type": "http", "url": "https://c1.simmail.dev/mcp", "headers": { "Authorization": "Bearer ${input:simmail-key}" } } }}Note the top-level key is servers, not mcpServers.
opencode.json in your project, or ~/.config/opencode/opencode.json:
{ "$schema": "https://opencode.ai/config.json", "mcp": { "simmail": { "type": "remote", "url": "https://c1.simmail.dev/mcp", "enabled": true, "oauth": false, "headers": { "Authorization": "Bearer {env:SIMMAIL_API_KEY}" } } }}"oauth": false stops OpenCode from trying to sign in with OAuth; the key is enough.
codex mcp add simmail --url https://c1.simmail.dev/mcp --bearer-token-env-var SIMMAIL_API_KEYOr in ~/.codex/config.toml:
[mcp_servers.simmail]url = "https://c1.simmail.dev/mcp"bearer_token_env_var = "SIMMAIL_API_KEY"bearer_token_env_var takes the variable’s name; Codex reads the key from it when it connects.
gemini mcp add --transport http \ --header "Authorization: Bearer $SIMMAIL_API_KEY" \ simmail https://c1.simmail.dev/mcpOr in ~/.gemini/settings.json (or .gemini/settings.json in a project):
{ "mcpServers": { "simmail": { "httpUrl": "https://c1.simmail.dev/mcp", "headers": { "Authorization": "Bearer $SIMMAIL_API_KEY" } } }}Use httpUrl: in Gemini CLI, url means the older SSE transport.
mcp_config.json (open it from Cascade’s MCP settings):
{ "mcpServers": { "simmail": { "serverUrl": "https://c1.simmail.dev/mcp", "headers": { "Authorization": "Bearer ${env:SIMMAIL_API_KEY}" } } }}In settings.json, or Settings → AI → MCP Servers → Add Remote Server:
{ "context_servers": { "simmail": { "url": "https://c1.simmail.dev/mcp", "headers": { "Authorization": "Bearer smk_your_key" } } }}cline_mcp_settings.json (MCP Servers → Configure):
{ "mcpServers": { "simmail": { "type": "streamableHttp", "url": "https://c1.simmail.dev/mcp", "headers": { "Authorization": "Bearer smk_your_key" }, "disabled": false } }}Set "type": "streamableHttp": without it, Cline uses the older SSE transport.
.continue/mcpServers/simmail.yaml:
name: simmailversion: 0.0.1schema: v1mcpServers: - name: simmail type: streamable-http url: https://c1.simmail.dev/mcp requestOptions: headers: Authorization: Bearer smk_your_keyChatGPT connectors don’t take an API key yet: they only sign in with OAuth, which simmail’s MCP endpoint doesn’t offer yet. Use one of the clients above, or the OpenAI API below.
From your own code
Section titled “From your own code”The Messages API connects to simmail itself, with the MCP connector (beta header mcp-client-2025-11-20). Pass the key without Bearer:
import os, anthropic
client = anthropic.Anthropic()msg = client.beta.messages.create( model="claude-opus-5-5", max_tokens=2000, betas=["mcp-client-2025-11-20"], mcp_servers=[{ "type": "url", "url": "https://c1.simmail.dev/mcp", "name": "simmail", "authorization_token": os.environ["SIMMAIL_API_KEY"], }], tools=[{"type": "mcp_toolset", "mcp_server_name": "simmail"}], messages=[{"role": "user", "content": "Email dana@harbor.test from app@yourcompany.test and tell me how she replies."}],)The Responses API’s remote MCP tool:
import osfrom openai import OpenAI
client = OpenAI()resp = client.responses.create( model="gpt-5", tools=[{ "type": "mcp", "server_label": "simmail", "server_url": "https://c1.simmail.dev/mcp", "authorization": os.environ["SIMMAIL_API_KEY"], "require_approval": "never", }], input="Email dana@harbor.test from app@yourcompany.test and tell me how she replies.",)With the OpenAI Agents SDK:
import osfrom agents import Agentfrom agents.mcp import MCPServerStreamableHttp
async with MCPServerStreamableHttp(name="simmail", params={ "url": "https://c1.simmail.dev/mcp", "headers": {"Authorization": f"Bearer {os.environ['SIMMAIL_API_KEY']}"},}) as simmail: agent = Agent(name="Sales agent", mcp_servers=[simmail])import { Client } from '@modelcontextprotocol/sdk/client/index.js';import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
const transport = new StreamableHTTPClientTransport(new URL('https://c1.simmail.dev/mcp'), { requestInit: { headers: { Authorization: `Bearer ${process.env.SIMMAIL_API_KEY}` } },});const client = new Client({ name: 'my-agent', version: '1.0.0' });await client.connect(transport);console.log(await client.listTools());import osfrom mcp import ClientSessionfrom mcp.client.streamable_http import streamablehttp_client
headers = {"Authorization": f"Bearer {os.environ['SIMMAIL_API_KEY']}"}async with streamablehttp_client("https://c1.simmail.dev/mcp", headers=headers) as (read, write, _): async with ClientSession(read, write) as session: await session.initialize() print(await session.list_tools())This is the mcp package’s 1.x API. In 2.x, pass an httpx client that carries the header instead; see the SDK’s transport docs.
Protocol versions
Section titled “Protocol versions”simmail serves both eras of MCP:
| Version | How it starts |
|---|---|
2025-03-26, 2025-06-18, 2025-11-25 | The initialize handshake. simmail answers with the version you ask for, or 2025-11-25 if it does not know yours. |
2026-07-28 | No handshake: server/discover, and the version in each request’s _meta (io.modelcontextprotocol/protocolVersion). If you also send the MCP-Protocol-Version header, it must match. |
The methods served are initialize, server/discover, ping, tools/list and tools/call. Notifications (requests without an id) are accepted with 202.
Trying it with curl
Section titled “Trying it with curl”curl -s https://c1.simmail.dev/mcp \ -H "Authorization: Bearer smk_your_key" \ -H "Content-Type: application/json" \ -d '{"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {"protocolVersion": "2025-06-18", "capabilities": {}, "clientInfo": {"name": "curl", "version": "1"}}}'{ "jsonrpc": "2.0", "id": 1, "result": { "protocolVersion": "2025-06-18", "capabilities": { "tools": { "listChanged": false } }, "serverInfo": { "name": "simmail", "title": "simmail · CI", "version": "1.0" }, "instructions": "simmail is an email sandbox whose recipients are simulated people. …" }}Then list the tools:
curl -s https://c1.simmail.dev/mcp \ -H "Authorization: Bearer smk_your_key" \ -H "Content-Type: application/json" \ -d '{"jsonrpc": "2.0", "id": 2, "method": "tools/list"}'Results and errors
Section titled “Results and errors”A tool’s result is one text item holding the API’s JSON answer. When the underlying call fails, isError is true and the text is the error message, such as “Dana Reyes did not reply before the timeout”.
Next: the tools and an example agent configuration.