Build a Web Research Agent with Abstraxn + Firecrawl
Most research agents cite URLs they never opened. Here's how we built one that scrapes first, summarizes second, and ships from a repo you can clone in minutes.

A PM on our team pasted a competitor's pricing URL into a research agent and asked for a comparison table. The agent came back in thirty seconds with clean rows, confident tone, and footnotes that looked legitimate. Every URL was real. Almost none of the numbers matched what was on the page that morning because the competitor had changed tiers overnight, and the model had no idea because it never opened the link.
That's the failure mode nobody demos on stage. Brainstorming? A model that riffing from memory is fine. Due diligence, support docs, compliance screenshots, anything where wrong details have a cost? You need the page in front of the model before it speaks.
This post walks through the research agent we built to fix that using Firecrawl for fetch, Abstraxn MCP for the tool layer, and a thin Next.js shell you can clone. It's part of Build your Agent with Abstraxn, the open examples series we use internally before we write the marketing version. If you haven't run Hello Wallet yet, do that first. Same scaffold, fewer moving parts, and you'll know your keys work before you add scraping.
The short version: A research agent without a scrape step is a summarizer with amnesia. We wire
firecrawl_scrapethrough Abstraxn MCP so the model fetches live markdown, then summarizes with citations. No Firecrawl SDK in your frontend, no scraper service to run yourself. Cloneexamples/01-firecrawl-research, enable Firecrawl in the dashboard, ask it to scrape a URL. If the answer quotes what you see in the browser, you're done.
The gap between a citation and a fetch
Models are trained to sound authoritative. Give them a URL in the prompt and many will behave as if they've read it by generating plausible pricing, plausible feature lists, and plausible quotes. Strip the URL and ask where each fact came from, and the story often falls apart.
Firecrawl handles the part models can't: turn a URL into clean markdown at request time. Abstraxn handles the part most teams don't want to build: host the tool on MCP, bind it to an agent, keep credentials out of the client. Your app sends the user's question; the model decides when to call firecrawl_scrape; Firecrawl returns content; the model summarizes with the page actually in context.
| Layer | What it does |
|---|---|
| Your chat UI or MCP client | Carries the conversation |
| Abstraxn MCP | Exposes firecrawl_scrape, enforces the allowlist |
| Firecrawl (via dashboard integration) | Fetches and normalizes the page |
| LLM | Reasons over scraped markdown, cites URLs |
You are not embedding Firecrawl in React. You are not passing scrape API keys to the browser. Abstraxn is the control plane; Firecrawl is the integration; your code is mostly a system prompt that says: summarize with citations, and do not invent page content when the tool fails.
Browser chat → Next.js /api/chat → Vercel AI SDK
→ Abstraxn MCP (firecrawl_scrape)
→ Firecrawl (via Abstraxn integrations)
The example also bootstraps a server wallet on first message just like every app in the series. Research doesn't need on-chain actions today, but the wallet is there when you extend the agent to paid data feeds or x402-gated docs later.
Try it from the dashboard first
We usually validate integrations this way before anyone clones a repo.
Sign in at agent.abstraxn.com, create or reuse an agent, and enable Firecrawl under Dashboard → Integrations (guide). Copy the MCP endpoint into Claude, Cursor, or your own runtime. Ask something concrete:
Scrape https://abstraxn.com and summarize what the company builds.
You should see a tool call in the trace, then a summary that tracks the live page instead of generic agentic-AI language the model already knows. If that works, the hard part is done. The Next.js example is for teams that want a branded UI, custom prompts, and a repo their engineers can fork.
The clone where one file defines behavior
Everything lives in abstraxn-agent-examples. Same packages as Hello Wallet and Trading; different lib/agent.ts.
// examples/01-firecrawl-research/lib/agent.ts
export const agentConfig = {
name: "Firecrawl Research Agent",
tools: "firecrawl", // → firecrawl_scrape + get_wallet_address
system: `You are a web research agent. Use firecrawl_scrape to fetch page content.
Summarize findings with clear citations (URL + short quote).
If scraping fails, explain the error and suggest another URL.
Do not invent page content.`,
};Tool sets stay centralized so we don't fork MCP wiring per example:
// packages/mcp/src/index.ts
firecrawl: ["firecrawl_scrape", "get_wallet_address"]Want stricter citations? Tighten the system prompt. Want a different tool mix? Change the tool set name. The route and bootstrap code stay the same.
// examples/01-firecrawl-research/app/api/chat/route.ts
export async function POST(req: Request) {
const { messages } = await req.json();
const session = await getOrCreateSession({
name: agentConfig.name,
description: agentConfig.system.slice(0, 120),
});
const mcp = createMcpFromBootstrap(session);
const result = await createAgentChat({
mcp,
config: {
...agentConfig,
system: `${agentConfig.system}\n\nAgent wallet: ${session.evmAddress ?? "unknown"}`,
},
messages,
});
return result.toUIMessageStreamResponse();
}Run it
git clone https://github.com/Abstraxn-Labs/abstraxn-agent-examples
cd abstraxn-agent-examples
pnpm install
cp .env.example .env
# ABSTRAXN_API_KEY + LLM_API_KEY (OpenAI by default)
pnpm run build:packages
pnpm --filter @abstraxn-examples/firecrawl-research devOpen http://localhost:3001. We usually test with our own site first since it is hard to fake whether the scrape ran:
Scrape https://abstraxn.com and summarize what Abstraxn builds.
In the UI you should see firecrawl_scrape fire before the answer streams. If the summary mentions something that's only on the page right now, you have ground truth. If it sounds like marketing copy the model already memorized, check the tool trace because the call probably didn't run.
After the first successful session, paste agent credentials from the terminal into .env so dev restarts don't mint a new wallet every time:
ABSTRAXN_AGENT_ID=
ABSTRAXN_MCP_TOKEN=
ABSTRAXN_EVM_ADDRESS=0x...Why we open-sourced the scaffold
Coinbase-style agent kits win on examples people can actually run. Abstraxn already ships Agent Kit and Agent Hub for production. What was missing was the cloneable layer: thin apps, shared packages, one story per use case that a developer can fork in an afternoon.
We write these posts the same way we build the repo with the concept first for whoever needs the why, and the code second for whoever needs to ship. Same link for both.
Next in the series
- Hello Wallet to prove Agent Kit before you add tools
- Firecrawl research (this post)
- Trading agent with spend policy
- Transaction monitoring
- Policy-enforced fraud guard
Clone it, point it at your docs, and tell us what you built.