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/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=08f77b633292d9ae4cb022c0fa5bd722dbd5c1aaaad600204f8ed38339bfd37b/node_modules/fastmcp/dist/chunk-LWU5CQGW.js
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=08f77b633292d9ae4cb022c0fa5bd722dbd5c1aaaad600204f8ed38339bfd37b/node_modules/fastmcp/dist/chunk-OJG4XYXA.js
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 withAgentHints(withStructured(fmtDeveloper(results), { results }), res.data, true);
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 withAgentHints(
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
- agent_hints;
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, readAgentHints(payload));
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 monitorResult(res);
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 monitorResult(res);
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 monitorResult(res);
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 monitorResult(res);
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 monitorResult(res);
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 monitorResult(res);
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 monitorResult(res);
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 monitorResult(res);
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
- researchHeaders(requestOrigin(mcpClient, session))
3254
+ originHeaders(requestOrigin(mcpClient, session))
3288
3255
  );
3289
3256
  const results = res.data?.results ?? [];
3290
- return withAgentHints(withStructured(fmtHits(results), { results }), res.data, true);
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
- researchHeaders(requestOrigin(mcpClient, session))
3285
+ originHeaders(requestOrigin(mcpClient, session))
3319
3286
  );
3320
3287
  const paper = res.data?.paper;
3321
- return withAgentHints(withStructured(
3288
+ return withStructured(
3322
3289
  fmtPaperMetadata(paper),
3323
3290
  paper ? { paper } : {}
3324
- ), res.data, true);
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
- researchHeaders(requestOrigin(mcpClient, session))
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 withAgentHints(withStructured(
3339
+ return withStructured(
3373
3340
  `${fmtHits(results)}
3374
3341
  (poolSize=${poolSize})${note}`,
3375
3342
  { results, poolSize, ...res.data?.note ? { note: res.data.note } : {} }
3376
- ), res.data, true);
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
- researchHeaders(requestOrigin(mcpClient, session))
3378
+ originHeaders(requestOrigin(mcpClient, session))
3412
3379
  );
3413
3380
  const passages = res.data?.passages ?? [];
3414
- return withAgentHints(withStructured(
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
- ), res.data, true);
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, hints) {
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
- const client = new FirecrawlApp(clientConfig);
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(preserveAgentHints(json?.data ?? json, json));
4609
+ return structuredText(withoutDiscoveredToolPrices(json?.data ?? json));
4719
4610
  }
4720
4611
  const client = getClient(session);
4721
4612
  const res = await relayTermsRequired(
4722
- () => sdkResultWithAgentHints(
4723
- client,
4724
- () => client.scrape(String(url), {
4725
- ...cleaned,
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 sdkResultWithAgentHints(
4769
- client,
4770
- () => client.map(String(url), {
4771
- ...cleaned,
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: { creditsCost: 0, alexandria: [{ provider: "firecrawl", capability: "find-tools", creditsCost: 0, data: page }] } }), alexandriaFeedbackAvailable()));
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
- return structuredCompact(withFindToolsNavigation(JSON.parse(result)));
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 at each executed capability's listed price in alexandria mode.`;
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 at the capability's listed price and needs a team with Alexandria enabled.
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,