firecrawl-mcp 3.25.5 → 3.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -83,6 +83,9 @@ https://mcp.firecrawl.dev/v2/mcp-search
83
83
 
84
84
  It exposes a fixed set of eight tools: `firecrawl_search`, `firecrawl_developer_search`, the four `firecrawl_research_*` tools, and the two Alexandria tools `firecrawl_find_tools` and `firecrawl_scrape`. Its `firecrawl_search` fetches no page content, and the surface has its own OAuth identity; the full endpoint above is unchanged. It backs a published connector listing, so its tool set is a contract rather than a profile to tune. See [docs/search-profile.md](docs/search-profile.md) for the full contract and what a change to it involves.
85
85
 
86
+ For packaged MCP workflows in ChatGPT, Codex, or Claude Code, see
87
+ [MCP plugin packages](plugins/README.md).
88
+
86
89
  ### Running with npx
87
90
 
88
91
  ```bash
@@ -735,6 +738,28 @@ The agent performs web searches, follows links, reads pages, and gathers data au
735
738
  - `prompt`: Natural language description of the data you want (required, max 10,000 characters)
736
739
  - `urls`: Optional array of URLs to focus the agent on specific pages
737
740
  - `schema`: Optional JSON schema for structured output
741
+ - `effort`: Optional. `"low"`, `"medium"` or `"high"` reasoning budget for the agent task.
742
+ - `maxCredits`: Optional positive integer. Spending limit in credits for this run. The API defaults to 2,500 when omitted, and caps a free request at 2,500.
743
+ - `strictConstrainToURLs`: Optional boolean. If `true`, the agent only visits the URLs in `urls`.
744
+ - `threadId`: Optional. Continue an existing thread: the `threadId` from an earlier `firecrawl_agent` or `firecrawl_agent_status` result. Omit to start a new thread. On a follow-up, omitted `mode`, `urls`, `schema` and `exchange` settings carry over from the previous turn.
745
+ - `mode`: Optional. `"extract"` (default) returns the complete structured result every turn. `"chat"` lets a follow-up that asks for no new data get a short reply in `message` instead of a re-run; `exchange.requireApproval` needs it.
746
+ - `exchange`: Optional. Alexandria provider settings for this turn, forwarded as-is to `POST /v2/agent`:
747
+ - `enabled`, `toolkits` (up to 5 provider slugs), `maxCalls` (1 to 30), `requireApproval` (paid calls end the turn with a `pendingApproval`; needs `mode: "chat"` on the same call, even on a follow-up)
748
+ - `onTermsRequired`: what to do when an Alexandria provider the agent would use needs data terms your team has not accepted. Gated providers are never called in any mode. Omitted on a follow-up keeps the previous turn's value.
749
+ - `"skip"` (default): answer with accepted providers only. `exchange.skippedProviders` on the status result lists the gated providers that would have helped.
750
+ - `"ask"`: the same, plus a terms `pendingApproval` and `exchange.requiresAction` with the exact `terms/show` and `terms/accept` calls for each provider. Each provider's `digest` is always present and is `string | null`; when it is `null`, `terms/show` returns the current digest to send.
751
+ - `approve`: `{ approvalId, callIds?, always? }` answers yes to the `pendingApproval` the previous turn ended on. `callIds` and `always` apply to paid-call approvals only.
752
+ - `decline`: `{ approvalId }` answers no. A declined terms offer keeps those providers out of the rest of the thread.
753
+ - `approve` and `decline` need `threadId`, and only one of them can be sent.
754
+
755
+ **Provider terms (ask mode):** there is no auto-accept mode. When a turn ends on a terms offer, the status result carries `pendingApproval` (`kind: "terms"`) and `exchange.requiresAction` with the `approvalId` and the exact `terms/show` and `terms/accept` calls. To use the provider:
756
+
757
+ 1. Show the user the terms (`terms/show` through `firecrawl_scrape` with `alexandria`).
758
+ 2. Get the user's explicit consent to that provider's terms. A data request is not consent.
759
+ 3. Run the `terms/accept` call through `firecrawl_scrape`.
760
+ 4. Continue the same thread: call `firecrawl_agent` with the same `threadId` and `exchange.approve: { "approvalId": "..." }`.
761
+
762
+ If the user says no, call `firecrawl_agent` with the same `threadId` and `exchange.decline: { "approvalId": "..." }` instead.
738
763
 
739
764
  **Prompt Example:**
740
765
 
@@ -781,9 +806,34 @@ Then poll with `firecrawl_agent_status` using the returned job ID.
781
806
  }
782
807
  ```
783
808
 
