Hello, I maintain actlint, a static linter that checks MCP tool annotations against what their input schemas allow.
The observation
On firecrawl-mcp@3.22.3, firecrawl_search declares readOnlyHint: true, but its input schema includes scrapeOptions.actions with action types click, write, press, and executeJavascript. As declared, the tool can fill and submit forms and run arbitrary JS on the pages it visits, while carrying the hint that lets a spec-conformant client skip its confirmation prompt (MCP spec on annotations).
The other tools with the same actions parameter (firecrawl_scrape, firecrawl_crawl, firecrawl_interact) all declare readOnlyHint: false. Search is the only one that says true, so most likely the annotation predates search gaining scrapeOptions.actions. It is accurate for the plain search path, and the README's search section doesn't document actions either.
Possible fixes
Roughly in order of thoroughness: split the action-driving path into a separate non-read-only tool, constrain or remove actions on the search tool's schema, or set readOnlyHint: false to match firecrawl_scrape.
To verify
Without taking my word for it: list the server's tools and compare firecrawl_search's annotations.readOnlyHint against its inputSchema (the scrapeOptions.actions[].type enum is ["wait","screenshot","scroll","scrape","click","write","press","executeJavascript","generatePDF"]).
Or run actlint, which reads tools/list only and never invokes a tool.
npx actlint npx firecrawl-mcp
npx actlint explain write-as-readonly
Expected result: one HIGH write-as-readonly finding on firecrawl_search, the other 25 tools clean.
Notes
I'm putting together a blog post on MCP annotation accuracy that mentions this, planned for 19 July 2026, and didn't want it to reach the repo second-hand. If it gets fixed or clarified before then, the post will say so. And if I've misread the tool, that's a bug in actlint and I'd genuinely like to know.
Hello, I maintain actlint, a static linter that checks MCP tool annotations against what their input schemas allow.
The observation
On
firecrawl-mcp@3.22.3,firecrawl_searchdeclaresreadOnlyHint: true, but its input schema includesscrapeOptions.actionswith action typesclick,write,press, andexecuteJavascript. As declared, the tool can fill and submit forms and run arbitrary JS on the pages it visits, while carrying the hint that lets a spec-conformant client skip its confirmation prompt (MCP spec on annotations).The other tools with the same
actionsparameter (firecrawl_scrape,firecrawl_crawl,firecrawl_interact) all declarereadOnlyHint: false. Search is the only one that saystrue, so most likely the annotation predates search gainingscrapeOptions.actions. It is accurate for the plain search path, and the README's search section doesn't documentactionseither.Possible fixes
Roughly in order of thoroughness: split the action-driving path into a separate non-read-only tool, constrain or remove
actionson the search tool's schema, or setreadOnlyHint: falseto matchfirecrawl_scrape.To verify
Without taking my word for it: list the server's tools and compare
firecrawl_search'sannotations.readOnlyHintagainst itsinputSchema(thescrapeOptions.actions[].typeenum is["wait","screenshot","scroll","scrape","click","write","press","executeJavascript","generatePDF"]).Or run actlint, which reads
tools/listonly and never invokes a tool.Expected result: one HIGH
write-as-readonlyfinding onfirecrawl_search, the other 25 tools clean.Notes
I'm putting together a blog post on MCP annotation accuracy that mentions this, planned for 19 July 2026, and didn't want it to reach the repo second-hand. If it gets fixed or clarified before then, the post will say so. And if I've misread the tool, that's a bug in actlint and I'd genuinely like to know.