From 2c622a8cdc51b7b15da05d3ae38b65d9b065ceec Mon Sep 17 00:00:00 2001 From: Erik Engervall Date: Fri, 19 Jun 2026 10:02:54 +0200 Subject: [PATCH] Enhance tool annotations with detailed descriptions for readOnlyHint, openWorldHint, and destructiveHint across various Firecrawl tools, improving clarity on their functionalities and effects. --- src/index.ts | 81 +++++++++++++++++++++++++------------------------ src/monitor.ts | 48 ++++++++++++++--------------- src/research.ts | 29 +++++++++--------- 3 files changed, 81 insertions(+), 77 deletions(-) diff --git a/src/index.ts b/src/index.ts index 01a3892..7d4633f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -565,9 +565,9 @@ server.addTool({ name: 'firecrawl_scrape', annotations: { title: 'Scrape a URL', - readOnlyHint: SAFE_MODE, - openWorldHint: true, - destructiveHint: false, + readOnlyHint: SAFE_MODE, // Fetches page content only; in cloud/safe mode interactive browser actions are disabled. + openWorldHint: true, // Accepts any user-supplied URL on the public web. + destructiveHint: false, // Does not modify, delete, or write to external websites. }, description: ` Scrape content from a single URL with advanced options. @@ -718,9 +718,9 @@ server.addTool({ name: 'firecrawl_map', annotations: { title: 'Map a website', - readOnlyHint: true, - openWorldHint: true, - destructiveHint: false, + readOnlyHint: true, // Discovers and returns indexed URLs; does not modify the target site. + openWorldHint: true, // Operates against arbitrary user-supplied web domains. + destructiveHint: false, // Read-only discovery; no deletion or destructive updates. }, description: ` Map a website to discover all indexed URLs on the site. @@ -784,9 +784,9 @@ server.addTool({ name: 'firecrawl_search', annotations: { title: 'Search the web', - readOnlyHint: true, - openWorldHint: true, - destructiveHint: false, + readOnlyHint: true, // Runs a web search and returns results; does not modify external sites. + openWorldHint: true, // Searches the open web across arbitrary domains and sources. + destructiveHint: false, // Query-only; no destructive side effects on external entities. }, description: ` Search the web and optionally extract content from search results. This is the most powerful web search tool available, and if available you should always default to using this tool for any web search needs. @@ -986,7 +986,9 @@ async function keylessPost( body: Record, session?: SessionData ): Promise { - const headers: Record = { 'Content-Type': 'application/json' }; + const headers: Record = { + 'Content-Type': 'application/json', + }; // Forward the real client IP (secret-authenticated) when proxying keyless // requests through the hosted MCP, so the API rate-limits per real IP. if (session?.keylessClientIp && process.env.KEYLESS_PROXY_SECRET) { @@ -1059,9 +1061,9 @@ if (!SEARCH_FEEDBACK_DISABLED) { name: 'firecrawl_search_feedback', annotations: { title: 'Send feedback on a search result', - readOnlyHint: false, - openWorldHint: true, - destructiveHint: false, + readOnlyHint: false, // POSTs structured feedback to the API, creating a server-side record. + openWorldHint: true, // Feedback references open-web search results and external URLs. + destructiveHint: false, // Additive only; records feedback and may refund credits, does not delete data. }, description: ` Send structured feedback on a previous \`firecrawl_search\` result. **Call this immediately after a search where you used the results** so we can improve search quality and refund 1 credit (search costs 2). @@ -1250,8 +1252,9 @@ if (!ENDPOINT_FEEDBACK_DISABLED) { name: 'firecrawl_feedback', annotations: { title: 'Send feedback on a Firecrawl job', - readOnlyHint: false, - openWorldHint: true, + readOnlyHint: false, // POSTs structured feedback for a completed job to /v2/feedback. + openWorldHint: true, // Feedback is tied to jobs that processed open-web URLs. + destructiveHint: false, // Additive only; submits ratings and notes, does not delete jobs or external content. }, description: ` Send structured feedback for a completed Firecrawl v2 job. Use this for endpoint-level feedback on \`scrape\`, \`parse\`, \`map\`, or \`search\` jobs when the job result was useful, partially useful, or failed to meet expectations. @@ -1381,9 +1384,9 @@ server.addTool({ name: 'firecrawl_crawl', annotations: { title: 'Start a site crawl', - readOnlyHint: false, - openWorldHint: true, - destructiveHint: false, + readOnlyHint: false, // Starts an asynchronous crawl job, creating a persistent server-side job. + openWorldHint: true, // Crawls user-specified URLs across the public web. + destructiveHint: false, // Reads pages from target sites; does not delete or alter external websites. }, description: ` Starts a crawl job on a website and extracts content from all pages. @@ -1466,9 +1469,9 @@ server.addTool({ name: 'firecrawl_check_crawl_status', annotations: { title: 'Get crawl status', - readOnlyHint: true, - openWorldHint: false, - destructiveHint: false, + readOnlyHint: true, // Retrieves status and results for an existing crawl job by ID; no mutations. + openWorldHint: false, // Queries only Firecrawl job state within the authenticated account. + destructiveHint: false, // Status lookup only; no deletes or updates. }, description: ` Check the status of a crawl job. @@ -1499,9 +1502,9 @@ server.addTool({ name: 'firecrawl_extract', annotations: { title: 'Extract structured data', - readOnlyHint: true, - openWorldHint: true, - destructiveHint: false, + readOnlyHint: true, // Uses LLM extraction to pull structured data from URLs without modifying those sites. + openWorldHint: true, // Accepts arbitrary user-supplied URLs on the public web. + destructiveHint: false, // Read-only extraction; no destructive changes to external content. }, description: ` Extract structured information from web pages using LLM capabilities. Supports both cloud AI and self-hosted LLM extraction. @@ -1575,9 +1578,9 @@ server.addTool({ name: 'firecrawl_agent', annotations: { title: 'Start a research agent', - readOnlyHint: false, - openWorldHint: true, - destructiveHint: false, + readOnlyHint: false, // Starts an autonomous research agent job on the Firecrawl API. + openWorldHint: true, // The agent browses and searches the open web to fulfill the prompt. + destructiveHint: false, // Gathers information only; does not delete external data or user resources. }, description: ` Autonomous web research agent. This is a separate AI agent layer that independently browses the internet, searches for information, navigates through pages, and extracts structured data based on your query. You describe what you need, and the agent figures out where to find it. @@ -1680,9 +1683,9 @@ server.addTool({ name: 'firecrawl_agent_status', annotations: { title: 'Get agent job status', - readOnlyHint: true, - openWorldHint: false, - destructiveHint: false, + readOnlyHint: true, // Polls an existing agent job by ID for progress and results; no mutations. + openWorldHint: false, // Queries only Firecrawl job state by job ID within the user's account. + destructiveHint: false, // Read-only status check. }, description: ` Check the status of an agent job and retrieve results when complete. Use this to poll for results after starting an agent with \`firecrawl_agent\`. @@ -1727,9 +1730,9 @@ server.addTool({ name: 'firecrawl_interact', annotations: { title: 'Interact with a scraped page', - readOnlyHint: false, - openWorldHint: true, - destructiveHint: false, + readOnlyHint: false, // Executes browser interactions (clicks, form input, scripts) in a live session. + openWorldHint: true, // Interacts with pages on the public web via the scraped session. + destructiveHint: false, // Transient page interactions only; does not delete monitors, jobs, or external sites. }, description: ` Interact with a previously scraped page in a live browser session. Scrape a page first with firecrawl_scrape, then use the returned scrapeId to click buttons, fill forms, extract dynamic content, or navigate deeper. @@ -1806,9 +1809,9 @@ server.addTool({ name: 'firecrawl_interact_stop', annotations: { title: 'Stop interact session', - readOnlyHint: false, - openWorldHint: false, - destructiveHint: true, + readOnlyHint: false, // Calls the API to stop and tear down an active interact session. + openWorldHint: false, // Operates only on a known Firecrawl scrape/interact session ID. + destructiveHint: true, // Terminates the live browser session; this end state cannot be resumed. }, description: ` Stop an interact session for a scraped page. Call this when you are done interacting to free resources. @@ -1922,9 +1925,9 @@ if (process.env.CLOUD_SERVICE !== 'true') { name: 'firecrawl_parse', annotations: { title: 'Parse a local file', - readOnlyHint: true, - openWorldHint: false, - destructiveHint: false, + readOnlyHint: true, // Reads and parses a local file; does not modify the file on disk. + openWorldHint: false, // Operates on a local filesystem path, not the open web. + destructiveHint: false, // Read-only parsing; no deletion or writes to the source file. }, description: ` Parse a file from the local filesystem using a self-hosted Firecrawl API's /v2/parse endpoint. diff --git a/src/monitor.ts b/src/monitor.ts index 9850705..ca53e98 100644 --- a/src/monitor.ts +++ b/src/monitor.ts @@ -160,9 +160,9 @@ export function registerMonitorTools(server: FastMCP): void { name: 'firecrawl_monitor_create', annotations: { title: 'Create monitor', - readOnlyHint: false, - openWorldHint: true, - destructiveHint: false, + readOnlyHint: false, // Creates a new recurring monitor configuration on the Firecrawl API. + openWorldHint: true, // Monitors user-specified URLs on the public web on a recurring schedule. + destructiveHint: false, // Additive; creates a new monitor without deleting existing monitors or external content. }, description: ` Create a Firecrawl monitor — a recurring scrape or crawl that diffs each result against the last retained snapshot. @@ -289,9 +289,9 @@ Full \`body\` requests require: \`name\`, \`schedule\` (with \`cron\` or \`text\ name: 'firecrawl_monitor_list', annotations: { title: 'List monitors', - readOnlyHint: true, - openWorldHint: false, - destructiveHint: false, + readOnlyHint: true, // Lists monitors for the authenticated account; no mutations. + openWorldHint: false, // Returns only the user's Firecrawl monitor records, not arbitrary web content. + destructiveHint: false, // Read-only listing. }, description: ` List all Firecrawl monitors for the authenticated account. @@ -321,9 +321,9 @@ List all Firecrawl monitors for the authenticated account. name: 'firecrawl_monitor_get', annotations: { title: 'Get monitor', - readOnlyHint: true, - openWorldHint: false, - destructiveHint: false, + readOnlyHint: true, // Fetches a single monitor by ID; no mutations. + openWorldHint: false, // Reads a specific monitor resource in the user's Firecrawl account. + destructiveHint: false, // Read-only retrieval. }, description: ` Get a single monitor by ID. @@ -351,9 +351,9 @@ Get a single monitor by ID. name: 'firecrawl_monitor_update', annotations: { title: 'Update monitor', - readOnlyHint: false, - openWorldHint: true, - destructiveHint: true, + readOnlyHint: false, // PATCHes an existing monitor (status, schedule, targets, webhooks, etc.). + openWorldHint: true, // Can change which external URLs are monitored and how recurring scrapes run. + destructiveHint: true, // Can pause, replace, or remove monitor configuration; changes overwrite prior settings. }, description: ` Update a monitor. Pass any subset of fields to patch: \`name\`, \`status\` ("active" | "paused"), \`schedule\`, \`targets\`, \`goal\`, \`judgeEnabled\`, \`webhook\`, \`notification\`, \`retentionDays\`. @@ -394,9 +394,9 @@ Update a monitor. Pass any subset of fields to patch: \`name\`, \`status\` ("act name: 'firecrawl_monitor_delete', annotations: { title: 'Delete monitor', - readOnlyHint: false, - destructiveHint: true, - openWorldHint: true, + readOnlyHint: false, // Permanently deletes a monitor via DELETE on the API. + openWorldHint: true, // Deletes a monitor that tracked open-web URLs. + destructiveHint: true, // Irreversibly removes the monitor and stops its schedule. }, description: ` Permanently delete a monitor and stop its schedule. This cannot be undone. @@ -426,9 +426,9 @@ Permanently delete a monitor and stop its schedule. This cannot be undone. name: 'firecrawl_monitor_run', annotations: { title: 'Run monitor now', - readOnlyHint: false, - openWorldHint: true, - destructiveHint: false, + readOnlyHint: false, // Triggers an immediate monitor check, queueing a new scrape/diff run. + openWorldHint: true, // The triggered check scrapes external URLs configured on the monitor. + destructiveHint: false, // Starts a read-only check job; does not delete the monitor or external sites. }, description: ` Trigger a monitor check immediately, outside its normal schedule. Returns the queued check. @@ -457,9 +457,9 @@ Trigger a monitor check immediately, outside its normal schedule. Returns the qu name: 'firecrawl_monitor_checks', annotations: { title: 'List monitor checks', - readOnlyHint: true, - openWorldHint: false, - destructiveHint: false, + readOnlyHint: true, // Lists historical check runs for a monitor; no mutations. + openWorldHint: false, // Returns check history for a known monitor ID within the user's account. + destructiveHint: false, // Read-only listing. }, description: ` List historical checks for a monitor. @@ -498,9 +498,9 @@ List historical checks for a monitor. name: 'firecrawl_monitor_check', annotations: { title: 'Get monitor check', - readOnlyHint: true, - openWorldHint: false, - destructiveHint: false, + readOnlyHint: true, // Retrieves a single check run with page-level diff results; no mutations. + openWorldHint: false, // Reads stored check results for a known monitor/check ID in the user's account. + destructiveHint: false, // Read-only retrieval of diff snapshots and judgments. }, description: ` Get a single check with page-level diff results. Filter \`pageStatus\` to surface only the pages that changed (or were new, removed, etc.). diff --git a/src/research.ts b/src/research.ts index b3f8c45..9fc5958 100644 --- a/src/research.ts +++ b/src/research.ts @@ -236,9 +236,9 @@ export function registerResearchTools( name: 'firecrawl_research_search_papers', annotations: { title: 'Search arXiv papers', - readOnlyHint: true, - openWorldHint: true, - destructiveHint: false, + readOnlyHint: true, // Semantic search over indexed arXiv metadata; returns ranked results only. + openWorldHint: true, // Searches the public arXiv research corpus. + destructiveHint: false, // Query-only; no writes to arXiv or the research index. }, description: 'Primary entry point for finding arXiv papers by topic. Semantic (HyDE) search over arXiv ' + @@ -304,8 +304,9 @@ export function registerResearchTools( name: 'firecrawl_research_inspect_paper', annotations: { title: 'Inspect a paper', - readOnlyHint: true, - openWorldHint: true, + readOnlyHint: true, // Fetches canonical metadata (title, abstract, authors) for one paper by ID. + openWorldHint: true, // Retrieves metadata for papers in public indexes (arXiv, PMC, DOI, etc.). + destructiveHint: false, // Read-only metadata lookup. }, description: 'Fetch canonical metadata for one paper by primaryId or canonical paperId. ' + @@ -337,9 +338,9 @@ export function registerResearchTools( name: 'firecrawl_research_related_papers', annotations: { title: 'Find related arXiv papers', - readOnlyHint: true, - openWorldHint: true, - destructiveHint: false, + readOnlyHint: true, // Finds related papers via citation graph expansion; returns candidates only. + openWorldHint: true, // Traverses relationships across the public research paper corpus. + destructiveHint: false, // Read-only graph query; no modifications. }, description: 'Expand from anchor papers you have already found, via the citation graph, ranked and filtered ' + @@ -401,9 +402,9 @@ export function registerResearchTools( name: 'firecrawl_research_read_paper', annotations: { title: 'Read a paper', - readOnlyHint: true, - openWorldHint: true, - destructiveHint: false, + readOnlyHint: true, // Retrieves relevant full-text passages from a paper; does not modify the paper. + openWorldHint: true, // Reads from publicly indexed paper full text when available. + destructiveHint: false, // Read-only passage retrieval. }, description: 'Read the most relevant in-body (full-text) passages of ONE specific paper for a question. Use ' + @@ -454,9 +455,9 @@ export function registerResearchTools( name: 'firecrawl_research_search_github', annotations: { title: 'Search GitHub history', - readOnlyHint: true, - openWorldHint: true, - destructiveHint: false, + readOnlyHint: true, // Searches indexed GitHub issue/PR history and READMEs; returns matches only. + openWorldHint: true, // Searches public GitHub content. + destructiveHint: false, // Query-only; does not create issues, PRs, or modify repositories. }, description: 'Search GitHub issue/PR history and repository readmes. Returns ranked matches with repo, ' +