How do I give a Vercel AI SDK app web access with UpRock?
Create an MCP client with createMCPClient from @ai-sdk/mcp pointed at UpRock's server, pass its tools to generateText or streamText, and the model can load pages on an opted-in device in the country it picks. Give tool calls an abort signal, because they have no default timeout, and close the client when the run ends.
Updated · Read as markdown
What the model gets
UpRock's MCP server runs over streamable HTTP at https://mcp.uprock.ai/mcp, with your API key in an Authorization: Bearer header (clients that can't send headers can use https://mcp.uprock.ai/<API_KEY>/mcp instead). client.tools() returns an object you can pass straight to generateText, with these keys:
| Tool | What it does |
|---|---|
crawl_fetch | Loads a page in a real browser on a device in the country you pass (url, country, device_type); returns a summary and links to the stored markdown and HTML |
resource_fetch | Reads a stored result in full (uri), such as that markdown |
video_search | Finds moments in public video by meaning (query) |
video_moment | Describes what happens in a stretch of one video (url, start_s, end_s) |
verify | Loads one URL from several regions with status and timings |
web_research | Multi-engine search from chosen countries. Use with care: when we tested on 21 Oct 2026 it returned empty or off-topic results from some countries |
To expose only some tools to the model, pick them out of the object, for example { crawl_fetch: tools.crawl_fetch, resource_fetch: tools.resource_fetch }.
The code
The example makes a direct call first (no model involved), then lets Claude choose the tools in generateText. Set UPROCK_API_KEY (from uprock.ai/app/api-keys) and ANTHROPIC_API_KEY, or swap in any other provider:
// npm i ai @ai-sdk/mcp @ai-sdk/anthropic (Node 18+) env: UPROCK_API_KEY, ANTHROPIC_API_KEYimport { createMCPClient } from "@ai-sdk/mcp";import { anthropic } from "@ai-sdk/anthropic";import { generateText, isStepCount } from "ai";const uprock = await createMCPClient({ transport: { type: "http", url: "https://mcp.uprock.ai/mcp", headers: { Authorization: `Bearer ${process.env.UPROCK_API_KEY}` }, },});type Block = { type: string; text?: string };const textOf = (result: unknown) => (result as { content: Block[] }).content.find((b) => b.type === "text")?.text ?? "";try { const tools = await uprock.tools(); // crawl_fetch, resource_fetch, video_search, ... // 1. A direct call, no model involved: load a page on a device in Germany. Tool calls have // no default timeout, so pass one. const options = { toolCallId: "1", messages: [], context: {}, abortSignal: AbortSignal.timeout(300_000), }; const page = JSON.parse( textOf( await tools.crawl_fetch.execute!( { url: "https://example.com", country: "DE" }, options, ), ), ); const markdown = textOf( await tools.resource_fetch.execute!( { uri: page.content.markdown.resource }, options, ), ); console.log(page.meta.title, markdown.length, "chars of markdown"); // 2. The same tools, chosen by a model. const { text } = await generateText({ model: anthropic("claude-sonnet-5-5"), tools, stopWhen: isStepCount(5), system: "When you need a web page as it looks in a specific country, or another fetch failed, call " + "crawl_fetch with the url and country, then resource_fetch on the markdown resource it returns.", prompt: "What does https://example.com say when opened from Germany?", }); console.log(text);} finally { await uprock.close(); // after generateText resolves; with streamText, close in onFinish}Calling execute yourself returns the raw MCP result, { content, isError }. In the AI SDK 7 types, its options need toolCallId, messages and context; abortSignal is optional but worth passing.
What comes back
The first text block of a crawl_fetch result is a JSON summary, small on purpose:
{ "status": "success", "meta": { "url": "https://example.com", "title": "Example Domain", "content_type": "text/html" }, "content": { "markdown": { "resource": "crawl://…/markdown", "size_bytes": 1342 } }}When the model calls the tool, the AI SDK turns text into text and everything else, including resource links, into JSON text, so the model sees this summary and the resource address. The system prompt in the example tells it to follow up with resource_fetch, which returns the page as markdown. Don't rely on meta.status_code: it isn't always present.
Good to know
- No default timeout. Pass an
abortSignalon direct calls; for model-driven calls, pass one togenerateText. - Close the client after
generateTextresolves, or inonFinishwithstreamText. - The key is in a header. Keep it in an environment variable, and don't log the client's config or
MCPClientErrorobjects whole. - Cost. One credit per page fetched: $0.50 per 1,000 pages by card or USDC, $0.40 with UPT. Cap the agent's steps (
isStepCount) and say in the system prompt when to ask before fetching many pages.
We ran this example on 21 Oct 2026 with ai 7.0.148 and @ai-sdk/mcp 2.0.81 against the live UpRock server. The direct calls returned example.com's title and markdown. For the generateText part we used the AI SDK's own mock model, scripted to call crawl_fetch and then answer, in place of Claude: the loop ran two steps and the tool call went through UpRock. On 6 Nov 2026 we ran the direct calls again with an UpRock API key in an Authorization header.
FAQ
Is it createMCPClient or experimental_createMCPClient?
createMCPClient, from @ai-sdk/mcp, in AI SDK 7. experimental_createMCPClient is still exported but marked deprecated, and the ai package itself no longer exports an MCP client.
Do I need to close the client?
Yes. With generateText, close it in a finally block after the call resolves, as in the example. With streamText, close it in onFinish, after the stream is done; closing earlier cuts off tool calls still running.
Why pass an abortSignal?
MCP tool calls in the AI SDK have no default timeout. A fresh UpRock fetch takes 10 to 40 seconds, so the example gives each direct call five minutes. When the model calls the tools, generateText's own abortSignal applies.
What does the model see when it calls crawl_fetch?
The AI SDK passes text content through and turns other content, including resource links, into JSON text. The model reads a short JSON summary with the page's title and a link to its stored markdown, and calls resource_fetch when it wants the full page.
Is my API key safe in logs?
Be careful, because the key is part of the server URL, and the AI SDK's docs warn not to log the url or responseBody of an MCPClientError. Keep the key in an environment variable and log error messages, not the error objects.
Other use cases to explore
- See a page as it looks in another country: one store page from five countries, with five prices, two languages and a cookie banner in one country only.
- Don't let a cache hide a failed fetch: a provider that quietly serves an older copy when a live fetch fails, and the setting that stops it.
- Cap what a single page can cost: one provider's credit table, from 1 to 75 credits a page, and how to stop before the expensive tiers.
- Search public video by moment: find the second something is shown or said, across platforms.
References
- AI SDK docs, MCP tools, checked 21 Oct 2026
- AI SDK reference, createMCPClient, checked 21 Oct 2026
- @ai-sdk/mcp on npm, checked 21 Oct 2026
- AI SDK docs, Anthropic provider, checked 21 Oct 2026
- UpRock, setup for every agent, checked 21 Oct 2026
- UpRock, everything in one file (API, CLI, MCP, pricing), checked 21 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.