@mseep/firecrawl-simple-mcp
Version:
MCP server for Firecrawl Simple — a web scraping and site mapping tool enabling LLMs to access and process web content
19 lines (17 loc) • 8.28 kB
JavaScript
import {FastMCP,UserError}from'fastmcp';import $ from'pino';import {z}from'zod';import {FirecrawlClient}from'firecrawl-simple-client';// Firecrawl Simple MCP Server - https://github.com/firecrawl/firecrawl-simple-mcp
var o=$();function C(e){let r=e.port??3003,t=e.tools,i=e.transportType??"stdio",l=e.version??"1.0.0",s=new FastMCP({name:"Firecrawl Simple MCP",version:l}),f=false;for(let n of t)s.addTool({name:n.name,description:n.description,parameters:n.parameters,execute:async(h,P)=>{try{return o.info(`Executing tool: ${n.name}`,{toolName:n.name}),await n.execute(h,P)}catch(d){throw d instanceof UserError||o.error(`Error executing tool ${n.name}`,d,{toolName:n.name}),d}}});return {start:async()=>{if(f){o.warn("Server is already running");return}try{let n=i==="sse"?{transportType:"sse",sse:{endpoint:"/sse",port:r}}:{transportType:"stdio"};await s.start(n),f=!0,o.info(`MCP Server started successfully with ${i} transport`,{transportType:i}),i==="sse"&&o.info(`Server listening on port ${String(r)}`,{port:r});}catch(n){throw o.error("Failed to start MCP Server",n),new Error(`Server start failed: ${n instanceof Error?n.message:String(n)}`)}},stop:async()=>{if(!f){o.warn("Server is not running");return}try{await s.stop(),f=!1,o.info("MCP Server stopped");}catch(n){throw o.error("Failed to stop MCP Server",n),new Error(`Server stop failed: ${n instanceof Error?n.message:String(n)}`)}},getPort:()=>r}}var I="1.0.2",F=z.object({port:z.number().int().positive().default(3003),transportType:z.enum(["stdio","sse"]).default("stdio"),logLevel:z.enum(["DEBUG","INFO","WARN","ERROR"]).default("INFO")}),L=z.object({url:z.string().url().default("http://localhost:3002/v1"),key:z.string().optional(),timeout:z.number().int().positive().default(3e4)}),E=z.object({version:z.string().default("1.0.0"),api:L,server:F});function M(){try{let e={version:I,api:{url:process.env.FIRECRAWL_API_URL??"http://localhost:3002/v1",key:process.env.FIRECRAWL_API_KEY,timeout:parseInt(process.env.FIRECRAWL_API_TIMEOUT??"30000",10)},server:{port:parseInt(process.env.FIRECRAWL_SERVER_PORT??"3003",10),transportType:process.env.FIRECRAWL_TRANSPORT_TYPE??"stdio",logLevel:process.env.FIRECRAWL_LOG_LEVEL??"INFO"}};return E.parse(e)}catch(e){if(e instanceof z.ZodError){let r=e.errors.map(t=>` - ${t.path.join(".")}: ${t.message}`).join(`
`);o.error({err:e},`Configuration validation errors:
${r}`);}else o.error({err:e},"Configuration error: "+(e instanceof Error?e.message:String(e)));return o.info("Using default configuration"),E.parse({})}}var u=M();function T(e){if(e instanceof Error){let r=e.message;return r.toLowerCase().includes("validation")?`Validation Error: ${r}`:r.toLowerCase().includes("api")?`API Error: ${r}`:A(e)?`Network Error: ${r}. Please check your connection and try again.`:O(e)?`Timeout Error: ${r}. Please try again with a longer timeout or a simpler request.`:`Error: ${r}`}return "An unknown error occurred"}function A(e){let r=e.message.toLowerCase();return r.includes("econnrefused")||r.includes("econnreset")||r.includes("socket hang up")||r.includes("network")}function O(e){let r=e.message.toLowerCase();return r.includes("timeout")||r.includes("timed out")||r.includes("etimedout")}var p=class extends Error{constructor(r){super(r),this.name="ValidationError";}};function R(e,r){let t=r.operation?` during ${r.operation}`:"";return o.error(`Error in ${r.toolName}${t}`,e,{toolName:r.toolName,operation:r.operation,input:r.input}),{content:[{type:"text",text:T(e)}],isError:true}}function g({name:e,description:r,schema:t,execute:i}){return {name:e,description:r,parameters:t,execute:async l=>{try{let s=t.parse(l);return o.info({params:s},`Executing ${e} tool`),await i(s)}catch(s){return R(s,{toolName:e,operation:"execution"})}}}}function v(e){return {content:[{type:"text",text:e}],isError:false}}function b(e){return v(JSON.stringify(e,null,2))}var S=null;function w(){return S||(o.debug("Creating new FirecrawlClient instance"),S=new FirecrawlClient({apiUrl:u.api.url,apiKey:u.api.key})),S}var _=z.object({url:z.string().url().describe("The URL to scrape (required)"),formats:z.array(z.enum(["markdown","rawHtml","screenshot"])).optional().default(["markdown"]).describe("Formats to include in the output"),includeTags:z.array(z.string()).optional().describe("HTML tags to include in the scraped result"),excludeTags:z.array(z.string()).optional().describe("HTML tags to exclude from the scraped result"),headers:z.record(z.string()).optional().describe("Custom HTTP headers to send with the request"),waitFor:z.number().optional().describe("Milliseconds to wait for JavaScript execution before scraping"),timeout:z.number().optional().default(3e4).describe("Request timeout in milliseconds")}),x=g({name:"firecrawl_scrape",description:"Scrape content from a URL with JavaScript rendering support",schema:_,async execute(e){let r={url:e.url,formats:e.formats,waitFor:e.waitFor,timeout:e.timeout,includeTags:e.includeTags,excludeTags:e.excludeTags,headers:e.headers},i=await w().scrapeWebpage(r);if(!i)throw new p("Failed to scrape webpage: No result returned");return b(i)}});var W=z.object({url:z.string().url().describe("The URL to start mapping from (required)"),search:z.string().optional().describe("Search query to use for mapping"),ignoreSitemap:z.boolean().optional().default(true).describe("Whether to ignore the website's sitemap"),includeSubdomains:z.boolean().optional().default(false).describe("Include subdomains of the website"),limit:z.number().optional().default(5e3).describe("Maximum number of links to return")}),y=g({name:"firecrawl_map",description:"Generate a sitemap of a given site",schema:W,execute:async e=>{let t=await w().generateSitemap({url:e.url,search:e.search,ignoreSitemap:e.ignoreSitemap,includeSubdomains:e.includeSubdomains,limit:e.limit});if(!t||typeof t!="object"||!("success"in t))throw new p("Invalid sitemap result: missing success flag");if(!t.success)throw new p("Sitemap generation failed");let i=t,l=Array.isArray(i.links)?i.links:[],s=`# Sitemap for ${e.url}
`;return l.length===0?s+=`No URLs found in the sitemap.
`:(s+=`Found ${String(l.length)} URLs:
`,l.forEach((n,h)=>{s+=`${String(h+1)}. ${n}
`;})),v(s)}});var V=`
\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
\u2551 \u2551
\u2551 Firecrawl Simple MCP Server \u2551
\u2551 Web scraping capabilities for LLMs via MCP \u2551
\u2551 \u2551
\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
`;async function j(){o.info(V),o.info("Starting Firecrawl Simple MCP Server"),o.info({apiUrl:u.api.url},`API URL: ${u.api.url}`),o.info({version:u.version},`Version: ${u.version}`);let e=[x,y],r=C({tools:e,port:u.server.port,transportType:u.server.transportType,version:u.version});G(r);try{await r.start(),o.info("MCP Server started successfully"),o.info("Available tools:"),e.forEach(t=>{o.info({toolName:t.name},`- ${t.name}: ${t.description??"No description"}`);});}catch(t){o.error({err:t},"Failed to start MCP Server"),process.exit(1);}}function G(e){process.on("SIGINT",()=>{o.info("Shutting down MCP Server..."),e.stop().then(()=>{process.exit(0);}).catch(r=>{o.error({err:r},"Error during shutdown"),process.exit(1);});}),process.on("SIGTERM",()=>{o.info("Shutting down MCP Server..."),e.stop().then(()=>{process.exit(0);}).catch(r=>{o.error({err:r},"Error during shutdown"),process.exit(1);});});}j().catch(e=>{o.error({err:e},"Unhandled error"),process.exit(1);});//# sourceMappingURL=index.js.map
//# sourceMappingURL=index.js.map