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.
Why Use MongoDB with the Agents SDK
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
seqcounter, 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.
Tutorial
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.
Prerequisites
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.
Set Up the Environment
Create and activate a virtual environment.
This tutorial uses uv to manage the environment:
uv venv source .venv/bin/activate
Install the dependencies.
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.
Set your environment variables.
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
Build the Agent
Create the application file.
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 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 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']}" ) 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())
Run the application.
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.
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.
How the Application Uses MongoDB
The application creates one AsyncMongoClient and shares it across the agents and the session:
The specialist agents query the
destinationsandpoliciescollections from their tool functions, so they answer from your data.MongoDBSessionwrites each conversation turn to theagent_sessionsandagent_messagescollections 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().
Next Steps
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
MongoDBSessionreference.