For AI agents: a documentation index is available at https://www.mongodb.com/docs/llms.txt — markdown versions of all pages are available by appending .md to any URL path.
Docs Menu

Integrate MongoDB with the OpenAI Agents SDK

You can use MongoDB as the backing database for agents that you build with the OpenAI Agents SDK. The Agents SDK is a Python framework for building agentic applications from a small set of primitives:

  • Agents, which are large language models (LLMs) configured with instructions and tools.

  • Handoffs, which let one agent delegate a task to another agent.

  • Guardrails, which validate the inputs and outputs of an agent.

  • Sessions, which store conversation history across agent runs.

The SDK follows two design principles. It includes enough features to build real applications, but few enough primitives to learn in a short time. Its defaults also produce good results, and you can customize every step of an agent run.

The Agents SDK provides MongoDBSession, a session implementation that persists conversation history in MongoDB. Storing that history in MongoDB gives your agents the following advantages:

  • Horizontally scalable, multi-process session storage. Session state lives in your cluster rather than in the memory of a single process, so any worker, container, or serverless function that connects to the same cluster can continue a conversation. Each message carries a monotonically increasing seq counter, which preserves message order across concurrent writers.

  • One database for conversations and application data. If your application already uses MongoDB, your agents read operational data and write session history through the same connection and the same driver, without a separate memory service to deploy and secure.

  • Flexible documents for agent state. The document model stores conversation turns, tool calls, and structured outputs together as they evolve, so you can extend what you record without a schema migration.

  • Queryable agent history. Session history is stored in ordinary collections, so you can query, aggregate, and index it to audit agent behavior or build analytics.

  • A path to retrieval. Because your agents already connect to MongoDB, you can add MongoDB Vector Search to the same cluster to give them semantic retrieval over your data. To learn more, see Agentic RAG.

In this tutorial, you build a multi-agent travel assistant. A triage agent answers questions by calling two specialist agents as tools, and both specialists read reference data from the same cluster that stores the conversation session.

To complete this tutorial, you must have the following:

  • Python 3.10 or later.

  • One of the following MongoDB cluster types:

    • An Atlas cluster running MongoDB version 6.0.11, 7.0.2, or later. Ensure that your IP address is included in your Atlas project's access list.

    • A local Atlas deployment created using Python and Docker. Install atlas-local-lib-py (pip install atlas-local-lib-py) to programmatically create and manage local deployments. To learn more, see the atlas-local-lib-py repository.

    • A MongoDB Community cluster with Search and Vector Search installed.

  • An OpenAI API Key. You must have an OpenAI account with credits available for API requests. To learn more about registering an OpenAI account, see the OpenAI API website.

1

This tutorial uses uv to manage the environment:

uv venv
source .venv/bin/activate
2

Install the Agents SDK with the mongodb extra. Quote the package name so that your shell doesn't interpret the brackets:

uv pip install "openai-agents[mongodb]"

The extra installs pymongo version 4.14 or later, which provides the AsyncMongoClient class that both the session and the agent tools use.

3

The application reads your Atlas connection string from ATLAS_URI, and the Agents SDK reads your key from OPENAI_API_KEY:

export ATLAS_URI="<connection-string>"
export OPENAI_API_KEY="<api-key>"

Replace the <connection-string> placeholder value with the SRV connection string for your cluster.

Your connection string should use the following format:

mongodb+srv://<db_username>:<db_password>@<clusterName>.<hostname>.mongodb.net
1

Create a file named multi_agent_app.py and paste the following code into it. The inline comments explain how each part of the application uses MongoDB.

