# 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 29 Oct 2026. Web page: https://uprock.ai/integrations/crewai

## On this page

- [What your crew gets](#what-your-crew-gets)
- [MCPServerAdapter or the mcps field](#mcpserveradapter-or-the-mcps-field)
- [The code](#the-code)
- [What comes back](#what-comes-back)
- [FAQ](#faq)
- [Other use cases to explore](#explore)
- [Related articles](#related)
- [References](#references)
- [Get started](#get-started)

## 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:

```python
# pip install "crewai[anthropic]" "crewai-tools[mcp]"   env: UPROCK_API_KEY, ANTHROPIC_API_KEY
import ast
import json
import os

from crewai import LLM, Agent, Crew, Task
from crewai_tools import MCPServerAdapter

UPROCK = {
    "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 supports


def 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 page


with 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:

```python
import os

from crewai import Agent
from crewai.project import CrewBase, agent


@CrewBase
class 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](https://uprock.ai/use-cases/web-pages-to-markdown): 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](https://uprock.ai/use-cases/agent-web-costs): pages, searches and video calls per run, priced per 1,000.
- [Add a fallback to a crawler you run](https://uprock.ai/compare/apify#hand-crawlees-failed-requests-to-uprock): hand the requests Crawlee gives up on to a device in the country you choose.
- [Search public video by moment](https://uprock.ai/video-semantic-search): find the second something is shown or said, across platforms.

## Related articles

- [How do I give Claude Code live web access with UpRock?](https://uprock.ai/integrations/claude-code.md): Add UpRock's MCP server to Claude Code with the key kept out of your repo, check it's connected, tell Claude when to use it, and know the output limits that matter for big pages.
- [How do I add UpRock to Cursor?](https://uprock.ai/integrations/cursor.md): Add UpRock's MCP server to Cursor with the key read from your environment, turn it on, pre-approve the fetch tools, add a rule for when to use it, and run it from Cursor's command-line agent.
- [How do I use UpRock as a LangChain tool?](https://uprock.ai/integrations/langchain.md): Load UpRock's MCP tools into LangChain in Python or JavaScript, call them directly or from an agent, and handle the result format, with code we ran against the live server.
- [How do I give a Vercel AI SDK app web access with UpRock?](https://uprock.ai/integrations/vercel-ai-sdk.md): Connect UpRock's MCP server with @ai-sdk/mcp, call its tools directly or let the model choose them in generateText, and avoid the timeout and key-logging traps, with code we ran against the live server.
- [How do I fetch web pages from a chosen country in n8n?](https://uprock.ai/integrations/n8n.md): Install UpRock's verified n8n node, add your key, import a two-node workflow we ran in n8n 2.44, and read the page's markdown in the next step, or give the node to an AI Agent as a tool.
- [How do I add UpRock to OpenAI's Codex CLI?](https://uprock.ai/integrations/codex.md): Add UpRock's MCP server to Codex with one command, keep the API key in an environment variable, raise the 60-second tool timeout, and add your own rules in AGENTS.md.
- [How do I give a Mastra agent web access with UpRock?](https://uprock.ai/integrations/mastra.md): Connect UpRock's MCP server with MCPClient from @mastra/mcp, raise its 60-second timeout, and call the tools directly or from an Agent, with tested code.
- [Integrations: all articles](https://uprock.ai/integrations.md)

## References

1. [CrewAI docs, MCP Servers as Tools in CrewAI (MCPServerAdapter, CrewBase)](https://docs.crewai.com/en/mcp/overview), checked 25 Oct 2026
2. [CrewAI docs, MCP DSL Integration (the mcps field, tool naming, timeouts)](https://docs.crewai.com/en/mcp/dsl-integration), checked 25 Oct 2026
3. [CrewAI docs, Streamable HTTP Transport](https://docs.crewai.com/en/mcp/streamable-http), checked 25 Oct 2026
4. [CrewAI source, how mcps tools are named (tool_resolver.py)](https://github.com/crewAIInc/crewAI/blob/main/lib/crewai/src/crewai/mcp/tool_resolver.py), checked 25 Oct 2026
5. [crewai-tools source, MCPServerAdapter (mcp_adapter.py)](https://github.com/crewAIInc/crewAI/blob/main/lib/crewai-tools/src/crewai_tools/adapters/mcp_adapter.py), checked 25 Oct 2026
6. [crewai on PyPI](https://pypi.org/project/crewai/), checked 29 Oct 2026
7. [UpRock, setup for every agent](https://uprock.ai/agents.md), checked 25 Oct 2026
8. [UpRock, everything in one file (API, CLI, MCP, pricing)](https://uprock.ai/llms-full.txt), checked 25 Oct 2026

## Get started

Get an API key: https://uprock.ai/app/api-keys

Paste this into your agent:

```text
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.
```

Setup for every client (MCP, skill, CLI): https://uprock.ai/agents.md
