How do I give a CrewAI agent web access with UpRock?
Connect UpRock's MCP server with MCPServerAdapter from crewai-tools, using the streamable-http transport and your API key in an Authorization header, and pass the tools it returns to your Agent. The newer mcps field works with the same header, but it stops every tool call after 30 seconds, and a fresh fetch can take longer.
Updated · Read as markdown
What your crew gets
UpRock's MCP server runs over streamable HTTP at https://mcp.uprock.ai/mcp, with your API key in an Authorization: Bearer header. MCPServerAdapter turns each of its tools into a CrewAI tool with the same name, and takes a list of names to load only some of them:
| Tool | What it does | Load it? |
|---|---|---|
crawl_fetch | Loads a page in a real browser on a desktop or mobile device in the country you pass; returns a summary and links to the stored markdown and HTML | Yes |
resource_fetch | Reads a stored result in full, such as that markdown | Yes, with crawl_fetch |
verify | Loads one URL from several regions with status, timings and screenshots | When the crew checks websites |
video_search | Finds moments in public video by meaning | When answers may be in video |
video_moment | Reads the time-stamped moments of one video | Use with care: it returned 502 "temporarily unavailable" when we tested on 25 Oct 2026 |
web_research | Searches several engines from chosen countries | Use with care: on 25 Oct 2026, 4 of the 8 results for a query about the MCP spec were unrelated Wikipedia pages |
Get a key at uprock.ai/app/api-keys and set it as UPROCK_API_KEY.
MCPServerAdapter or the mcps field
CrewAI's docs recommend the mcps field on Agent for most MCP servers. It works with UpRock as long as the key goes in a header, but MCPServerAdapter is still the better fit. This is what each setup gave us:
| How UpRock is added | Tool names the model sees | Limit per tool call |
|---|---|---|
MCPServerAdapter(...), or get_mcp_tools() in a @CrewBase crew | crawl_fetch, resource_fetch | None |
mcps=[MCPServerHTTP(url="https://mcp.uprock.ai/mcp", headers=...)] | mcp_uprock_ai_mcp_crawl_fetch, mcp_uprock_ai_mcp_resource_fetch, ... | 30 seconds, fixed |
mcps with the key in the URL (https://mcp.uprock.ai/<API_KEY>/mcp) | mcp_uprock_ai_<your key>_mcp_887879dd: the key, with the tool's own name cut off to fit 64 characters | 30 seconds, fixed |
A fresh UpRock fetch takes 10 to 40 seconds, so through mcps some will be cut off. The last row is why the key never goes in the URL with CrewAI: CrewAI builds tool names from the URL, path included, so the key would go to your model provider with every request, show up in verbose logs and in CrewAI's "MCP Connected" panel, and the model couldn't tell the tools apart.
The code
The example makes a direct call first, which needs no model, then gives the same two tools to an agent in a crew:
# pip install "crewai[anthropic]" "crewai-tools[mcp]" env: UPROCK_API_KEY, ANTHROPIC_API_KEYimport astimport jsonimport osfrom crewai import LLM, Agent, Crew, Taskfrom crewai_tools import MCPServerAdapterUPROCK = { "url": "https://mcp.uprock.ai/mcp", "transport": "streamable-http", "headers": {"Authorization": f"Bearer {os.environ['UPROCK_API_KEY']}"},}MODEL = "anthropic/claude-sonnet-5-5" # any model CrewAI supportsdef summary(output: str) -> dict: """crawl_fetch returns a JSON summary and two resource links. The adapter keeps the text and returns str() of a list when there's more than one block.""" text = ast.literal_eval(output)[0] if output.startswith("[") else output try: page = json.loads(text) except ValueError: page = {} if page.get("status") != "success": raise RuntimeError(f"UpRock: {text}") return pagewith MCPServerAdapter( UPROCK, "crawl_fetch", "resource_fetch", connect_timeout=60) as tools: crawl_fetch, resource_fetch = tools["crawl_fetch"], tools["resource_fetch"] # 1. A direct call, no model involved: load a page on a device in Germany. page = summary(crawl_fetch.run(url="https://example.com", country="DE")) markdown = resource_fetch.run(uri=page["content"]["markdown"]["resource"]) print(page["meta"]["title"], len(markdown), "chars of markdown") # 2. The same tools in a crew. reader = Agent( role="Web reader", goal="Read web pages as they look in the country the user names", backstory=( "When you need a page from a specific country, or another fetch failed, " "call crawl_fetch with the url and country, then resource_fetch on the " "markdown resource it returns." ), tools=tools, llm=LLM(model=MODEL), ) task = Task( description="What does https://example.com say when opened from Germany?", expected_output="The page title and one sentence on what the page says.", agent=reader, ) print(Crew(agents=[reader], tasks=[task]).kickoff())Keep the crew inside the with block: the adapter closes the connection when the block ends.
In a crew made with crewai create
Projects scaffolded with crewai create crew use a @CrewBase class. Give it the server once and pick tools per agent:
import osfrom crewai import Agentfrom crewai.project import CrewBase, agent@CrewBaseclass ResearchCrew: mcp_server_params = { "url": "https://mcp.uprock.ai/mcp", "transport": "streamable-http", "headers": {"Authorization": f"Bearer {os.environ['UPROCK_API_KEY']}"}, } mcp_connect_timeout = 60 @agent def reader(self) -> Agent: return Agent( config=self.agents_config["reader"], tools=self.get_mcp_tools("crawl_fetch", "resource_fetch"), )Add your @task and @crew methods as usual. CrewBase opens one adapter for the whole crew and closes it after kickoff().
What comes back
The first call above printed Example Domain 958 chars of markdown. Here's what each tool hands back through the adapter:
| Tool | What you get | How to read it |
|---|---|---|
crawl_fetch | str() of a one-item list holding the JSON summary (status, title, and the crawl:// addresses of the markdown and HTML); the two resource links are dropped | ast.literal_eval(output)[0], then json.loads |
resource_fetch | The page as markdown, as a plain string | Use it as is |
| Any tool that fails | The error text as a plain string, such as all 3 attempts failed; last error: ... Invalid API key; the adapter doesn't raise. A wrong key took 14 seconds to fail, because UpRock tried three times | Check before parsing, as summary() does |
Inside a crew the agent sees the same strings, and the backstory tells it to follow up with resource_fetch. Two more things: meta.status_code isn't reliable (when we fetched a page that answers 403, status said success and status_code was missing), and a fresh fetch takes 10 to 40 seconds (19 in this test), against under half a second for a page fetched recently.
On 29 Oct 2026 we re-ran the direct calls in both examples with the key in the header, using crewai and crewai-tools 1.15.33 and mcp 1.30.0 on Python 3.12, and called crawl_fetch through the mcps field with the header; the 30-second limit is MCP_TOOL_EXECUTION_TIMEOUT in that version's source. Before that, on 25 Oct with 1.15.30 and the key in the URL, we ran both examples against the live UpRock server. The direct calls returned example.com's title and markdown. For the crew we swapped LLM(model=MODEL) for a scripted test model with no API key: it called crawl_fetch and then resource_fetch through UpRock and finished with the page title. The @CrewBase class ran the same way with a minimal agents.yaml. The key-in-URL mcps names come from that version, with a made-up key and a model that recorded what it was sent.
FAQ
Can I use the mcps field on Agent instead?
Yes, with MCPServerHTTP(url="https://mcp.uprock.ai/mcp", headers={"Authorization": f"Bearer {key}"}); the tools are then named mcp_uprock_ai_mcp_crawl_fetch and so on. It stops every tool call after 30 seconds (a fixed limit in crewai 1.15.33), and a fresh fetch can take 10 to 40, so MCPServerAdapter is the safer choice. Never give mcps the older address with the key in the URL: CrewAI builds tool names from the URL, so the key reached the model in every tool name when we tried it.
Why does crawl_fetch return a string that starts with a square bracket?
crawl_fetch answers with a JSON summary plus two resource links. MCPServerAdapter keeps only text blocks, and when a tool returns more than one block it returns str() of a list of them. Read it with ast.literal_eval and take the first item, as the example's summary() does.
Does MCPServerAdapter time out on slow fetches?
connect_timeout (30 seconds by default) only covers connecting. In crewai-tools 1.15.30 and 1.15.33 the tool calls themselves had no time limit, and a fresh fetch that took 19 seconds went through. The mcps field is different: it stops each tool call after 30 seconds.
Can I use it in a crew made with crewai create?
Yes. Set mcp_server_params on the @CrewBase class and call self.get_mcp_tools("crawl_fetch", "resource_fetch") in the agent method. CrewBase uses MCPServerAdapter underneath, so the tool names stay plain, and it closes the connection after kickoff.
What does it cost?
One credit per page fetched, $0.50 per 1,000 pages by card or USDC and $0.40 with UPT, prepaid. Video search is $1 per 1,000 searches.
Other use cases to explore
- Turn web pages into markdown for an agent: what a page looks like after a real browser loads it, and when that beats a plain fetch.
- Work out what your agents spend on the web: pages, searches and video calls per run, priced per 1,000.
- Add a fallback to a crawler you run: hand the requests Crawlee gives up on to a device in the country you choose.
- Search public video by moment: find the second something is shown or said, across platforms.
References
- CrewAI docs, MCP Servers as Tools in CrewAI (MCPServerAdapter, CrewBase), checked 25 Oct 2026
- CrewAI docs, MCP DSL Integration (the mcps field, tool naming, timeouts), checked 25 Oct 2026
- CrewAI docs, Streamable HTTP Transport, checked 25 Oct 2026
- CrewAI source, how mcps tools are named (tool_resolver.py), checked 25 Oct 2026
- crewai-tools source, MCPServerAdapter (mcp_adapter.py), checked 25 Oct 2026
- crewai on PyPI, checked 29 Oct 2026
- UpRock, setup for every agent, checked 25 Oct 2026
- UpRock, everything in one file (API, CLI, MCP, pricing), checked 25 Oct 2026
Get started
Add UpRock in one paste.
Paste this into Claude Code, Codex, Cursor or any agent with a terminal. It reads our docs, sets up the MCP server or CLI, and tells you the cost before it spends anything.
Set up UpRock for me: read https://uprock.ai/agents.md, connect the UpRock MCP server, and run one test crawl. Tell me what it costs before you spend anything.