Add live web search to a CrewAI agent

Superhighway guides

CrewAI builds multi-agent workflows from three pieces: an Agent (a role with a goal and a set of tools), a Task (a unit of work assigned to an agent), and a Crew (the orchestrator that runs the tasks). Any tool you hand an agent's tools= list becomes callable — either all five Superhighway tools at once via MCPServerAdapter, or individual @tool-decorated functions over the REST API.

The Agent / Task / Crew pattern

Every CrewAI program wires up the same three objects:

Two paths

PathBest forWhat you need
MCPServerAdapterAll five tools, fully autonomous — agent pays per call via x402A funded Base wallet + npx
@tool + API keyA curated set of tool functions, controlled spend, no walletA free API key from /pricing

Use MCPServerAdapter when you want the agent to have the full toolbox and pay as it goes with no human in the loop. Use @tool when you want to pick exactly which capabilities the agent gets and bill against a single API key.

Path 1: MCPServerAdapter (recommended for autonomous agents)

pip install "crewai-tools[mcp]"
import os
from crewai import Agent, Task, Crew
from crewai_tools import MCPServerAdapter

# The dict config launches the MCP server as a stdio subprocess.
server_config = {
    "superhighway": {
        "command": "npx",
        "args": ["-y", "superhighway-mcp"],
        "env": {
            "AGENT_PRIVATE_KEY": os.environ["AGENT_PRIVATE_KEY"],
            "X402_NETWORK": "base",
        },
        "transport": "stdio",
    }
}

# The context manager starts the server, discovers its tools, and stops
# it cleanly on exit. mcp_tools is an iterable of CrewAI-ready tools.
with MCPServerAdapter(server_config) as mcp_tools:
    print("Available tools:", [tool.name for tool in mcp_tools])

    researcher = Agent(
        role="Web Researcher",
        goal="Find accurate, up-to-date information from the live web",
        backstory="A meticulous analyst who always verifies claims against current sources.",
        tools=mcp_tools,  # all five tools: web_search, news_search, image_search, scrape, research
        verbose=True,
    )

    task = Task(
        description="Find the top 3 AI web-search APIs and their per-call pricing.",
        expected_output="A ranked list of 3 APIs with prices and source URLs.",
        agent=researcher,
    )

    result = Crew(agents=[researcher], tasks=[task]).kickoff()
    print(result.raw)

AGENT_PRIVATE_KEY is the private key of a wallet holding USDC on Base. Each tool call costs $0.001–$0.005 and settles automatically over the x402 protocol — no signup, no API key, no human approval. The with block is important: MCPServerAdapter manages the subprocess lifecycle, so the server is started on entry and torn down on exit. Build everything that uses mcp_tools — agent, task, crew, and kickoff() — inside the block. To restrict the agent to a subset, pass tool names: MCPServerAdapter(server_config, "web_search", "research").

Path 2: @tool functions with an API key

CrewAI's @tool decorator turns a plain Python function into an agent tool. The decorator argument is the tool's display name; the docstring is the description the model reads to decide when to call it — so write it for the model, not for humans. Get a free API key (1,000 calls/month, email only) and wrap exactly the endpoints you want.

pip install crewai crewai-tools requests
import os
import requests
from crewai import Agent, Task, Crew
from crewai.tools import tool

BASE = "https://superhighway.walls.sh"
HEADERS = {"X-Api-Key": os.environ["SUPERHIGHWAY_API_KEY"]}

@tool("Web Search")
def web_search(query: str) -> str:
    """Search the live web for current information and return ranked results
    with titles, URLs, and descriptions. Use for general up-to-date facts."""
    r = requests.get(f"{BASE}/search", params={"q": query, "limit": 5}, headers=HEADERS)
    return str(r.json())

@tool("News Search")
def news_search(query: str) -> str:
    """Search recent news articles with published dates. Use when recency
    matters — breaking events, latest releases, current headlines."""
    r = requests.get(f"{BASE}/news", params={"q": query, "limit": 5}, headers=HEADERS)
    return str(r.json())

@tool("Deep Research")
def research(query: str) -> str:
    """Search the web AND read the top pages in a single call, returning a
    synthesized answer with sources. Use for questions needing real depth."""
    r = requests.get(f"{BASE}/research", params={"q": query, "pages": 3}, headers=HEADERS)
    return str(r.json())

analyst = Agent(
    role="Market Analyst",
    goal="Answer questions with current, well-sourced web information",
    backstory="An analyst who never guesses — every claim is backed by a live source.",
    tools=[web_search, news_search, research],
    verbose=True,
)

task = Task(
    description="What changed in the latest Python release? Cite the source.",
    expected_output="A short summary of the headline changes with a source URL.",
    agent=analyst,
)

result = Crew(agents=[analyst], tasks=[task]).kickoff()
print(result.raw)

The key CrewAI pattern: @tool("Display Name") from crewai.tools wraps any function, and its docstring becomes the description the model uses for tool selection — a vague docstring means the agent calls the wrong tool. Functions take typed arguments (query: str) so CrewAI can build the input schema. Pass the decorated functions directly in tools=[...]. You can also mix MCP tools and @tool functions in one list by concatenating them.

Which tools are available

Tool / endpointWhat it returnsPrice
web_search / /searchRanked web results — title, URL, description$0.001
news_search / /newsRecent news with published dates$0.001
image_search / /imagesImage URLs, thumbnails, source pages$0.001
scrape / /scrapeAny URL → clean markdown text$0.002
research / /researchSearch + read top pages in one call$0.005

Full API reference: /openapi.json. Get a free API key or learn the x402 wallet flow.