firecrawl-mcp 3.25.0 → 3.25.2
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 +2 -0
- package/dist/index.js +48 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1211,3 +1211,5 @@ Use the existing `firecrawl_feedback` tool with `endpoint: "alexandria"`:
|
|
|
1211
1211
|
```
|
|
1212
1212
|
|
|
1213
1213
|
This uses authenticated `POST /v2/feedback`, without a job ID, job-age deadline, or credit refund. Optional `providerFeedback` and `capabilityFeedback` arrays describe coverage gaps and execution issues; the tool schema lists supported issue values. A `new_capability_request` requires `requestedFunctionality`; `missing_capability` (the provider exists but lacks the capability) does not. Existing feedback opt-out and authentication controls apply.
|
|
1214
|
+
|
|
1215
|
+
Agents are pointed at this loop from three places: the server instructions, the `firecrawl_scrape` and `firecrawl_find_tools` descriptions, and a `feedbackTool` object attached to every Alexandria execution and discovery result (with the tool name and a skeleton of the arguments). The hint is omitted for Firecrawl-internal calls such as `bash` and when `firecrawl_feedback` is not registered (`FIRECRAWL_NO_ENDPOINT_FEEDBACK` or keyless startup).
|
package/dist/index.js
CHANGED
|
@@ -45,6 +45,31 @@ var alexandriaFeedbackFields = {
|
|
|
45
45
|
)
|
|
46
46
|
).max(20).optional()
|
|
47
47
|
};
|
|
48
|
+
var ALEXANDRIA_FEEDBACK_GUIDANCE = 'After an Alexandria task, whether a capability ran or discovery found nothing for the website, call firecrawl_feedback once per website with endpoint "alexandria": requestedWebsite (the url the user needed data from and the requestedFunctionality they needed), a rating, a rationale from observed results, and any providerFeedback or capabilityFeedback gaps. It is free, needs no job ID, has no deadline, and follows the answer rather than replacing it.';
|
|
49
|
+
var ALEXANDRIA_FEEDBACK_HINT = {
|
|
50
|
+
name: "firecrawl_feedback",
|
|
51
|
+
when: "Once per website after the task is complete, including when no provider covered the site. Free; no job ID or deadline.",
|
|
52
|
+
arguments: {
|
|
53
|
+
endpoint: "alexandria",
|
|
54
|
+
rating: "<good | partial | bad>",
|
|
55
|
+
requestedWebsite: {
|
|
56
|
+
url: "<website the user needed data from>",
|
|
57
|
+
requestedFunctionality: "<what they needed from it>"
|
|
58
|
+
},
|
|
59
|
+
rationale: "<why this rating, from observed results>",
|
|
60
|
+
providerFeedback: "<optional [{name, issue, why}]: providers that were missing, thin, or unavailable>",
|
|
61
|
+
capabilityFeedback: "<optional [{name, provider, issue, why, requestedFunctionality?}]: capabilities that were missing, wrong, or failed>"
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
function alexandriaCallsWarrantFeedback(calls) {
|
|
65
|
+
return calls.some(
|
|
66
|
+
(call) => call.provider !== "firecrawl" || call.capability === "find-tools"
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
function withAlexandriaFeedbackHint(envelope, enabled) {
|
|
70
|
+
if (!enabled || !envelope || typeof envelope !== "object") return envelope;
|
|
71
|
+
return { ...envelope, feedbackTool: ALEXANDRIA_FEEDBACK_HINT };
|
|
72
|
+
}
|
|
48
73
|
var alexandriaSessionFeedbackSchema = z.strictObject({
|
|
49
74
|
endpoint: z.literal("alexandria"),
|
|
50
75
|
rating: z.enum(["good", "bad", "partial"]),
|
|
@@ -105,7 +130,10 @@ var findToolsSchema = z2.object({
|
|
|
105
130
|
limit: z2.number().int().min(1).max(100).optional(),
|
|
106
131
|
offset: z2.number().int().nonnegative().optional()
|
|
107
132
|
}).strict();
|
|
108
|
-
var
|
|
133
|
+
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";
|
|
134
|
+
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.";
|
|
135
|
+
var ALEXANDRIA_SOURCES_OPT_OUT = 'Passing sources without alexandria in it (for example ["web"] or ["news"]) excludes Alexandria provider matches; omit sources unless you specifically need web-only or news-only results, or include "alexandria" alongside them.';
|
|
136
|
+
var ALEXANDRIA_INSTRUCTIONS = "Start with the user\u2019s actual question and constraints. Authenticated search returns matching Alexandria providers beside web results; prefer a provider over page scraping when the task needs the same fields across several entities, provenance, exact figures, or many records, and use web results when they already answer the question. Authenticated search defaults to web + semantic Alexandria tools + domain-matched tools. Keyless search defaults to web only. " + ALEXANDRIA_CATALOGUE_SENTENCE + " Coverage varies; discover current tools rather than assuming one exists. Semantic discovery matches the data you need to capabilities even without a provider website in the web results. Domain matching connects result websites to tools that may fetch richer details, related records or collections beyond the linked page. Inspect coverage and required inputs; a matching domain alone does not guarantee a fit. " + ALEXANDRIA_SOURCES_OPT_OUT + ' Use sources: ["alexandria"] for semantic tools only, sources: ["web"] for web only, or sources: ["web"], domainTools: true for web plus domain tools. domainTools: false disables domain matching. Results in data.tools describe available tools, not executed data. Search defaults to toolDetail: "compact", returning only provider, capability and description; "summary" adds metadata and navigation. Inspect selected tools with firecrawl_find_tools using their providers and capabilities plus expand:["options","response"]; request examples only when the input shape is unclear. Batch related contract inspections and reuse complete contracts. Alternatively set toolDetail: "full" for contracts upfront. On the full MCP surface, firecrawl_find_tools supports semantic query lookup and is the list equivalent: {} lists categories; {categories:["<category-id>"]} lists providers; {providers:["<provider-id>"]} lists compact tools; adding capabilities:["<capability-id>"] expands the selected contract. Avoid expanding the entire catalogue. Read required inputs and requiresOneOf groups (at least one member per group), example.request/example.response when present, and response.key in the selected contract. Do not assume records is the result key. Follow the declared pagination input and response cursor, preserving filters; catalogue next is separate from provider pagination. Execute through firecrawl_scrape with alexandria:{provider,capability,options}. Search scrapeOptions fetches web pages, never provider tools. Use web results when sufficient, tools when they offer a direct route to deeper data. ' + ALEXANDRIA_FEEDBACK_GUIDANCE;
|
|
109
137
|
function findToolsOptions(args2) {
|
|
110
138
|
const level = args2.level ?? (args2.query || args2.capabilities?.length || args2.providers?.length || args2.groups?.length || args2.urls?.length ? "tools" : args2.categories?.length ? "providers" : "categories");
|
|
111
139
|
if (level === "categories" && (args2.query || args2.providers?.length || args2.categories?.length || args2.groups?.length || args2.capabilities?.length || args2.urls?.length || args2.expand !== void 0)) {
|
|
@@ -139,8 +167,8 @@ var ALEXANDRIA_SEARCH_INSTRUCTIONS = 'Authenticated search combines web results,
|
|
|
139
167
|
|
|
140
168
|
// src/alexandria-output.ts
|
|
141
169
|
var INLINE_TOKEN_BUDGET = 2e4;
|
|
142
|
-
async function alexandriaOutput(payload, calls, post, recoveryRequestId) {
|
|
143
|
-
const serialized = JSON.stringify(payload);
|
|
170
|
+
async function alexandriaOutput(payload, calls, post, recoveryRequestId, extras = {}) {
|
|
171
|
+
const serialized = JSON.stringify({ ...payload, ...extras });
|
|
144
172
|
const responseBytes = Buffer.byteLength(serialized, "utf8");
|
|
145
173
|
const estimatedTokens = Math.ceil(responseBytes / 4);
|
|
146
174
|
const items = payload?.data?.alexandria;
|
|
@@ -193,7 +221,8 @@ async function alexandriaOutput(payload, calls, post, recoveryRequestId) {
|
|
|
193
221
|
}
|
|
194
222
|
}
|
|
195
223
|
}
|
|
196
|
-
}
|
|
224
|
+
},
|
|
225
|
+
...extras
|
|
197
226
|
});
|
|
198
227
|
} catch {
|
|
199
228
|
return serialized;
|
|
@@ -1641,7 +1670,7 @@ var searchToolBaseFields = {
|
|
|
1641
1670
|
location: z7.string().optional(),
|
|
1642
1671
|
includeDomains: z7.array(searchDomainSchema).optional(),
|
|
1643
1672
|
excludeDomains: z7.array(searchDomainSchema).optional(),
|
|
1644
|
-
sources: z7.array(searchSourceSchema).optional().describe("Search sources; authenticated sessions default to web + alexandria, keyless sessions to web only. Use alexandria alone for
|
|
1673
|
+
sources: z7.array(searchSourceSchema).optional().describe("Search sources; authenticated sessions default to web + alexandria, keyless sessions to web only. " + ALEXANDRIA_SOURCES_OPT_OUT + ' Use ["alexandria"] alone for provider discovery without web results.'),
|
|
1645
1674
|
categories: z7.array(z7.enum(["github", "research", "pdf", "developer"])).optional().describe(
|
|
1646
1675
|
'Limit results to specific source types. `github` searches GitHub repositories, code, issues, and docs; `research` restricts ordinary web results to research-affiliated websites and returns page snippets, which is separate from the `firecrawl_research_*` tools that search paper abstracts and full text across biomedical (PubMed, bioRxiv, medRxiv) and arXiv literature; `pdf` searches PDF results; `developer` searches an index built for coding agents over repositories, GitHub issues, merged pull requests, repository READMEs, and curated documentation sites. `developer` returns hits in `data.web` with `category: "developer"`; the other categories also filter `data.web`.'
|
|
1647
1676
|
),
|
|
@@ -1823,7 +1852,8 @@ var ConsoleLogger = class {
|
|
|
1823
1852
|
var openAiAppsChallengeToken = normalizeHeader(
|
|
1824
1853
|
process.env.OPENAI_APPS_CHALLENGE_TOKEN
|
|
1825
1854
|
);
|
|
1826
|
-
var FULL_PROFILE_INSTRUCTIONS = `Execution with firecrawl_scrape alexandria uses requestId; reuse the returned ID for retries of the same payload, never a new ID to bypass a pending or uncertain 409. Firecrawl provides web search, page retrieval, site URL discovery, multi-page collection, structured page data, monitoring, and multi-source research that returns structured data. Match the requested operation to the tool boundary: firecrawl_scrape retrieves one supplied page and can return JSON matching a supplied schema, firecrawl_map enumerates URLs under a site without retrieving their content, and firecrawl_agent runs multi-source research and returns structured data when the URLs are not known or the answer spans several sites (an entity plus its fields, a list, a dataset); its result is read with firecrawl_agent_status. For biomedical, life-science, clinical, or arXiv literature, the firecrawl_research_* tools search a paper index of abstracts and full text; firecrawl_search with categories: ["research"] is a website filter over ordinary web results and reaches different sources. For a programming question \u2014 code behaviour, a library or framework, an API contract, an error message, or a known bug \u2014 firecrawl_developer_search (or firecrawl_search with categories: ["developer"]) searches an index of repositories, GitHub issues, merged pull requests, READMEs, and curated documentation sites.
|
|
1855
|
+
var FULL_PROFILE_INSTRUCTIONS = `Execution with firecrawl_scrape alexandria uses requestId; reuse the returned ID for retries of the same payload, never a new ID to bypass a pending or uncertain 409. Firecrawl provides web search, page retrieval, site URL discovery, multi-page collection, structured page data, monitoring, and multi-source research that returns structured data. Match the requested operation to the tool boundary: firecrawl_scrape retrieves one supplied page and can return JSON matching a supplied schema, firecrawl_map enumerates URLs under a site without retrieving their content, and firecrawl_agent runs multi-source research and returns structured data when the URLs are not known or the answer spans several sites (an entity plus its fields, a list, a dataset); its result is read with firecrawl_agent_status. For biomedical, life-science, clinical, or arXiv literature, the firecrawl_research_* tools search a paper index of abstracts and full text; firecrawl_search with categories: ["research"] is a website filter over ordinary web results and reaches different sources. For a programming question \u2014 code behaviour, a library or framework, an API contract, an error message, or a known bug \u2014 firecrawl_developer_search (or firecrawl_search with categories: ["developer"]) searches an index of repositories, GitHub issues, merged pull requests, READMEs, and curated documentation sites. Authenticated firecrawl_search returns web results together with matching Alexandria providers in data.tools. ${ALEXANDRIA_CATALOGUE_SENTENCE} When a provider matches, prefer it over scraping pages if the task needs the same fields across several entities, provenance, exact figures or timestamps, or a large set of records; execute it through firecrawl_scrape with the returned contract. If web results already answer the question, use them. Before scraping more than one page for the same fields, spend one free firecrawl_find_tools call to check for a provider. Use firecrawl_find_tools to read a contract that was not returned in full or to browse the catalogue by category. ${ALEXANDRIA_SOURCES_OPT_OUT} If no provider fits, continue with web search or firecrawl_agent. firecrawl_search with sources: [{type: "alexandria"}] returns compact tool summaries in data.tools; toolDetail: "full" includes contracts, firecrawl_find_tools starts with categories, lists providers, then compact tools, and expands the selected full contract, and firecrawl_scrape with alexandria: [{provider, capability, options}] executes up to ten capabilities and returns their results. Alexandria access needs an API key on a team with it enabled. A terms-gated Alexandria provider fails with code THIRD_PARTY_DATA_TERMS_REQUIRED and a requiresAction.url. Follow the returned terms/show and terms/accept calls through firecrawl_scrape; acceptance requires explicit user authorization for the reviewed version and digest and confirmed:true. Otherwise direct an organization admin to the dashboard URL. Do not repeat successful provider calls just because the client could not display their output. Provide only the required inputs and account for stated network or external side effects.
|
|
1856
|
+
${ALEXANDRIA_FEEDBACK_GUIDANCE}`;
|
|
1827
1857
|
var KEYLESS_PROFILE_INSTRUCTIONS = `Hosted keyless sessions expose firecrawl_search, firecrawl_scrape, and firecrawl_parse with usage limits. firecrawl_search searches the web. For programming questions, firecrawl_search with categories: ["developer"] searches indexed repositories, GitHub issues, merged pull requests, repository READMEs, and curated documentation sites. For biomedical, life-science, clinical, or arXiv literature, firecrawl_search with categories: ["research"] filters ordinary web results to research-affiliated websites. firecrawl_scrape retrieves one supplied page and can return JSON matching a supplied schema. firecrawl_parse processes supported local files through its two-phase upload flow. An Authorization bearer API key can provide higher usage limits and expose additional tools, subject to plan, deployment, and team policy, including firecrawl_map for site URL discovery, firecrawl_agent and firecrawl_agent_status for multi-source research that returns structured data when the URLs are not known, firecrawl_research_* for paper-index and repository research, and firecrawl_find_tools as the progressive Alexandria catalogue lookup alongside the Alexandria options of firecrawl_search and firecrawl_scrape for catalogued data providers.`;
|
|
1828
1858
|
var SEARCH_PROFILE_INSTRUCTIONS = ALEXANDRIA_SEARCH_INSTRUCTIONS + ` Firecrawl provides web, developer, and research search. Use firecrawl_search to find relevant results across the web and specialized indexes. For a programming question, firecrawl_developer_search searches indexed repositories, GitHub issues, merged pull requests, READMEs, and curated documentation sites 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 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. All tools are read-only and return ranked results.`;
|
|
1829
1859
|
var SEARCH_PROFILE_TOOLS = /* @__PURE__ */ new Set([
|
|
@@ -2674,7 +2704,9 @@ Firecrawl may reuse recently indexed content instead of refetching the page, and
|
|
|
2674
2704
|
|
|
2675
2705
|
Returns the selected content formats and page metadata. Authenticated responses can include a \`metadata.scrapeId\` for optional scrape feedback.
|
|
2676
2706
|
|
|
2707
|
+
On an authenticated session with Alexandria access, if you are about to scrape the same fields from several pages, first run \`firecrawl_search\` with \`sources\` unset (or \`firecrawl_find_tools\`): a matching Alexandria provider returns those fields as typed records in one call. Keyless sessions have no provider matches; scrape directly.
|
|
2677
2708
|
Alexandria mode: pass \`alexandria\` (one \`{provider, capability, options}\` object or an array of 1-10) instead of \`url\` to execute catalogued Alexandria capabilities found through \`firecrawl_search\` sources \`alexandria\` or \`firecrawl_find_tools\`. The optional requestId identifies one logical execution: reuse the returned ID for retries of the identical payload, never a new ID to bypass pending or uncertain execution. Each call may include version to pin a published workflow; omitting it uses latest. Only timeout also applies at the top level in this mode. Returns per-capability results in \`data.alexandria\`, including \`data\`, \`records\`, or an \`error\` with a code. Check each item for errors even when the outer response is successful. Alexandria needs an API key on a team with Alexandria enabled.
|
|
2709
|
+
Alexandria mode: pass \`alexandria\` (one \`{provider, capability, options}\` object or an array of 1-10) instead of \`url\` to execute catalogued Alexandria capabilities found through \`firecrawl_search\` sources \`alexandria\` or \`firecrawl_find_tools\`. The optional requestId identifies one logical execution: reuse the returned ID for retries of the identical payload, never a new ID to bypass pending or uncertain execution. Each call may include version to pin a published workflow; omitting it uses latest. Only timeout also applies at the top level in this mode. Returns per-capability results in \`data.alexandria\`, including \`data\`, \`records\`, or an \`error\` with a code. Check each item for errors even when the outer response is successful. Alexandria needs an API key on a team with Alexandria enabled. Alexandria results include a \`feedbackTool\` pointer: after the task, report how the catalogue served the website through \`firecrawl_feedback\` with endpoint \`alexandria\` (free, no job ID).
|
|
2678
2710
|
|
|
2679
2711
|
For potentially large workflow results, supply and preserve a top-level requestId before execution. If a response provides nextTool, follow its instructions to access the result without repeating a successful provider call.
|
|
2680
2712
|
|
|
@@ -2866,9 +2898,10 @@ async function executeExchangeCalls(session, alexandria, suppliedRequestId, time
|
|
|
2866
2898
|
),
|
|
2867
2899
|
{ tool: "firecrawl_scrape", requestId, providers: (Array.isArray(alexandria) ? alexandria : [alexandria]).map((call) => call.provider) }
|
|
2868
2900
|
);
|
|
2901
|
+
const calls = Array.isArray(alexandria) ? alexandria : [alexandria];
|
|
2869
2902
|
return alexandriaOutput(
|
|
2870
2903
|
{ ...response?.data ?? {}, requestId },
|
|
2871
|
-
|
|
2904
|
+
calls,
|
|
2872
2905
|
async (body, id) => {
|
|
2873
2906
|
const result = await client.http.post(
|
|
2874
2907
|
"/v2/scrape",
|
|
@@ -2877,7 +2910,8 @@ async function executeExchangeCalls(session, alexandria, suppliedRequestId, time
|
|
|
2877
2910
|
);
|
|
2878
2911
|
return result?.data;
|
|
2879
2912
|
},
|
|
2880
|
-
randomUUID()
|
|
2913
|
+
randomUUID(),
|
|
2914
|
+
alexandriaFeedbackAvailable() && alexandriaCallsWarrantFeedback(calls) ? { feedbackTool: ALEXANDRIA_FEEDBACK_HINT } : {}
|
|
2881
2915
|
);
|
|
2882
2916
|
} catch (error) {
|
|
2883
2917
|
if (error?.response?.status === 401) throw error;
|
|
@@ -2896,7 +2930,7 @@ server.addTool({
|
|
|
2896
2930
|
destructiveHint: false,
|
|
2897
2931
|
idempotentHint: true
|
|
2898
2932
|
},
|
|
2899
|
-
description: "
|
|
2933
|
+
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. Inspect a selected contract before executing through firecrawl_scrape; reuse contracts already returned. Follow nextTool for further discovery or pagination. Discovery does not execute providers. Use firecrawl_search when you also need web results. Results include a feedbackTool pointer: after the task, report how the catalogue served the website through firecrawl_feedback with endpoint alexandria, including when nothing covered it (free, no job ID).",
|
|
2900
2934
|
parameters: findToolsSchema,
|
|
2901
2935
|
execute: async (args2, { session, client: mcpClient }) => {
|
|
2902
2936
|
const origin = requestOrigin(mcpClient, session);
|
|
@@ -2924,7 +2958,7 @@ server.addTool({
|
|
|
2924
2958
|
}));
|
|
2925
2959
|
const page = { level: "categories", items, total: rows.length };
|
|
2926
2960
|
if (offset + options.limit < rows.length) page.nextTool = { name: "firecrawl_find_tools", arguments: { level: "categories", limit: options.limit, offset: offset + options.limit } };
|
|
2927
|
-
return compactText(withFindToolsNavigation({ success: true, data: { creditsCost: 0, alexandria: [{ provider: "firecrawl", capability: "find-tools", creditsCost: 0, data: page }] } }));
|
|
2961
|
+
return compactText(withAlexandriaFeedbackHint(withFindToolsNavigation({ success: true, data: { creditsCost: 0, alexandria: [{ provider: "firecrawl", capability: "find-tools", creditsCost: 0, data: page }] } }), alexandriaFeedbackAvailable()));
|
|
2928
2962
|
}
|
|
2929
2963
|
const result = await executeExchangeCalls(session, { provider: "firecrawl", capability: "find-tools", options }, void 0, void 0, origin);
|
|
2930
2964
|
return compactText(withFindToolsNavigation(JSON.parse(result)));
|
|
@@ -3218,7 +3252,10 @@ if (ENDPOINT_FEEDBACK_DISABLED) {
|
|
|
3218
3252
|
"[firecrawl-mcp] Endpoint feedback tool disabled by FIRECRAWL_NO_ENDPOINT_FEEDBACK; firecrawl_feedback will not be registered."
|
|
3219
3253
|
);
|
|
3220
3254
|
}
|
|
3221
|
-
|
|
3255
|
+
function alexandriaFeedbackAvailable() {
|
|
3256
|
+
return !ENDPOINT_FEEDBACK_DISABLED && !isLocalKeylessStartup();
|
|
3257
|
+
}
|
|
3258
|
+
if (alexandriaFeedbackAvailable()) {
|
|
3222
3259
|
server.addTool({
|
|
3223
3260
|
name: "firecrawl_feedback",
|
|
3224
3261
|
annotations: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "firecrawl-mcp",
|
|
3
|
-
"version": "3.25.
|
|
3
|
+
"version": "3.25.2",
|
|
4
4
|
"description": "MCP server for Firecrawl — search, scrape, and interact with the web, and search scientific papers. Supports both cloud and self-hosted instances. Features include web search, scraping, page interaction, batch processing, LLM-powered content analysis, and research paper search over biomedical and arXiv literature (PubMed, bioRxiv, medRxiv, arXiv) with citation-graph expansion and full-text reading.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"mcpName": "io.github.firecrawl/firecrawl-mcp-server",
|