Chapter 3: Tool Selection: Scrape, Map, Crawl, Search, Extract

April 13, 2026 · View on GitHub

Firecrawl MCP exposes distinct tools for each information-retrieval pattern. Choosing the right tool avoids unnecessary API credits and reduces latency. This chapter maps each tool to its use case, explains key parameters, and provides the decision logic for complex research tasks.

Learning Goals

  • Choose tools based on known vs. unknown URL scope
  • Combine tools for multi-step research pipelines
  • Understand format options and extraction schemas
  • Avoid over-crawling when simpler methods suffice

Tool Decision Framework

flowchart TD
    START[What do I need?]
    START --> Q1{Do I have\nexact URLs?}
    Q1 -- Yes, one URL --> SCRAPE[firecrawl_scrape\nSingle URL, rich formats]
    Q1 -- Yes, multiple URLs --> BATCH[firecrawl_batch_scrape\nUp to 10 URLs in parallel]
    Q1 -- No --> Q2{Do I know\nthe domain?}
    Q2 -- Yes, want URL list --> MAP[firecrawl_map\nDiscover all URLs on domain]
    Q2 -- Yes, want content --> CRAWL[firecrawl_crawl\nTraverse site, collect pages]
    Q2 -- No, need web search --> SEARCH[firecrawl_search\nGoogle-style search + scrape]
    SCRAPE --> Q3{Need structured data?}
    Q3 -- Yes --> EXTRACT[firecrawl_extract\nLLM-powered schema extraction]
    Q3 -- No --> DONE[Done]

firecrawl_scrape — Single URL Content Extraction

The primary workhorse. Fetches and converts a single URL to the requested output formats. The description in source code: "The most powerful, fastest and most reliable scraper tool."

// From src/index.ts — scrapeParamsSchema (key parameters)
const scrapeParamsSchema = z.object({
  url: z.string().url(),
  formats: z.array(z.enum([
    'markdown', 'html', 'rawHtml', 'screenshot',
    'links', 'summary', 'changeTracking', 'branding',
    'json', 'query'
  ])).optional(),
  onlyMainContent: z.boolean().optional(),  // strip nav/footer
  waitFor: z.number().optional(),           // ms to wait for JS rendering
  mobile: z.boolean().optional(),           // use mobile viewport
  proxy: z.enum(['basic', 'stealth', 'enhanced', 'auto']).optional(),
  location: z.object({ country: z.string().optional() }).optional(),
  storeInCache: z.boolean().optional(),     // cache result
  zeroDataRetention: z.boolean().optional(),// delete after return
});

Key formats options:

FormatOutput
markdownClean markdown (default, best for LLMs)
htmlProcessed HTML
rawHtmlRaw HTML before processing
screenshotBase64-encoded PNG screenshot
linksArray of all links on the page
summaryLLM-generated page summary
jsonStructured extraction (requires jsonOptions.prompt or .schema)
queryAnswer a specific question about the page content

firecrawl_map — URL Discovery

Returns a list of all URLs on a domain without fetching content. Use this when you need to discover what pages exist before deciding what to scrape.

sequenceDiagram
    participant LLM
    participant MCP Server
    participant Firecrawl API

    LLM->>MCP Server: firecrawl_map {url: "https://docs.example.com"}
    MCP Server->>Firecrawl API: map request
    Firecrawl API-->>MCP Server: ["/docs/intro", "/docs/api", "/blog/post-1", ...]
    MCP Server-->>LLM: URL list (up to sitemap limit)
    LLM->>LLM: Filter relevant URLs
    LLM->>MCP Server: firecrawl_batch_scrape {urls: [filtered list]}

Parameters: url, limit (max URLs to return), search (filter by keyword), ignoreSitemap, includeSubdomains.

firecrawl_crawl — Recursive Site Traversal

Crawls a site by following internal links, collecting content from each page. Returns a job ID; content is returned asynchronously or polled via firecrawl_check_crawl_status.

