Using MailFlat with the OpenAI Agents SDK
There is no MailFlat package for the OpenAI Agents SDK and none is needed: attach the MCP server, or wrap the Python client in two function tools.
How it fits together
We ship official integrations for LangChain and the Vercel AI SDK, and nothing specific to the OpenAI Agents SDK. That is not a gap you have to work around: the SDK already speaks MCP, which is the whole MailFlat tool surface, and its function-tool decorator turns any Python function into a tool in one line. Pick by how much control you want over what the agent can do.
Route one: attach the MCP server
All seven tools at once, no wrapper code. The server is a subprocess the SDK starts and stops around the run.
pip install openai-agents mailflat-mcp
The agent
Everything inside the context manager can call MailFlat tools; when the block exits the server shuts down with it.
import asyncio, os
from agents import Agent, Runner
from agents.mcp import MCPServerStdio
async def main() -> None:
async with MCPServerStdio(
params={
"command": "uvx",
"args": ["mailflat-mcp"],
"env": {"MAILFLAT_API_KEY": os.environ["MAILFLAT_API_KEY"]},
},
) as mailflat:
agent = Agent(
name="Signup bot",
instructions="Use MailFlat inboxes for any address you need.",
mcp_servers=[mailflat],
)
result = await Runner.run(
agent,
"Open an inbox labelled agents-demo and tell me the address.",
)
print(result.final_output)
asyncio.run(main())
Route two: two function tools
Narrower on purpose. The agent gets exactly what the task needs, the docstrings become the tool descriptions the model reads, and nothing can delete an inbox.
from agents import Agent, Runner, function_tool
from mailflat import MailFlat, OTPTimeoutError
mf = MailFlat() # reads MAILFLAT_API_KEY
@function_tool
def open_inbox(label: str) -> str:
"""Open a disposable inbox and return its email address."""
return mf.create(label=label, retention_hours=2).address
@function_tool
def read_code(address: str, timeout: int = 60) -> str:
"""Wait for a one-time code sent to this address and return it."""
try:
return mf.inbox(address).wait_for_otp(timeout=timeout)
except OTPTimeoutError:
return "no code arrived before the timeout"
agent = Agent(
name="Signup bot",
instructions="Use open_inbox for any address you need, then read_code.",
tools=[open_inbox, read_code],
)
retention_hours=2 is the cleanup: the inbox empties itself, so the agent never needs a delete tool at all.
Run it
Runner.run drives the loop — tool call, result, next step — until the agent has an answer.
import asyncio
result = asyncio.run(Runner.run(
agent,
"Open an inbox for the signup test, then report the first code it receives.",
))
print(result.final_output)
Worth knowing
Route one hands the agent every tool including delete_inbox; route two hands it only what you wrapped. Choose route two when the same key can reach inboxes you care about.
wait_for_otp blocks the run while it polls, so keep the timeout near what the mail really takes. An encrypted inbox raises EncryptedInboxError instead of returning a code — the server cannot read it.
Both routes read MAILFLAT_API_KEY from the environment. Give the agent its own key rather than the one your dashboard session uses, so revoking it costs you nothing.
See also
MCP server
Run the MailFlat MCP server and any Model Context Protocol client gains real inbox tools: open an address, wait for the one-time code, send mail, clean up.
LangChainMailFlatToolkit turns the Python SDK into LangChain tools, so an agent can open inboxes and read verification codes as part of its normal tool loop.
PythonThe official Python client wraps the REST API in two calls: open an inbox, wait for the code. Works in pytest, unittest, Robot Framework or a plain script.