firecrawl-mcp 3.29.1 → 3.30.1
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 +14 -51
- package/dist/index.js +118 -242
- package/dist/server.d.ts +28 -6
- package/dist/server.js +109 -236
- package/package.json +1 -1
- package/dist/agent-hints.js +0 -46
package/dist/index.js
CHANGED
|
@@ -85,7 +85,7 @@ var alexandriaSessionFeedbackSchema = z.strictObject({
|
|
|
85
85
|
// src/server.ts
|
|
86
86
|
import FirecrawlApp from "firecrawl";
|
|
87
87
|
|
|
88
|
-
// node_modules/.pnpm/fastmcp@4.3.2_patch_hash=
|
|
88
|
+
// node_modules/.pnpm/fastmcp@4.3.2_patch_hash=37f9a424ae5b0b6202b2b16109a1ea88b69cdcda5407f13eda6654a56489ad70/node_modules/fastmcp/dist/chunk-LWU5CQGW.js
|
|
89
89
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
90
90
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
91
91
|
import {
|
|
@@ -889,6 +889,7 @@ ${error2 instanceof Error ? error2.stack : JSON.stringify(error2)}`
|
|
|
889
889
|
// Top-level Tool.title (MCP 2025-06-18). Clients such as Codex index this
|
|
890
890
|
// for tool search and do not read annotations.title.
|
|
891
891
|
...tool.annotations?.title && { title: tool.annotations.title },
|
|
892
|
+
...tool.icons && { icons: tool.icons },
|
|
892
893
|
description: tool.description,
|
|
893
894
|
inputSchema: tool.parameters ? strictJsonSchema(await toJsonSchema(tool.parameters)) : {
|
|
894
895
|
additionalProperties: false,
|
|
@@ -2064,7 +2065,7 @@ var FastMCP = class extends FastMCPEventEmitter {
|
|
|
2064
2065
|
}
|
|
2065
2066
|
};
|
|
2066
2067
|
|
|
2067
|
-
// node_modules/.pnpm/fastmcp@4.3.2_patch_hash=
|
|
2068
|
+
// node_modules/.pnpm/fastmcp@4.3.2_patch_hash=37f9a424ae5b0b6202b2b16109a1ea88b69cdcda5407f13eda6654a56489ad70/node_modules/fastmcp/dist/chunk-OJG4XYXA.js
|
|
2068
2069
|
import { z as z3 } from "zod";
|
|
2069
2070
|
import { createHmac as createHmac2, pbkdf2, randomBytes } from "crypto";
|
|
2070
2071
|
import { promisify } from "util";
|
|
@@ -2077,45 +2078,6 @@ import { randomUUID as randomUUID2 } from "crypto";
|
|
|
2077
2078
|
import path from "path";
|
|
2078
2079
|
import { z as z12 } from "zod";
|
|
2079
2080
|
|
|
2080
|
-
// src/agent-hints.ts
|
|
2081
|
-
var AGENT_HINTS_HEADERS = { "X-Firecrawl-Agent-Hints": "true" };
|
|
2082
|
-
function readAgentHints(value) {
|
|
2083
|
-
if (!value || typeof value !== "object") return void 0;
|
|
2084
|
-
const hints = value.agent_hints;
|
|
2085
|
-
return Array.isArray(hints) && hints.every((hint) => typeof hint === "string") ? hints : void 0;
|
|
2086
|
-
}
|
|
2087
|
-
function preserveAgentHints(data, envelope) {
|
|
2088
|
-
const hints = readAgentHints(envelope);
|
|
2089
|
-
if (!hints) return data;
|
|
2090
|
-
return data && typeof data === "object" && !Array.isArray(data) ? { ...data, agent_hints: hints } : { data, agent_hints: hints };
|
|
2091
|
-
}
|
|
2092
|
-
function agentHintsText(hints) {
|
|
2093
|
-
return `Firecrawl API agent_hints (response guidance, separate from page content):
|
|
2094
|
-
${JSON.stringify(hints, null, 2)}`;
|
|
2095
|
-
}
|
|
2096
|
-
function withAgentHints(result, response, separateText = false) {
|
|
2097
|
-
const hints = readAgentHints(response);
|
|
2098
|
-
if (!hints) return result;
|
|
2099
|
-
return {
|
|
2100
|
-
...result,
|
|
2101
|
-
content: separateText && hints.length ? [...result.content, { type: "text", text: agentHintsText(hints) }] : result.content,
|
|
2102
|
-
structuredContent: { ...result.structuredContent, agent_hints: hints }
|
|
2103
|
-
};
|
|
2104
|
-
}
|
|
2105
|
-
function readErrorAgentHints(error2) {
|
|
2106
|
-
const hints = readAgentHints(error2);
|
|
2107
|
-
if (hints) return hints;
|
|
2108
|
-
if (!error2 || typeof error2 !== "object") return void 0;
|
|
2109
|
-
const extras = error2.extras;
|
|
2110
|
-
const extrasHints = readAgentHints(extras);
|
|
2111
|
-
if (extrasHints) return extrasHints;
|
|
2112
|
-
const details = error2.details;
|
|
2113
|
-
const detailsHints = readAgentHints(details);
|
|
2114
|
-
if (detailsHints) return detailsHints;
|
|
2115
|
-
const response = error2.response;
|
|
2116
|
-
return readAgentHints(response?.data);
|
|
2117
|
-
}
|
|
2118
|
-
|
|
2119
2081
|
// src/tool-output.ts
|
|
2120
2082
|
import { z as z4 } from "zod";
|
|
2121
2083
|
function isRecord(value) {
|
|
@@ -2144,9 +2106,6 @@ var unknown = (description) => z4.unknown().optional().describe(description);
|
|
|
2144
2106
|
var success = bool("Whether the API call succeeded.");
|
|
2145
2107
|
var error = unknown("Error message or error object when the call did not succeed.");
|
|
2146
2108
|
var warning = str("Non-fatal warning about the result.");
|
|
2147
|
-
var agentHints = {
|
|
2148
|
-
agent_hints: z4.array(z4.string()).optional().describe("Optional response guidance from the Firecrawl API.")
|
|
2149
|
-
};
|
|
2150
2109
|
var alexandriaEnvelope = {
|
|
2151
2110
|
requestId: str("Identifier of this Alexandria execution."),
|
|
2152
2111
|
scrape_id: str("Identifier of the underlying scrape."),
|
|
@@ -2164,7 +2123,6 @@ var alexandriaEnvelope = {
|
|
|
2164
2123
|
feedbackTool: unknown("Pointer to the feedback tool for reporting how this result served the task.")
|
|
2165
2124
|
};
|
|
2166
2125
|
var scrapeOutputSchema = z4.object({
|
|
2167
|
-
...agentHints,
|
|
2168
2126
|
// URL mode: the scraped document, with the formats that were requested.
|
|
2169
2127
|
markdown: str("Page content as markdown."),
|
|
2170
2128
|
html: str("Processed HTML of the page."),
|
|
@@ -2196,7 +2154,6 @@ var scrapeOutputSchema = z4.object({
|
|
|
2196
2154
|
...alexandriaEnvelope
|
|
2197
2155
|
}).describe("A scraped document, or the Alexandria execution envelope when `alexandria` was passed.");
|
|
2198
2156
|
var mapOutputSchema = z4.object({
|
|
2199
|
-
...agentHints,
|
|
2200
2157
|
links: unknown("URLs discovered under the website."),
|
|
2201
2158
|
success,
|
|
2202
2159
|
error,
|
|
@@ -2204,7 +2161,6 @@ var mapOutputSchema = z4.object({
|
|
|
2204
2161
|
id: str("Identifier of the map run, for optional map feedback.")
|
|
2205
2162
|
}).describe("URLs indexed under the requested website.");
|
|
2206
2163
|
var searchOutputSchema = z4.object({
|
|
2207
|
-
...agentHints,
|
|
2208
2164
|
success,
|
|
2209
2165
|
data: unknown("Ranked results grouped by source, such as `web`, `news`, `images`, and `alexandria`."),
|
|
2210
2166
|
error,
|
|
@@ -2216,14 +2172,12 @@ var searchOutputSchema = z4.object({
|
|
|
2216
2172
|
feedbackTool: unknown("Pointer to the feedback tool for this search.")
|
|
2217
2173
|
}).describe("Ranked search results grouped by source.");
|
|
2218
2174
|
var findToolsOutputSchema = z4.object({
|
|
2219
|
-
...agentHints,
|
|
2220
2175
|
success,
|
|
2221
2176
|
data: unknown("Discovery page in `data.alexandria[0].data`, with `level`, `items`, `total`, and an optional `nextTool`."),
|
|
2222
2177
|
error,
|
|
2223
2178
|
...alexandriaEnvelope
|
|
2224
2179
|
}).describe("One page of the Alexandria catalogue: categories, providers, tools, or one contract.");
|
|
2225
2180
|
var feedbackOutputSchema = z4.object({
|
|
2226
|
-
...agentHints,
|
|
2227
2181
|
success,
|
|
2228
2182
|
error,
|
|
2229
2183
|
status: num("HTTP status when the submission was rejected."),
|
|
@@ -2242,7 +2196,6 @@ var feedbackOutputSchema = z4.object({
|
|
|
2242
2196
|
raw: str("Response body when it was not JSON.")
|
|
2243
2197
|
}).describe("Result of submitting feedback.");
|
|
2244
2198
|
var crawlOutputSchema = z4.object({
|
|
2245
|
-
...agentHints,
|
|
2246
2199
|
success,
|
|
2247
2200
|
error,
|
|
2248
2201
|
warning,
|
|
@@ -2257,7 +2210,6 @@ var crawlOutputSchema = z4.object({
|
|
|
2257
2210
|
data: unknown("Scraped documents collected by the crawl.")
|
|
2258
2211
|
}).describe("Crawl job state and the documents collected so far.");
|
|
2259
2212
|
var agentOutputSchema = z4.object({
|
|
2260
|
-
...agentHints,
|
|
2261
2213
|
success,
|
|
2262
2214
|
error,
|
|
2263
2215
|
id: str("Agent job identifier, for `firecrawl_agent_status`."),
|
|
@@ -2266,7 +2218,6 @@ var agentOutputSchema = z4.object({
|
|
|
2266
2218
|
threadTurn: num("Turn number of this job within its thread.")
|
|
2267
2219
|
}).describe("The queued research job. The result is read with `firecrawl_agent_status`.");
|
|
2268
2220
|
var agentStatusOutputSchema = z4.object({
|
|
2269
|
-
...agentHints,
|
|
2270
2221
|
success,
|
|
2271
2222
|
error,
|
|
2272
2223
|
id: str("Agent job identifier."),
|
|
@@ -2294,7 +2245,6 @@ var agentStatusOutputSchema = z4.object({
|
|
|
2294
2245
|
)
|
|
2295
2246
|
}).describe("Progress or final result of a research agent job.");
|
|
2296
2247
|
var interactOutputSchema = z4.object({
|
|
2297
|
-
...agentHints,
|
|
2298
2248
|
success,
|
|
2299
2249
|
error: unknown("Why the interaction or the session could not run."),
|
|
2300
2250
|
url: str("The URL the session was opened from, when opening failed."),
|
|
@@ -2309,14 +2259,12 @@ var interactOutputSchema = z4.object({
|
|
|
2309
2259
|
liveUrl: str("URL for viewing the live session.")
|
|
2310
2260
|
}).describe("Result of a browser interaction, with the session identifier to continue or stop it.");
|
|
2311
2261
|
var interactStopOutputSchema = z4.object({
|
|
2312
|
-
...agentHints,
|
|
2313
2262
|
success,
|
|
2314
2263
|
error,
|
|
2315
2264
|
message: str("Confirmation that the session was stopped."),
|
|
2316
2265
|
scrapeId: str("Session that was stopped.")
|
|
2317
2266
|
}).describe("Confirmation that the interact session was stopped.");
|
|
2318
2267
|
var parseOutputSchema = z4.object({
|
|
2319
|
-
...agentHints,
|
|
2320
2268
|
success,
|
|
2321
2269
|
error,
|
|
2322
2270
|
warning,
|
|
@@ -2344,39 +2292,33 @@ var deprecatedToolOutputSchema = z4.object({
|
|
|
2344
2292
|
docs_url: str("Documentation for the replacement.")
|
|
2345
2293
|
}).describe("A pointer to the replacement tool. This entry point is deprecated and always errors.");
|
|
2346
2294
|
var monitorOutputSchema = z4.object({
|
|
2347
|
-
...agentHints,
|
|
2348
2295
|
success,
|
|
2349
2296
|
error,
|
|
2350
2297
|
data: unknown("The monitor record: configuration, schedule, targets, and current state.")
|
|
2351
2298
|
}).describe("One monitor record.");
|
|
2352
2299
|
var monitorListOutputSchema = z4.object({
|
|
2353
|
-
...agentHints,
|
|
2354
2300
|
success,
|
|
2355
2301
|
error,
|
|
2356
2302
|
data: unknown("One page of monitor records."),
|
|
2357
2303
|
pagination: unknown("Pagination metadata for the listing.")
|
|
2358
2304
|
}).describe("One page of monitors for the authenticated account.");
|
|
2359
2305
|
var monitorDeleteOutputSchema = z4.object({
|
|
2360
|
-
...agentHints,
|
|
2361
2306
|
success,
|
|
2362
2307
|
error,
|
|
2363
2308
|
data: unknown("Deletion details, when the API returns any.")
|
|
2364
2309
|
}).describe("Deletion status for the monitor.");
|
|
2365
2310
|
var monitorRunOutputSchema = z4.object({
|
|
2366
|
-
...agentHints,
|
|
2367
2311
|
success,
|
|
2368
2312
|
error,
|
|
2369
2313
|
data: unknown("The queued check.")
|
|
2370
2314
|
}).describe("The check queued outside the monitor schedule.");
|
|
2371
2315
|
var monitorChecksOutputSchema = z4.object({
|
|
2372
|
-
...agentHints,
|
|
2373
2316
|
success,
|
|
2374
2317
|
error,
|
|
2375
2318
|
data: unknown("One page of check summaries."),
|
|
2376
2319
|
pagination: unknown("Pagination metadata for the listing.")
|
|
2377
2320
|
}).describe("One page of historical checks for the monitor.");
|
|
2378
2321
|
var monitorCheckOutputSchema = z4.object({
|
|
2379
|
-
...agentHints,
|
|
2380
2322
|
success,
|
|
2381
2323
|
error,
|
|
2382
2324
|
data: unknown("The check and its page-level results: each page reports `same`, `new`, `changed`, `removed`, or `error`, with diffs and any goal judgment."),
|
|
@@ -2395,25 +2337,20 @@ var paperSchema = z4.looseObject({
|
|
|
2395
2337
|
updateDate: str("Date the paper was last updated.")
|
|
2396
2338
|
});
|
|
2397
2339
|
var researchSearchOutputSchema = z4.object({
|
|
2398
|
-
...agentHints,
|
|
2399
2340
|
results: z4.array(paperSchema).describe("Ranked papers, in the order the text block lists them.")
|
|
2400
2341
|
}).describe("Ranked papers with canonical IDs, titles, authors, and abstracts.");
|
|
2401
2342
|
var researchPaperOutputSchema = z4.object({
|
|
2402
|
-
...agentHints,
|
|
2403
2343
|
paper: paperSchema.optional().describe("Canonical metadata for the requested paper, absent when it was not found.")
|
|
2404
2344
|
}).describe("Canonical metadata for one paper.");
|
|
2405
2345
|
var researchRelatedOutputSchema = z4.object({
|
|
2406
|
-
...agentHints,
|
|
2407
2346
|
results: z4.array(paperSchema).describe("Ranked citation-graph candidates."),
|
|
2408
2347
|
poolSize: z4.number().describe("Number of candidates evaluated before ranking."),
|
|
2409
2348
|
note: str("Note about how the candidates were produced.")
|
|
2410
2349
|
}).describe("Ranked citation-graph candidates and the size of the evaluated pool.");
|
|
2411
2350
|
var researchReadOutputSchema = z4.object({
|
|
2412
|
-
...agentHints,
|
|
2413
2351
|
passages: z4.array(z4.looseObject({ text: str("Passage text.") })).describe("In-body passages relevant to the question; empty when no full text is indexed.")
|
|
2414
2352
|
}).describe("Full-text passages from one paper.");
|
|
2415
2353
|
var developerSearchOutputSchema = z4.object({
|
|
2416
|
-
...agentHints,
|
|
2417
2354
|
results: z4.array(
|
|
2418
2355
|
z4.looseObject({
|
|
2419
2356
|
id: str("Stable result id, such as `issue:owner/repo#123` or `doc:<hash>`; its prefix gives the source type."),
|
|
@@ -2424,7 +2361,6 @@ var developerSearchOutputSchema = z4.object({
|
|
|
2424
2361
|
).describe("Ranked results, in the order the text block lists them.")
|
|
2425
2362
|
}).describe("Ranked developer-index results with their matched passages.");
|
|
2426
2363
|
var govSearchOutputSchema = z4.object({
|
|
2427
|
-
...agentHints,
|
|
2428
2364
|
results: z4.array(
|
|
2429
2365
|
z4.looseObject({
|
|
2430
2366
|
url: str("Source URL."),
|
|
@@ -2486,7 +2422,8 @@ var findToolsSchema = z5.object({
|
|
|
2486
2422
|
level: z5.enum(["categories", "providers", "groups", "tools"]).optional(),
|
|
2487
2423
|
expand: z5.array(z5.enum(["options", "response", "examples"])).optional().describe('Use ["options", "response"] for inputs and output shape without example payloads; [] keeps results compact. Omit for full contracts on selected capabilities.'),
|
|
2488
2424
|
limit: z5.number().int().min(1).max(100).optional(),
|
|
2489
|
-
offset: z5.number().int().nonnegative().optional()
|
|
2425
|
+
offset: z5.number().int().nonnegative().optional(),
|
|
2426
|
+
includeCosts: z5.boolean().optional().describe("Include per-capability credit prices (creditsCost, perRecord) in tool results.")
|
|
2490
2427
|
}).strict();
|
|
2491
2428
|
var ALEXANDRIA_CATALOGUE_VERTICALS = "companies, people, jobs, finance and filings, public records and government spending, real estate, places and restaurants, retail and prices, package registries and developer data, news, research, and more";
|
|
2492
2429
|
var ALEXANDRIA_CATALOGUE_SENTENCE = "Alexandria is Firecrawl's catalogue of data providers and workflows across " + ALEXANDRIA_CATALOGUE_VERTICALS + "; providers return typed, sourced records through published contracts.";
|
|
@@ -2498,7 +2435,7 @@ function findToolsOptions(args2) {
|
|
|
2498
2435
|
if (level === "categories" && (args2.query || args2.providers?.length || args2.categories?.length || args2.groups?.length || args2.capabilities?.length || args2.urls?.length || args2.expand !== void 0)) {
|
|
2499
2436
|
throw new Error("Category index accepts only level, limit and offset. Select a category to browse providers.");
|
|
2500
2437
|
}
|
|
2501
|
-
const { expand, ...selectors } = args2;
|
|
2438
|
+
const { expand, includeCosts, ...selectors } = args2;
|
|
2502
2439
|
return {
|
|
2503
2440
|
...selectors,
|
|
2504
2441
|
...expand !== void 0 ? { expand } : {},
|
|
@@ -2507,10 +2444,10 @@ function findToolsOptions(args2) {
|
|
|
2507
2444
|
...args2.expand === void 0 && level === "tools" && args2.capabilities?.length ? { expand: ["options", "response", "examples"] } : {}
|
|
2508
2445
|
};
|
|
2509
2446
|
}
|
|
2510
|
-
function withFindToolsNavigation(envelope) {
|
|
2447
|
+
function withFindToolsNavigation(envelope, carry = {}) {
|
|
2511
2448
|
const page = envelope?.data?.alexandria?.[0]?.data;
|
|
2512
2449
|
if (!page || !Array.isArray(page.items)) return envelope;
|
|
2513
|
-
const link = (next) => next?.provider === "firecrawl" && next?.capability === "find-tools" && next.options ? { name: "firecrawl_find_tools", arguments: next.options } : void 0;
|
|
2450
|
+
const link = (next) => next?.provider === "firecrawl" && next?.capability === "find-tools" && next.options ? { name: "firecrawl_find_tools", arguments: { ...next.options, ...carry } } : void 0;
|
|
2514
2451
|
for (const item of page.items) {
|
|
2515
2452
|
if (page.level === "providers" && link(item.next)) {
|
|
2516
2453
|
const selectors = { ...item.next.options };
|
|
@@ -2524,6 +2461,49 @@ function withFindToolsNavigation(envelope) {
|
|
|
2524
2461
|
return envelope;
|
|
2525
2462
|
}
|
|
2526
2463
|
var ALEXANDRIA_SEARCH_INSTRUCTIONS = 'Authenticated search combines web results, semantic tool summaries and domain matches. Use sources: ["alexandria"] for semantic tools only. ' + ALEXANDRIA_SOURCES_OPT_OUT + ' Tool matches describe available structured-data capabilities, not executed data. toolDetail: "compact" (default) returns only provider, capability and description; "summary" adds metadata; "full" includes their input and output contracts. firecrawl_scrape with an alexandria body executes a selected capability; firecrawl_find_tools provides catalogue browsing and full contracts.';
|
|
2464
|
+
var TOOL_PRICE_KEYS = ["creditsCost", "perRecord", "billing", "recordsPerUnit", "zeroDataRetentionCreditsCost"];
|
|
2465
|
+
function withoutToolPrice(tool) {
|
|
2466
|
+
if (!tool || typeof tool !== "object" || Array.isArray(tool)) return tool;
|
|
2467
|
+
const copy = { ...tool };
|
|
2468
|
+
for (const key of TOOL_PRICE_KEYS) delete copy[key];
|
|
2469
|
+
return copy;
|
|
2470
|
+
}
|
|
2471
|
+
function withoutDiscoveredToolPrices(body) {
|
|
2472
|
+
const tools = body?.data?.tools ?? body?.tools;
|
|
2473
|
+
if (!Array.isArray(tools)) return body;
|
|
2474
|
+
return body?.data?.tools ? { ...body, data: { ...body.data, tools: tools.map(withoutToolPrice) } } : { ...body, tools: tools.map(withoutToolPrice) };
|
|
2475
|
+
}
|
|
2476
|
+
function withoutPagePrices(page) {
|
|
2477
|
+
if (!page || typeof page !== "object") return page;
|
|
2478
|
+
return {
|
|
2479
|
+
...page,
|
|
2480
|
+
...Array.isArray(page.items) ? { items: page.items.map(withoutToolPrice) } : {},
|
|
2481
|
+
...Array.isArray(page.relatedTools) ? {
|
|
2482
|
+
relatedTools: page.relatedTools.map((group) => Array.isArray(group?.tools) ? { ...group, tools: group.tools.map((entry) => entry?.tool ? { ...entry, tool: withoutToolPrice(entry.tool) } : withoutToolPrice(entry)) } : group)
|
|
2483
|
+
} : {}
|
|
2484
|
+
};
|
|
2485
|
+
}
|
|
2486
|
+
function withoutResultPrices(body) {
|
|
2487
|
+
const results = body?.data?.alexandria;
|
|
2488
|
+
if (!Array.isArray(results)) return body;
|
|
2489
|
+
return {
|
|
2490
|
+
...body,
|
|
2491
|
+
data: {
|
|
2492
|
+
...body.data,
|
|
2493
|
+
alexandria: results.map((entry) => {
|
|
2494
|
+
const stripped = withoutToolPrice(entry);
|
|
2495
|
+
return entry?.provider === "firecrawl" && entry?.capability === "find-tools" && stripped && typeof stripped === "object" ? { ...stripped, data: withoutPagePrices(entry.data) } : stripped;
|
|
2496
|
+
})
|
|
2497
|
+
}
|
|
2498
|
+
};
|
|
2499
|
+
}
|
|
2500
|
+
function withoutFindToolsPrices(envelope) {
|
|
2501
|
+
const stripped = withoutResultPrices(envelope);
|
|
2502
|
+
if (!stripped?.data || typeof stripped.data !== "object") return stripped;
|
|
2503
|
+
const data = { ...stripped.data };
|
|
2504
|
+
delete data.creditsCost;
|
|
2505
|
+
return { ...stripped, data };
|
|
2506
|
+
}
|
|
2527
2507
|
|
|
2528
2508
|
// src/alexandria-output.ts
|
|
2529
2509
|
var INLINE_TOKEN_BUDGET = 2e4;
|
|
@@ -2673,7 +2653,7 @@ Returns ranked results with an ID, source type, URL, title, and the matched pass
|
|
|
2673
2653
|
const client = getClient(session);
|
|
2674
2654
|
const res = await client.http.get(`${BASE}?${params.toString()}`, originHeaders(requestOrigin(mcpClient, session)));
|
|
2675
2655
|
const results = res.data?.results ?? [];
|
|
2676
|
-
return
|
|
2656
|
+
return withStructured(fmtDeveloper(results), { results });
|
|
2677
2657
|
}
|
|
2678
2658
|
});
|
|
2679
2659
|
}
|
|
@@ -2722,11 +2702,7 @@ Returns ranked results with a position, title, URL, and matched snippet. Results
|
|
|
2722
2702
|
originHeaders(requestOrigin(mcpClient, session))
|
|
2723
2703
|
);
|
|
2724
2704
|
const results = res.data?.data?.web ?? [];
|
|
2725
|
-
return
|
|
2726
|
-
withStructured(fmtGov(results), { results }),
|
|
2727
|
-
res.data,
|
|
2728
|
-
true
|
|
2729
|
-
);
|
|
2705
|
+
return withStructured(fmtGov(results), { results });
|
|
2730
2706
|
}
|
|
2731
2707
|
});
|
|
2732
2708
|
}
|
|
@@ -2737,12 +2713,10 @@ import { z as z8 } from "zod";
|
|
|
2737
2713
|
// src/core-http-error.ts
|
|
2738
2714
|
var CoreHttpError = class extends Error {
|
|
2739
2715
|
status;
|
|
2740
|
-
|
|
2741
|
-
constructor(message, status, agentHints2) {
|
|
2716
|
+
constructor(message, status) {
|
|
2742
2717
|
super(message);
|
|
2743
2718
|
this.name = "CoreHttpError";
|
|
2744
2719
|
this.status = status;
|
|
2745
|
-
if (agentHints2 !== void 0) this.agent_hints = agentHints2;
|
|
2746
2720
|
}
|
|
2747
2721
|
};
|
|
2748
2722
|
|
|
@@ -2765,7 +2739,6 @@ async function monitorRequest(api, session, origin, path2, init = {}) {
|
|
|
2765
2739
|
}
|
|
2766
2740
|
const headers = {
|
|
2767
2741
|
...originHeaders(origin),
|
|
2768
|
-
...AGENT_HINTS_HEADERS,
|
|
2769
2742
|
...extraHeaders
|
|
2770
2743
|
};
|
|
2771
2744
|
if (apiKey2) headers.Authorization = `Bearer ${apiKey2}`;
|
|
@@ -2778,13 +2751,10 @@ async function monitorRequest(api, session, origin, path2, init = {}) {
|
|
|
2778
2751
|
const payload = await response.json().catch(() => ({}));
|
|
2779
2752
|
if (!response.ok || payload?.success === false) {
|
|
2780
2753
|
const message = payload?.error || `HTTP ${response.status}: ${response.statusText || "Request failed"}`;
|
|
2781
|
-
throw new CoreHttpError(message, response.status
|
|
2754
|
+
throw new CoreHttpError(message, response.status);
|
|
2782
2755
|
}
|
|
2783
2756
|
return payload;
|
|
2784
2757
|
}
|
|
2785
|
-
function monitorResult(data) {
|
|
2786
|
-
return withAgentHints(structuredText(data), data);
|
|
2787
|
-
}
|
|
2788
2758
|
var pageStatusSchema = z8.enum(["same", "new", "changed", "removed", "error"]);
|
|
2789
2759
|
var checkStatusSchema = z8.enum([
|
|
2790
2760
|
"queued",
|
|
@@ -2910,7 +2880,7 @@ In the simple form, a \`goal\` is required. If \`queries\` contains one or more
|
|
|
2910
2880
|
body
|
|
2911
2881
|
}
|
|
2912
2882
|
);
|
|
2913
|
-
return
|
|
2883
|
+
return structuredText(res);
|
|
2914
2884
|
}
|
|
2915
2885
|
});
|
|
2916
2886
|
server.addTool({
|
|
@@ -2943,7 +2913,7 @@ List monitors for the authenticated account with optional pagination controls. R
|
|
|
2943
2913
|
query: { limit, offset }
|
|
2944
2914
|
}
|
|
2945
2915
|
);
|
|
2946
|
-
return
|
|
2916
|
+
return structuredText(res);
|
|
2947
2917
|
}
|
|
2948
2918
|
});
|
|
2949
2919
|
server.addTool({
|
|
@@ -2970,7 +2940,7 @@ Retrieve one monitor by ID, including its configuration and current state. This
|
|
|
2970
2940
|
requestOrigin(mcpClient, session),
|
|
2971
2941
|
`/monitor/${encodeURIComponent(id)}`
|
|
2972
2942
|
);
|
|
2973
|
-
return
|
|
2943
|
+
return structuredText(res);
|
|
2974
2944
|
}
|
|
2975
2945
|
});
|
|
2976
2946
|
server.addTool({
|
|
@@ -3003,7 +2973,7 @@ Returns the updated monitor.
|
|
|
3003
2973
|
`/monitor/${encodeURIComponent(id)}`,
|
|
3004
2974
|
{ method: "PATCH", body }
|
|
3005
2975
|
);
|
|
3006
|
-
return
|
|
2976
|
+
return structuredText(res);
|
|
3007
2977
|
}
|
|
3008
2978
|
});
|
|
3009
2979
|
server.addTool({
|
|
@@ -3032,7 +3002,7 @@ Permanently delete a monitor by ID and stop its future schedule. This operation
|
|
|
3032
3002
|
`/monitor/${encodeURIComponent(id)}`,
|
|
3033
3003
|
{ method: "DELETE" }
|
|
3034
3004
|
);
|
|
3035
|
-
return
|
|
3005
|
+
return structuredText(res);
|
|
3036
3006
|
}
|
|
3037
3007
|
});
|
|
3038
3008
|
server.addTool({
|
|
@@ -3060,7 +3030,7 @@ Queue an immediate check for a monitor outside its normal schedule. This starts
|
|
|
3060
3030
|
`/monitor/${encodeURIComponent(id)}/run`,
|
|
3061
3031
|
{ method: "POST" }
|
|
3062
3032
|
);
|
|
3063
|
-
return
|
|
3033
|
+
return structuredText(res);
|
|
3064
3034
|
}
|
|
3065
3035
|
});
|
|
3066
3036
|
server.addTool({
|
|
@@ -3093,7 +3063,7 @@ List historical checks for a monitor, optionally filtered by status and bounded
|
|
|
3093
3063
|
`/monitor/${encodeURIComponent(id)}/checks`,
|
|
3094
3064
|
{ query: { limit, offset, status } }
|
|
3095
3065
|
);
|
|
3096
|
-
return
|
|
3066
|
+
return structuredText(res);
|
|
3097
3067
|
}
|
|
3098
3068
|
});
|
|
3099
3069
|
server.addTool({
|
|
@@ -3129,7 +3099,7 @@ Markdown tracking returns a unified text diff, JSON tracking returns field paths
|
|
|
3129
3099
|
`/monitor/${encodeURIComponent(id)}/checks/${encodeURIComponent(checkId)}`,
|
|
3130
3100
|
{ query: { limit, skip, status: pageStatus } }
|
|
3131
3101
|
);
|
|
3132
|
-
return
|
|
3102
|
+
return structuredText(res);
|
|
3133
3103
|
}
|
|
3134
3104
|
});
|
|
3135
3105
|
}
|
|
@@ -3137,9 +3107,6 @@ Markdown tracking returns a unified text diff, JSON tracking returns field paths
|
|
|
3137
3107
|
// src/research.ts
|
|
3138
3108
|
import { z as z9 } from "zod";
|
|
3139
3109
|
var BASE3 = "/v2/search/research";
|
|
3140
|
-
function researchHeaders(origin) {
|
|
3141
|
-
return { ...originHeaders(origin), ...AGENT_HINTS_HEADERS };
|
|
3142
|
-
}
|
|
3143
3110
|
function appendParam(params, key, value) {
|
|
3144
3111
|
if (value == null) return;
|
|
3145
3112
|
if (Array.isArray(value)) {
|
|
@@ -3284,10 +3251,10 @@ Returns ranked papers with canonical IDs, titles, authors, and abstracts.
|
|
|
3284
3251
|
const client = getClient(session);
|
|
3285
3252
|
const res = await client.http.get(
|
|
3286
3253
|
withQuery(`${BASE3}/papers`, params),
|
|
3287
|
-
|
|
3254
|
+
originHeaders(requestOrigin(mcpClient, session))
|
|
3288
3255
|
);
|
|
3289
3256
|
const results = res.data?.results ?? [];
|
|
3290
|
-
return
|
|
3257
|
+
return withStructured(fmtHits(results), { results });
|
|
3291
3258
|
}
|
|
3292
3259
|
});
|
|
3293
3260
|
server.addTool({
|
|
@@ -3315,13 +3282,13 @@ Retrieve canonical metadata for one paper ID, such as an arXiv, PMC, PMID, or DO
|
|
|
3315
3282
|
const client = getClient(session);
|
|
3316
3283
|
const res = await client.http.get(
|
|
3317
3284
|
`${BASE3}/papers/${encodeURIComponent(paperId)}`,
|
|
3318
|
-
|
|
3285
|
+
originHeaders(requestOrigin(mcpClient, session))
|
|
3319
3286
|
);
|
|
3320
3287
|
const paper = res.data?.paper;
|
|
3321
|
-
return
|
|
3288
|
+
return withStructured(
|
|
3322
3289
|
fmtPaperMetadata(paper),
|
|
3323
3290
|
paper ? { paper } : {}
|
|
3324
|
-
)
|
|
3291
|
+
);
|
|
3325
3292
|
}
|
|
3326
3293
|
});
|
|
3327
3294
|
server.addTool({
|
|
@@ -3363,17 +3330,17 @@ Returns ranked candidates and the evaluated pool size.
|
|
|
3363
3330
|
`${BASE3}/papers/${encodeURIComponent(primary)}/similar`,
|
|
3364
3331
|
params
|
|
3365
3332
|
),
|
|
3366
|
-
|
|
3333
|
+
originHeaders(requestOrigin(mcpClient, session))
|
|
3367
3334
|
);
|
|
3368
3335
|
const results = res.data?.results ?? [];
|
|
3369
3336
|
const poolSize = res.data?.poolSize ?? 0;
|
|
3370
3337
|
const note = res.data?.note ? `
|
|
3371
3338
|
note: ${res.data.note}` : "";
|
|
3372
|
-
return
|
|
3339
|
+
return withStructured(
|
|
3373
3340
|
`${fmtHits(results)}
|
|
3374
3341
|
(poolSize=${poolSize})${note}`,
|
|
3375
3342
|
{ results, poolSize, ...res.data?.note ? { note: res.data.note } : {} }
|
|
3376
|
-
)
|
|
3343
|
+
);
|
|
3377
3344
|
}
|
|
3378
3345
|
});
|
|
3379
3346
|
server.addTool({
|
|
@@ -3408,13 +3375,13 @@ Returns matching passages or a notice when full text is unavailable.
|
|
|
3408
3375
|
const client = getClient(session);
|
|
3409
3376
|
const res = await client.http.get(
|
|
3410
3377
|
withQuery(`${BASE3}/papers/${encodeURIComponent(paperId)}`, params),
|
|
3411
|
-
|
|
3378
|
+
originHeaders(requestOrigin(mcpClient, session))
|
|
3412
3379
|
);
|
|
3413
3380
|
const passages = res.data?.passages ?? [];
|
|
3414
|
-
return
|
|
3381
|
+
return withStructured(
|
|
3415
3382
|
passages.length ? passages.map((p) => p.text).join("\n---\n") : "(no full-text passages available for this paper)",
|
|
3416
3383
|
{ passages }
|
|
3417
|
-
)
|
|
3384
|
+
);
|
|
3418
3385
|
}
|
|
3419
3386
|
});
|
|
3420
3387
|
server.addTool({
|
|
@@ -3640,20 +3607,6 @@ async function runWithCredentialRecovery(run, requestId, session) {
|
|
|
3640
3607
|
return await run();
|
|
3641
3608
|
} catch (error2) {
|
|
3642
3609
|
if (session?.authType !== "api-key" || !isCoreCredentialRejection(error2, session)) {
|
|
3643
|
-
const hints = readErrorAgentHints(error2);
|
|
3644
|
-
if (hints) {
|
|
3645
|
-
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
3646
|
-
throw new UserError(
|
|
3647
|
-
hints.length ? `${message}
|
|
3648
|
-
|
|
3649
|
-
${agentHintsText(hints)}` : message,
|
|
3650
|
-
{
|
|
3651
|
-
...error2 instanceof UserError ? error2.extras : {},
|
|
3652
|
-
error: message,
|
|
3653
|
-
agent_hints: hints
|
|
3654
|
-
}
|
|
3655
|
-
);
|
|
3656
|
-
}
|
|
3657
3610
|
throw error2;
|
|
3658
3611
|
}
|
|
3659
3612
|
const payload = recoveryPayload("CREDENTIAL_INVALID", requestId);
|
|
@@ -3712,8 +3665,6 @@ var searchDomainSchema = z11.string().trim().toLowerCase().min(1).max(253).regex
|
|
|
3712
3665
|
var searchToolBaseFields = {
|
|
3713
3666
|
toolDetail: z11.enum(["compact", "summary", "full"]).optional().describe("Compact by default. Compact returns only provider, capability and description; full includes contracts. Inspect selected compact tools with firecrawl_find_tools providers and capabilities."),
|
|
3714
3667
|
query: z11.string().min(1).describe("Query for web and semantic tool discovery. Operators include quoted phrases, `-term`, `site:host`, `inurl:term`, `intitle:term`, and `related:host`; the set is non-exhaustive. Catalogue browsing is available through firecrawl_find_tools."),
|
|
3715
|
-
objective: z11.string().trim().min(1).max(5e3).optional().describe("Optional broader goal for this search, if known. Avoid sensitive information."),
|
|
3716
|
-
clientModel: z11.string().trim().min(1).max(128).optional().describe("Optional model identifier, if known."),
|
|
3717
3668
|
domainTools: z11.boolean().optional().describe(
|
|
3718
3669
|
"Include domain-matched tools for result URLs. Defaults to true when Alexandria is combined with web, news or images; semantic-only search leaves domain matching off."
|
|
3719
3670
|
),
|
|
@@ -3779,7 +3730,7 @@ function termsRequiredAction(body) {
|
|
|
3779
3730
|
url: action.url
|
|
3780
3731
|
};
|
|
3781
3732
|
}
|
|
3782
|
-
function termsRequiredError(action, context
|
|
3733
|
+
function termsRequiredError(action, context) {
|
|
3783
3734
|
const requestId = context.requestId;
|
|
3784
3735
|
const retryIdentity = requestId ? ` and requestId ${requestId}` : "";
|
|
3785
3736
|
const message = `Alexandria provider terms required. An organization admin must accept the ${action.terms} provider's terms (version ${action.version}) before this request can run.`;
|
|
@@ -3794,7 +3745,6 @@ Do not retry until acceptance is confirmed.`,
|
|
|
3794
3745
|
code: TERMS_REQUIRED_CODE,
|
|
3795
3746
|
status: 403,
|
|
3796
3747
|
message,
|
|
3797
|
-
...hints ? { agent_hints: hints } : {},
|
|
3798
3748
|
...requestId ? { requestId } : {},
|
|
3799
3749
|
requiresAction: action,
|
|
3800
3750
|
nextTool: {
|
|
@@ -3825,8 +3775,7 @@ Do not retry until acceptance is confirmed.`,
|
|
|
3825
3775
|
function throwIfTermsRequired(error2, context) {
|
|
3826
3776
|
const source = error2;
|
|
3827
3777
|
const action = termsRequiredAction(source?.response?.data ?? source?.details);
|
|
3828
|
-
if (action)
|
|
3829
|
-
throw termsRequiredError(action, context, readErrorAgentHints(error2));
|
|
3778
|
+
if (action) throw termsRequiredError(action, context);
|
|
3830
3779
|
}
|
|
3831
3780
|
async function relayTermsRequired(run, context) {
|
|
3832
3781
|
try {
|
|
@@ -3844,7 +3793,6 @@ async function relayExchangeError(run, context) {
|
|
|
3844
3793
|
const response = error2?.response;
|
|
3845
3794
|
if (!response || response.status === 401) throw error2;
|
|
3846
3795
|
const data = response.data;
|
|
3847
|
-
const hints = readErrorAgentHints(error2);
|
|
3848
3796
|
const message = typeof data?.error === "string" ? data.error : `Alexandria request failed (HTTP ${response.status})`;
|
|
3849
3797
|
const disabledProvider = response.status === 403 ? context.providers?.find((provider) => message === `Access to ${provider} is disabled for this organization.`) : void 0;
|
|
3850
3798
|
if (disabledProvider) {
|
|
@@ -3854,7 +3802,6 @@ async function relayExchangeError(run, context) {
|
|
|
3854
3802
|
code: typeof data?.code === "string" ? data.code : "exchange_error",
|
|
3855
3803
|
status: 403,
|
|
3856
3804
|
message,
|
|
3857
|
-
...hints ? { agent_hints: hints } : {},
|
|
3858
3805
|
nextTool: {
|
|
3859
3806
|
name: "firecrawl_scrape",
|
|
3860
3807
|
arguments: {
|
|
@@ -3868,7 +3815,6 @@ async function relayExchangeError(run, context) {
|
|
|
3868
3815
|
code: typeof data?.code === "string" ? data.code : "exchange_error",
|
|
3869
3816
|
status: response.status,
|
|
3870
3817
|
message,
|
|
3871
|
-
...hints ? { agent_hints: hints } : {},
|
|
3872
3818
|
...typeof data?.chargeId === "string" ? { chargeId: data.chargeId } : {}
|
|
3873
3819
|
});
|
|
3874
3820
|
}
|
|
@@ -3915,10 +3861,6 @@ function copySession(session) {
|
|
|
3915
3861
|
Object.getOwnPropertyDescriptors(session ?? {})
|
|
3916
3862
|
);
|
|
3917
3863
|
}
|
|
3918
|
-
function resultAgentHints(result) {
|
|
3919
|
-
return result && typeof result === "object" ? readAgentHints(result.structuredContent) : void 0;
|
|
3920
|
-
}
|
|
3921
|
-
var warnedMissingAgentHintsInterceptor = false;
|
|
3922
3864
|
var ConsoleLogger = class {
|
|
3923
3865
|
constructor(shouldLog) {
|
|
3924
3866
|
this.shouldLog = shouldLog;
|
|
@@ -4070,20 +4012,10 @@ function createFirecrawlMcpServer(options2 = {}) {
|
|
|
4070
4012
|
requestId,
|
|
4071
4013
|
session
|
|
4072
4014
|
);
|
|
4073
|
-
hooks.onToolResult?.({
|
|
4074
|
-
...call,
|
|
4075
|
-
status: "success",
|
|
4076
|
-
result,
|
|
4077
|
-
agentHints: resultAgentHints(result)
|
|
4078
|
-
});
|
|
4015
|
+
hooks.onToolResult?.({ ...call, status: "success", result });
|
|
4079
4016
|
return result;
|
|
4080
4017
|
} catch (error2) {
|
|
4081
|
-
hooks.onToolResult?.({
|
|
4082
|
-
...call,
|
|
4083
|
-
status: "error",
|
|
4084
|
-
error: error2,
|
|
4085
|
-
agentHints: readErrorAgentHints(error2)
|
|
4086
|
-
});
|
|
4018
|
+
hooks.onToolResult?.({ ...call, status: "error", error: error2 });
|
|
4087
4019
|
throw error2;
|
|
4088
4020
|
}
|
|
4089
4021
|
}
|
|
@@ -4114,44 +4046,7 @@ function createFirecrawlMcpServer(options2 = {}) {
|
|
|
4114
4046
|
if (apiKey2) {
|
|
4115
4047
|
clientConfig.apiKey = apiKey2;
|
|
4116
4048
|
}
|
|
4117
|
-
|
|
4118
|
-
const axiosInstance = client.http?.instance;
|
|
4119
|
-
if (axiosInstance?.interceptors?.request?.use) {
|
|
4120
|
-
axiosInstance.interceptors.request.use((request) => {
|
|
4121
|
-
if (typeof request.headers?.set === "function") {
|
|
4122
|
-
request.headers.set("X-Firecrawl-Agent-Hints", "true");
|
|
4123
|
-
} else {
|
|
4124
|
-
request.headers = { ...request.headers ?? {}, ...AGENT_HINTS_HEADERS };
|
|
4125
|
-
}
|
|
4126
|
-
return request;
|
|
4127
|
-
});
|
|
4128
|
-
} else if (!warnedMissingAgentHintsInterceptor) {
|
|
4129
|
-
warnedMissingAgentHintsInterceptor = true;
|
|
4130
|
-
console.warn(
|
|
4131
|
-
"[firecrawl-mcp] SDK request interceptor unavailable; API agent hints may be absent."
|
|
4132
|
-
);
|
|
4133
|
-
}
|
|
4134
|
-
return client;
|
|
4135
|
-
}
|
|
4136
|
-
async function sdkResultWithAgentHints(client, execute) {
|
|
4137
|
-
const responseInterceptors = client.http?.instance?.interceptors?.response;
|
|
4138
|
-
if (!responseInterceptors?.use) return execute();
|
|
4139
|
-
let hints;
|
|
4140
|
-
const interceptor = responseInterceptors.use((response) => {
|
|
4141
|
-
hints = readAgentHints(response?.data) ?? hints;
|
|
4142
|
-
return response;
|
|
4143
|
-
});
|
|
4144
|
-
try {
|
|
4145
|
-
const result = await execute();
|
|
4146
|
-
return preserveAgentHints(result, { agent_hints: hints });
|
|
4147
|
-
} catch (error2) {
|
|
4148
|
-
if (hints && error2 && typeof error2 === "object" && !readErrorAgentHints(error2)) {
|
|
4149
|
-
error2.agent_hints = hints;
|
|
4150
|
-
}
|
|
4151
|
-
throw error2;
|
|
4152
|
-
} finally {
|
|
4153
|
-
responseInterceptors.eject?.(interceptor);
|
|
4154
|
-
}
|
|
4049
|
+
return new FirecrawlApp(clientConfig);
|
|
4155
4050
|
}
|
|
4156
4051
|
const SAFE_MODE = config.safeMode;
|
|
4157
4052
|
function getClient(session) {
|
|
@@ -4504,7 +4399,6 @@ function createFirecrawlMcpServer(options2 = {}) {
|
|
|
4504
4399
|
const response = await fetch(`${resolveApiBaseUrl()}${pathName}`, {
|
|
4505
4400
|
method: "POST",
|
|
4506
4401
|
headers: {
|
|
4507
|
-
...AGENT_HINTS_HEADERS,
|
|
4508
4402
|
"Content-Type": "application/json",
|
|
4509
4403
|
...extraHeaders,
|
|
4510
4404
|
Authorization: `Bearer ${apiKey2}`,
|
|
@@ -4522,8 +4416,7 @@ function createFirecrawlMcpServer(options2 = {}) {
|
|
|
4522
4416
|
if (!response.ok) {
|
|
4523
4417
|
throw new CoreHttpError(
|
|
4524
4418
|
parsed?.error || parsed?.message || `Firecrawl request failed (HTTP ${response.status})`,
|
|
4525
|
-
response.status
|
|
4526
|
-
readAgentHints(parsed)
|
|
4419
|
+
response.status
|
|
4527
4420
|
);
|
|
4528
4421
|
}
|
|
4529
4422
|
return parsed;
|
|
@@ -4605,7 +4498,6 @@ function createFirecrawlMcpServer(options2 = {}) {
|
|
|
4605
4498
|
session,
|
|
4606
4499
|
origin
|
|
4607
4500
|
);
|
|
4608
|
-
const uploadHints = readAgentHints(uploadJson);
|
|
4609
4501
|
const upload = parseApiData(uploadJson);
|
|
4610
4502
|
if (!upload?.uploadUrl || !upload?.uploadRef) {
|
|
4611
4503
|
throw new Error(
|
|
@@ -4616,7 +4508,6 @@ function createFirecrawlMcpServer(options2 = {}) {
|
|
|
4616
4508
|
const uploadForCommand = { ...upload, headers: uploadHeaders };
|
|
4617
4509
|
return asText({
|
|
4618
4510
|
success: true,
|
|
4619
|
-
...uploadHints ? { agent_hints: uploadHints } : {},
|
|
4620
4511
|
mode: "hosted-upload-ref-awaiting-upload",
|
|
4621
4512
|
message: "Hosted MCP cannot read local files. Run the local upload command, then call firecrawl_parse again with uploadRef. No Firecrawl API key is included in this command.",
|
|
4622
4513
|
upload: {
|
|
@@ -4715,20 +4606,17 @@ Alexandria mode, on an authenticated session with Alexandria access: \`alexandri
|
|
|
4715
4606
|
},
|
|
4716
4607
|
session
|
|
4717
4608
|
);
|
|
4718
|
-
return structuredText(
|
|
4609
|
+
return structuredText(withoutDiscoveredToolPrices(json?.data ?? json));
|
|
4719
4610
|
}
|
|
4720
4611
|
const client = getClient(session);
|
|
4721
4612
|
const res = await relayTermsRequired(
|
|
4722
|
-
() =>
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
origin
|
|
4727
|
-
})
|
|
4728
|
-
),
|
|
4613
|
+
() => client.scrape(String(url), {
|
|
4614
|
+
...cleaned,
|
|
4615
|
+
origin
|
|
4616
|
+
}),
|
|
4729
4617
|
{ tool: "firecrawl_scrape" }
|
|
4730
4618
|
);
|
|
4731
|
-
return structuredText(res);
|
|
4619
|
+
return structuredText(withoutDiscoveredToolPrices(res));
|
|
4732
4620
|
}
|
|
4733
4621
|
};
|
|
4734
4622
|
server.addTool({
|
|
@@ -4765,13 +4653,10 @@ Returns matching URLs rather than page bodies. Retrieve one page with \`firecraw
|
|
|
4765
4653
|
const client = getClient(session);
|
|
4766
4654
|
const cleaned = removeEmptyTopLevel(options3);
|
|
4767
4655
|
log.info("Mapping URL", { url: String(url) });
|
|
4768
|
-
const res = await
|
|
4769
|
-
|
|
4770
|
-
|
|
4771
|
-
|
|
4772
|
-
origin: requestOrigin(mcpClient, session)
|
|
4773
|
-
})
|
|
4774
|
-
);
|
|
4656
|
+
const res = await client.map(String(url), {
|
|
4657
|
+
...cleaned,
|
|
4658
|
+
origin: requestOrigin(mcpClient, session)
|
|
4659
|
+
});
|
|
4775
4660
|
return structuredText(res);
|
|
4776
4661
|
}
|
|
4777
4662
|
});
|
|
@@ -4834,7 +4719,7 @@ For a programming question, add \`categories: ["developer"]\`; its hits return i
|
|
|
4834
4719
|
const json = await keylessPost("/v2/search", searchBody, session);
|
|
4835
4720
|
const keylessResponse = { ...json ?? {} };
|
|
4836
4721
|
delete keylessResponse.id;
|
|
4837
|
-
return structuredCompact(keylessResponse);
|
|
4722
|
+
return structuredCompact(withoutDiscoveredToolPrices(keylessResponse));
|
|
4838
4723
|
}
|
|
4839
4724
|
const client = getClient(session);
|
|
4840
4725
|
const postSearch = () => postSearchWithFallback(
|
|
@@ -4844,10 +4729,10 @@ For a programming question, add \`categories: ["developer"]\`; its hits return i
|
|
|
4844
4729
|
);
|
|
4845
4730
|
const context = { tool: "firecrawl_search" };
|
|
4846
4731
|
const httpRes = exchangeSource ? await relayExchangeError(postSearch, context) : await relayTermsRequired(postSearch, context);
|
|
4847
|
-
return structuredCompact(httpRes?.data ?? {});
|
|
4732
|
+
return structuredCompact(withoutDiscoveredToolPrices(httpRes?.data ?? {}));
|
|
4848
4733
|
}
|
|
4849
4734
|
});
|
|
4850
|
-
async function executeExchangeCalls(session, alexandria, suppliedRequestId, timeout, origin = requestOrigin(void 0, session)) {
|
|
4735
|
+
async function executeExchangeCalls(session, alexandria, suppliedRequestId, timeout, origin = requestOrigin(void 0, session), includeCosts = false) {
|
|
4851
4736
|
assertExchangeCredential2(session);
|
|
4852
4737
|
const client = getClient(session);
|
|
4853
4738
|
const requestId = suppliedRequestId ?? randomUUID2();
|
|
@@ -4869,7 +4754,7 @@ For a programming question, add \`categories: ["developer"]\`; its hits return i
|
|
|
4869
4754
|
);
|
|
4870
4755
|
const calls = Array.isArray(alexandria) ? alexandria : [alexandria];
|
|
4871
4756
|
return alexandriaOutput(
|
|
4872
|
-
{ ...response?.data ?? {}, requestId },
|
|
4757
|
+
{ ...includeCosts ? response?.data ?? {} : withoutResultPrices(response?.data ?? {}), requestId },
|
|
4873
4758
|
calls,
|
|
4874
4759
|
async (body, id) => {
|
|
4875
4760
|
const result = await client.http.post(
|
|
@@ -4910,6 +4795,7 @@ For a programming question, add \`categories: ["developer"]\`; its hits return i
|
|
|
4910
4795
|
} catch (error2) {
|
|
4911
4796
|
throw new UserError2(error2 instanceof Error ? error2.message : String(error2));
|
|
4912
4797
|
}
|
|
4798
|
+
const carry = args2.includeCosts ? { includeCosts: true } : {};
|
|
4913
4799
|
if (options3.level === "categories") {
|
|
4914
4800
|
assertExchangeCredential2(session);
|
|
4915
4801
|
const response = await relayExchangeError(
|
|
@@ -4927,11 +4813,12 @@ For a programming question, add \`categories: ["developer"]\`; its hits return i
|
|
|
4927
4813
|
next: { provider: "firecrawl", capability: "find-tools", options: { categories: [row.cohort], level: "providers", limit: options3.limit } }
|
|
4928
4814
|
}));
|
|
4929
4815
|
const page = { level: "categories", items, total: rows.length };
|
|
4930
|
-
if (offset + options3.limit < rows.length) page.nextTool = { name: "firecrawl_find_tools", arguments: { level: "categories", limit: options3.limit, offset: offset + options3.limit } };
|
|
4931
|
-
return structuredCompact(withAlexandriaFeedbackHint(withFindToolsNavigation({ success: true, data: {
|
|
4816
|
+
if (offset + options3.limit < rows.length) page.nextTool = { name: "firecrawl_find_tools", arguments: { level: "categories", limit: options3.limit, offset: offset + options3.limit, ...carry } };
|
|
4817
|
+
return structuredCompact(withAlexandriaFeedbackHint(withFindToolsNavigation({ success: true, data: { alexandria: [{ provider: "firecrawl", capability: "find-tools", data: page }] } }, carry), alexandriaFeedbackAvailable()));
|
|
4932
4818
|
}
|
|
4933
|
-
const result = await executeExchangeCalls(session, { provider: "firecrawl", capability: "find-tools", options: options3 }, void 0, void 0, origin);
|
|
4934
|
-
|
|
4819
|
+
const result = await executeExchangeCalls(session, { provider: "firecrawl", capability: "find-tools", options: options3 }, void 0, void 0, origin, carry.includeCosts);
|
|
4820
|
+
const envelope = JSON.parse(result);
|
|
4821
|
+
return structuredCompact(withFindToolsNavigation(carry.includeCosts ? envelope : withoutFindToolsPrices(envelope), carry));
|
|
4935
4822
|
}
|
|
4936
4823
|
};
|
|
4937
4824
|
server.addTool(findToolsTool);
|
|
@@ -4951,7 +4838,6 @@ For a programming question, add \`categories: ["developer"]\`; its hits return i
|
|
|
4951
4838
|
const origin = originOverride ?? (typeof body.origin === "string" && body.origin.length > 0 ? body.origin : requestOrigin(void 0, session));
|
|
4952
4839
|
await hooks.beforeKeylessRequest?.(session, origin);
|
|
4953
4840
|
const headers = {
|
|
4954
|
-
...AGENT_HINTS_HEADERS,
|
|
4955
4841
|
...originHeaders(origin),
|
|
4956
4842
|
"Content-Type": "application/json",
|
|
4957
4843
|
...resolveOutbound(session).headers
|
|
@@ -4969,14 +4855,11 @@ For a programming question, add \`categories: ["developer"]\`; its hits return i
|
|
|
4969
4855
|
retryAfterSeconds: Number.isFinite(json?.retry_after_seconds) && json.retry_after_seconds > 0 ? json.retry_after_seconds : void 0,
|
|
4970
4856
|
signupUrl: keylessSignupUrlFrom(json?.signup_url)
|
|
4971
4857
|
});
|
|
4972
|
-
const hints = readAgentHints(json);
|
|
4973
|
-
if (hints) payload.agent_hints = hints;
|
|
4974
4858
|
throw new UserError2(String(payload.message), payload);
|
|
4975
4859
|
}
|
|
4976
4860
|
throw new CoreHttpError(
|
|
4977
4861
|
json?.error || `Firecrawl request failed (HTTP ${response.status})`,
|
|
4978
|
-
response.status
|
|
4979
|
-
readAgentHints(json)
|
|
4862
|
+
response.status
|
|
4980
4863
|
);
|
|
4981
4864
|
}
|
|
4982
4865
|
return json;
|
|
@@ -4997,8 +4880,7 @@ For a programming question, add \`categories: ["developer"]\`; its hits return i
|
|
|
4997
4880
|
creditsUsed: body.creditsUsed,
|
|
4998
4881
|
expiresAt: body.expiresAt,
|
|
4999
4882
|
next: body.next ?? null,
|
|
5000
|
-
data: initialDocs
|
|
5001
|
-
...readAgentHints(body) ? { agent_hints: readAgentHints(body) } : {}
|
|
4883
|
+
data: initialDocs
|
|
5002
4884
|
};
|
|
5003
4885
|
}
|
|
5004
4886
|
const docs = initialDocs.slice();
|
|
@@ -5022,8 +4904,7 @@ For a programming question, add \`categories: ["developer"]\`; its hits return i
|
|
|
5022
4904
|
creditsUsed: body.creditsUsed,
|
|
5023
4905
|
expiresAt: body.expiresAt,
|
|
5024
4906
|
next: null,
|
|
5025
|
-
data: docs
|
|
5026
|
-
...readAgentHints(body) ? { agent_hints: readAgentHints(body) } : {}
|
|
4907
|
+
data: docs
|
|
5027
4908
|
};
|
|
5028
4909
|
}
|
|
5029
4910
|
async function waitForCrawlCompletionWithOrigin(client, jobId, origin, pollInterval = 2, timeout) {
|
|
@@ -5119,7 +5000,6 @@ Eligibility is limited to successful searches within the feedback age window. Th
|
|
|
5119
5000
|
}
|
|
5120
5001
|
if (querySuggestions) body.querySuggestions = querySuggestions;
|
|
5121
5002
|
const headers = {
|
|
5122
|
-
...AGENT_HINTS_HEADERS,
|
|
5123
5003
|
...originHeaders(origin),
|
|
5124
5004
|
"Content-Type": "application/json"
|
|
5125
5005
|
};
|
|
@@ -5160,8 +5040,7 @@ Eligibility is limited to successful searches within the feedback age window. Th
|
|
|
5160
5040
|
status: response.status,
|
|
5161
5041
|
feedbackErrorCode: parsed?.feedbackErrorCode,
|
|
5162
5042
|
error: parsed?.error ?? `HTTP ${response.status}`,
|
|
5163
|
-
retryable: response.status >= 500
|
|
5164
|
-
...readAgentHints(parsed) ? { agent_hints: readAgentHints(parsed) } : {}
|
|
5043
|
+
retryable: response.status >= 500
|
|
5165
5044
|
});
|
|
5166
5045
|
}
|
|
5167
5046
|
return structuredText(parsed);
|
|
@@ -5245,7 +5124,6 @@ Returns submission status, feedback ID, and accounting fields.
|
|
|
5245
5124
|
} = args2;
|
|
5246
5125
|
const apiBase = resolveApiBaseUrl();
|
|
5247
5126
|
const headers = {
|
|
5248
|
-
...AGENT_HINTS_HEADERS,
|
|
5249
5127
|
...originHeaders(origin),
|
|
5250
5128
|
"Content-Type": "application/json"
|
|
5251
5129
|
};
|
|
@@ -5301,8 +5179,7 @@ Returns submission status, feedback ID, and accounting fields.
|
|
|
5301
5179
|
status: response.status,
|
|
5302
5180
|
feedbackErrorCode: parsed?.feedbackErrorCode,
|
|
5303
5181
|
error: parsed?.error ?? `HTTP ${response.status}`,
|
|
5304
|
-
retryable: response.status >= 500
|
|
5305
|
-
...readAgentHints(parsed) ? { agent_hints: readAgentHints(parsed) } : {}
|
|
5182
|
+
retryable: response.status >= 500
|
|
5306
5183
|
});
|
|
5307
5184
|
}
|
|
5308
5185
|
return structuredText(parsed);
|
|
@@ -5790,7 +5667,6 @@ Set \`redactPII\` to request redaction of personally identifiable information in
|
|
|
5790
5667
|
form.append("file", blob, filename);
|
|
5791
5668
|
form.append("options", JSON.stringify(optionsPayload));
|
|
5792
5669
|
const headers = {
|
|
5793
|
-
...AGENT_HINTS_HEADERS,
|
|
5794
5670
|
...originHeaders(origin)
|
|
5795
5671
|
};
|
|
5796
5672
|
const outbound = resolveOutbound(session);
|
|
@@ -5812,15 +5688,9 @@ Set \`redactPII\` to request redaction of personally identifiable information in
|
|
|
5812
5688
|
});
|
|
5813
5689
|
const responseText = await response.text();
|
|
5814
5690
|
if (!response.ok) {
|
|
5815
|
-
let parsed;
|
|
5816
|
-
try {
|
|
5817
|
-
parsed = JSON.parse(responseText);
|
|
5818
|
-
} catch {
|
|
5819
|
-
}
|
|
5820
5691
|
throw new CoreHttpError(
|
|
5821
5692
|
`Parse request failed with status ${response.status}: ${responseText}`,
|
|
5822
|
-
response.status
|
|
5823
|
-
readAgentHints(parsed)
|
|
5693
|
+
response.status
|
|
5824
5694
|
);
|
|
5825
5695
|
}
|
|
5826
5696
|
try {
|
|
@@ -5848,6 +5718,9 @@ Set \`redactPII\` to request redaction of personally identifiable information in
|
|
|
5848
5718
|
builtInTool: (name2) => builtInTools.get(name2)
|
|
5849
5719
|
}
|
|
5850
5720
|
);
|
|
5721
|
+
hooks.registerResources?.({
|
|
5722
|
+
addResource: (resource) => server.addResource(resource)
|
|
5723
|
+
});
|
|
5851
5724
|
return {
|
|
5852
5725
|
start: (args2) => server.start(args2),
|
|
5853
5726
|
stop: () => server.stop()
|
|
@@ -6005,7 +5878,7 @@ function getOAuthIssuer() {
|
|
|
6005
5878
|
normalizeHeader(process.env.FIRECRAWL_OAUTH_ISSUER) ?? DEFAULT_OAUTH_ISSUER
|
|
6006
5879
|
);
|
|
6007
5880
|
}
|
|
6008
|
-
var SEARCH_PROFILE_INSTRUCTIONS = ALEXANDRIA_SEARCH_INSTRUCTIONS + ` Firecrawl provides web, developer, government, and research search, and executes catalogued Alexandria data providers. Use firecrawl_search to find relevant results across the web and specialized indexes; authenticated searches also return matching Alexandria providers in data.tools. firecrawl_find_tools provides catalogue browsing and provider contracts; firecrawl_scrape with an alexandria body executes a selected capability; firecrawl_scrape with a url retrieves one supplied page. For a programming question, firecrawl_developer_search searches indexed public repositories, GitHub issues, merged pull requests, READMEs, and code documentation and returns the matched passages, and skills: "only" narrows it to agent-skill files; firecrawl_search with categories: ["developer"] reaches the same index beside ordinary web results, returning the hits in the web group rather than as passages and offering no skills filter. For a legal or regulatory question, firecrawl_gov_search searches primary law and regulatory material from US federal, state, and local government sources: statutes, regulations, codes, court opinions, and other government publications; firecrawl_search with categories: ["gov"] reaches the same sources in the web group and cannot be combined with other categories. For a biomedical, life-science, clinical, or arXiv literature question, the firecrawl_research_* tools search the paper index, while categories: ["research"] on firecrawl_search filters ordinary web results to research-affiliated websites. Use the firecrawl_research_* tools to search academic and research literature, expand from anchor papers via the citation graph, and read full-text passages from a specific paper. Search and discovery tools are read-only and return ranked results. Billing: web, developer, and research search are billed per request; government search is free; Alexandria discovery (firecrawl_search with sources ["alexandria"] alone, and firecrawl_find_tools) is free; firecrawl_scrape is billed, as a page retrieval in url mode or
|
|
5881
|
+
var SEARCH_PROFILE_INSTRUCTIONS = ALEXANDRIA_SEARCH_INSTRUCTIONS + ` Firecrawl provides web, developer, government, and research search, and executes catalogued Alexandria data providers. Use firecrawl_search to find relevant results across the web and specialized indexes; authenticated searches also return matching Alexandria providers in data.tools. firecrawl_find_tools provides catalogue browsing and provider contracts; firecrawl_scrape with an alexandria body executes a selected capability; firecrawl_scrape with a url retrieves one supplied page. For a programming question, firecrawl_developer_search searches indexed public repositories, GitHub issues, merged pull requests, READMEs, and code documentation and returns the matched passages, and skills: "only" narrows it to agent-skill files; firecrawl_search with categories: ["developer"] reaches the same index beside ordinary web results, returning the hits in the web group rather than as passages and offering no skills filter. For a legal or regulatory question, firecrawl_gov_search searches primary law and regulatory material from US federal, state, and local government sources: statutes, regulations, codes, court opinions, and other government publications; firecrawl_search with categories: ["gov"] reaches the same sources in the web group and cannot be combined with other categories. For a biomedical, life-science, clinical, or arXiv literature question, the firecrawl_research_* tools search the paper index, while categories: ["research"] on firecrawl_search filters ordinary web results to research-affiliated websites. Use the firecrawl_research_* tools to search academic and research literature, expand from anchor papers via the citation graph, and read full-text passages from a specific paper. Search and discovery tools are read-only and return ranked results. Billing: web, developer, and research search are billed per request; government search is free; Alexandria discovery (firecrawl_search with sources ["alexandria"] alone, and firecrawl_find_tools) is free; firecrawl_scrape is billed, as a page retrieval in url mode or per executed capability in alexandria mode (pass includeCosts to firecrawl_find_tools to see prices).`;
|
|
6009
5882
|
var SEARCH_PROFILE_TOOLS = /* @__PURE__ */ new Set([
|
|
6010
5883
|
"firecrawl_search",
|
|
6011
5884
|
"firecrawl_developer_search",
|
|
@@ -6514,7 +6387,7 @@ Scrape one URL and return its content, or execute catalogued Alexandria capabili
|
|
|
6514
6387
|
|
|
6515
6388
|
\`firecrawl_search\` with \`sources\` unset and \`firecrawl_find_tools\` can discover providers for the same fields across several pages; a matching Alexandria provider returns typed records in one call.
|
|
6516
6389
|
|
|
6517
|
-
Alexandria mode: \`alexandria\` selects catalogued capability execution and is mutually exclusive with \`url\`. Alexandria execution is billed
|
|
6390
|
+
Alexandria mode: \`alexandria\` selects catalogued capability execution and is mutually exclusive with \`url\`. Alexandria execution is billed per capability (pass includeCosts to firecrawl_find_tools to see prices if you need) and needs a team with Alexandria enabled.
|
|
6518
6391
|
`;
|
|
6519
6392
|
}
|
|
6520
6393
|
var SEARCH_SURFACE_FIND_TOOLS_DESCRIPTION = "Browse Alexandria data providers and workflows or read a selected contract. Alexandria covers " + ALEXANDRIA_CATALOGUE_VERTICALS + ": typed, sourced records through published contracts. Prefer normal firecrawl_search for a data task; it already returns matching providers. Use this tool when the contract you need was not returned in full, to browse a category when search found nothing, or before scraping the same fields from several pages. Discovery is free. Use query for semantic discovery or urls to find providers for a website. With no arguments, browse categories, then providers and tools. Contracts describe the inputs and outputs for execution through firecrawl_scrape. nextTool identifies further discovery or pagination. Discovery does not execute providers. Use firecrawl_search when you also need web results.";
|
|
@@ -6540,6 +6413,13 @@ ${ALEXANDRIA_SEARCH_INSTRUCTIONS}
|
|
|
6540
6413
|
Returns result groups in \`data\` and an operation \`id\`.
|
|
6541
6414
|
`,
|
|
6542
6415
|
outputSchema: searchOutputSchema,
|
|
6416
|
+
beforeValidate: (args2) => {
|
|
6417
|
+
if (args2 && typeof args2 === "object") {
|
|
6418
|
+
delete args2.objective;
|
|
6419
|
+
delete args2.clientModel;
|
|
6420
|
+
}
|
|
6421
|
+
return void 0;
|
|
6422
|
+
},
|
|
6543
6423
|
parameters: z13.object({ ...searchToolBaseFields }).strict().refine(searchDomainsAreExclusive, SEARCH_DOMAINS_CONFLICT_MESSAGE).refine(
|
|
6544
6424
|
searchQueryIsValid,
|
|
6545
6425
|
"A query is required. Use firecrawl_find_tools to browse the catalogue."
|
|
@@ -6547,8 +6427,6 @@ Returns result groups in \`data\` and an operation \`id\`.
|
|
|
6547
6427
|
execute: async (args2, { session, log, client: mcpClient }) => {
|
|
6548
6428
|
const {
|
|
6549
6429
|
query,
|
|
6550
|
-
objective,
|
|
6551
|
-
clientModel,
|
|
6552
6430
|
includeDomains,
|
|
6553
6431
|
excludeDomains,
|
|
6554
6432
|
limit,
|
|
@@ -6566,8 +6444,6 @@ Returns result groups in \`data\` and an operation \`id\`.
|
|
|
6566
6444
|
const searchBody = {
|
|
6567
6445
|
query: searchQuery,
|
|
6568
6446
|
...removeEmptyTopLevel({
|
|
6569
|
-
objective,
|
|
6570
|
-
clientModel,
|
|
6571
6447
|
limit,
|
|
6572
6448
|
includeDomains,
|
|
6573
6449
|
excludeDomains,
|