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/server.js
CHANGED
|
@@ -80,7 +80,7 @@ var alexandriaSessionFeedbackSchema = z.strictObject({
|
|
|
80
80
|
// src/server.ts
|
|
81
81
|
import FirecrawlApp from "firecrawl";
|
|
82
82
|
|
|
83
|
-
// node_modules/.pnpm/fastmcp@4.3.2_patch_hash=
|
|
83
|
+
// node_modules/.pnpm/fastmcp@4.3.2_patch_hash=37f9a424ae5b0b6202b2b16109a1ea88b69cdcda5407f13eda6654a56489ad70/node_modules/fastmcp/dist/chunk-LWU5CQGW.js
|
|
84
84
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
85
85
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
86
86
|
import {
|
|
@@ -884,6 +884,7 @@ ${error2 instanceof Error ? error2.stack : JSON.stringify(error2)}`
|
|
|
884
884
|
// Top-level Tool.title (MCP 2025-06-18). Clients such as Codex index this
|
|
885
885
|
// for tool search and do not read annotations.title.
|
|
886
886
|
...tool.annotations?.title && { title: tool.annotations.title },
|
|
887
|
+
...tool.icons && { icons: tool.icons },
|
|
887
888
|
description: tool.description,
|
|
888
889
|
inputSchema: tool.parameters ? strictJsonSchema(await toJsonSchema(tool.parameters)) : {
|
|
889
890
|
additionalProperties: false,
|
|
@@ -2059,7 +2060,7 @@ var FastMCP = class extends FastMCPEventEmitter {
|
|
|
2059
2060
|
}
|
|
2060
2061
|
};
|
|
2061
2062
|
|
|
2062
|
-
// node_modules/.pnpm/fastmcp@4.3.2_patch_hash=
|
|
2063
|
+
// node_modules/.pnpm/fastmcp@4.3.2_patch_hash=37f9a424ae5b0b6202b2b16109a1ea88b69cdcda5407f13eda6654a56489ad70/node_modules/fastmcp/dist/chunk-OJG4XYXA.js
|
|
2063
2064
|
import { z as z3 } from "zod";
|
|
2064
2065
|
import { createHmac as createHmac2, pbkdf2, randomBytes } from "crypto";
|
|
2065
2066
|
import { promisify } from "util";
|
|
@@ -2072,45 +2073,6 @@ import { randomUUID as randomUUID2 } from "crypto";
|
|
|
2072
2073
|
import path from "path";
|
|
2073
2074
|
import { z as z12 } from "zod";
|
|
2074
2075
|
|
|
2075
|
-
// src/agent-hints.ts
|
|
2076
|
-
var AGENT_HINTS_HEADERS = { "X-Firecrawl-Agent-Hints": "true" };
|
|
2077
|
-
function readAgentHints(value) {
|
|
2078
|
-
if (!value || typeof value !== "object") return void 0;
|
|
2079
|
-
const hints = value.agent_hints;
|
|
2080
|
-
return Array.isArray(hints) && hints.every((hint) => typeof hint === "string") ? hints : void 0;
|
|
2081
|
-
}
|
|
2082
|
-
function preserveAgentHints(data, envelope) {
|
|
2083
|
-
const hints = readAgentHints(envelope);
|
|
2084
|
-
if (!hints) return data;
|
|
2085
|
-
return data && typeof data === "object" && !Array.isArray(data) ? { ...data, agent_hints: hints } : { data, agent_hints: hints };
|
|
2086
|
-
}
|
|
2087
|
-
function agentHintsText(hints) {
|
|
2088
|
-
return `Firecrawl API agent_hints (response guidance, separate from page content):
|
|
2089
|
-
${JSON.stringify(hints, null, 2)}`;
|
|
2090
|
-
}
|
|
2091
|
-
function withAgentHints(result, response, separateText = false) {
|
|
2092
|
-
const hints = readAgentHints(response);
|
|
2093
|
-
if (!hints) return result;
|
|
2094
|
-
return {
|
|
2095
|
-
...result,
|
|
2096
|
-
content: separateText && hints.length ? [...result.content, { type: "text", text: agentHintsText(hints) }] : result.content,
|
|
2097
|
-
structuredContent: { ...result.structuredContent, agent_hints: hints }
|
|
2098
|
-
};
|
|
2099
|
-
}
|
|
2100
|
-
function readErrorAgentHints(error2) {
|
|
2101
|
-
const hints = readAgentHints(error2);
|
|
2102
|
-
if (hints) return hints;
|
|
2103
|
-
if (!error2 || typeof error2 !== "object") return void 0;
|
|
2104
|
-
const extras = error2.extras;
|
|
2105
|
-
const extrasHints = readAgentHints(extras);
|
|
2106
|
-
if (extrasHints) return extrasHints;
|
|
2107
|
-
const details = error2.details;
|
|
2108
|
-
const detailsHints = readAgentHints(details);
|
|
2109
|
-
if (detailsHints) return detailsHints;
|
|
2110
|
-
const response = error2.response;
|
|
2111
|
-
return readAgentHints(response?.data);
|
|
2112
|
-
}
|
|
2113
|
-
|
|
2114
2076
|
// src/tool-output.ts
|
|
2115
2077
|
import { z as z4 } from "zod";
|
|
2116
2078
|
function isRecord(value) {
|
|
@@ -2139,9 +2101,6 @@ var unknown = (description) => z4.unknown().optional().describe(description);
|
|
|
2139
2101
|
var success = bool("Whether the API call succeeded.");
|
|
2140
2102
|
var error = unknown("Error message or error object when the call did not succeed.");
|
|
2141
2103
|
var warning = str("Non-fatal warning about the result.");
|
|
2142
|
-
var agentHints = {
|
|
2143
|
-
agent_hints: z4.array(z4.string()).optional().describe("Optional response guidance from the Firecrawl API.")
|
|
2144
|
-
};
|
|
2145
2104
|
var alexandriaEnvelope = {
|
|
2146
2105
|
requestId: str("Identifier of this Alexandria execution."),
|
|
2147
2106
|
scrape_id: str("Identifier of the underlying scrape."),
|
|
@@ -2159,7 +2118,6 @@ var alexandriaEnvelope = {
|
|
|
2159
2118
|
feedbackTool: unknown("Pointer to the feedback tool for reporting how this result served the task.")
|
|
2160
2119
|
};
|
|
2161
2120
|
var scrapeOutputSchema = z4.object({
|
|
2162
|
-
...agentHints,
|
|
2163
2121
|
// URL mode: the scraped document, with the formats that were requested.
|
|
2164
2122
|
markdown: str("Page content as markdown."),
|
|
2165
2123
|
html: str("Processed HTML of the page."),
|
|
@@ -2191,7 +2149,6 @@ var scrapeOutputSchema = z4.object({
|
|
|
2191
2149
|
...alexandriaEnvelope
|
|
2192
2150
|
}).describe("A scraped document, or the Alexandria execution envelope when `alexandria` was passed.");
|
|
2193
2151
|
var mapOutputSchema = z4.object({
|
|
2194
|
-
...agentHints,
|
|
2195
2152
|
links: unknown("URLs discovered under the website."),
|
|
2196
2153
|
success,
|
|
2197
2154
|
error,
|
|
@@ -2199,7 +2156,6 @@ var mapOutputSchema = z4.object({
|
|
|
2199
2156
|
id: str("Identifier of the map run, for optional map feedback.")
|
|
2200
2157
|
}).describe("URLs indexed under the requested website.");
|
|
2201
2158
|
var searchOutputSchema = z4.object({
|
|
2202
|
-
...agentHints,
|
|
2203
2159
|
success,
|
|
2204
2160
|
data: unknown("Ranked results grouped by source, such as `web`, `news`, `images`, and `alexandria`."),
|
|
2205
2161
|
error,
|
|
@@ -2211,14 +2167,12 @@ var searchOutputSchema = z4.object({
|
|
|
2211
2167
|
feedbackTool: unknown("Pointer to the feedback tool for this search.")
|
|
2212
2168
|
}).describe("Ranked search results grouped by source.");
|
|
2213
2169
|
var findToolsOutputSchema = z4.object({
|
|
2214
|
-
...agentHints,
|
|
2215
2170
|
success,
|
|
2216
2171
|
data: unknown("Discovery page in `data.alexandria[0].data`, with `level`, `items`, `total`, and an optional `nextTool`."),
|
|
2217
2172
|
error,
|
|
2218
2173
|
...alexandriaEnvelope
|
|
2219
2174
|
}).describe("One page of the Alexandria catalogue: categories, providers, tools, or one contract.");
|
|
2220
2175
|
var feedbackOutputSchema = z4.object({
|
|
2221
|
-
...agentHints,
|
|
2222
2176
|
success,
|
|
2223
2177
|
error,
|
|
2224
2178
|
status: num("HTTP status when the submission was rejected."),
|
|
@@ -2237,7 +2191,6 @@ var feedbackOutputSchema = z4.object({
|
|
|
2237
2191
|
raw: str("Response body when it was not JSON.")
|
|
2238
2192
|
}).describe("Result of submitting feedback.");
|
|
2239
2193
|
var crawlOutputSchema = z4.object({
|
|
2240
|
-
...agentHints,
|
|
2241
2194
|
success,
|
|
2242
2195
|
error,
|
|
2243
2196
|
warning,
|
|
@@ -2252,7 +2205,6 @@ var crawlOutputSchema = z4.object({
|
|
|
2252
2205
|
data: unknown("Scraped documents collected by the crawl.")
|
|
2253
2206
|
}).describe("Crawl job state and the documents collected so far.");
|
|
2254
2207
|
var agentOutputSchema = z4.object({
|
|
2255
|
-
...agentHints,
|
|
2256
2208
|
success,
|
|
2257
2209
|
error,
|
|
2258
2210
|
id: str("Agent job identifier, for `firecrawl_agent_status`."),
|
|
@@ -2261,7 +2213,6 @@ var agentOutputSchema = z4.object({
|
|
|
2261
2213
|
threadTurn: num("Turn number of this job within its thread.")
|
|
2262
2214
|
}).describe("The queued research job. The result is read with `firecrawl_agent_status`.");
|
|
2263
2215
|
var agentStatusOutputSchema = z4.object({
|
|
2264
|
-
...agentHints,
|
|
2265
2216
|
success,
|
|
2266
2217
|
error,
|
|
2267
2218
|
id: str("Agent job identifier."),
|
|
@@ -2289,7 +2240,6 @@ var agentStatusOutputSchema = z4.object({
|
|
|
2289
2240
|
)
|
|
2290
2241
|
}).describe("Progress or final result of a research agent job.");
|
|
2291
2242
|
var interactOutputSchema = z4.object({
|
|
2292
|
-
...agentHints,
|
|
2293
2243
|
success,
|
|
2294
2244
|
error: unknown("Why the interaction or the session could not run."),
|
|
2295
2245
|
url: str("The URL the session was opened from, when opening failed."),
|
|
@@ -2304,14 +2254,12 @@ var interactOutputSchema = z4.object({
|
|
|
2304
2254
|
liveUrl: str("URL for viewing the live session.")
|
|
2305
2255
|
}).describe("Result of a browser interaction, with the session identifier to continue or stop it.");
|
|
2306
2256
|
var interactStopOutputSchema = z4.object({
|
|
2307
|
-
...agentHints,
|
|
2308
2257
|
success,
|
|
2309
2258
|
error,
|
|
2310
2259
|
message: str("Confirmation that the session was stopped."),
|
|
2311
2260
|
scrapeId: str("Session that was stopped.")
|
|
2312
2261
|
}).describe("Confirmation that the interact session was stopped.");
|
|
2313
2262
|
var parseOutputSchema = z4.object({
|
|
2314
|
-
...agentHints,
|
|
2315
2263
|
success,
|
|
2316
2264
|
error,
|
|
2317
2265
|
warning,
|
|
@@ -2339,39 +2287,33 @@ var deprecatedToolOutputSchema = z4.object({
|
|
|
2339
2287
|
docs_url: str("Documentation for the replacement.")
|
|
2340
2288
|
}).describe("A pointer to the replacement tool. This entry point is deprecated and always errors.");
|
|
2341
2289
|
var monitorOutputSchema = z4.object({
|
|
2342
|
-
...agentHints,
|
|
2343
2290
|
success,
|
|
2344
2291
|
error,
|
|
2345
2292
|
data: unknown("The monitor record: configuration, schedule, targets, and current state.")
|
|
2346
2293
|
}).describe("One monitor record.");
|
|
2347
2294
|
var monitorListOutputSchema = z4.object({
|
|
2348
|
-
...agentHints,
|
|
2349
2295
|
success,
|
|
2350
2296
|
error,
|
|
2351
2297
|
data: unknown("One page of monitor records."),
|
|
2352
2298
|
pagination: unknown("Pagination metadata for the listing.")
|
|
2353
2299
|
}).describe("One page of monitors for the authenticated account.");
|
|
2354
2300
|
var monitorDeleteOutputSchema = z4.object({
|
|
2355
|
-
...agentHints,
|
|
2356
2301
|
success,
|
|
2357
2302
|
error,
|
|
2358
2303
|
data: unknown("Deletion details, when the API returns any.")
|
|
2359
2304
|
}).describe("Deletion status for the monitor.");
|
|
2360
2305
|
var monitorRunOutputSchema = z4.object({
|
|
2361
|
-
...agentHints,
|
|
2362
2306
|
success,
|
|
2363
2307
|
error,
|
|
2364
2308
|
data: unknown("The queued check.")
|
|
2365
2309
|
}).describe("The check queued outside the monitor schedule.");
|
|
2366
2310
|
var monitorChecksOutputSchema = z4.object({
|
|
2367
|
-
...agentHints,
|
|
2368
2311
|
success,
|
|
2369
2312
|
error,
|
|
2370
2313
|
data: unknown("One page of check summaries."),
|
|
2371
2314
|
pagination: unknown("Pagination metadata for the listing.")
|
|
2372
2315
|
}).describe("One page of historical checks for the monitor.");
|
|
2373
2316
|
var monitorCheckOutputSchema = z4.object({
|
|
2374
|
-
...agentHints,
|
|
2375
2317
|
success,
|
|
2376
2318
|
error,
|
|
2377
2319
|
data: unknown("The check and its page-level results: each page reports `same`, `new`, `changed`, `removed`, or `error`, with diffs and any goal judgment."),
|
|
@@ -2390,25 +2332,20 @@ var paperSchema = z4.looseObject({
|
|
|
2390
2332
|
updateDate: str("Date the paper was last updated.")
|
|
2391
2333
|
});
|
|
2392
2334
|
var researchSearchOutputSchema = z4.object({
|
|
2393
|
-
...agentHints,
|
|
2394
2335
|
results: z4.array(paperSchema).describe("Ranked papers, in the order the text block lists them.")
|
|
2395
2336
|
}).describe("Ranked papers with canonical IDs, titles, authors, and abstracts.");
|
|
2396
2337
|
var researchPaperOutputSchema = z4.object({
|
|
2397
|
-
...agentHints,
|
|
2398
2338
|
paper: paperSchema.optional().describe("Canonical metadata for the requested paper, absent when it was not found.")
|
|
2399
2339
|
}).describe("Canonical metadata for one paper.");
|
|
2400
2340
|
var researchRelatedOutputSchema = z4.object({
|
|
2401
|
-
...agentHints,
|
|
2402
2341
|
results: z4.array(paperSchema).describe("Ranked citation-graph candidates."),
|
|
2403
2342
|
poolSize: z4.number().describe("Number of candidates evaluated before ranking."),
|
|
2404
2343
|
note: str("Note about how the candidates were produced.")
|
|
2405
2344
|
}).describe("Ranked citation-graph candidates and the size of the evaluated pool.");
|
|
2406
2345
|
var researchReadOutputSchema = z4.object({
|
|
2407
|
-
...agentHints,
|
|
2408
2346
|
passages: z4.array(z4.looseObject({ text: str("Passage text.") })).describe("In-body passages relevant to the question; empty when no full text is indexed.")
|
|
2409
2347
|
}).describe("Full-text passages from one paper.");
|
|
2410
2348
|
var developerSearchOutputSchema = z4.object({
|
|
2411
|
-
...agentHints,
|
|
2412
2349
|
results: z4.array(
|
|
2413
2350
|
z4.looseObject({
|
|
2414
2351
|
id: str("Stable result id, such as `issue:owner/repo#123` or `doc:<hash>`; its prefix gives the source type."),
|
|
@@ -2419,7 +2356,6 @@ var developerSearchOutputSchema = z4.object({
|
|
|
2419
2356
|
).describe("Ranked results, in the order the text block lists them.")
|
|
2420
2357
|
}).describe("Ranked developer-index results with their matched passages.");
|
|
2421
2358
|
var govSearchOutputSchema = z4.object({
|
|
2422
|
-
...agentHints,
|
|
2423
2359
|
results: z4.array(
|
|
2424
2360
|
z4.looseObject({
|
|
2425
2361
|
url: str("Source URL."),
|
|
@@ -2481,7 +2417,8 @@ var findToolsSchema = z5.object({
|
|
|
2481
2417
|
level: z5.enum(["categories", "providers", "groups", "tools"]).optional(),
|
|
2482
2418
|
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.'),
|
|
2483
2419
|
limit: z5.number().int().min(1).max(100).optional(),
|
|
2484
|
-
offset: z5.number().int().nonnegative().optional()
|
|
2420
|
+
offset: z5.number().int().nonnegative().optional(),
|
|
2421
|
+
includeCosts: z5.boolean().optional().describe("Include per-capability credit prices (creditsCost, perRecord) in tool results.")
|
|
2485
2422
|
}).strict();
|
|
2486
2423
|
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";
|
|
2487
2424
|
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.";
|
|
@@ -2493,7 +2430,7 @@ function findToolsOptions(args) {
|
|
|
2493
2430
|
if (level === "categories" && (args.query || args.providers?.length || args.categories?.length || args.groups?.length || args.capabilities?.length || args.urls?.length || args.expand !== void 0)) {
|
|
2494
2431
|
throw new Error("Category index accepts only level, limit and offset. Select a category to browse providers.");
|
|
2495
2432
|
}
|
|
2496
|
-
const { expand, ...selectors } = args;
|
|
2433
|
+
const { expand, includeCosts, ...selectors } = args;
|
|
2497
2434
|
return {
|
|
2498
2435
|
...selectors,
|
|
2499
2436
|
...expand !== void 0 ? { expand } : {},
|
|
@@ -2502,10 +2439,10 @@ function findToolsOptions(args) {
|
|
|
2502
2439
|
...args.expand === void 0 && level === "tools" && args.capabilities?.length ? { expand: ["options", "response", "examples"] } : {}
|
|
2503
2440
|
};
|
|
2504
2441
|
}
|
|
2505
|
-
function withFindToolsNavigation(envelope) {
|
|
2442
|
+
function withFindToolsNavigation(envelope, carry = {}) {
|
|
2506
2443
|
const page = envelope?.data?.alexandria?.[0]?.data;
|
|
2507
2444
|
if (!page || !Array.isArray(page.items)) return envelope;
|
|
2508
|
-
const link = (next) => next?.provider === "firecrawl" && next?.capability === "find-tools" && next.options ? { name: "firecrawl_find_tools", arguments: next.options } : void 0;
|
|
2445
|
+
const link = (next) => next?.provider === "firecrawl" && next?.capability === "find-tools" && next.options ? { name: "firecrawl_find_tools", arguments: { ...next.options, ...carry } } : void 0;
|
|
2509
2446
|
for (const item of page.items) {
|
|
2510
2447
|
if (page.level === "providers" && link(item.next)) {
|
|
2511
2448
|
const selectors = { ...item.next.options };
|
|
@@ -2519,6 +2456,49 @@ function withFindToolsNavigation(envelope) {
|
|
|
2519
2456
|
return envelope;
|
|
2520
2457
|
}
|
|
2521
2458
|
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.';
|
|
2459
|
+
var TOOL_PRICE_KEYS = ["creditsCost", "perRecord", "billing", "recordsPerUnit", "zeroDataRetentionCreditsCost"];
|
|
2460
|
+
function withoutToolPrice(tool) {
|
|
2461
|
+
if (!tool || typeof tool !== "object" || Array.isArray(tool)) return tool;
|
|
2462
|
+
const copy = { ...tool };
|
|
2463
|
+
for (const key of TOOL_PRICE_KEYS) delete copy[key];
|
|
2464
|
+
return copy;
|
|
2465
|
+
}
|
|
2466
|
+
function withoutDiscoveredToolPrices(body) {
|
|
2467
|
+
const tools = body?.data?.tools ?? body?.tools;
|
|
2468
|
+
if (!Array.isArray(tools)) return body;
|
|
2469
|
+
return body?.data?.tools ? { ...body, data: { ...body.data, tools: tools.map(withoutToolPrice) } } : { ...body, tools: tools.map(withoutToolPrice) };
|
|
2470
|
+
}
|
|
2471
|
+
function withoutPagePrices(page) {
|
|
2472
|
+
if (!page || typeof page !== "object") return page;
|
|
2473
|
+
return {
|
|
2474
|
+
...page,
|
|
2475
|
+
...Array.isArray(page.items) ? { items: page.items.map(withoutToolPrice) } : {},
|
|
2476
|
+
...Array.isArray(page.relatedTools) ? {
|
|
2477
|
+
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)
|
|
2478
|
+
} : {}
|
|
2479
|
+
};
|
|
2480
|
+
}
|
|
2481
|
+
function withoutResultPrices(body) {
|
|
2482
|
+
const results = body?.data?.alexandria;
|
|
2483
|
+
if (!Array.isArray(results)) return body;
|
|
2484
|
+
return {
|
|
2485
|
+
...body,
|
|
2486
|
+
data: {
|
|
2487
|
+
...body.data,
|
|
2488
|
+
alexandria: results.map((entry) => {
|
|
2489
|
+
const stripped = withoutToolPrice(entry);
|
|
2490
|
+
return entry?.provider === "firecrawl" && entry?.capability === "find-tools" && stripped && typeof stripped === "object" ? { ...stripped, data: withoutPagePrices(entry.data) } : stripped;
|
|
2491
|
+
})
|
|
2492
|
+
}
|
|
2493
|
+
};
|
|
2494
|
+
}
|
|
2495
|
+
function withoutFindToolsPrices(envelope) {
|
|
2496
|
+
const stripped = withoutResultPrices(envelope);
|
|
2497
|
+
if (!stripped?.data || typeof stripped.data !== "object") return stripped;
|
|
2498
|
+
const data = { ...stripped.data };
|
|
2499
|
+
delete data.creditsCost;
|
|
2500
|
+
return { ...stripped, data };
|
|
2501
|
+
}
|
|
2522
2502
|
|
|
2523
2503
|
// src/alexandria-output.ts
|
|
2524
2504
|
var INLINE_TOKEN_BUDGET = 2e4;
|
|
@@ -2668,7 +2648,7 @@ Returns ranked results with an ID, source type, URL, title, and the matched pass
|
|
|
2668
2648
|
const client = getClient(session);
|
|
2669
2649
|
const res = await client.http.get(`${BASE}?${params.toString()}`, originHeaders(requestOrigin(mcpClient, session)));
|
|
2670
2650
|
const results = res.data?.results ?? [];
|
|
2671
|
-
return
|
|
2651
|
+
return withStructured(fmtDeveloper(results), { results });
|
|
2672
2652
|
}
|
|
2673
2653
|
});
|
|
2674
2654
|
}
|
|
@@ -2717,11 +2697,7 @@ Returns ranked results with a position, title, URL, and matched snippet. Results
|
|
|
2717
2697
|
originHeaders(requestOrigin(mcpClient, session))
|
|
2718
2698
|
);
|
|
2719
2699
|
const results = res.data?.data?.web ?? [];
|
|
2720
|
-
return
|
|
2721
|
-
withStructured(fmtGov(results), { results }),
|
|
2722
|
-
res.data,
|
|
2723
|
-
true
|
|
2724
|
-
);
|
|
2700
|
+
return withStructured(fmtGov(results), { results });
|
|
2725
2701
|
}
|
|
2726
2702
|
});
|
|
2727
2703
|
}
|
|
@@ -2732,12 +2708,10 @@ import { z as z8 } from "zod";
|
|
|
2732
2708
|
// src/core-http-error.ts
|
|
2733
2709
|
var CoreHttpError = class extends Error {
|
|
2734
2710
|
status;
|
|
2735
|
-
|
|
2736
|
-
constructor(message, status, agentHints2) {
|
|
2711
|
+
constructor(message, status) {
|
|
2737
2712
|
super(message);
|
|
2738
2713
|
this.name = "CoreHttpError";
|
|
2739
2714
|
this.status = status;
|
|
2740
|
-
if (agentHints2 !== void 0) this.agent_hints = agentHints2;
|
|
2741
2715
|
}
|
|
2742
2716
|
};
|
|
2743
2717
|
|
|
@@ -2760,7 +2734,6 @@ async function monitorRequest(api, session, origin, path2, init = {}) {
|
|
|
2760
2734
|
}
|
|
2761
2735
|
const headers = {
|
|
2762
2736
|
...originHeaders(origin),
|
|
2763
|
-
...AGENT_HINTS_HEADERS,
|
|
2764
2737
|
...extraHeaders
|
|
2765
2738
|
};
|
|
2766
2739
|
if (apiKey) headers.Authorization = `Bearer ${apiKey}`;
|
|
@@ -2773,13 +2746,10 @@ async function monitorRequest(api, session, origin, path2, init = {}) {
|
|
|
2773
2746
|
const payload = await response.json().catch(() => ({}));
|
|
2774
2747
|
if (!response.ok || payload?.success === false) {
|
|
2775
2748
|
const message = payload?.error || `HTTP ${response.status}: ${response.statusText || "Request failed"}`;
|
|
2776
|
-
throw new CoreHttpError(message, response.status
|
|
2749
|
+
throw new CoreHttpError(message, response.status);
|
|
2777
2750
|
}
|
|
2778
2751
|
return payload;
|
|
2779
2752
|
}
|
|
2780
|
-
function monitorResult(data) {
|
|
2781
|
-
return withAgentHints(structuredText(data), data);
|
|
2782
|
-
}
|
|
2783
2753
|
var pageStatusSchema = z8.enum(["same", "new", "changed", "removed", "error"]);
|
|
2784
2754
|
var checkStatusSchema = z8.enum([
|
|
2785
2755
|
"queued",
|
|
@@ -2905,7 +2875,7 @@ In the simple form, a \`goal\` is required. If \`queries\` contains one or more
|
|
|
2905
2875
|
body
|
|
2906
2876
|
}
|
|
2907
2877
|
);
|
|
2908
|
-
return
|
|
2878
|
+
return structuredText(res);
|
|
2909
2879
|
}
|
|
2910
2880
|
});
|
|
2911
2881
|
server.addTool({
|
|
@@ -2938,7 +2908,7 @@ List monitors for the authenticated account with optional pagination controls. R
|
|
|
2938
2908
|
query: { limit, offset }
|
|
2939
2909
|
}
|
|
2940
2910
|
);
|
|
2941
|
-
return
|
|
2911
|
+
return structuredText(res);
|
|
2942
2912
|
}
|
|
2943
2913
|
});
|
|
2944
2914
|
server.addTool({
|
|
@@ -2965,7 +2935,7 @@ Retrieve one monitor by ID, including its configuration and current state. This
|
|
|
2965
2935
|
requestOrigin(mcpClient, session),
|
|
2966
2936
|
`/monitor/${encodeURIComponent(id)}`
|
|
2967
2937
|
);
|
|
2968
|
-
return
|
|
2938
|
+
return structuredText(res);
|
|
2969
2939
|
}
|
|
2970
2940
|
});
|
|
2971
2941
|
server.addTool({
|
|
@@ -2998,7 +2968,7 @@ Returns the updated monitor.
|
|
|
2998
2968
|
`/monitor/${encodeURIComponent(id)}`,
|
|
2999
2969
|
{ method: "PATCH", body }
|
|
3000
2970
|
);
|
|
3001
|
-
return
|
|
2971
|
+
return structuredText(res);
|
|
3002
2972
|
}
|
|
3003
2973
|
});
|
|
3004
2974
|
server.addTool({
|
|
@@ -3027,7 +2997,7 @@ Permanently delete a monitor by ID and stop its future schedule. This operation
|
|
|
3027
2997
|
`/monitor/${encodeURIComponent(id)}`,
|
|
3028
2998
|
{ method: "DELETE" }
|
|
3029
2999
|
);
|
|
3030
|
-
return
|
|
3000
|
+
return structuredText(res);
|
|
3031
3001
|
}
|
|
3032
3002
|
});
|
|
3033
3003
|
server.addTool({
|
|
@@ -3055,7 +3025,7 @@ Queue an immediate check for a monitor outside its normal schedule. This starts
|
|
|
3055
3025
|
`/monitor/${encodeURIComponent(id)}/run`,
|
|
3056
3026
|
{ method: "POST" }
|
|
3057
3027
|
);
|
|
3058
|
-
return
|
|
3028
|
+
return structuredText(res);
|
|
3059
3029
|
}
|
|
3060
3030
|
});
|
|
3061
3031
|
server.addTool({
|
|
@@ -3088,7 +3058,7 @@ List historical checks for a monitor, optionally filtered by status and bounded
|
|
|
3088
3058
|
`/monitor/${encodeURIComponent(id)}/checks`,
|
|
3089
3059
|
{ query: { limit, offset, status } }
|
|
3090
3060
|
);
|
|
3091
|
-
return
|
|
3061
|
+
return structuredText(res);
|
|
3092
3062
|
}
|
|
3093
3063
|
});
|
|
3094
3064
|
server.addTool({
|
|
@@ -3124,7 +3094,7 @@ Markdown tracking returns a unified text diff, JSON tracking returns field paths
|
|
|
3124
3094
|
`/monitor/${encodeURIComponent(id)}/checks/${encodeURIComponent(checkId)}`,
|
|
3125
3095
|
{ query: { limit, skip, status: pageStatus } }
|
|
3126
3096
|
);
|
|
3127
|
-
return
|
|
3097
|
+
return structuredText(res);
|
|
3128
3098
|
}
|
|
3129
3099
|
});
|
|
3130
3100
|
}
|
|
@@ -3132,9 +3102,6 @@ Markdown tracking returns a unified text diff, JSON tracking returns field paths
|
|
|
3132
3102
|
// src/research.ts
|
|
3133
3103
|
import { z as z9 } from "zod";
|
|
3134
3104
|
var BASE3 = "/v2/search/research";
|
|
3135
|
-
function researchHeaders(origin) {
|
|
3136
|
-
return { ...originHeaders(origin), ...AGENT_HINTS_HEADERS };
|
|
3137
|
-
}
|
|
3138
3105
|
function appendParam(params, key, value) {
|
|
3139
3106
|
if (value == null) return;
|
|
3140
3107
|
if (Array.isArray(value)) {
|
|
@@ -3279,10 +3246,10 @@ Returns ranked papers with canonical IDs, titles, authors, and abstracts.
|
|
|
3279
3246
|
const client = getClient(session);
|
|
3280
3247
|
const res = await client.http.get(
|
|
3281
3248
|
withQuery(`${BASE3}/papers`, params),
|
|
3282
|
-
|
|
3249
|
+
originHeaders(requestOrigin(mcpClient, session))
|
|
3283
3250
|
);
|
|
3284
3251
|
const results = res.data?.results ?? [];
|
|
3285
|
-
return
|
|
3252
|
+
return withStructured(fmtHits(results), { results });
|
|
3286
3253
|
}
|
|
3287
3254
|
});
|
|
3288
3255
|
server.addTool({
|
|
@@ -3310,13 +3277,13 @@ Retrieve canonical metadata for one paper ID, such as an arXiv, PMC, PMID, or DO
|
|
|
3310
3277
|
const client = getClient(session);
|
|
3311
3278
|
const res = await client.http.get(
|
|
3312
3279
|
`${BASE3}/papers/${encodeURIComponent(paperId)}`,
|
|
3313
|
-
|
|
3280
|
+
originHeaders(requestOrigin(mcpClient, session))
|
|
3314
3281
|
);
|
|
3315
3282
|
const paper = res.data?.paper;
|
|
3316
|
-
return
|
|
3283
|
+
return withStructured(
|
|
3317
3284
|
fmtPaperMetadata(paper),
|
|
3318
3285
|
paper ? { paper } : {}
|
|
3319
|
-
)
|
|
3286
|
+
);
|
|
3320
3287
|
}
|
|
3321
3288
|
});
|
|
3322
3289
|
server.addTool({
|
|
@@ -3358,17 +3325,17 @@ Returns ranked candidates and the evaluated pool size.
|
|
|
3358
3325
|
`${BASE3}/papers/${encodeURIComponent(primary)}/similar`,
|
|
3359
3326
|
params
|
|
3360
3327
|
),
|
|
3361
|
-
|
|
3328
|
+
originHeaders(requestOrigin(mcpClient, session))
|
|
3362
3329
|
);
|
|
3363
3330
|
const results = res.data?.results ?? [];
|
|
3364
3331
|
const poolSize = res.data?.poolSize ?? 0;
|
|
3365
3332
|
const note = res.data?.note ? `
|
|
3366
3333
|
note: ${res.data.note}` : "";
|
|
3367
|
-
return
|
|
3334
|
+
return withStructured(
|
|
3368
3335
|
`${fmtHits(results)}
|
|
3369
3336
|
(poolSize=${poolSize})${note}`,
|
|
3370
3337
|
{ results, poolSize, ...res.data?.note ? { note: res.data.note } : {} }
|
|
3371
|
-
)
|
|
3338
|
+
);
|
|
3372
3339
|
}
|
|
3373
3340
|
});
|
|
3374
3341
|
server.addTool({
|
|
@@ -3403,13 +3370,13 @@ Returns matching passages or a notice when full text is unavailable.
|
|
|
3403
3370
|
const client = getClient(session);
|
|
3404
3371
|
const res = await client.http.get(
|
|
3405
3372
|
withQuery(`${BASE3}/papers/${encodeURIComponent(paperId)}`, params),
|
|
3406
|
-
|
|
3373
|
+
originHeaders(requestOrigin(mcpClient, session))
|
|
3407
3374
|
);
|
|
3408
3375
|
const passages = res.data?.passages ?? [];
|
|
3409
|
-
return
|
|
3376
|
+
return withStructured(
|
|
3410
3377
|
passages.length ? passages.map((p) => p.text).join("\n---\n") : "(no full-text passages available for this paper)",
|
|
3411
3378
|
{ passages }
|
|
3412
|
-
)
|
|
3379
|
+
);
|
|
3413
3380
|
}
|
|
3414
3381
|
});
|
|
3415
3382
|
server.addTool({
|
|
@@ -3635,20 +3602,6 @@ async function runWithCredentialRecovery(run, requestId, session) {
|
|
|
3635
3602
|
return await run();
|
|
3636
3603
|
} catch (error2) {
|
|
3637
3604
|
if (session?.authType !== "api-key" || !isCoreCredentialRejection(error2, session)) {
|
|
3638
|
-
const hints = readErrorAgentHints(error2);
|
|
3639
|
-
if (hints) {
|
|
3640
|
-
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
3641
|
-
throw new UserError(
|
|
3642
|
-
hints.length ? `${message}
|
|
3643
|
-
|
|
3644
|
-
${agentHintsText(hints)}` : message,
|
|
3645
|
-
{
|
|
3646
|
-
...error2 instanceof UserError ? error2.extras : {},
|
|
3647
|
-
error: message,
|
|
3648
|
-
agent_hints: hints
|
|
3649
|
-
}
|
|
3650
|
-
);
|
|
3651
|
-
}
|
|
3652
3605
|
throw error2;
|
|
3653
3606
|
}
|
|
3654
3607
|
const payload = recoveryPayload("CREDENTIAL_INVALID", requestId);
|
|
@@ -3707,8 +3660,6 @@ var searchDomainSchema = z11.string().trim().toLowerCase().min(1).max(253).regex
|
|
|
3707
3660
|
var searchToolBaseFields = {
|
|
3708
3661
|
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."),
|
|
3709
3662
|
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."),
|
|
3710
|
-
objective: z11.string().trim().min(1).max(5e3).optional().describe("Optional broader goal for this search, if known. Avoid sensitive information."),
|
|
3711
|
-
clientModel: z11.string().trim().min(1).max(128).optional().describe("Optional model identifier, if known."),
|
|
3712
3663
|
domainTools: z11.boolean().optional().describe(
|
|
3713
3664
|
"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."
|
|
3714
3665
|
),
|
|
@@ -3774,7 +3725,7 @@ function termsRequiredAction(body) {
|
|
|
3774
3725
|
url: action.url
|
|
3775
3726
|
};
|
|
3776
3727
|
}
|
|
3777
|
-
function termsRequiredError(action, context
|
|
3728
|
+
function termsRequiredError(action, context) {
|
|
3778
3729
|
const requestId = context.requestId;
|
|
3779
3730
|
const retryIdentity = requestId ? ` and requestId ${requestId}` : "";
|
|
3780
3731
|
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.`;
|
|
@@ -3789,7 +3740,6 @@ Do not retry until acceptance is confirmed.`,
|
|
|
3789
3740
|
code: TERMS_REQUIRED_CODE,
|
|
3790
3741
|
status: 403,
|
|
3791
3742
|
message,
|
|
3792
|
-
...hints ? { agent_hints: hints } : {},
|
|
3793
3743
|
...requestId ? { requestId } : {},
|
|
3794
3744
|
requiresAction: action,
|
|
3795
3745
|
nextTool: {
|
|
@@ -3820,8 +3770,7 @@ Do not retry until acceptance is confirmed.`,
|
|
|
3820
3770
|
function throwIfTermsRequired(error2, context) {
|
|
3821
3771
|
const source = error2;
|
|
3822
3772
|
const action = termsRequiredAction(source?.response?.data ?? source?.details);
|
|
3823
|
-
if (action)
|
|
3824
|
-
throw termsRequiredError(action, context, readErrorAgentHints(error2));
|
|
3773
|
+
if (action) throw termsRequiredError(action, context);
|
|
3825
3774
|
}
|
|
3826
3775
|
async function relayTermsRequired(run, context) {
|
|
3827
3776
|
try {
|
|
@@ -3839,7 +3788,6 @@ async function relayExchangeError(run, context) {
|
|
|
3839
3788
|
const response = error2?.response;
|
|
3840
3789
|
if (!response || response.status === 401) throw error2;
|
|
3841
3790
|
const data = response.data;
|
|
3842
|
-
const hints = readErrorAgentHints(error2);
|
|
3843
3791
|
const message = typeof data?.error === "string" ? data.error : `Alexandria request failed (HTTP ${response.status})`;
|
|
3844
3792
|
const disabledProvider = response.status === 403 ? context.providers?.find((provider) => message === `Access to ${provider} is disabled for this organization.`) : void 0;
|
|
3845
3793
|
if (disabledProvider) {
|
|
@@ -3849,7 +3797,6 @@ async function relayExchangeError(run, context) {
|
|
|
3849
3797
|
code: typeof data?.code === "string" ? data.code : "exchange_error",
|
|
3850
3798
|
status: 403,
|
|
3851
3799
|
message,
|
|
3852
|
-
...hints ? { agent_hints: hints } : {},
|
|
3853
3800
|
nextTool: {
|
|
3854
3801
|
name: "firecrawl_scrape",
|
|
3855
3802
|
arguments: {
|
|
@@ -3863,7 +3810,6 @@ async function relayExchangeError(run, context) {
|
|
|
3863
3810
|
code: typeof data?.code === "string" ? data.code : "exchange_error",
|
|
3864
3811
|
status: response.status,
|
|
3865
3812
|
message,
|
|
3866
|
-
...hints ? { agent_hints: hints } : {},
|
|
3867
3813
|
...typeof data?.chargeId === "string" ? { chargeId: data.chargeId } : {}
|
|
3868
3814
|
});
|
|
3869
3815
|
}
|
|
@@ -3910,10 +3856,6 @@ function copySession(session) {
|
|
|
3910
3856
|
Object.getOwnPropertyDescriptors(session ?? {})
|
|
3911
3857
|
);
|
|
3912
3858
|
}
|
|
3913
|
-
function resultAgentHints(result) {
|
|
3914
|
-
return result && typeof result === "object" ? readAgentHints(result.structuredContent) : void 0;
|
|
3915
|
-
}
|
|
3916
|
-
var warnedMissingAgentHintsInterceptor = false;
|
|
3917
3859
|
var ConsoleLogger = class {
|
|
3918
3860
|
constructor(shouldLog) {
|
|
3919
3861
|
this.shouldLog = shouldLog;
|
|
@@ -4065,20 +4007,10 @@ function createFirecrawlMcpServer(options = {}) {
|
|
|
4065
4007
|
requestId,
|
|
4066
4008
|
session
|
|
4067
4009
|
);
|
|
4068
|
-
hooks.onToolResult?.({
|
|
4069
|
-
...call,
|
|
4070
|
-
status: "success",
|
|
4071
|
-
result,
|
|
4072
|
-
agentHints: resultAgentHints(result)
|
|
4073
|
-
});
|
|
4010
|
+
hooks.onToolResult?.({ ...call, status: "success", result });
|
|
4074
4011
|
return result;
|
|
4075
4012
|
} catch (error2) {
|
|
4076
|
-
hooks.onToolResult?.({
|
|
4077
|
-
...call,
|
|
4078
|
-
status: "error",
|
|
4079
|
-
error: error2,
|
|
4080
|
-
agentHints: readErrorAgentHints(error2)
|
|
4081
|
-
});
|
|
4013
|
+
hooks.onToolResult?.({ ...call, status: "error", error: error2 });
|
|
4082
4014
|
throw error2;
|
|
4083
4015
|
}
|
|
4084
4016
|
}
|
|
@@ -4109,44 +4041,7 @@ function createFirecrawlMcpServer(options = {}) {
|
|
|
4109
4041
|
if (apiKey) {
|
|
4110
4042
|
clientConfig.apiKey = apiKey;
|
|
4111
4043
|
}
|
|
4112
|
-
|
|
4113
|
-
const axiosInstance = client.http?.instance;
|
|
4114
|
-
if (axiosInstance?.interceptors?.request?.use) {
|
|
4115
|
-
axiosInstance.interceptors.request.use((request) => {
|
|
4116
|
-
if (typeof request.headers?.set === "function") {
|
|
4117
|
-
request.headers.set("X-Firecrawl-Agent-Hints", "true");
|
|
4118
|
-
} else {
|
|
4119
|
-
request.headers = { ...request.headers ?? {}, ...AGENT_HINTS_HEADERS };
|
|
4120
|
-
}
|
|
4121
|
-
return request;
|
|
4122
|
-
});
|
|
4123
|
-
} else if (!warnedMissingAgentHintsInterceptor) {
|
|
4124
|
-
warnedMissingAgentHintsInterceptor = true;
|
|
4125
|
-
console.warn(
|
|
4126
|
-
"[firecrawl-mcp] SDK request interceptor unavailable; API agent hints may be absent."
|
|
4127
|
-
);
|
|
4128
|
-
}
|
|
4129
|
-
return client;
|
|
4130
|
-
}
|
|
4131
|
-
async function sdkResultWithAgentHints(client, execute) {
|
|
4132
|
-
const responseInterceptors = client.http?.instance?.interceptors?.response;
|
|
4133
|
-
if (!responseInterceptors?.use) return execute();
|
|
4134
|
-
let hints;
|
|
4135
|
-
const interceptor = responseInterceptors.use((response) => {
|
|
4136
|
-
hints = readAgentHints(response?.data) ?? hints;
|
|
4137
|
-
return response;
|
|
4138
|
-
});
|
|
4139
|
-
try {
|
|
4140
|
-
const result = await execute();
|
|
4141
|
-
return preserveAgentHints(result, { agent_hints: hints });
|
|
4142
|
-
} catch (error2) {
|
|
4143
|
-
if (hints && error2 && typeof error2 === "object" && !readErrorAgentHints(error2)) {
|
|
4144
|
-
error2.agent_hints = hints;
|
|
4145
|
-
}
|
|
4146
|
-
throw error2;
|
|
4147
|
-
} finally {
|
|
4148
|
-
responseInterceptors.eject?.(interceptor);
|
|
4149
|
-
}
|
|
4044
|
+
return new FirecrawlApp(clientConfig);
|
|
4150
4045
|
}
|
|
4151
4046
|
const SAFE_MODE = config.safeMode;
|
|
4152
4047
|
function getClient(session) {
|
|
@@ -4499,7 +4394,6 @@ function createFirecrawlMcpServer(options = {}) {
|
|
|
4499
4394
|
const response = await fetch(`${resolveApiBaseUrl()}${pathName}`, {
|
|
4500
4395
|
method: "POST",
|
|
4501
4396
|
headers: {
|
|
4502
|
-
...AGENT_HINTS_HEADERS,
|
|
4503
4397
|
"Content-Type": "application/json",
|
|
4504
4398
|
...extraHeaders,
|
|
4505
4399
|
Authorization: `Bearer ${apiKey}`,
|
|
@@ -4517,8 +4411,7 @@ function createFirecrawlMcpServer(options = {}) {
|
|
|
4517
4411
|
if (!response.ok) {
|
|
4518
4412
|
throw new CoreHttpError(
|
|
4519
4413
|
parsed?.error || parsed?.message || `Firecrawl request failed (HTTP ${response.status})`,
|
|
4520
|
-
response.status
|
|
4521
|
-
readAgentHints(parsed)
|
|
4414
|
+
response.status
|
|
4522
4415
|
);
|
|
4523
4416
|
}
|
|
4524
4417
|
return parsed;
|
|
@@ -4600,7 +4493,6 @@ function createFirecrawlMcpServer(options = {}) {
|
|
|
4600
4493
|
session,
|
|
4601
4494
|
origin
|
|
4602
4495
|
);
|
|
4603
|
-
const uploadHints = readAgentHints(uploadJson);
|
|
4604
4496
|
const upload = parseApiData(uploadJson);
|
|
4605
4497
|
if (!upload?.uploadUrl || !upload?.uploadRef) {
|
|
4606
4498
|
throw new Error(
|
|
@@ -4611,7 +4503,6 @@ function createFirecrawlMcpServer(options = {}) {
|
|
|
4611
4503
|
const uploadForCommand = { ...upload, headers: uploadHeaders };
|
|
4612
4504
|
return asText({
|
|
4613
4505
|
success: true,
|
|
4614
|
-
...uploadHints ? { agent_hints: uploadHints } : {},
|
|
4615
4506
|
mode: "hosted-upload-ref-awaiting-upload",
|
|
4616
4507
|
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.",
|
|
4617
4508
|
upload: {
|
|
@@ -4710,20 +4601,17 @@ Alexandria mode, on an authenticated session with Alexandria access: \`alexandri
|
|
|
4710
4601
|
},
|
|
4711
4602
|
session
|
|
4712
4603
|
);
|
|
4713
|
-
return structuredText(
|
|
4604
|
+
return structuredText(withoutDiscoveredToolPrices(json?.data ?? json));
|
|
4714
4605
|
}
|
|
4715
4606
|
const client = getClient(session);
|
|
4716
4607
|
const res = await relayTermsRequired(
|
|
4717
|
-
() =>
|
|
4718
|
-
|
|
4719
|
-
|
|
4720
|
-
|
|
4721
|
-
origin
|
|
4722
|
-
})
|
|
4723
|
-
),
|
|
4608
|
+
() => client.scrape(String(url), {
|
|
4609
|
+
...cleaned,
|
|
4610
|
+
origin
|
|
4611
|
+
}),
|
|
4724
4612
|
{ tool: "firecrawl_scrape" }
|
|
4725
4613
|
);
|
|
4726
|
-
return structuredText(res);
|
|
4614
|
+
return structuredText(withoutDiscoveredToolPrices(res));
|
|
4727
4615
|
}
|
|
4728
4616
|
};
|
|
4729
4617
|
server.addTool({
|
|
@@ -4760,13 +4648,10 @@ Returns matching URLs rather than page bodies. Retrieve one page with \`firecraw
|
|
|
4760
4648
|
const client = getClient(session);
|
|
4761
4649
|
const cleaned = removeEmptyTopLevel(options2);
|
|
4762
4650
|
log.info("Mapping URL", { url: String(url) });
|
|
4763
|
-
const res = await
|
|
4764
|
-
|
|
4765
|
-
|
|
4766
|
-
|
|
4767
|
-
origin: requestOrigin(mcpClient, session)
|
|
4768
|
-
})
|
|
4769
|
-
);
|
|
4651
|
+
const res = await client.map(String(url), {
|
|
4652
|
+
...cleaned,
|
|
4653
|
+
origin: requestOrigin(mcpClient, session)
|
|
4654
|
+
});
|
|
4770
4655
|
return structuredText(res);
|
|
4771
4656
|
}
|
|
4772
4657
|
});
|
|
@@ -4829,7 +4714,7 @@ For a programming question, add \`categories: ["developer"]\`; its hits return i
|
|
|
4829
4714
|
const json = await keylessPost("/v2/search", searchBody, session);
|
|
4830
4715
|
const keylessResponse = { ...json ?? {} };
|
|
4831
4716
|
delete keylessResponse.id;
|
|
4832
|
-
return structuredCompact(keylessResponse);
|
|
4717
|
+
return structuredCompact(withoutDiscoveredToolPrices(keylessResponse));
|
|
4833
4718
|
}
|
|
4834
4719
|
const client = getClient(session);
|
|
4835
4720
|
const postSearch = () => postSearchWithFallback(
|
|
@@ -4839,10 +4724,10 @@ For a programming question, add \`categories: ["developer"]\`; its hits return i
|
|
|
4839
4724
|
);
|
|
4840
4725
|
const context = { tool: "firecrawl_search" };
|
|
4841
4726
|
const httpRes = exchangeSource ? await relayExchangeError(postSearch, context) : await relayTermsRequired(postSearch, context);
|
|
4842
|
-
return structuredCompact(httpRes?.data ?? {});
|
|
4727
|
+
return structuredCompact(withoutDiscoveredToolPrices(httpRes?.data ?? {}));
|
|
4843
4728
|
}
|
|
4844
4729
|
});
|
|
4845
|
-
async function executeExchangeCalls(session, alexandria, suppliedRequestId, timeout, origin = requestOrigin(void 0, session)) {
|
|
4730
|
+
async function executeExchangeCalls(session, alexandria, suppliedRequestId, timeout, origin = requestOrigin(void 0, session), includeCosts = false) {
|
|
4846
4731
|
assertExchangeCredential2(session);
|
|
4847
4732
|
const client = getClient(session);
|
|
4848
4733
|
const requestId = suppliedRequestId ?? randomUUID2();
|
|
@@ -4864,7 +4749,7 @@ For a programming question, add \`categories: ["developer"]\`; its hits return i
|
|
|
4864
4749
|
);
|
|
4865
4750
|
const calls = Array.isArray(alexandria) ? alexandria : [alexandria];
|
|
4866
4751
|
return alexandriaOutput(
|
|
4867
|
-
{ ...response?.data ?? {}, requestId },
|
|
4752
|
+
{ ...includeCosts ? response?.data ?? {} : withoutResultPrices(response?.data ?? {}), requestId },
|
|
4868
4753
|
calls,
|
|
4869
4754
|
async (body, id) => {
|
|
4870
4755
|
const result = await client.http.post(
|
|
@@ -4905,6 +4790,7 @@ For a programming question, add \`categories: ["developer"]\`; its hits return i
|
|
|
4905
4790
|
} catch (error2) {
|
|
4906
4791
|
throw new UserError2(error2 instanceof Error ? error2.message : String(error2));
|
|
4907
4792
|
}
|
|
4793
|
+
const carry = args.includeCosts ? { includeCosts: true } : {};
|
|
4908
4794
|
if (options2.level === "categories") {
|
|
4909
4795
|
assertExchangeCredential2(session);
|
|
4910
4796
|
const response = await relayExchangeError(
|
|
@@ -4922,11 +4808,12 @@ For a programming question, add \`categories: ["developer"]\`; its hits return i
|
|
|
4922
4808
|
next: { provider: "firecrawl", capability: "find-tools", options: { categories: [row.cohort], level: "providers", limit: options2.limit } }
|
|
4923
4809
|
}));
|
|
4924
4810
|
const page = { level: "categories", items, total: rows.length };
|
|
4925
|
-
if (offset + options2.limit < rows.length) page.nextTool = { name: "firecrawl_find_tools", arguments: { level: "categories", limit: options2.limit, offset: offset + options2.limit } };
|
|
4926
|
-
return structuredCompact(withAlexandriaFeedbackHint(withFindToolsNavigation({ success: true, data: {
|
|
4811
|
+
if (offset + options2.limit < rows.length) page.nextTool = { name: "firecrawl_find_tools", arguments: { level: "categories", limit: options2.limit, offset: offset + options2.limit, ...carry } };
|
|
4812
|
+
return structuredCompact(withAlexandriaFeedbackHint(withFindToolsNavigation({ success: true, data: { alexandria: [{ provider: "firecrawl", capability: "find-tools", data: page }] } }, carry), alexandriaFeedbackAvailable()));
|
|
4927
4813
|
}
|
|
4928
|
-
const result = await executeExchangeCalls(session, { provider: "firecrawl", capability: "find-tools", options: options2 }, void 0, void 0, origin);
|
|
4929
|
-
|
|
4814
|
+
const result = await executeExchangeCalls(session, { provider: "firecrawl", capability: "find-tools", options: options2 }, void 0, void 0, origin, carry.includeCosts);
|
|
4815
|
+
const envelope = JSON.parse(result);
|
|
4816
|
+
return structuredCompact(withFindToolsNavigation(carry.includeCosts ? envelope : withoutFindToolsPrices(envelope), carry));
|
|
4930
4817
|
}
|
|
4931
4818
|
};
|
|
4932
4819
|
server.addTool(findToolsTool);
|
|
@@ -4946,7 +4833,6 @@ For a programming question, add \`categories: ["developer"]\`; its hits return i
|
|
|
4946
4833
|
const origin = originOverride ?? (typeof body.origin === "string" && body.origin.length > 0 ? body.origin : requestOrigin(void 0, session));
|
|
4947
4834
|
await hooks.beforeKeylessRequest?.(session, origin);
|
|
4948
4835
|
const headers = {
|
|
4949
|
-
...AGENT_HINTS_HEADERS,
|
|
4950
4836
|
...originHeaders(origin),
|
|
4951
4837
|
"Content-Type": "application/json",
|
|
4952
4838
|
...resolveOutbound(session).headers
|
|
@@ -4964,14 +4850,11 @@ For a programming question, add \`categories: ["developer"]\`; its hits return i
|
|
|
4964
4850
|
retryAfterSeconds: Number.isFinite(json?.retry_after_seconds) && json.retry_after_seconds > 0 ? json.retry_after_seconds : void 0,
|
|
4965
4851
|
signupUrl: keylessSignupUrlFrom(json?.signup_url)
|
|
4966
4852
|
});
|
|
4967
|
-
const hints = readAgentHints(json);
|
|
4968
|
-
if (hints) payload.agent_hints = hints;
|
|
4969
4853
|
throw new UserError2(String(payload.message), payload);
|
|
4970
4854
|
}
|
|
4971
4855
|
throw new CoreHttpError(
|
|
4972
4856
|
json?.error || `Firecrawl request failed (HTTP ${response.status})`,
|
|
4973
|
-
response.status
|
|
4974
|
-
readAgentHints(json)
|
|
4857
|
+
response.status
|
|
4975
4858
|
);
|
|
4976
4859
|
}
|
|
4977
4860
|
return json;
|
|
@@ -4992,8 +4875,7 @@ For a programming question, add \`categories: ["developer"]\`; its hits return i
|
|
|
4992
4875
|
creditsUsed: body.creditsUsed,
|
|
4993
4876
|
expiresAt: body.expiresAt,
|
|
4994
4877
|
next: body.next ?? null,
|
|
4995
|
-
data: initialDocs
|
|
4996
|
-
...readAgentHints(body) ? { agent_hints: readAgentHints(body) } : {}
|
|
4878
|
+
data: initialDocs
|
|
4997
4879
|
};
|
|
4998
4880
|
}
|
|
4999
4881
|
const docs = initialDocs.slice();
|
|
@@ -5017,8 +4899,7 @@ For a programming question, add \`categories: ["developer"]\`; its hits return i
|
|
|
5017
4899
|
creditsUsed: body.creditsUsed,
|
|
5018
4900
|
expiresAt: body.expiresAt,
|
|
5019
4901
|
next: null,
|
|
5020
|
-
data: docs
|
|
5021
|
-
...readAgentHints(body) ? { agent_hints: readAgentHints(body) } : {}
|
|
4902
|
+
data: docs
|
|
5022
4903
|
};
|
|
5023
4904
|
}
|
|
5024
4905
|
async function waitForCrawlCompletionWithOrigin(client, jobId, origin, pollInterval = 2, timeout) {
|
|
@@ -5114,7 +4995,6 @@ Eligibility is limited to successful searches within the feedback age window. Th
|
|
|
5114
4995
|
}
|
|
5115
4996
|
if (querySuggestions) body.querySuggestions = querySuggestions;
|
|
5116
4997
|
const headers = {
|
|
5117
|
-
...AGENT_HINTS_HEADERS,
|
|
5118
4998
|
...originHeaders(origin),
|
|
5119
4999
|
"Content-Type": "application/json"
|
|
5120
5000
|
};
|
|
@@ -5155,8 +5035,7 @@ Eligibility is limited to successful searches within the feedback age window. Th
|
|
|
5155
5035
|
status: response.status,
|
|
5156
5036
|
feedbackErrorCode: parsed?.feedbackErrorCode,
|
|
5157
5037
|
error: parsed?.error ?? `HTTP ${response.status}`,
|
|
5158
|
-
retryable: response.status >= 500
|
|
5159
|
-
...readAgentHints(parsed) ? { agent_hints: readAgentHints(parsed) } : {}
|
|
5038
|
+
retryable: response.status >= 500
|
|
5160
5039
|
});
|
|
5161
5040
|
}
|
|
5162
5041
|
return structuredText(parsed);
|
|
@@ -5240,7 +5119,6 @@ Returns submission status, feedback ID, and accounting fields.
|
|
|
5240
5119
|
} = args;
|
|
5241
5120
|
const apiBase = resolveApiBaseUrl();
|
|
5242
5121
|
const headers = {
|
|
5243
|
-
...AGENT_HINTS_HEADERS,
|
|
5244
5122
|
...originHeaders(origin),
|
|
5245
5123
|
"Content-Type": "application/json"
|
|
5246
5124
|
};
|
|
@@ -5296,8 +5174,7 @@ Returns submission status, feedback ID, and accounting fields.
|
|
|
5296
5174
|
status: response.status,
|
|
5297
5175
|
feedbackErrorCode: parsed?.feedbackErrorCode,
|
|
5298
5176
|
error: parsed?.error ?? `HTTP ${response.status}`,
|
|
5299
|
-
retryable: response.status >= 500
|
|
5300
|
-
...readAgentHints(parsed) ? { agent_hints: readAgentHints(parsed) } : {}
|
|
5177
|
+
retryable: response.status >= 500
|
|
5301
5178
|
});
|
|
5302
5179
|
}
|
|
5303
5180
|
return structuredText(parsed);
|
|
@@ -5785,7 +5662,6 @@ Set \`redactPII\` to request redaction of personally identifiable information in
|
|
|
5785
5662
|
form.append("file", blob, filename);
|
|
5786
5663
|
form.append("options", JSON.stringify(optionsPayload));
|
|
5787
5664
|
const headers = {
|
|
5788
|
-
...AGENT_HINTS_HEADERS,
|
|
5789
5665
|
...originHeaders(origin)
|
|
5790
5666
|
};
|
|
5791
5667
|
const outbound = resolveOutbound(session);
|
|
@@ -5807,15 +5683,9 @@ Set \`redactPII\` to request redaction of personally identifiable information in
|
|
|
5807
5683
|
});
|
|
5808
5684
|
const responseText = await response.text();
|
|
5809
5685
|
if (!response.ok) {
|
|
5810
|
-
let parsed;
|
|
5811
|
-
try {
|
|
5812
|
-
parsed = JSON.parse(responseText);
|
|
5813
|
-
} catch {
|
|
5814
|
-
}
|
|
5815
5686
|
throw new CoreHttpError(
|
|
5816
5687
|
`Parse request failed with status ${response.status}: ${responseText}`,
|
|
5817
|
-
response.status
|
|
5818
|
-
readAgentHints(parsed)
|
|
5688
|
+
response.status
|
|
5819
5689
|
);
|
|
5820
5690
|
}
|
|
5821
5691
|
try {
|
|
@@ -5843,6 +5713,9 @@ Set \`redactPII\` to request redaction of personally identifiable information in
|
|
|
5843
5713
|
builtInTool: (name2) => builtInTools.get(name2)
|
|
5844
5714
|
}
|
|
5845
5715
|
);
|
|
5716
|
+
hooks.registerResources?.({
|
|
5717
|
+
addResource: (resource) => server.addResource(resource)
|
|
5718
|
+
});
|
|
5846
5719
|
return {
|
|
5847
5720
|
start: (args) => server.start(args),
|
|
5848
5721
|
stop: () => server.stop()
|