Use carefully: Crawls can consume significant API credits. Always set maxDepth and limit:

{
  "url": "https://docs.example.com",
  "maxDepth": 2,
  "limit": 50,
  "scrapeOptions": {
    "formats": ["markdown"],
    "onlyMainContent": true
  }
}

firecrawl_search — Web Search + Scrape

Performs a web search and returns scraped content for the top results in a single call. Useful when you don't know which domain contains the information you need.

flowchart LR
    QUERY[Search query:\nnpm package zod v4 changes]
    QUERY --> SEARCH_API[Firecrawl search\n= web search + automatic scraping]
    SEARCH_API --> RESULTS[Top N results\nwith markdown content]
    RESULTS --> LLM[LLM synthesizes\nfrom multiple sources]

Parameters: query, limit (number of results), lang, country, scrapeOptions (format control for each result).

firecrawl_extract — LLM-Powered Structured Extraction

Extracts structured data from one or more URLs using a schema or natural language prompt. Returns a JSON object rather than raw content.

{
  "urls": ["https://example.com/product"],
  "prompt": "Extract product name, price, and availability",
  "schema": {
    "type": "object",
    "properties": {
      "name": { "type": "string" },
      "price": { "type": "number" },
      "available": { "type": "boolean" }
    }
  }
}

Best for: pricing data, contact information, structured product catalogs, repeated page patterns.

firecrawl_batch_scrape — Parallel Multi-URL Scraping

Submits up to 10 URLs for parallel scraping. Returns a job ID. Poll with firecrawl_check_batch_scrape_status to get results.

Tool Selection Summary

ToolBest ForCredit CostResponse Mode
firecrawl_scrapeSingle known URLLow (1 credit)Synchronous
firecrawl_batch_scrape2–10 known URLsMediumAsync (poll)
firecrawl_mapDiscover URLs on domainLowSynchronous
firecrawl_crawlFull site content harvestHighAsync (poll)
firecrawl_searchUnknown source, topic-firstMediumSynchronous
firecrawl_extractStructured data extractionMediumSync or Async

Source Code Walkthrough

src/index.ts

The firecrawl_map tool definition in src/index.ts illustrates the tool registration pattern used by all tools in this chapter:

server.addTool({
  name: 'firecrawl_map',
  description: `Map a website to discover all indexed URLs on the site.

**Best for:** Discovering URLs on a website before deciding what to scrape...
**Not recommended for:** When you already know which specific URL you need (use scrape)...`,
  parameters: z.object({
    url: z.string().url(),
    search: z.string().optional(),
    sitemap: z.enum(['include', 'skip', 'only']).optional(),
    includeSubdomains: z.boolean().optional(),
    limit: z.number().optional(),
    ignoreQueryParameters: z.boolean().optional(),
  }),
  execute: async (
    args: unknown,
    { session, log }: { session?: SessionData; log: Logger }
  ): Promise<string> => {
    const { url, ...options } = args as { url: string } & Record<string, unknown>;
    const client = getClient(session);
    const cleaned = removeEmptyTopLevel(options as Record<string, unknown>);
    log.info('Mapping URL', { url: String(url) });
    const res = await client.map(String(url), { ...cleaned, origin: ORIGIN } as any);
    return asText(res);
  },
});

This registration pattern is important because it defines how each tool in this chapter connects Zod-validated inputs to the @mendable/firecrawl-js SDK client — with removeEmptyTopLevel stripping null/empty fields before the API call.

Summary

firecrawl_scrape is the default choice for any known URL. Use firecrawl_map to discover URLs before batch-scraping. Use firecrawl_search when you don't know the source. Use firecrawl_crawl only with explicit depth and limit constraints. Use firecrawl_extract when you need structured JSON instead of prose content.

Next: Chapter 4: Client Integrations: Cursor, Claude, Windsurf, VS Code