Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-unused-vars": [
"error",
{ "argsIgnorePattern": "^_" }
{
"argsIgnorePattern": "^_"
}
]
},
"overrides": [
Expand All @@ -30,6 +32,15 @@
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/no-explicit-any": "off"
}
},
{
"files": ["web/**/*.ts", "web/**/*.tsx"],
"env": {
"browser": true
},
"parserOptions": {
"project": "./web/tsconfig.json"
}
}
]
}
25 changes: 21 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ jobs:

- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 10

- name: Use Node.js
uses: actions/setup-node@v3
Expand All @@ -25,10 +23,29 @@ jobs:
cache: 'pnpm'

- name: Install dependencies
run: pnpm install
run: pnpm install --frozen-lockfile

- name: Build
run: pnpm run build

- name: Test
run: pnpm test
run: pnpm test

- name: Lint
run: pnpm lint

- name: Install browser dependencies
run: npx --yes agent-browser@0.38.1 install --with-deps

- name: Browser regressions
run: |
node scripts/preview-usage-ui.mjs &
preview_pid=$!
trap 'kill "$preview_pid"' EXIT
ready=false
for attempt in $(seq 1 30); do
if curl --fail --silent http://127.0.0.1:4173/ > /dev/null; then ready=true; break; fi
sleep 1
done
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
if [ "$ready" != true ]; then echo "Preview server did not start" >&2; exit 1; fi
node scripts/verify-usage-preview.mjs http://127.0.0.1:4173
2 changes: 0 additions & 2 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ jobs:

- name: Install pnpm
uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v4
with:
version: 10