809
+ **Usage Example (follow-up on the same thread):**
810
+
811
+ ```json
812
+ {
813
+ "name": "firecrawl_agent",
814
+ "arguments": {
815
+ "prompt": "Only keep the startups based in Europe",
816
+ "threadId": "0199a1b2-0000-7000-8000-000000000031"
817
+ }
818
+ }
819
+ ```
820
+
821
+ **Usage Example (continue the thread after the user accepted a provider's terms):**
822
+
823
+ ```json
824
+ {
825
+ "name": "firecrawl_agent",
826
+ "arguments": {
827
+ "prompt": "I accepted the Apollo terms. Continue.",
828
+ "threadId": "0199a1b2-0000-7000-8000-000000000031",
829
+ "exchange": { "approve": { "approvalId": "0199a1b2-0000-7000-8000-000000000033" } }
830
+ }
831
+ }
832
+ ```
833
+
784
834
  **Returns:**
785
835
 
786
- - Job ID for status checking. Use `firecrawl_agent_status` to poll for results.
836
+ - Job ID for status checking, plus `threadId` and `threadTurn`. Use `firecrawl_agent_status` to poll for results.
787
837
 
788
838
  ### 9. Check Agent Status (`firecrawl_agent_status`)
789
839
 
@@ -1099,6 +1149,33 @@ Example log messages:
1099
1149
  [ERROR] Rate limit exceeded
1100
1150
  ```
1101
1151
 
1152
+ ## API response hints
1153
+
1154
+ The MCP server explicitly enables Firecrawl API response hints on its outbound
1155
+ requests with `X-Firecrawl-Agent-Hints: true`; the API leaves them disabled for
1156
+ ordinary callers. When Firecrawl returns an optional `agent_hints` array of
1157
+ strings, JSON tool results preserve it in their existing text and
1158
+ `structuredContent` alongside the tool's other structured fields. Readable
1159
+ Developer and Research outputs keep their existing text and show hints in a
1160
+ separate, labeled text block. Empty results can include hints. Error hints
1161
+ remain visible with `isError: true`.
1162
+ Responses without hints keep their existing output format. Guidance is API
1163
+ metadata, separate from the scraped page's content; it is not generated or
1164
+ executed by the MCP adapter.
1165
+
1166
+ The strings are passed through unchanged. An HTTP operation mentioned in a
1167
+ hint is not necessarily an MCP tool: Alexandria discovery is available through
1168
+ `firecrawl_find_tools`, and provider execution uses `firecrawl_scrape` with an
1169
+ `alexandria` body. The search-only profile exposes those paths and URL-mode
1170
+ Scrape, but does not expose feedback tools. Clients should use their advertised
1171
+ tool schemas and available capabilities. This change does not add tools,
1172
+ translate prose into tool calls, or submit feedback automatically.
1173
+
1174
+ The pinned `firecrawl` 4.40.0 discards outer-envelope hints in high-level
1175
+ Scrape and Map responses and normalized SDK errors. The adapter captures hints
1176
+ from the SDK HTTP response while retaining the SDK's request and retry behavior.
1177
+ Authentication recovery retains its existing guidance.
1178
+
1102
1179
  ## Error Handling
1103
1180
 
1104
1181
  The server provides robust error handling:
@@ -0,0 +1,46 @@
1
+ // src/agent-hints.ts
2
+ var AGENT_HINTS_HEADERS = { "X-Firecrawl-Agent-Hints": "true" };
3
+ function readAgentHints(value) {
4
+ if (!value || typeof value !== "object") return void 0;
5
+ const hints = value.agent_hints;
6
+ return Array.isArray(hints) && hints.every((hint) => typeof hint === "string") ? hints : void 0;
7
+ }
8
+ function preserveAgentHints(data, envelope) {
9
+ const hints = readAgentHints(envelope);
10
+ if (!hints) return data;
11
+ return data && typeof data === "object" && !Array.isArray(data) ? { ...data, agent_hints: hints } : { data, agent_hints: hints };
12
+ }
13
+ function agentHintsText(hints) {
14
+ return `Firecrawl API agent_hints (response guidance, separate from page content):
15
+ ${JSON.stringify(hints, null, 2)}`;
16
+ }
17
+ function withAgentHints(result, response, separateText = false) {
18
+ const hints = readAgentHints(response);
19
+ if (!hints) return result;
20
+ return {
21
+ ...result,
22
+ content: separateText && hints.length ? [...result.content, { type: "text", text: agentHintsText(hints) }] : result.content,
23
+ structuredContent: { ...result.structuredContent, agent_hints: hints }
24
+ };
25
+ }
26
+ function readErrorAgentHints(error) {
27
+ const hints = readAgentHints(error);
28
+ if (hints) return hints;
29
+ if (!error || typeof error !== "object") return void 0;
30
+ const extras = error.extras;
31
+ const extrasHints = readAgentHints(extras);
32
+ if (extrasHints) return extrasHints;
33
+ const details = error.details;
34
+ const detailsHints = readAgentHints(details);
35
+ if (detailsHints) return detailsHints;
36
+ const response = error.response;
37
+ return readAgentHints(response?.data);
38
+ }
39
+ export {
40
+ AGENT_HINTS_HEADERS,
41
+ agentHintsText,
42
+ preserveAgentHints,
43
+ readAgentHints,
44
+ readErrorAgentHints,
45
+ withAgentHints
46
+ };