firecrawl-mcp 3.21.4 → 3.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +20 -2
  2. package/dist/index.js +64 -13
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -26,6 +26,24 @@ A Model Context Protocol (MCP) server that brings [Firecrawl](https://github.com
26
26
 
27
27
  ## Installation
28
28
 
29
+ ### Hosted MCP (keyless free tier)
30
+
31
+ Connect to the remote hosted server with no setup:
32
+
33
+ ```
34
+ https://mcp.firecrawl.dev/v2/mcp
35
+ ```
36
+
37
+ On the keyless free tier, `scrape`, `search`, and `interact` work without an API key (rate-limited). Other tools such as `crawl`, `map`, `agent`, and `extract` still need a key.
38
+
39
+ Prefer an API key or OAuth whenever the human can sign up. It unlocks the full tool set and higher limits. With a key, use:
40
+
41
+ ```
42
+ https://mcp.firecrawl.dev/{FIRECRAWL_API_KEY}/v2/mcp
43
+ ```
44
+
45
+ See the [MCP server docs](https://docs.firecrawl.dev/mcp-server) and the [agent onboarding guide](https://www.firecrawl.dev/agent-onboarding/SKILL.md) for setup details.
46
+
29
47
  ### Running with npx
30
48
 
31
49
  ```bash
@@ -326,14 +344,14 @@ Use this guide to select the right tool for your task:
326
344
  - **If you want to search the web for info:** use **search**
327
345
  - **If you need complex research across multiple unknown sources:** use **agent**
328
346
  - **If you want to analyze a whole site or section:** use **crawl** (with limits!)
329
- - **If you need interactive browser automation** (click, type, navigate): use **scrape** + **interact**
347
+ - **If you need interactive browser automation** (click, type, navigate): use **interact** with a URL for a fresh page, or **scrape** + **interact** when you already scraped the page or need tighter scrape control
330
348
 
331
349
  ### Quick Reference Table
332
350
 
333
351
  | Tool | Best for | Returns |
334
352
  | ------------ | ---------------------------------------------- | ------------------------------ |
335
353
  | scrape | Single page content | JSON (preferred) or markdown |
336
- | interact | Interact with a scraped page | Execution result |
354
+ | interact | Interact with a URL or scraped page | Execution result + scrapeId for URL mode |
337
355
  | batch_scrape | Multiple known URLs | JSON (preferred) or markdown[] |
338
356
  | map | Discovering URLs on a site | URL[] |
339
357
  | crawl | Multi-page extraction (with limits) | markdown/html[] |
package/dist/index.js CHANGED
@@ -3846,24 +3846,28 @@ server.addTool({
3846
3846
  // Transient page interactions only; does not delete monitors, jobs, or external sites.
3847
3847
  },
3848
3848
  description: `
3849
- Interact with a previously scraped page in a live browser session. Scrape a page first with firecrawl_scrape, then use the returned scrapeId to click buttons, fill forms, extract dynamic content, or navigate deeper.
3849
+ Interact with a page in a live browser session: click buttons, fill forms, extract dynamic content, or navigate deeper.
3850
3850
 
3851
3851
  **Best for:** Multi-step workflows on a single page \u2014 searching a site, clicking through results, filling forms, extracting data that requires interaction.
3852
- **Requires:** A scrapeId from a previous firecrawl_scrape call (found in the metadata of the scrape response).
3852
+ **Two ways to target a page:**
3853
+ - Pass a \`url\` to interact directly. The session is opened for you in one call (use this for a fresh page).
3854
+ - Pass a \`scrapeId\` from a previous firecrawl_scrape to reuse that already-loaded page (cheaper when you just scraped it).
3853
3855
 
3854
3856
  **Arguments:**
3855
- - scrapeId: The scrape job ID from a previous scrape (required)
3857
+ - url: Page to interact with; opens a session for you (use this OR scrapeId)
3858
+ - scrapeId: Scrape job ID from a previous scrape, found in its metadata (use this OR url)
3856
3859
  - prompt: Natural language instruction describing the action to take (use this OR code)
3857
3860
  - code: Code to execute in the browser session (use this OR prompt)
3858
3861
  - language: "bash", "python", or "node" (optional, defaults to "node", only used with code)
3859
- - timeout: Execution timeout in seconds, 1-300 (optional, defaults to 30)
3862
+ - timeout: Interact execution timeout in seconds, 1-300 (optional, defaults to 30)
3863
+ - scrapeOptions: Optional scrape controls used only with url mode, such as waitFor, maxAge, proxy, or zeroDataRetention
3860
3864
 
3861
- **Usage Example (prompt):**
3865
+ **Usage Example (prompt, direct via url):**
3862
3866
  \`\`\`json
3863
3867
  {
3864
3868
  "name": "firecrawl_interact",
3865
3869
  "arguments": {
3866
- "scrapeId": "scrape-id-from-previous-scrape",
3870
+ "url": "https://example.com/products",
3867
3871
  "prompt": "Click on the first product and tell me its price"
3868
3872
  }
3869
3873
  }
@@ -3883,24 +3887,71 @@ Interact with a previously scraped page in a live browser session. Scrape a page
3883
3887
  **Returns:** Execution result including output, stdout, stderr, exit code, and live view URLs.
3884
3888
  `,
3885
3889
  parameters: z4.object({
3886
- scrapeId: z4.string(),
3887
- prompt: z4.string().optional(),
3888
- code: z4.string().optional(),
3890
+ scrapeId: z4.string().trim().min(1).optional(),
3891
+ url: z4.string().trim().url().optional(),
3892
+ prompt: z4.string().trim().min(1).optional(),
3893
+ code: z4.string().trim().min(1).optional(),
3889
3894
  language: z4.enum(["bash", "python", "node"]).optional(),
3890
- timeout: z4.number().min(1).max(300).optional()
3895
+ timeout: z4.number().min(1).max(300).optional(),
3896
+ scrapeOptions: scrapeParamsSchema.omit({ url: true }).partial().optional()
3897
+ }).refine((data) => Boolean(data.scrapeId) !== Boolean(data.url), {
3898
+ message: "Provide either 'url' (interact directly) or 'scrapeId' (reuse a previous scrape), not both."
3899
+ }).refine((data) => !data.scrapeOptions || Boolean(data.url), {
3900
+ message: "scrapeOptions can only be used with 'url' mode."
3891
3901
  }).refine((data) => data.code || data.prompt, {
3892
3902
  message: "Either 'code' or 'prompt' must be provided."
3893
3903
  }),
3894
3904
  execute: async (args2, { session, log }) => {
3895
3905
  const client = getClient(session);
3896
- const { scrapeId, prompt, code, language, timeout } = args2;
3897
- log.info("Interacting with scraped page", { scrapeId });
3906
+ const {
3907
+ scrapeId: providedScrapeId,
3908
+ url,
3909
+ prompt,
3910
+ code,
3911
+ language,
3912
+ timeout,
3913
+ scrapeOptions
3914
+ } = args2;
3915
+ let scrapeId = providedScrapeId;
3916
+ const openedFromUrl = !scrapeId;
3917
+ if (openedFromUrl) {
3918
+ log.info("Opening interact session from url", { url });
3919
+ const cleanedScrapeOptions = removeEmptyTopLevel(scrapeOptions ?? {});
3920
+ const scraped = await client.scrape(String(url), {
3921
+ ...cleanedScrapeOptions,
3922
+ origin: ORIGIN
3923
+ });
3924
+ scrapeId = scraped?.metadata?.scrapeId;
3925
+ if (!scrapeId) {
3926
+ return asText2({
3927
+ error: "Could not open an interact session: the scrape did not return a scrapeId. Try firecrawl_scrape first, then pass its scrapeId.",
3928
+ url
3929
+ });
3930
+ }
3931
+ }
3932
+ if (!scrapeId) {
3933
+ return asText2({
3934
+ error: "Could not open an interact session: missing scrapeId.",
3935
+ url
3936
+ });
3937
+ }
3938
+ const activeScrapeId = scrapeId;
3939
+ log.info("Interacting with page", { scrapeId: activeScrapeId });
3898
3940
  const interactArgs = { origin: ORIGIN };
3899
3941
  if (prompt) interactArgs.prompt = prompt;
3900
3942
  if (code) interactArgs.code = code;
3901
3943
  if (language) interactArgs.language = language;
3902
3944
  if (timeout != null) interactArgs.timeout = timeout;
3903
- const res = await client.interact(scrapeId, interactArgs);
3945
+ const res = await client.interact(activeScrapeId, interactArgs);
3946
+ if (openedFromUrl && res && typeof res === "object" && !Array.isArray(res)) {
3947
+ return asText2({
3948
+ ...res,
3949
+ scrapeId: activeScrapeId
3950
+ });
3951
+ }
3952
+ if (openedFromUrl) {
3953
+ return asText2({ scrapeId: activeScrapeId, result: res });
3954
+ }
3904
3955
  return asText2(res);
3905
3956
  }
3906
3957
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "firecrawl-mcp",
3
- "version": "3.21.4",
3
+ "version": "3.22.0",
4
4
  "description": "MCP server for Firecrawl — search, scrape, and interact with the web. Supports both cloud and self-hosted instances. Features include web search, scraping, page interaction, batch processing, and LLM-powered content analysis.",
5
5
  "type": "module",
6
6
  "mcpName": "io.github.firecrawl/firecrawl-mcp-server",