firecrawl_mcp/controller/
search.rs1use async_claude::define_tool;
2use firecrawl_sdk::search::SearchInput;
3use rmcp::{handler::server::tool::parse_json_object, model::JsonObject};
4
5use crate::controller::FirecrawlMCP;
6
7pub const SEARCH_TOOL_NAME: &str = "firecrawl_search";
8pub const SEARCH_TOOL_DESCRIPTION: &str = "Search and retrieve content from web pages with optional scraping. Returns SERP results by default (url, title, description) or full page content when scrapeOptions are provided.";
9
10define_tool!(
11 FIRECRAWL_SEARCH,
12 SEARCH_TOOL_NAME,
13 SEARCH_TOOL_DESCRIPTION,
14 SearchInput
15);
16
17impl FirecrawlMCP {
18 pub async fn search(&self, input: JsonObject) -> Result<String, rmcp::Error> {
19 let options = parse_json_object::<SearchInput>(input)?;
21
22 let results = self
24 .client
25 .search(options.query, Some(options.options))
26 .await
27 .map_err(|e| rmcp::Error::internal_error(e.to_string(), None))?;
28
29 if results.is_empty() {
31 return Ok("No search results found.".to_string());
32 }
33
34 let formatted = results
35 .iter()
36 .map(|r| {
37 format!(
38 "Title: {}\nURL: {}\nDescription: {}\n",
39 r.title, r.url, r.description
40 )
41 })
42 .collect::<Vec<_>>()
43 .join("\n---\n\n");
44
45 Ok(formatted)
46 }
47}