- name: Set up Node.js
uses: actions/setup-node@v6
Expand Down
36 changes: 35 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,10 @@ A Model Context Protocol (MCP) server that brings [Firecrawl](https://github.com
- Use `firecrawl_interact` when a page needs a click, type, or navigate action before you can read it — pass a `url` for a fresh page or a `scrapeId` to continue on one you already scraped.
- Use the `firecrawl_monitor_*` tools when the same page needs to be checked on a recurring schedule with diffs and change alerts, rather than fetched once.
- Use `firecrawl_credit_usage` to check credits left or monthly consumption, optionally broken down by API key.
- Use `firecrawl_usage_dashboard` to open the usage interface in an MCP Apps host; ChatGPT can also expose it as a global sidebar entrypoint.
- Consider something else when you need to hold a browser session open across many of your own steps with your own retry and termination logic: each `firecrawl_interact` call runs one `prompt` or `code` turn to completion and returns control — the session can persist across calls via `scrapeId` and ends with `firecrawl_interact_stop`, but you cannot drive it interactively step-by-step from the client side within a single call.

This server lists 26 tools when the full profile registers with default settings (feedback tools included, not running in local-keyless mode). Setting `FIRECRAWL_NO_SEARCH_FEEDBACK=1` and/or `FIRECRAWL_NO_ENDPOINT_FEEDBACK=1` removes the corresponding feedback tools and reduces this count, as does local keyless startup. For clients with a tool-slot limit: the hosted keyless endpoint (`https://mcp.firecrawl.dev/v2/mcp`, no API key) exposes only 3 — `firecrawl_scrape`, `firecrawl_search`, `firecrawl_parse` — and the dedicated [search-only endpoint](#search-only-endpoint) (`https://mcp.firecrawl.dev/v2/mcp-search`) exposes a fixed set of 8 tools (search, developer and research search, plus Alexandria catalogue lookup and execution).
This server lists 27 tools when the full profile registers with default settings (feedback tools included, not running in local-keyless mode). Setting `FIRECRAWL_NO_SEARCH_FEEDBACK=1` and/or `FIRECRAWL_NO_ENDPOINT_FEEDBACK=1` removes the corresponding feedback tools and reduces this count, as does local keyless startup. For clients with a tool-slot limit: the hosted keyless endpoint (`https://mcp.firecrawl.dev/v2/mcp`, no API key) exposes only 3 — `firecrawl_scrape`, `firecrawl_search`, `firecrawl_parse` — and the dedicated [search-only endpoint](#search-only-endpoint) (`https://mcp.firecrawl.dev/v2/mcp-search`) exposes a fixed set of 8 tools (search, developer and research search, plus Alexandria catalogue lookup and execution).

## Installation

Expand Down Expand Up @@ -1293,3 +1294,36 @@ The existing `firecrawl_feedback` tool accepts `endpoint: "alexandria"`:
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.

Eligible Alexandria execution and discovery results include a `feedbackTool` pointer with the tool name and a skeleton of the arguments. The pointer is omitted for Firecrawl-internal calls such as `bash` and when `firecrawl_feedback` is not registered (`FIRECRAWL_NO_ENDPOINT_FEEDBACK` or keyless startup).

### Usage interface

The full and account profiles expose `firecrawl_usage_dashboard`, with a global
ChatGPT sidebar entrypoint and the `ui://firecrawl/usage.html` MCP Apps resource.
The search-only profile and hosted anonymous keyless tool list do not include it.
The app-only launcher opens fullscreen. The interface uses the Firecrawl web design system, including Suisse fonts and
light/dark tokens, and refreshes balance and monthly usage through the existing
`firecrawl_credit_usage` tool. Its Providers tab browses the complete live
Alexandria catalog with collection tabs, category shelves and bundled provider
logos. It searches and filters providers, and supports whole-provider
or individual-tool selections. Selecting attaches the tool context to the native
chat composer using MCP Apps model-context support. Type your request in the
chat composer; the app does not send a message or provide a chatbox. Discovery
is free; capability execution happens through the chat's Firecrawl tools under
existing account access and pricing. Selections guide the chat without enforcing
an exclusive provider allowlist. It never handles API keys in the browser.

`pnpm build` embeds the SDK, styles, and fonts into `dist/usage.html`; no external
asset host is needed. Run `pnpm typecheck:ui` for the browser source, and
`pnpm preview:usage` for a local mock-host preview with explicitly labeled sample
data. This preview does not require credentials or call the Firecrawl API.

For the desktop plugin sidebar flow, build and run
`node scripts/install-usage-plugin.mjs` on macOS. This installs **Firecrawl Usage
Dev** from a dedicated local marketplace with a Keychain-backed MCP server.
Restart the desktop app, open its Plugins entry, open the plugin app, and choose
**Pin to sidebar**. See the [local plugin setup](plugins/openai/firecrawl-usage-dev/README.md).

To enable the interface in ChatGPT, deploy this server build behind the registered
Firecrawl account connection and refresh the connection's tools/resources in
developer mode. The existing OpenAI package keeps its registered app reference;
this change does not publish a plugin or change marketplace/submission settings.
30 changes: 25 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"version": "3.27.2",
"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.",
"type": "module",
"packageManager": "pnpm@10.17.1",
"mcpName": "io.github.firecrawl/firecrawl-mcp-server",
"bin": {
"firecrawl-mcp": "dist/index.js"
Expand All @@ -14,16 +15,19 @@
"access": "public"
},
"scripts": {
"build": "rm -rf dist && tsup && node -e \"require('fs').chmodSync('dist/index.js', '755')\"",
"test": "npm run build && node --test --test-concurrency=1 tests/*.test.mjs",
"build": "rm -rf dist && tsup && node scripts/build-usage-ui.mjs && node -e \"require('fs').chmodSync('dist/index.js', '755')\"",
"test": "npm run build && npm run typecheck:ui && node --test --test-concurrency=1 tests/*.test.mjs",
"start": "node dist/index.js",
"start:cloud": "CLOUD_SERVICE=true node dist/index.js",
"lint": "eslint src/**/*.ts",
"lint:fix": "eslint src/**/*.ts --fix",
"lint": "eslint src/**/*.ts \"web/**/*.{ts,tsx}\"",
"lint:fix": "eslint src/**/*.ts \"web/**/*.{ts,tsx}\" --fix",
"format": "prettier --write .",
"prepare": "npm run build",
"publish-prod": "npm run build && npm publish",
"publish-beta": "npm run build && npm publish --tag beta"
"publish-beta": "npm run build && npm publish --tag beta",
"typecheck:ui": "tsc -p web/tsconfig.json",
"preview:usage": "npm run build && node scripts/preview-usage-ui.mjs",
"plugin:prepare:openai": "node scripts/prepare-openai-plugin.mjs"
},
"license": "MIT",
"dependencies": {
Expand Down Expand Up @@ -65,11 +69,27 @@
},
"homepage": "https://github.com/firecrawl/firecrawl-mcp-server#readme",
"devDependencies": {
"@modelcontextprotocol/ext-apps": "^2.0.3",
"@radix-ui/react-dialog": "1.1.6",
"@radix-ui/react-select": "2.2.6",
"@radix-ui/react-slot": "1.1.2",
"@tailwindcss/typography": "0.5.19",
"@types/node": "^24.3.1",
"@types/react": "19.2.8",
"@types/react-dom": "19.2.3",
"@typescript-eslint/eslint-plugin": "8.48.1",
"@typescript-eslint/parser": "8.48.1",
"classnames": "2.5.1",
"esbuild": "^0.27.7",
"eslint": "8.57.1",
"eslint-config-prettier": "10.1.8",
"lucide-react": "0.539.0",
"motion": "12.20.2",
"postcss": "8.5.6",
"react": "19.2.3",
"react-dom": "19.2.3",
"tailwind-gradient-mask-image": "1.2.0",
"tailwindcss": "3.4.17",
"tsup": "^8.5.0",
"typescript": "^5.9.2"
}
Expand Down
26 changes: 16 additions & 10 deletions patches/fastmcp@4.3.2.patch
Original file line number Diff line number Diff line change
@@ -1,31 +1,35 @@
diff --git a/dist/FastMCP.d.cts b/dist/FastMCP.d.cts
index 8eba099cc20f7ae5f70060bebb3871c387cfb2de..c3031da662933c366c7320171db47c246cd3191a 100644
index 8eba099cc20f7ae5f70060bebb3871c387cfb2de..bd4417c78cf53b8f3b8e6152fd940eca4feabf7f 100644
--- a/dist/FastMCP.d.cts
+++ b/dist/FastMCP.d.cts
@@ -605,6 +605,8 @@ type Tool<T extends FastMCPSessionAuth, Params extends ToolParameters = ToolPara
@@ -605,7 +605,10 @@ type Tool<T extends FastMCPSessionAuth, Params extends ToolParameters = ToolPara
streamingHint?: boolean;
} & ToolAnnotations;
canAccess?: (auth: T) => boolean;
+ beforeValidate?: (args: unknown, auth: T) => ContentResult | Promise<ContentResult | undefined> | undefined;
+ canList?: (auth: T) => boolean;
description?: string;
+ icons?: { src: string; mimeType?: string; sizes?: string[]; theme?: "light" | "dark" }[];
execute: (args: StandardSchemaV1.InferOutput<Params>, context: Context<T>) => Promise<AudioContent | ContentResult | ImageContent | ResourceContent | ResourceLink | StandardSchemaV1.InferOutput<OutputParams> | string | TextContent | void>;
name: string;
outputSchema?: OutputParams;
diff --git a/dist/FastMCP.d.ts b/dist/FastMCP.d.ts
index 810df0c5b6511f34685a0651e6df83acd0239e7b..5c82680c32900c1ca39679e1be25e64c3408aee9 100644
index 810df0c5b6511f34685a0651e6df83acd0239e7b..519e4bbba760ff914bc8d451995b1cd1cb21a5b4 100644
--- a/dist/FastMCP.d.ts
+++ b/dist/FastMCP.d.ts
@@ -605,6 +605,8 @@ type Tool<T extends FastMCPSessionAuth, Params extends ToolParameters = ToolPara
@@ -605,7 +605,10 @@ type Tool<T extends FastMCPSessionAuth, Params extends ToolParameters = ToolPara
streamingHint?: boolean;
} & ToolAnnotations;
canAccess?: (auth: T) => boolean;
+ beforeValidate?: (args: unknown, auth: T) => ContentResult | Promise<ContentResult | undefined> | undefined;
+ canList?: (auth: T) => boolean;
description?: string;
+ icons?: { src: string; mimeType?: string; sizes?: string[]; theme?: "light" | "dark" }[];
execute: (args: StandardSchemaV1.InferOutput<Params>, context: Context<T>) => Promise<AudioContent | ContentResult | ImageContent | ResourceContent | ResourceLink | StandardSchemaV1.InferOutput<OutputParams> | string | TextContent | void>;
name: string;
outputSchema?: OutputParams;
diff --git a/dist/chunk-LWU5CQGW.js b/dist/chunk-LWU5CQGW.js
index 474670585c1fff7d9609d0f900d0743df14a7688..86d120ca21d74d6c335a8c3c9763e2f4ac835d10 100644
index 474670585c1fff7d9609d0f900d0743df14a7688..8f3b93f6fc8eb9de279d2bd7a8e98d95075facdb 100644
--- a/dist/chunk-LWU5CQGW.js
+++ b/dist/chunk-LWU5CQGW.js
@@ -986,6 +986,9 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
Expand All @@ -38,7 +42,7 @@ index 474670585c1fff7d9609d0f900d0743df14a7688..86d120ca21d74d6c335a8c3c9763e2f4
let cachedToolsList = null;
this.#server.setRequestHandler(ListToolsRequestSchema, async () => {
if (cachedToolsList) {
@@ -994,9 +997,12 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
@@ -994,9 +997,13 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
};
}
cachedToolsList = await Promise.all(
Expand All @@ -49,10 +53,11 @@ index 474670585c1fff7d9609d0f900d0743df14a7688..86d120ca21d74d6c335a8c3c9763e2f4
+ // Top-level Tool.title (MCP 2025-06-18). Clients such as Codex index this
+ // for tool search and do not read annotations.title.
+ ...tool.annotations?.title && { title: tool.annotations.title },
+ ...tool.icons && { icons: tool.icons },
description: tool.description,
inputSchema: tool.parameters ? strictJsonSchema(await toJsonSchema(tool.parameters)) : {
additionalProperties: false,
@@ -1026,6 +1032,15 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
@@ -1026,6 +1033,15 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
`Unknown tool: ${request.params.name}`
);
}
Expand All @@ -69,7 +74,7 @@ index 474670585c1fff7d9609d0f900d0743df14a7688..86d120ca21d74d6c335a8c3c9763e2f4
if (tool.parameters) {
const parsed = await tool.parameters["~standard"].validate(
diff --git a/dist/chunk-UYG7NPM6.cjs b/dist/chunk-UYG7NPM6.cjs
index 3b695bf493c4f54fd970e145cf14fdd8effc9c6d..3e17b1d1f71f3bf41eb5e589fa272e670f27c150 100644
index 3b695bf493c4f54fd970e145cf14fdd8effc9c6d..1141ef0c4a9323709200bd166e7a678e2d493c44 100644
--- a/dist/chunk-UYG7NPM6.cjs
+++ b/dist/chunk-UYG7NPM6.cjs
@@ -986,6 +986,9 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
Expand All @@ -82,7 +87,7 @@ index 3b695bf493c4f54fd970e145cf14fdd8effc9c6d..3e17b1d1f71f3bf41eb5e589fa272e67
let cachedToolsList = null;
this.#server.setRequestHandler(_typesjs.ListToolsRequestSchema, async () => {
if (cachedToolsList) {
@@ -994,9 +997,12 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
@@ -994,9 +997,13 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
};
}
cachedToolsList = await Promise.all(
Expand All @@ -93,10 +98,11 @@ index 3b695bf493c4f54fd970e145cf14fdd8effc9c6d..3e17b1d1f71f3bf41eb5e589fa272e67
+ // Top-level Tool.title (MCP 2025-06-18). Clients such as Codex index this
+ // for tool search and do not read annotations.title.
+ ...tool.annotations?.title && { title: tool.annotations.title },
+ ...tool.icons && { icons: tool.icons },
description: tool.description,
inputSchema: tool.parameters ? _xsschema.strictJsonSchema.call(void 0, await _xsschema.toJsonSchema.call(void 0, tool.parameters)) : {
additionalProperties: false,
@@ -1026,6 +1032,15 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
@@ -1026,6 +1033,15 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
`Unknown tool: ${request.params.name}`
);
}
Expand Down
6 changes: 6 additions & 0 deletions plugins/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ plugin submission and registered app mapping. Replace the previous skill set
with the package's `skills/` contents, preserving the reference directories.
Test the draft in ChatGPT and Codex before submitting it for publication.

The maintained OpenAI source preserves its registered app mapping. For the
current remote-MCP submission format, use `pnpm plugin:prepare:openai` with a new
output directory; it preserves the published identity, metadata and skills while
omitting app-reference files and development launchers. See the
[production package guide](openai/app-6a314a73f8ac819195b0d55e36b9c609/README.md).

For a plugin archive, include the manifest, connection file, and `skills/`
directory at the archive root. Include dotfiles such as `.app.json`, `.mcp.json`,
`.codex-plugin/`, and `.claude-plugin/` as applicable. A skill-only upload contains
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{
"apps": {
"app-6a314a73f8ac819195b0d55e36b9c609": {
"id": "asdk_app_6a314a73f8ac819195b0d55e36b9c609"
"id": "asdk_app_6a314a73f8ac819195b0d55e36b9c609",
"required": true
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,28 @@
"author": {
"name": "SideGuide Technologies, Inc."
},
"description": "Firecrawl helps users search the web, extract page and document content, discover structured data providers, and research developer documentation and scientific papers. It also supports browser interactions, multi-page crawls, structured research jobs, website change monitoring, and account credit-usage checks.",
"description": "Search the web and access data providers and specialized indexes through Alexandria. Research companies, compare products, and find the data you need for your work. Access any page into clean content, and explore scientific papers and code repositories from your conversation.",
"interface": {
"capabilities": ["Read", "Write"],
"capabilities": [],
"category": "Productivity",
"defaultPrompt": [
"Find current sources for a topic and summarize them",
"Read a webpage and extract its main points",
"Find research papers and verify their key claims"
"Search the web for this week's biggest AI announcements and link to the original sources.",
"Scrape Stripe's API changelog and summarize the changes from the last 30 days.",
"Find sources in Alexandria for US inflation data and pull the latest available figures."
],
"developerName": "SideGuide Technologies, Inc.",
"displayName": "Firecrawl",
"longDescription": "Firecrawl helps users search the web, extract page and document content, discover structured data providers, and research developer documentation and scientific papers. It also supports browser interactions, multi-page crawls, structured research jobs, website change monitoring, and account credit-usage checks.",
"longDescription": "Search the web and access data providers and specialized indexes through Alexandria. Research companies, compare products, and find the data you need for your work. Access any page into clean content, and explore scientific papers and code repositories from your conversation.",
"privacyPolicyURL": "https://www.firecrawl.dev/privacy-policy",
"shortDescription": "Search and extract web data",
"shortDescription": "Search and access more data",
"supportURL": "https://www.firecrawl.dev/support",
"termsOfServiceURL": "https://www.firecrawl.dev/terms-of-service",
"websiteURL": "https://firecrawl.dev"
"websiteURL": "https://firecrawl.dev",
"logo": "./assets/firecrawl.svg",
"composerIcon": "./assets/firecrawl.svg",
"brandColor": "#fa5d19"
},
"name": "app-6a314a73f8ac819195b0d55e36b9c609",
"skills": "./skills",
"version": "2.1.1"
"version": "2.2.1"
}
Loading
Loading