You add web search to an OpenAI Agents SDK agent by registering a web search tool on the agent, so the model can look up live information while it runs. An agent is a model with instructions and a set of tools it can call. A tool is a capability the model can use to do something beyond writing text, like searching the web.
There are three ways to add web search. You can use OpenAI's hosted WebSearchTool, you can build your own tool with the @function_tool decorator, or you can connect an external provider through the Model Context Protocol (MCP).
This guide covers all three, when to pick each, and how to keep your search-enabled agent reliable in production. Web search is one part of the wider pattern of agentic search, where an agent plans, retrieves, and iterates through queries on its own.
Why Give an Agent Web Search
A model only knows what was in its training data, so it goes stale over time. Web search fixes this by letting the agent pull in current facts at runtime.
According to OpenAI's web search guide, "Web search allows models to access up-to-date information from the internet and provide answers with sourced citations." This grounds the answer in real pages instead of the model's memory.
Grounding matters because it reduces made-up answers and gives users sources they can check. You can read more about how live retrieval anchors model output in this guide to web grounding.
Prerequisites: What You Need Before You Start
You need a few things in place before you write any agent code.
- Python environment: a recent Python version with a virtual environment.
- The SDK installed: run
pip install openai-agents. - An API key: set the
OPENAI_API_KEYenvironment variable. - A mental model: the SDK gives you an
Agentplus aRunnerthat manages turns, tools, and output. This is different from calling the Responses API directly, where you own the loop yourself.
Option 1: Add OpenAI's Hosted WebSearchTool
The fastest way to add web search is OpenAI's hosted WebSearchTool. It runs on OpenAI's servers through the Responses API, so you do not write any scraping or networking code yourself.
Per the OpenAI Agents SDK tools guide, "The WebSearchTool lets an agent search the web." You import it from the SDK and drop it into your agent's tools list.
Register WebSearchTool on Your Agent
Here is the minimal, runnable recipe. Import the tool, attach it to an agent, and run the agent.
from agents import Agent, Runner, WebSearchTool
# 1. Define an agent and give it the hosted web search tool
search_agent = Agent(
name="Web Search Assistant",
instructions=(
"You are a research assistant. Use web search to find current, "
"reliable information before you answer, and cite your sources."
),
tools=[WebSearchTool()],
)
# 2. Run the agent and read the result
result = Runner.run_sync(search_agent, "What are today's top technology headlines?")
print(result.final_output)Runner.run_sync runs the agent and blocks until it finishes. If your app is async, use await Runner.run(...) instead. Either way, the model decides when to call the search tool. The final text lands in result.final_output.
Configure the Search (Location, Context Size)
WebSearchTool takes several options that shape how it searches. The most useful is search_context_size, which controls how much context the search uses.
| Option | What it does |
|---|---|
search_context_size | Accepts "low", "medium", or "high"; defaults to "medium". Use "low" for fast, cheap lookups and "high" for thorough research. |
user_location | Tailors results to a location so answers are locally relevant. |
filters | Restricts results based on attributes. |
external_web_access | Controls whether the tool fetches live content; set False for cached or indexed-only behavior where supported. |
search_content_types | Chooses the content types to return, such as text or images. |
image_settings | Configures image results, such as how many to return. |
One important limit: the SDK tool reference describes WebSearchTool as "A hosted tool that lets the LLM search the web. Currently only supported with OpenAI models, using the Responses API." If you use a non-OpenAI model, you need the custom tool route below.
Option 2: Build a Custom Web Search Tool With function_tool
Sometimes the hosted tool does not fit. You may run a non-OpenAI model, want your own search provider, or need tighter control over cost and output. In those cases, wrap any web search API in a Python function and expose it as a tool.
The OpenAI Agents SDK tools documentation explains that any Python function can become a tool: the SDK reads the function name, the docstring, and the argument types to build the tool automatically. Unlike the hosted tool, custom function tools work with any supported model.
Wrap a Web Search API in a Tool
The example below wraps a web search API in a @function_tool. The function calls the API, then returns clean text the model can read.
import os
import requests
from agents import Agent, Runner, function_tool
@function_tool
def web_search(query: str) -> str:
"""Search the live web for a query and return a sourced answer."""
response = requests.post(
"https://api.olostep.com/v1/answers",
headers={"Authorization": f"Bearer {os.environ['OLOSTEP_API_KEY']}"},
json={"query": query},
timeout=30,
)
return response.text
search_agent = Agent(
name="Custom Search Assistant",
instructions="Use the web_search tool to answer with current, cited information.",
tools=[web_search],
)
result = Runner.run_sync(search_agent, "Summarize this week's AI infrastructure news.")
print(result.final_output)The key detail is what your tool returns. Give the model clean, LLM-ready content, such as Markdown or structured JSON, so it can read the results without extra parsing. A real-time web search API returns a synthesized, cited answer from the live web, and you can also scrape pages into Markdown when the agent needs to read a full page. To wire this up quickly, you can give your agent web data with a one-command install or a context file.
Option 3: Connect a Search Provider Through MCP
MCP lets your agent talk to an external tool server without you writing wrapper functions. It is a good fit when a search provider already ships an MCP server.
The SDK MCP guide explains that "the HostedMCPTool forwards a server label (and optional connector metadata) to the Responses API." The model then lists and calls the remote server's tools directly. Add a HostedMCPTool to your tools=[] list for hosted servers, or add local transports to the mcp_servers=[] list for servers you run yourself.
from agents import Agent, HostedMCPTool
agent = Agent(
name="MCP Search Assistant",
instructions="Use the connected search tools to answer with current information.",
tools=[
HostedMCPTool(
tool_config={"server_label": "search", "server_url": "https://your-mcp-server"}
)
],
)If your provider offers a server, such as the Olostep MCP server, this route gives the agent web access without custom glue code.
Hosted vs. Custom vs. MCP: Which Approach Should You Use
Each approach trades off speed, control, and cost. Use this table to choose.
| Dimension | Hosted WebSearchTool | Custom @function_tool | MCP provider |
|---|---|---|---|
| Model support | OpenAI models only | Any supported model | Depends on transport; hosted variant is OpenAI models |
| Setup effort | Lowest | Medium | Low to medium |
| Control over provider | None | Full | Full |
| Structured, cited output | Built-in citations | Whatever your API returns | Whatever the server returns |
| Cost model | Per search tool call | Your provider's pricing | Your provider's pricing |
| Best fit | Fastest path on OpenAI models | Cross-model, custom, cost control | A provider that ships an MCP server |
Start simple: if you are on OpenAI models and want the quickest path, use the hosted tool. Scale on your terms: move to a custom tool or MCP when you need cross-model support, your own structured and cited output, or cost control at scale.
Getting Structured, Cited Output From Web Search
Grounded answers are most useful when they come with their sources. A common pattern is to return an { "answer": ..., "sources": [...] } shape, which you can enforce with structured output using a Pydantic model or a JSON schema.
If you build your own tool, the cleanest option is a search layer that already returns this shape. The Answers API returns a synthesized answer with its sources and a custom JSON schema, with safeguards against hallucinations and missing data. That gives your agent a predictable, citable result instead of raw HTML.
Production Considerations: Cost, Rate Limits, and Reliability
Web search is not free. OpenAI's web search guide notes that "Search actions incur a tool call cost," which is billed per call on top of your token usage, so check current rates before you scale.
Reliability also needs attention because live search is unpredictable. Plan for these cases:
- Empty or noisy results. Instruct the agent to say when it cannot find an answer instead of guessing.
- Timeouts and retries. Set a timeout on your tool calls, then retry transient failures a small number of times.
- Provider fallback. Keep a second search path ready so one outage does not break your agent.
- Caching. Cache repeated queries to cut cost and latency.
A managed web data layer helps here because it handles browser infrastructure, proxies, and retries for you. This removes scraper maintenance work, so you can focus on building your agent.
Frequently Asked Questions
How do I add web search to an OpenAI Agents SDK agent?
Register a web search tool on your Agent, such as tools=[WebSearchTool()], then run the agent with Runner. The model calls the tool when it needs current information.
Does WebSearchTool work with non-OpenAI models?
No. The hosted WebSearchTool is currently supported only with OpenAI models through the Responses API, so use a custom @function_tool or an MCP provider for other models.
How much does the hosted web search tool cost?
OpenAI's documentation states that search actions incur a tool call cost on top of your token usage, so check the current OpenAI pricing page for the exact rate.
Can I use both web search and file search in one agent?
Yes. You can pass more than one hosted tool in the same tools list, such as WebSearchTool() and FileSearchTool(), and the model chooses which to call.
Hosted WebSearchTool, a custom function tool, or MCP — which should I use?
Use the hosted tool for the fastest path on OpenAI models, and choose a custom function tool or MCP when you need cross-model support, your own structured and cited output, or cost control at scale.
Do I use Runner.run or Runner.run_sync?
Use Runner.run_sync in a normal script and await Runner.run(...) inside async code; both return a result whose final_output holds the answer.



