> ## Documentation Index
> Fetch the complete documentation index at: https://sendmux.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# OpenAI Agents SDK

> Give an OpenAI Agents SDK agent a Sendmux mailbox through an MCP server.

Use this page to attach Sendmux to an <a href="https://openai.github.io/openai-agents-python/" rel="nofollow noopener noreferrer" target="_blank">OpenAI Agents SDK</a> agent. Servers passed to `mcp_servers` expose their tools to the agent automatically, so you do not write tool wrappers.

<Warning>
  Replace placeholder keys and tokens before running any snippet. Do not commit
  `smx_root_`, `smx_mbx_`, or private HTTP bearer tokens to version control.
</Warning>

## Requirements

* Python 3.10 or newer.
* `openai-agents` installed.
* A Sendmux key for the surface you are calling. Mailbox work needs an `smx_mbx_` key or a scoped `smx_agent_` token.

## Install

```bash theme={null}
pip install openai-agents sendmux-mcp
```

## Connect over local stdio

The SDK manages the subprocess for you and passes your key through its environment.

```python triage.py theme={null}
import asyncio
import os

from agents import Agent, Runner
from agents.mcp import MCPServerStdio


async def main() -> None:
    async with MCPServerStdio(
        name="Sendmux mailbox",
        params={
            "command": "sendmux-mcp-mailbox",
            "env": {"SENDMUX_API_KEY": os.environ["SENDMUX_MAILBOX_API_KEY"]},
        },
        cache_tools_list=True,
    ) as server:
        agent = Agent(
            name="Inbox agent",
            instructions=(
                "You triage the mailbox you have been granted. "
                "Search before you read, and quote the message you acted on."
            ),
            mcp_servers=[server],
        )

        result = await Runner.run(agent, "What arrived overnight that needs a reply?")
        print(result.final_output)


asyncio.run(main())
```

Run more than one surface by switching to the `sendmux-mcp` entry point:

```python theme={null}
params={
    "command": "sendmux-mcp",
    "env": {
        "SENDMUX_MCP_SURFACES": "mailbox,sending",
        "SENDMUX_MAILBOX_API_KEY": os.environ["SENDMUX_MAILBOX_API_KEY"],
        "SENDMUX_SENDING_API_KEY": os.environ["SENDMUX_SENDING_API_KEY"],
    },
}
```

## Connect over private HTTP

Use this when the agent runs somewhere it cannot spawn a process. Start the server yourself:

```bash theme={null}
SENDMUX_API_KEY=smx_mbx_... \
SENDMUX_MCP_HTTP_BEARER_TOKEN=local-mcp-token \
sendmux-mcp-mailbox --transport http --host 127.0.0.1 --port 8765
```

Then connect with the streamable HTTP server:

```python theme={null}
import os

from agents.mcp import MCPServerStreamableHttp

server = MCPServerStreamableHttp(
    name="Sendmux mailbox",
    params={
        "url": "http://127.0.0.1:8765/mcp",
        "headers": {"Authorization": f"Bearer {os.environ['SENDMUX_MCP_HTTP_BEARER_TOKEN']}"},
        "timeout": 10,
    },
    cache_tools_list=True,
    max_retry_attempts=3,
)
```

## Require approval before an agent sends

The SDK can hold a tool for approval before it runs. Pair this with the Sendmux sending gate when a human should see the message first.

```python theme={null}
server = MCPServerStdio(
    name="Sendmux",
    params={"command": "sendmux-mcp-mailbox", "env": {"SENDMUX_API_KEY": mailbox_key}},
    tool_filter=["mailbox_list_messages", "mailbox_search_message_snippets", "mailbox_get_message"],
    require_approval="never",
)
```

<Note>
  `tool_filter` narrows what the model can see at all. Use it to build a
  read-only triage agent, then add the sending tools only to the agent that is
  meant to reply.
</Note>

## Give each user their own mailbox

Mailbox-scoped keys are the isolation boundary. Open a server per tenant so the agent working one tenant structurally cannot read another tenant's mail.

```python theme={null}
def server_for(mailbox_key: str) -> MCPServerStdio:
    return MCPServerStdio(
        name="Sendmux mailbox",
        params={
            "command": "sendmux-mcp-mailbox",
            "env": {"SENDMUX_API_KEY": mailbox_key},
        },
        cache_tools_list=True,
    )
```

## Sending stays gated

A durable `smx_agent_` token includes `mailbox.read` and `email.receive`, not `email.send`. After a named human owner accepts the invite and approves sending, exchange the durable token for a one-hour Sending-resource token and pass that as `SENDMUX_SENDING_API_KEY`.

## Troubleshooting

<AccordionGroup>
  <Accordion title="The agent sees no tools">
    Confirm the surfaces the server started with. `sendmux-mcp` requires
    `SENDMUX_MCP_SURFACES`; the single-surface entry points do not. Check
    `tool_filter` as well, since it hides everything it does not name.
  </Accordion>

  <Accordion title="The subprocess exits immediately">
    Check the key prefix. Mailbox accepts `smx_mbx_` or a scoped `smx_agent_`,
    Sending accepts a send-capable `smx_mbx_` or an owner-approved
    Sending-resource `smx_agent_`, and Management requires `smx_root_`.
  </Accordion>

  <Accordion title="Tool calls time out">
    Raise `client_session_timeout_seconds`, and set `max_retry_attempts` so
    transient list and call failures retry with backoff.
  </Accordion>

  <Accordion title="You granted more than one mailbox">
    Start the workflow with `mailbox_list_granted_mailboxes` and pass the
    returned `mailbox_id` to tools that act on one mailbox.
  </Accordion>
</AccordionGroup>

## Next steps

<CardGroup cols={2}>
  <Card title="Agent frameworks" icon="layer-group" href="/docs/ai-integrations/frameworks">
    Compare connections across frameworks.
  </Card>

  <Card title="MCP" icon="plug" href="/docs/ai-integrations/mcp">
    Review environment variables and tool discovery.
  </Card>

  <Card title="Agent access" icon="user-shield" href="/docs/ai-integrations/agent-access">
    Register an agent and complete owner approval.
  </Card>

  <Card title="Python SDK" icon="code" href="/docs/developer-tools/sdks/python">
    Call Sendmux directly when you want full endpoint coverage.
  </Card>
</CardGroup>