multi_agent_app.py
"""Multi-agent travel assistant backed by MongoDB Atlas.
A triage agent answers travel questions by calling two specialist
agents as tools. Both specialists read reference data from the same
Atlas cluster that stores the conversation session, so every agent in
the application shares one database.
"""
import asyncio
import os
from agents import Agent, Runner, function_tool
from agents.extensions.memory import MongoDBSession
from pymongo import AsyncMongoClient
# The script reads your credentials from the environment so that you
# don't commit them to source control.
REQUIRED_ENV_VARS = ("ATLAS_URI", "OPENAI_API_KEY")
DATABASE_NAME = "travel_assistant"
# One client serves both the agent tools and the session store. Because
# you create the client yourself, your application owns its lifecycle.
# main() assigns both of these after it validates the environment.
client: AsyncMongoClient | None = None
database = None
@function_tool
async def lookup_destination(city: str) -> str:
"""Look up travel guidance for a destination city."""
# Sub-agent tools query the shared database directly, so the agents
# answer from your data instead of from model training data.
document = await database.destinations.find_one({"city": city})
if document is None:
return f"No destination guide found for {city}."
return (
f"{document['city']}: best months are {document['best_months']}. "
f"{document['summary']}"
)
@function_tool
async def lookup_policy(topic: str) -> str:
"""Look up the company travel policy for a topic."""
document = await database.policies.find_one({"topic": topic})
if document is None:
return f"No policy found for {topic}."
return f"{document['topic']}: {document['rule']}"
# Each specialist is a full agent with its own instructions and tools.
destination_agent = Agent(
name="Destination expert",
instructions=(
"You advise travelers on destinations. Always call "
"lookup_destination and answer only from what it returns."
),
tools=[lookup_destination],
)
policy_agent = Agent(
name="Policy expert",
instructions=(
"You answer questions about the company travel policy. Always "
"call lookup_policy and answer only from what it returns."
),
tools=[lookup_policy],
)
# The as_tool() pattern turns each specialist into a tool that the
# triage agent can call. Unlike a handoff, control returns to the
# triage agent after each call, so it can combine both answers in one
# reply.
triage_agent = Agent(
name="Travel assistant",
instructions=(
"You are a travel assistant. Use the destination and policy "
"tools to gather facts before you answer, and call both when "
"the question needs both. Remember details the traveler shared "
"earlier in the conversation."
),
tools=[
destination_agent.as_tool(
tool_name="ask_destination_expert",
tool_description="Get travel guidance about a city.",
),
policy_agent.as_tool(
tool_name="ask_policy_expert",
tool_description="Get the company travel policy for a topic.",
),
],
)
async def seed_reference_data() -> None:
"""Load the sample data that the specialist agents read."""
await database.destinations.delete_many({})
await database.policies.delete_many({})
await database.destinations.insert_many(
[
{
"city": "Lisbon",
"best_months": "March through May",
"summary": "Mild spring weather and low hotel rates.",
},
{
"city": "Reykjavik",
"best_months": "June through August",
"summary": "Long daylight hours and open highland roads.",
},
]
)
await database.policies.insert_many(
[
{"topic": "flights", "rule": "Book economy for flights under six hours."},
{"topic": "hotels", "rule": "Nightly rates must stay under 250 USD."},
]
)
async def main() -> None:
global client, database
# Fail fast with a clear message instead of surfacing a connection
# error or an authentication error later in the run.
missing = [name for name in REQUIRED_ENV_VARS if not os.environ.get(name)]
if missing:
raise SystemExit(
"Set these environment variables before you run this script: "
+ ", ".join(missing)
)
client = AsyncMongoClient(os.environ["ATLAS_URI"])
database = client[DATABASE_NAME]
await seed_reference_data()
# The session stores conversation history in Atlas. Pass the
# existing client so the session and the agent tools share one
# connection pool.
session = MongoDBSession(
session_id="traveler-123",
client=client,
database=DATABASE_NAME,
)
# Confirm connectivity before the first run.
await session.ping()
# The Runner loads prior turns from the session and writes the new
# turn back, so the second question resolves "there" without you
# passing the history yourself.
first = await Runner.run(
triage_agent,
"I'm planning a trip to Lisbon. When should I go?",
session=session,
)
print(first.final_output)
second = await Runner.run(
triage_agent,
"What's our hotel budget for that trip?",
session=session,
)
print(second.final_output)
# session.close() is a no-op when you supply the client, so close
# the client yourself.
await client.close()
if __name__ == "__main__":
asyncio.run(main())
2
python multi_agent_app.py

The agent answers the first question from the destinations collection and the second question from the policies collection. Because the session stores the first turn in MongoDB, the assistant resolves "that trip" in the second question without you passing the history yourself.

Your output might differ, because the model generates a new response for each run.

For Lisbon, the best time to go is **March through May**.
That's the sweet spot for **mild weather**, comfortable sightseeing, **fewer crowds**, and generally **better hotel rates** than peak summer. If you want the best single month, I'd pick **May** for warmer days while still avoiding the biggest summer crowds.
I still don't see a company policy entry for a **Lisbon hotel budget/nightly cap**.
Best next step: check the company booking tool or ask your travel/admin team to confirm the approved lodging allowance for Lisbon.

The application creates one AsyncMongoClient and shares it across the agents and the session:

  • The specialist agents query the destinations and policies collections from their tool functions, so they answer from your data.

  • MongoDBSession writes each conversation turn to the agent_sessions and agent_messages collections in the same database. Both collection names are configurable, and the session creates the required indexes on first use.

Because the application constructs the client itself, the client lifecycle belongs to the application and session.close() does nothing. To have the session own the client instead, create it with MongoDBSession.from_uri().

To learn more about coordinating multiple agents with the Agents SDK, see the following pages in the OpenAI documentation:

  • Orchestrating multiple agents for the tradeoffs between orchestrating through code and orchestrating through an LLM.

  • Handoffs for delegating a conversation to another agent instead of calling it as a tool.

  • Guardrails for validating agent inputs and outputs.

  • Sessions for the full MongoDBSession reference.