firecrawl-mcp 3.30.3 → 3.31.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 +5 -1
- package/dist/index.js +79 -6
- package/dist/origin.js +77 -5
- package/dist/server.d.ts +36 -8
- package/dist/server.js +86 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -73,6 +73,10 @@ Authorization: Bearer <FIRECRAWL_API_KEY>
|
|
|
73
73
|
|
|
74
74
|
Never put an API key in the server URL. Never put an API key in an agent chat. Configure it directly in the client or secret manager. See the [hosted MCP setup guide](https://docs.firecrawl.dev/mcp-server) and the [agent onboarding guide](https://www.firecrawl.dev/agent-onboarding/SKILL.md) for client-specific instructions.
|
|
75
75
|
|
|
76
|
+
#### Naming your integration
|
|
77
|
+
|
|
78
|
+
An integration that connects over HTTP can name itself with an `X-Firecrawl-Origin` header, for example `X-Firecrawl-Origin: my-agent`. The server reports it to Firecrawl as the request origin `mcp-my-agent@<server version>`, in place of the client name or User-Agent it would otherwise report. Use letters, digits and dashes: each run of other characters becomes one dash, leading and trailing dashes are dropped, and the name is cut at 48 characters. Tool results are unaffected; only the origin sent to the Firecrawl API (and passed to an embedder's `beforeKeylessRequest`) changes.
|
|
79
|
+
|
|
76
80
|
#### Search-only endpoint
|
|
77
81
|
|
|
78
82
|
A fixed-scope search surface is also hosted at:
|
|
@@ -1246,7 +1250,7 @@ Options mirror the CLI's environment variables: `apiUrl`, `apiKey`, `transport`,
|
|
|
1246
1250
|
|
|
1247
1251
|
FastMCP is bundled inside the package, so use the types exported from `firecrawl-mcp/server` (`Session`, `ToolDefinition`, `ToolRegistrar`, `FirecrawlMcpServerHooks` and others) rather than importing `fastmcp` yourself.
|
|
1248
1252
|
|
|
1249
|
-
The entry point also exports the helpers the built-in tools use, such as `recoveryPayload`, `normalizeHeader`, `requestOrigin`, `searchToolBaseFields`, `searchOutputSchema` and `structuredCompact`, so extra tools and hooks can match the built-in behaviour. They are unstable as well.
|
|
1253
|
+
The entry point also exports the helpers the built-in tools use, such as `recoveryPayload`, `normalizeHeader`, `requestOrigin`, `isRuntimeUserAgent`, `initializeClientSlug`, `searchToolBaseFields`, `searchOutputSchema` and `structuredCompact`, so extra tools and hooks can match the built-in behaviour. They are unstable as well.
|
|
1250
1254
|
|
|
1251
1255
|
## Logging System
|
|
1252
1256
|
|
package/dist/index.js
CHANGED
|
@@ -2583,19 +2583,79 @@ import { z as z6 } from "zod";
|
|
|
2583
2583
|
// src/origin.ts
|
|
2584
2584
|
import { createRequire } from "module";
|
|
2585
2585
|
var ORIGIN_SERVER = "mcp-fastmcp";
|
|
2586
|
+
var DECLARED_ORIGIN_HEADER = "x-firecrawl-origin";
|
|
2586
2587
|
var NAME_MAX = 48;
|
|
2588
|
+
var RUNTIME_PRODUCTS = /* @__PURE__ */ new Set([
|
|
2589
|
+
"apache-httpasyncclient",
|
|
2590
|
+
"apache-httpclient",
|
|
2591
|
+
"aiohttp",
|
|
2592
|
+
"axios",
|
|
2593
|
+
"bun",
|
|
2594
|
+
"curl",
|
|
2595
|
+
"dart",
|
|
2596
|
+
"deno",
|
|
2597
|
+
"faraday",
|
|
2598
|
+
"go-http-client",
|
|
2599
|
+
"got",
|
|
2600
|
+
"guzzlehttp",
|
|
2601
|
+
"java-http-client",
|
|
2602
|
+
"ktor-client",
|
|
2603
|
+
"libcurl-agent",
|
|
2604
|
+
"mozilla",
|
|
2605
|
+
"node",
|
|
2606
|
+
"node-fetch",
|
|
2607
|
+
"okhttp",
|
|
2608
|
+
"python",
|
|
2609
|
+
"python-httpx",
|
|
2610
|
+
"python-httpx2",
|
|
2611
|
+
"python-requests",
|
|
2612
|
+
"python-urllib",
|
|
2613
|
+
"reqwest",
|
|
2614
|
+
"ruby",
|
|
2615
|
+
"undici",
|
|
2616
|
+
"wget"
|
|
2617
|
+
]);
|
|
2618
|
+
var GENERIC_CLIENT_NAMES = /* @__PURE__ */ new Set([
|
|
2619
|
+
"client",
|
|
2620
|
+
"example-client",
|
|
2621
|
+
"mcp",
|
|
2622
|
+
"mcp-client",
|
|
2623
|
+
"test",
|
|
2624
|
+
"test-client"
|
|
2625
|
+
]);
|
|
2587
2626
|
function slugOf(name2) {
|
|
2588
2627
|
return (name2 ?? "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, NAME_MAX).replace(/-+$/, "");
|
|
2589
2628
|
}
|
|
2629
|
+
function isOwnSlug(slug) {
|
|
2630
|
+
return slug === "" || slug === "fastmcp" || slug === "firecrawl-fastmcp";
|
|
2631
|
+
}
|
|
2590
2632
|
function userAgentProduct(userAgent) {
|
|
2591
2633
|
const first = (userAgent ?? "").trim().split(/\s+/)[0] ?? "";
|
|
2592
2634
|
return slugOf(first.split("/")[0]);
|
|
2593
2635
|
}
|
|
2594
|
-
function
|
|
2636
|
+
function initializeClientSlug(name2) {
|
|
2637
|
+
const slug = slugOf(name2);
|
|
2638
|
+
return isOwnSlug(slug) || GENERIC_CLIENT_NAMES.has(slug) ? "" : slug;
|
|
2639
|
+
}
|
|
2640
|
+
function referrerSlug(referrer) {
|
|
2641
|
+
let host;
|
|
2642
|
+
try {
|
|
2643
|
+
host = new URL(referrer ?? "").hostname.toLowerCase().replace(/\.$/, "");
|
|
2644
|
+
} catch {
|
|
2645
|
+
return "";
|
|
2646
|
+
}
|
|
2647
|
+
if (!host.includes(".") || host.endsWith(".localhost") || host.endsWith(".local") || /^[\d.]+$/.test(host) || host.startsWith("[")) {
|
|
2648
|
+
return "";
|
|
2649
|
+
}
|
|
2650
|
+
return slugOf(host.replace(/^www\./, ""));
|
|
2651
|
+
}
|
|
2652
|
+
function originForClient(client, serverVersion2, userAgent, signals = {}) {
|
|
2653
|
+
const declared = slugOf(signals.declaredOrigin);
|
|
2595
2654
|
const slug = slugOf(client?.name);
|
|
2596
|
-
const
|
|
2597
|
-
const
|
|
2598
|
-
const
|
|
2655
|
+
const product = userAgentProduct(userAgent);
|
|
2656
|
+
const remembered = initializeClientSlug(signals.initializeClient?.name);
|
|
2657
|
+
const referrer = referrerSlug(signals.referrer);
|
|
2658
|
+
const base = !isOwnSlug(declared) ? `mcp-${declared}` : !isOwnSlug(slug) ? `mcp-${slug}` : product && !RUNTIME_PRODUCTS.has(product) ? `mcp-ua-${product}` : remembered ? `mcp-${remembered}` : referrer ? `mcp-ref-${referrer}` : product ? `mcp-ua-${product}` : ORIGIN_SERVER;
|
|
2599
2659
|
return serverVersion2 ? `${base}@${serverVersion2}` : base;
|
|
2600
2660
|
}
|
|
2601
2661
|
function originHeaders(origin) {
|
|
@@ -2608,7 +2668,12 @@ function requestOrigin(client, session) {
|
|
|
2608
2668
|
return originForClient(
|
|
2609
2669
|
client?.version ?? null,
|
|
2610
2670
|
serverVersion,
|
|
2611
|
-
session?.clientUserAgent
|
|
2671
|
+
session?.clientUserAgent,
|
|
2672
|
+
{
|
|
2673
|
+
declaredOrigin: session?.clientOrigin,
|
|
2674
|
+
initializeClient: session?.initializeClient,
|
|
2675
|
+
referrer: session?.clientReferrer
|
|
2676
|
+
}
|
|
2612
2677
|
);
|
|
2613
2678
|
}
|
|
2614
2679
|
|
|
@@ -3961,10 +4026,18 @@ function createFirecrawlMcpServer(options2 = {}) {
|
|
|
3961
4026
|
const cached = request?.[authResultByRequest];
|
|
3962
4027
|
if (cached) return cached;
|
|
3963
4028
|
const authResult = authenticateSession(request).then((session) => {
|
|
3964
|
-
const
|
|
4029
|
+
const headers = request?.headers;
|
|
4030
|
+
const userAgent = headers?.["user-agent"];
|
|
3965
4031
|
if (typeof userAgent === "string" && userAgent !== "") {
|
|
3966
4032
|
session.clientUserAgent = userAgent;
|
|
3967
4033
|
}
|
|
4034
|
+
const declaredOrigin = normalizeHeader(headers?.[DECLARED_ORIGIN_HEADER]);
|
|
4035
|
+
if (declaredOrigin) session.clientOrigin = declaredOrigin;
|
|
4036
|
+
const referrer = [
|
|
4037
|
+
normalizeHeader(headers?.["origin"]),
|
|
4038
|
+
normalizeHeader(headers?.["referer"])
|
|
4039
|
+
].find((value) => value && value !== "null");
|
|
4040
|
+
if (referrer) session.clientReferrer = referrer;
|
|
3968
4041
|
return session;
|
|
3969
4042
|
});
|
|
3970
4043
|
if (request) request[authResultByRequest] = authResult;
|
package/dist/origin.js
CHANGED
|
@@ -1,19 +1,83 @@
|
|
|
1
1
|
// src/origin.ts
|
|
2
2
|
import { createRequire } from "module";
|
|
3
3
|
var ORIGIN_SERVER = "mcp-fastmcp";
|
|
4
|
+
var DECLARED_ORIGIN_HEADER = "x-firecrawl-origin";
|
|
4
5
|
var NAME_MAX = 48;
|
|
6
|
+
var RUNTIME_PRODUCTS = /* @__PURE__ */ new Set([
|
|
7
|
+
"apache-httpasyncclient",
|
|
8
|
+
"apache-httpclient",
|
|
9
|
+
"aiohttp",
|
|
10
|
+
"axios",
|
|
11
|
+
"bun",
|
|
12
|
+
"curl",
|
|
13
|
+
"dart",
|
|
14
|
+
"deno",
|
|
15
|
+
"faraday",
|
|
16
|
+
"go-http-client",
|
|
17
|
+
"got",
|
|
18
|
+
"guzzlehttp",
|
|
19
|
+
"java-http-client",
|
|
20
|
+
"ktor-client",
|
|
21
|
+
"libcurl-agent",
|
|
22
|
+
"mozilla",
|
|
23
|
+
"node",
|
|
24
|
+
"node-fetch",
|
|
25
|
+
"okhttp",
|
|
26
|
+
"python",
|
|
27
|
+
"python-httpx",
|
|
28
|
+
"python-httpx2",
|
|
29
|
+
"python-requests",
|
|
30
|
+
"python-urllib",
|
|
31
|
+
"reqwest",
|
|
32
|
+
"ruby",
|
|
33
|
+
"undici",
|
|
34
|
+
"wget"
|
|
35
|
+
]);
|
|
36
|
+
var GENERIC_CLIENT_NAMES = /* @__PURE__ */ new Set([
|
|
37
|
+
"client",
|
|
38
|
+
"example-client",
|
|
39
|
+
"mcp",
|
|
40
|
+
"mcp-client",
|
|
41
|
+
"test",
|
|
42
|
+
"test-client"
|
|
43
|
+
]);
|
|
5
44
|
function slugOf(name) {
|
|
6
45
|
return (name ?? "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, NAME_MAX).replace(/-+$/, "");
|
|
7
46
|
}
|
|
47
|
+
function isOwnSlug(slug) {
|
|
48
|
+
return slug === "" || slug === "fastmcp" || slug === "firecrawl-fastmcp";
|
|
49
|
+
}
|
|
8
50
|
function userAgentProduct(userAgent) {
|
|
9
51
|
const first = (userAgent ?? "").trim().split(/\s+/)[0] ?? "";
|
|
10
52
|
return slugOf(first.split("/")[0]);
|
|
11
53
|
}
|
|
12
|
-
function
|
|
54
|
+
function isRuntimeUserAgent(userAgent) {
|
|
55
|
+
const product = userAgentProduct(userAgent);
|
|
56
|
+
return product === "" || RUNTIME_PRODUCTS.has(product);
|
|
57
|
+
}
|
|
58
|
+
function initializeClientSlug(name) {
|
|
59
|
+
const slug = slugOf(name);
|
|
60
|
+
return isOwnSlug(slug) || GENERIC_CLIENT_NAMES.has(slug) ? "" : slug;
|
|
61
|
+
}
|
|
62
|
+
function referrerSlug(referrer) {
|
|
63
|
+
let host;
|
|
64
|
+
try {
|
|
65
|
+
host = new URL(referrer ?? "").hostname.toLowerCase().replace(/\.$/, "");
|
|
66
|
+
} catch {
|
|
67
|
+
return "";
|
|
68
|
+
}
|
|
69
|
+
if (!host.includes(".") || host.endsWith(".localhost") || host.endsWith(".local") || /^[\d.]+$/.test(host) || host.startsWith("[")) {
|
|
70
|
+
return "";
|
|
71
|
+
}
|
|
72
|
+
return slugOf(host.replace(/^www\./, ""));
|
|
73
|
+
}
|
|
74
|
+
function originForClient(client, serverVersion2, userAgent, signals = {}) {
|
|
75
|
+
const declared = slugOf(signals.declaredOrigin);
|
|
13
76
|
const slug = slugOf(client?.name);
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
const
|
|
77
|
+
const product = userAgentProduct(userAgent);
|
|
78
|
+
const remembered = initializeClientSlug(signals.initializeClient?.name);
|
|
79
|
+
const referrer = referrerSlug(signals.referrer);
|
|
80
|
+
const base = !isOwnSlug(declared) ? `mcp-${declared}` : !isOwnSlug(slug) ? `mcp-${slug}` : product && !RUNTIME_PRODUCTS.has(product) ? `mcp-ua-${product}` : remembered ? `mcp-${remembered}` : referrer ? `mcp-ref-${referrer}` : product ? `mcp-ua-${product}` : ORIGIN_SERVER;
|
|
17
81
|
return serverVersion2 ? `${base}@${serverVersion2}` : base;
|
|
18
82
|
}
|
|
19
83
|
function originHeaders(origin) {
|
|
@@ -26,11 +90,19 @@ function requestOrigin(client, session) {
|
|
|
26
90
|
return originForClient(
|
|
27
91
|
client?.version ?? null,
|
|
28
92
|
serverVersion,
|
|
29
|
-
session?.clientUserAgent
|
|
93
|
+
session?.clientUserAgent,
|
|
94
|
+
{
|
|
95
|
+
declaredOrigin: session?.clientOrigin,
|
|
96
|
+
initializeClient: session?.initializeClient,
|
|
97
|
+
referrer: session?.clientReferrer
|
|
98
|
+
}
|
|
30
99
|
);
|
|
31
100
|
}
|
|
32
101
|
export {
|
|
102
|
+
DECLARED_ORIGIN_HEADER,
|
|
33
103
|
ORIGIN_SERVER,
|
|
104
|
+
initializeClientSlug,
|
|
105
|
+
isRuntimeUserAgent,
|
|
34
106
|
originForClient,
|
|
35
107
|
originHeaders,
|
|
36
108
|
requestOrigin,
|
package/dist/server.d.ts
CHANGED
|
@@ -6,10 +6,20 @@ import { z } from 'zod';
|
|
|
6
6
|
declare function normalizeHeader(value: string | string[] | undefined): string | undefined;
|
|
7
7
|
declare function withoutTrailingSlash(value: string): string;
|
|
8
8
|
|
|
9
|
+
/** The header a connection sets to name the integration it comes from. */
|
|
10
|
+
declare const DECLARED_ORIGIN_HEADER = "x-firecrawl-origin";
|
|
9
11
|
type ClientImplementation = {
|
|
10
12
|
name?: string;
|
|
11
13
|
version?: string;
|
|
12
14
|
};
|
|
15
|
+
/** Whether a User-Agent is absent or names an HTTP runtime rather than an MCP client. */
|
|
16
|
+
declare function isRuntimeUserAgent(userAgent: string | null | undefined): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* The token an initialize client name stamps when it reaches a call only
|
|
19
|
+
* through `ClientSignals.initializeClient`; empty for the server's own names
|
|
20
|
+
* and the defaults SDKs send when the integration sets none.
|
|
21
|
+
*/
|
|
22
|
+
declare function initializeClientSlug(name: string | null | undefined): string;
|
|
13
23
|
/** The header form of an origin, for the requests that reach the API without a body. */
|
|
14
24
|
declare function originHeaders(origin: string): Record<string, string>;
|
|
15
25
|
/**
|
|
@@ -19,14 +29,19 @@ declare function originHeaders(origin: string): Record<string, string>;
|
|
|
19
29
|
type McpClient = {
|
|
20
30
|
version?: ClientImplementation | undefined;
|
|
21
31
|
} | undefined;
|
|
32
|
+
/** The client signals the authenticated session carries (see SessionData). */
|
|
33
|
+
type OriginSession = {
|
|
34
|
+
clientUserAgent?: string;
|
|
35
|
+
clientOrigin?: string;
|
|
36
|
+
clientReferrer?: string;
|
|
37
|
+
initializeClient?: ClientImplementation;
|
|
38
|
+
};
|
|
22
39
|
/**
|
|
23
40
|
* The origin of every request a tool call makes: the call's client, the
|
|
24
|
-
*
|
|
25
|
-
* no client name), and this server's version.
|
|
41
|
+
* client signals of the request the session was authenticated with
|
|
42
|
+
* (stateless HTTP calls carry no client name), and this server's version.
|
|
26
43
|
*/
|
|
27
|
-
declare function requestOrigin(client: McpClient, session?:
|
|
28
|
-
clientUserAgent?: string;
|
|
29
|
-
} | undefined): string;
|
|
44
|
+
declare function requestOrigin(client: McpClient, session?: OriginSession | undefined): string;
|
|
30
45
|
|
|
31
46
|
/** An API-issued keyless signup link, or undefined for anything else. */
|
|
32
47
|
declare function keylessSignupUrlFrom(value: unknown): string | undefined;
|
|
@@ -209,10 +224,23 @@ interface SessionData {
|
|
|
209
224
|
*/
|
|
210
225
|
firecrawlApiKey?: string;
|
|
211
226
|
/**
|
|
212
|
-
* The User-Agent of the HTTP request that opened the session, the
|
|
213
|
-
* client
|
|
227
|
+
* The User-Agent of the HTTP request that opened the session, one of the
|
|
228
|
+
* client signals a stateless HTTP tool call carries (see src/origin.ts).
|
|
214
229
|
*/
|
|
215
230
|
clientUserAgent?: string;
|
|
231
|
+
/** The `X-Firecrawl-Origin` header: the integration the connection names. */
|
|
232
|
+
clientOrigin?: string;
|
|
233
|
+
/** The `Origin` or `Referer` header of that request. */
|
|
234
|
+
clientReferrer?: string;
|
|
235
|
+
/**
|
|
236
|
+
* The client an earlier initialize named, for stateless HTTP calls that do
|
|
237
|
+
* not carry it. Set by an embedder that can recover it; read only when the
|
|
238
|
+
* User-Agent names a runtime rather than a client.
|
|
239
|
+
*/
|
|
240
|
+
initializeClient?: {
|
|
241
|
+
name?: string;
|
|
242
|
+
version?: string;
|
|
243
|
+
};
|
|
216
244
|
authType?: 'api-key' | 'oauth' | 'env' | 'keyless' | 'none';
|
|
217
245
|
/** Admitted, but the supplied credential cannot be used. */
|
|
218
246
|
credentialError?: 'CREDENTIAL_INVALID';
|
|
@@ -428,4 +456,4 @@ declare const structuredCompactResult: (data: unknown) => ToolResult;
|
|
|
428
456
|
|
|
429
457
|
declare function createFirecrawlMcpServer(options?: FirecrawlMcpServerOptions): FirecrawlMcpServer;
|
|
430
458
|
|
|
431
|
-
export { ALEXANDRIA_CATALOGUE_VERTICALS, ALEXANDRIA_SEARCH_INSTRUCTIONS, type AuthenticationRequest, type ExtraToolsContext, type FirecrawlMcpServer, type FirecrawlMcpServerHooks, type FirecrawlMcpServerOptions, type FirecrawlMcpServerStartArgs, type HttpApp, type InstructionDefaults, keylessToolNames as KEYLESS_TOOL_NAMES, type OutboundRequest, type ProtectedResourceMetadata, type ResourceContent, type ResourceDefinition, type ResourceRegistrar, SEARCH_DOMAINS_CONFLICT_MESSAGE, type Session, type SessionData, type ToolCallEvent, type ToolContext, type ToolDefinition, type ToolIcon, type ToolLogger, type ToolRegistrar, type ToolResult, UserError, assertExchangeCredential, createFirecrawlMcpServer, defaultDomainTools, enterpriseAllowsAlexandria, hasAlexandria, invalidApiKeyRecoveryPayload, invalidOAuthRecoveryPayload, keylessQuotaReason, keylessSignupUrlFrom, normalizeHeader, normalizeSearchSources, originHeaders, postSearchWithFallback, recoveryPayload, relayExchangeError, relayTermsRequired, removeEmptyTopLevel, requestOrigin, searchDomainsAreExclusive, searchOutputSchema, searchQueryIsValid, searchToolBaseFields, structuredCompactResult as structuredCompact, withAlexandriaSource, withoutTrailingSlash };
|
|
459
|
+
export { ALEXANDRIA_CATALOGUE_VERTICALS, ALEXANDRIA_SEARCH_INSTRUCTIONS, type AuthenticationRequest, DECLARED_ORIGIN_HEADER, type ExtraToolsContext, type FirecrawlMcpServer, type FirecrawlMcpServerHooks, type FirecrawlMcpServerOptions, type FirecrawlMcpServerStartArgs, type HttpApp, type InstructionDefaults, keylessToolNames as KEYLESS_TOOL_NAMES, type OutboundRequest, type ProtectedResourceMetadata, type ResourceContent, type ResourceDefinition, type ResourceRegistrar, SEARCH_DOMAINS_CONFLICT_MESSAGE, type Session, type SessionData, type ToolCallEvent, type ToolContext, type ToolDefinition, type ToolIcon, type ToolLogger, type ToolRegistrar, type ToolResult, UserError, assertExchangeCredential, createFirecrawlMcpServer, defaultDomainTools, enterpriseAllowsAlexandria, hasAlexandria, initializeClientSlug, invalidApiKeyRecoveryPayload, invalidOAuthRecoveryPayload, isRuntimeUserAgent, keylessQuotaReason, keylessSignupUrlFrom, normalizeHeader, normalizeSearchSources, originHeaders, postSearchWithFallback, recoveryPayload, relayExchangeError, relayTermsRequired, removeEmptyTopLevel, requestOrigin, searchDomainsAreExclusive, searchOutputSchema, searchQueryIsValid, searchToolBaseFields, structuredCompactResult as structuredCompact, withAlexandriaSource, withoutTrailingSlash };
|
package/dist/server.js
CHANGED
|
@@ -2578,19 +2578,83 @@ import { z as z6 } from "zod";
|
|
|
2578
2578
|
// src/origin.ts
|
|
2579
2579
|
import { createRequire } from "module";
|
|
2580
2580
|
var ORIGIN_SERVER = "mcp-fastmcp";
|
|
2581
|
+
var DECLARED_ORIGIN_HEADER = "x-firecrawl-origin";
|
|
2581
2582
|
var NAME_MAX = 48;
|
|
2583
|
+
var RUNTIME_PRODUCTS = /* @__PURE__ */ new Set([
|
|
2584
|
+
"apache-httpasyncclient",
|
|
2585
|
+
"apache-httpclient",
|
|
2586
|
+
"aiohttp",
|
|
2587
|
+
"axios",
|
|
2588
|
+
"bun",
|
|
2589
|
+
"curl",
|
|
2590
|
+
"dart",
|
|
2591
|
+
"deno",
|
|
2592
|
+
"faraday",
|
|
2593
|
+
"go-http-client",
|
|
2594
|
+
"got",
|
|
2595
|
+
"guzzlehttp",
|
|
2596
|
+
"java-http-client",
|
|
2597
|
+
"ktor-client",
|
|
2598
|
+
"libcurl-agent",
|
|
2599
|
+
"mozilla",
|
|
2600
|
+
"node",
|
|
2601
|
+
"node-fetch",
|
|
2602
|
+
"okhttp",
|
|
2603
|
+
"python",
|
|
2604
|
+
"python-httpx",
|
|
2605
|
+
"python-httpx2",
|
|
2606
|
+
"python-requests",
|
|
2607
|
+
"python-urllib",
|
|
2608
|
+
"reqwest",
|
|
2609
|
+
"ruby",
|
|
2610
|
+
"undici",
|
|
2611
|
+
"wget"
|
|
2612
|
+
]);
|
|
2613
|
+
var GENERIC_CLIENT_NAMES = /* @__PURE__ */ new Set([
|
|
2614
|
+
"client",
|
|
2615
|
+
"example-client",
|
|
2616
|
+
"mcp",
|
|
2617
|
+
"mcp-client",
|
|
2618
|
+
"test",
|
|
2619
|
+
"test-client"
|
|
2620
|
+
]);
|
|
2582
2621
|
function slugOf(name2) {
|
|
2583
2622
|
return (name2 ?? "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, NAME_MAX).replace(/-+$/, "");
|
|
2584
2623
|
}
|
|
2624
|
+
function isOwnSlug(slug) {
|
|
2625
|
+
return slug === "" || slug === "fastmcp" || slug === "firecrawl-fastmcp";
|
|
2626
|
+
}
|
|
2585
2627
|
function userAgentProduct(userAgent) {
|
|
2586
2628
|
const first = (userAgent ?? "").trim().split(/\s+/)[0] ?? "";
|
|
2587
2629
|
return slugOf(first.split("/")[0]);
|
|
2588
2630
|
}
|
|
2589
|
-
function
|
|
2631
|
+
function isRuntimeUserAgent(userAgent) {
|
|
2632
|
+
const product = userAgentProduct(userAgent);
|
|
2633
|
+
return product === "" || RUNTIME_PRODUCTS.has(product);
|
|
2634
|
+
}
|
|
2635
|
+
function initializeClientSlug(name2) {
|
|
2636
|
+
const slug = slugOf(name2);
|
|
2637
|
+
return isOwnSlug(slug) || GENERIC_CLIENT_NAMES.has(slug) ? "" : slug;
|
|
2638
|
+
}
|
|
2639
|
+
function referrerSlug(referrer) {
|
|
2640
|
+
let host;
|
|
2641
|
+
try {
|
|
2642
|
+
host = new URL(referrer ?? "").hostname.toLowerCase().replace(/\.$/, "");
|
|
2643
|
+
} catch {
|
|
2644
|
+
return "";
|
|
2645
|
+
}
|
|
2646
|
+
if (!host.includes(".") || host.endsWith(".localhost") || host.endsWith(".local") || /^[\d.]+$/.test(host) || host.startsWith("[")) {
|
|
2647
|
+
return "";
|
|
2648
|
+
}
|
|
2649
|
+
return slugOf(host.replace(/^www\./, ""));
|
|
2650
|
+
}
|
|
2651
|
+
function originForClient(client, serverVersion2, userAgent, signals = {}) {
|
|
2652
|
+
const declared = slugOf(signals.declaredOrigin);
|
|
2590
2653
|
const slug = slugOf(client?.name);
|
|
2591
|
-
const
|
|
2592
|
-
const
|
|
2593
|
-
const
|
|
2654
|
+
const product = userAgentProduct(userAgent);
|
|
2655
|
+
const remembered = initializeClientSlug(signals.initializeClient?.name);
|
|
2656
|
+
const referrer = referrerSlug(signals.referrer);
|
|
2657
|
+
const base = !isOwnSlug(declared) ? `mcp-${declared}` : !isOwnSlug(slug) ? `mcp-${slug}` : product && !RUNTIME_PRODUCTS.has(product) ? `mcp-ua-${product}` : remembered ? `mcp-${remembered}` : referrer ? `mcp-ref-${referrer}` : product ? `mcp-ua-${product}` : ORIGIN_SERVER;
|
|
2594
2658
|
return serverVersion2 ? `${base}@${serverVersion2}` : base;
|
|
2595
2659
|
}
|
|
2596
2660
|
function originHeaders(origin) {
|
|
@@ -2603,7 +2667,12 @@ function requestOrigin(client, session) {
|
|
|
2603
2667
|
return originForClient(
|
|
2604
2668
|
client?.version ?? null,
|
|
2605
2669
|
serverVersion,
|
|
2606
|
-
session?.clientUserAgent
|
|
2670
|
+
session?.clientUserAgent,
|
|
2671
|
+
{
|
|
2672
|
+
declaredOrigin: session?.clientOrigin,
|
|
2673
|
+
initializeClient: session?.initializeClient,
|
|
2674
|
+
referrer: session?.clientReferrer
|
|
2675
|
+
}
|
|
2607
2676
|
);
|
|
2608
2677
|
}
|
|
2609
2678
|
|
|
@@ -3956,10 +4025,18 @@ function createFirecrawlMcpServer(options = {}) {
|
|
|
3956
4025
|
const cached = request?.[authResultByRequest];
|
|
3957
4026
|
if (cached) return cached;
|
|
3958
4027
|
const authResult = authenticateSession(request).then((session) => {
|
|
3959
|
-
const
|
|
4028
|
+
const headers = request?.headers;
|
|
4029
|
+
const userAgent = headers?.["user-agent"];
|
|
3960
4030
|
if (typeof userAgent === "string" && userAgent !== "") {
|
|
3961
4031
|
session.clientUserAgent = userAgent;
|
|
3962
4032
|
}
|
|
4033
|
+
const declaredOrigin = normalizeHeader(headers?.[DECLARED_ORIGIN_HEADER]);
|
|
4034
|
+
if (declaredOrigin) session.clientOrigin = declaredOrigin;
|
|
4035
|
+
const referrer = [
|
|
4036
|
+
normalizeHeader(headers?.["origin"]),
|
|
4037
|
+
normalizeHeader(headers?.["referer"])
|
|
4038
|
+
].find((value) => value && value !== "null");
|
|
4039
|
+
if (referrer) session.clientReferrer = referrer;
|
|
3963
4040
|
return session;
|
|
3964
4041
|
});
|
|
3965
4042
|
if (request) request[authResultByRequest] = authResult;
|
|
@@ -5734,6 +5811,7 @@ Set \`redactPII\` to request redaction of personally identifiable information in
|
|
|
5734
5811
|
export {
|
|
5735
5812
|
ALEXANDRIA_CATALOGUE_VERTICALS,
|
|
5736
5813
|
ALEXANDRIA_SEARCH_INSTRUCTIONS,
|
|
5814
|
+
DECLARED_ORIGIN_HEADER,
|
|
5737
5815
|
keylessToolNames as KEYLESS_TOOL_NAMES,
|
|
5738
5816
|
SEARCH_DOMAINS_CONFLICT_MESSAGE,
|
|
5739
5817
|
UserError2 as UserError,
|
|
@@ -5742,8 +5820,10 @@ export {
|
|
|
5742
5820
|
defaultDomainTools,
|
|
5743
5821
|
enterpriseAllowsAlexandria,
|
|
5744
5822
|
hasAlexandria,
|
|
5823
|
+
initializeClientSlug,
|
|
5745
5824
|
invalidApiKeyRecoveryPayload,
|
|
5746
5825
|
invalidOAuthRecoveryPayload,
|
|
5826
|
+
isRuntimeUserAgent,
|
|
5747
5827
|
keylessQuotaReason,
|
|
5748
5828
|
keylessSignupUrlFrom,
|
|
5749
5829
|
normalizeHeader,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "firecrawl-mcp",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.31.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",
|