firecrawl-mcp 3.31.1 → 3.32.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.
package/README.md CHANGED
@@ -273,6 +273,9 @@ Optionally, you can add it to a file called `.vscode/mcp.json` in your workspace
273
273
  - `FIRECRAWL_API_URL` (Optional): Custom API endpoint for self-hosted instances
274
274
  - Example: `https://firecrawl.your-domain.com`
275
275
  - If not provided, the cloud API will be used (requires API key)
276
+ - `FIRECRAWL_INTEGRATION` (Optional): Integration tag for apps that launch this server, such as an editor extension
277
+ - Sent as the `integration` field of scrape, batch scrape, crawl, map, search, extract, agent, parse, interact and feedback requests
278
+ - Use a value that starts with `_`, for example `_zed`
276
279
 
277
280
  #### MCP OAuth (Bearer access tokens)
278
281
 
package/dist/index.js CHANGED
@@ -3559,6 +3559,22 @@ The historical view returns periods sorted by start date with \`startDate\`, \`e
3559
3559
  });
3560
3560
  }
3561
3561
 
3562
+ // src/integration.ts
3563
+ var TAGGED_PATH = /^\/v2\/(scrape|batch\/scrape|crawl|map|search|extract|agent|parse|feedback|scrape\/[^/]+\/interact|search\/[^/]+\/feedback)$/;
3564
+ function integrationFrom(value) {
3565
+ const tag = (value ?? "").trim();
3566
+ return tag === "" ? void 0 : tag;
3567
+ }
3568
+ function pathOf(url) {
3569
+ const path2 = url.replace(/^[a-z][a-z0-9+.-]*:\/\/[^/]+/i, "").split(/[?#]/)[0];
3570
+ return path2.replace(/\/+$/, "");
3571
+ }
3572
+ function withIntegration(url, body, integration) {
3573
+ if (!integration || body.integration != null) return body;
3574
+ if (!TAGGED_PATH.test(pathOf(url))) return body;
3575
+ return { ...body, integration };
3576
+ }
3577
+
3562
3578
  // src/headers.ts
3563
3579
  function normalizeHeader(value) {
3564
3580
  if (value == null) return void 0;
@@ -3999,7 +4015,8 @@ function createFirecrawlMcpServer(options2 = {}) {
3999
4015
  fileAccess: options2.fileAccess ?? "local",
4000
4016
  requireCredential: options2.requireCredential ?? false,
4001
4017
  searchFeedback: options2.searchFeedback ?? true,
4002
- endpointFeedback: options2.endpointFeedback ?? true
4018
+ endpointFeedback: options2.endpointFeedback ?? true,
4019
+ integration: integrationFrom(options2.integration)
4003
4020
  };
4004
4021
  const logging = options2.logging ?? config.transport === "httpStream";
4005
4022
  const instructionDefaults = {
@@ -4127,7 +4144,22 @@ function createFirecrawlMcpServer(options2 = {}) {
4127
4144
  if (apiKey2) {
4128
4145
  clientConfig.apiKey = apiKey2;
4129
4146
  }
4130
- return new FirecrawlApp(clientConfig);
4147
+ const client = new FirecrawlApp(clientConfig);
4148
+ if (config.integration) {
4149
+ client.http?.instance?.interceptors?.request?.use((request) => {
4150
+ const isPost = String(request.method ?? "").toLowerCase() === "post";
4151
+ const isPlainObject = request.data != null && typeof request.data === "object" && !Array.isArray(request.data) && !(request.data instanceof FormData);
4152
+ if (isPost && isPlainObject) {
4153
+ request.data = withIntegration(
4154
+ request.url ?? "",
4155
+ request.data,
4156
+ config.integration
4157
+ );
4158
+ }
4159
+ return request;
4160
+ });
4161
+ }
4162
+ return client;
4131
4163
  }
4132
4164
  const SAFE_MODE = config.safeMode;
4133
4165
  function getClient(session) {
@@ -4461,7 +4493,7 @@ function createFirecrawlMcpServer(options2 = {}) {
4461
4493
  function buildParseOptionsPayload(options3, origin) {
4462
4494
  const transformed = transformScrapeParams(options3);
4463
4495
  const cleaned = removeEmptyTopLevel(transformed);
4464
- return { origin, ...cleaned };
4496
+ return withIntegration("/v2/parse", { origin, ...cleaned }, config.integration);
4465
4497
  }
4466
4498
  function buildContinuationArguments(uploadRef, options3) {
4467
4499
  return {
@@ -4485,7 +4517,7 @@ function createFirecrawlMcpServer(options2 = {}) {
4485
4517
  Authorization: `Bearer ${apiKey2}`,
4486
4518
  ...origin ? originHeaders(origin) : {}
4487
4519
  },
4488
- body: JSON.stringify(body)
4520
+ body: JSON.stringify(withIntegration(pathName, body, config.integration))
4489
4521
  });
4490
4522
  const responseText = await response.text();
4491
4523
  let parsed;
@@ -4928,7 +4960,7 @@ For a programming question, add \`categories: ["developer"]\`; its hits return i
4928
4960
  const response = await fetch(`${resolveApiBaseUrl()}${path2}`, {
4929
4961
  method: "POST",
4930
4962
  headers,
4931
- body: JSON.stringify(body)
4963
+ body: JSON.stringify(withIntegration(path2, body, config.integration))
4932
4964
  });
4933
4965
  const json = await response.json().catch(() => ({}));
4934
4966
  if (!response.ok) {
@@ -5098,7 +5130,13 @@ Eligibility is limited to successful searches within the feedback age window. Th
5098
5130
  const response = await fetch(endpoint, {
5099
5131
  method: "POST",
5100
5132
  headers,
5101
- body: JSON.stringify(body)
5133
+ body: JSON.stringify(
5134
+ withIntegration(
5135
+ `/v2/search/${encodeURIComponent(searchId)}/feedback`,
5136
+ body,
5137
+ config.integration
5138
+ )
5139
+ )
5102
5140
  });
5103
5141
  const responseText = await response.text();
5104
5142
  let parsed;
@@ -5237,7 +5275,7 @@ Returns submission status, feedback ID, and accounting fields.
5237
5275
  const response = await fetch(`${apiBase}/v2/feedback`, {
5238
5276
  method: "POST",
5239
5277
  headers,
5240
- body: JSON.stringify(body)
5278
+ body: JSON.stringify(withIntegration("/v2/feedback", body, config.integration))
5241
5279
  });
5242
5280
  const responseText = await response.text();
5243
5281
  let parsed;
@@ -6718,7 +6756,8 @@ var options = {
6718
6756
  fileAccess: hosted ? "upload" : "local",
6719
6757
  requireCredential: hosted,
6720
6758
  searchFeedback: !searchFeedbackDisabled,
6721
- endpointFeedback: !endpointFeedbackDisabled
6759
+ endpointFeedback: !endpointFeedbackDisabled,
6760
+ integration: process.env.FIRECRAWL_INTEGRATION
6722
6761
  };
6723
6762
  var serviceSettings = { hosted, transport, apiKey, apiUrl };
6724
6763
  var primaryHooks = createServiceHooks(primaryProfile, serviceSettings);
@@ -0,0 +1,19 @@
1
+ // src/integration.ts
2
+ var TAGGED_PATH = /^\/v2\/(scrape|batch\/scrape|crawl|map|search|extract|agent|parse|feedback|scrape\/[^/]+\/interact|search\/[^/]+\/feedback)$/;
3
+ function integrationFrom(value) {
4
+ const tag = (value ?? "").trim();
5
+ return tag === "" ? void 0 : tag;
6
+ }
7
+ function pathOf(url) {
8
+ const path = url.replace(/^[a-z][a-z0-9+.-]*:\/\/[^/]+/i, "").split(/[?#]/)[0];
9
+ return path.replace(/\/+$/, "");
10
+ }
11
+ function withIntegration(url, body, integration) {
12
+ if (!integration || body.integration != null) return body;
13
+ if (!TAGGED_PATH.test(pathOf(url))) return body;
14
+ return { ...body, integration };
15
+ }
16
+ export {
17
+ integrationFrom,
18
+ withIntegration
19
+ };
package/dist/server.d.ts CHANGED
@@ -420,6 +420,8 @@ interface FirecrawlMcpServerOptions {
420
420
  searchFeedback?: boolean;
421
421
  /** Register firecrawl_feedback. Defaults to true. */
422
422
  endpointFeedback?: boolean;
423
+ /** Tag sent as the `integration` field of API requests that accept one, such as `_zed`. */
424
+ integration?: string;
423
425
  /** Extension hooks. Unstable: may change in any release. */
424
426
  unstable_hooks?: FirecrawlMcpServerHooks;
425
427
  }
package/dist/server.js CHANGED
@@ -3558,6 +3558,22 @@ The historical view returns periods sorted by start date with \`startDate\`, \`e
3558
3558
  });
3559
3559
  }
3560
3560
 
3561
+ // src/integration.ts
3562
+ var TAGGED_PATH = /^\/v2\/(scrape|batch\/scrape|crawl|map|search|extract|agent|parse|feedback|scrape\/[^/]+\/interact|search\/[^/]+\/feedback)$/;
3563
+ function integrationFrom(value) {
3564
+ const tag = (value ?? "").trim();
3565
+ return tag === "" ? void 0 : tag;
3566
+ }
3567
+ function pathOf(url) {
3568
+ const path2 = url.replace(/^[a-z][a-z0-9+.-]*:\/\/[^/]+/i, "").split(/[?#]/)[0];
3569
+ return path2.replace(/\/+$/, "");
3570
+ }
3571
+ function withIntegration(url, body, integration) {
3572
+ if (!integration || body.integration != null) return body;
3573
+ if (!TAGGED_PATH.test(pathOf(url))) return body;
3574
+ return { ...body, integration };
3575
+ }
3576
+
3561
3577
  // src/headers.ts
3562
3578
  function normalizeHeader(value) {
3563
3579
  if (value == null) return void 0;
@@ -3998,7 +4014,8 @@ function createFirecrawlMcpServer(options = {}) {
3998
4014
  fileAccess: options.fileAccess ?? "local",
3999
4015
  requireCredential: options.requireCredential ?? false,
4000
4016
  searchFeedback: options.searchFeedback ?? true,
4001
- endpointFeedback: options.endpointFeedback ?? true
4017
+ endpointFeedback: options.endpointFeedback ?? true,
4018
+ integration: integrationFrom(options.integration)
4002
4019
  };
4003
4020
  const logging = options.logging ?? config.transport === "httpStream";
4004
4021
  const instructionDefaults = {
@@ -4126,7 +4143,22 @@ function createFirecrawlMcpServer(options = {}) {
4126
4143
  if (apiKey) {
4127
4144
  clientConfig.apiKey = apiKey;
4128
4145
  }
4129
- return new FirecrawlApp(clientConfig);
4146
+ const client = new FirecrawlApp(clientConfig);
4147
+ if (config.integration) {
4148
+ client.http?.instance?.interceptors?.request?.use((request) => {
4149
+ const isPost = String(request.method ?? "").toLowerCase() === "post";
4150
+ const isPlainObject = request.data != null && typeof request.data === "object" && !Array.isArray(request.data) && !(request.data instanceof FormData);
4151
+ if (isPost && isPlainObject) {
4152
+ request.data = withIntegration(
4153
+ request.url ?? "",
4154
+ request.data,
4155
+ config.integration
4156
+ );
4157
+ }
4158
+ return request;
4159
+ });
4160
+ }
4161
+ return client;
4130
4162
  }
4131
4163
  const SAFE_MODE = config.safeMode;
4132
4164
  function getClient(session) {
@@ -4460,7 +4492,7 @@ function createFirecrawlMcpServer(options = {}) {
4460
4492
  function buildParseOptionsPayload(options2, origin) {
4461
4493
  const transformed = transformScrapeParams(options2);
4462
4494
  const cleaned = removeEmptyTopLevel(transformed);
4463
- return { origin, ...cleaned };
4495
+ return withIntegration("/v2/parse", { origin, ...cleaned }, config.integration);
4464
4496
  }
4465
4497
  function buildContinuationArguments(uploadRef, options2) {
4466
4498
  return {
@@ -4484,7 +4516,7 @@ function createFirecrawlMcpServer(options = {}) {
4484
4516
  Authorization: `Bearer ${apiKey}`,
4485
4517
  ...origin ? originHeaders(origin) : {}
4486
4518
  },
4487
- body: JSON.stringify(body)
4519
+ body: JSON.stringify(withIntegration(pathName, body, config.integration))
4488
4520
  });
4489
4521
  const responseText = await response.text();
4490
4522
  let parsed;
@@ -4927,7 +4959,7 @@ For a programming question, add \`categories: ["developer"]\`; its hits return i
4927
4959
  const response = await fetch(`${resolveApiBaseUrl()}${path2}`, {
4928
4960
  method: "POST",
4929
4961
  headers,
4930
- body: JSON.stringify(body)
4962
+ body: JSON.stringify(withIntegration(path2, body, config.integration))
4931
4963
  });
4932
4964
  const json = await response.json().catch(() => ({}));
4933
4965
  if (!response.ok) {
@@ -5097,7 +5129,13 @@ Eligibility is limited to successful searches within the feedback age window. Th
5097
5129
  const response = await fetch(endpoint, {
5098
5130
  method: "POST",
5099
5131
  headers,
5100
- body: JSON.stringify(body)
5132
+ body: JSON.stringify(
5133
+ withIntegration(
5134
+ `/v2/search/${encodeURIComponent(searchId)}/feedback`,
5135
+ body,
5136
+ config.integration
5137
+ )
5138
+ )
5101
5139
  });
5102
5140
  const responseText = await response.text();
5103
5141
  let parsed;
@@ -5236,7 +5274,7 @@ Returns submission status, feedback ID, and accounting fields.
5236
5274
  const response = await fetch(`${apiBase}/v2/feedback`, {
5237
5275
  method: "POST",
5238
5276
  headers,
5239
- body: JSON.stringify(body)
5277
+ body: JSON.stringify(withIntegration("/v2/feedback", body, config.integration))
5240
5278
  });
5241
5279
  const responseText = await response.text();
5242
5280
  let parsed;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "firecrawl-mcp",
3
- "version": "3.31.1",
3
+ "version": "3.32.0",
4
4
  "description": "MCP server for Firecrawl — search, scrape, and interact with the web, and search scientific papers. Supports both cloud and self-hosted instances. Features include web search, scraping, page interaction, batch processing, LLM-powered content analysis, and research paper search over biomedical and arXiv literature (PubMed, bioRxiv, medRxiv, arXiv) with citation-graph expansion and full-text reading.",
5
5
  "type": "module",
6
6
  "mcpName": "io.github.firecrawl/firecrawl-mcp-server",