MCP Server Firecrawl
by Msparihar
- src
- tools
import { AxiosInstance } from "axios";
import { ErrorHandlingConfig, retryRequest } from "../error-handling.js";
import { ScrapeUrlArgs } from "../types.js";
/**
* Options for configuring the scrape tool
*/
export interface ScrapeToolOptions {
/** Axios instance for making requests */
axiosInstance: AxiosInstance;
/** Error handling configuration */
errorConfig: ErrorHandlingConfig;
}
/**
* Handles content scraping operations
*/
export class ScrapeTool {
private axiosInstance: AxiosInstance;
private errorConfig: ErrorHandlingConfig;
constructor(options: ScrapeToolOptions) {
this.axiosInstance = options.axiosInstance;
this.errorConfig = options.errorConfig;
}
/**
* Get the tool definition for registration
*/
getDefinition() {
return {
name: "scrape_url",
description: "Scrape content from a URL using Firecrawl API",
inputSchema: {
type: "object",
properties: {
url: {
type: "string",
description: "URL to scrape",
},
jsonOptions: {
type: "object",
properties: {
prompt: {
type: "string",
description: "Prompt for extracting specific information",
},
schema: {
type: "object",
description: "Schema for extraction",
},
systemPrompt: {
type: "string",
description: "System prompt for extraction",
},
},
},
formats: {
type: "array",
items: {
type: "string",
enum: [
"markdown",
"html",
"rawHtml",
"links",
"screenshot",
"screenshot@fullPage",
"json",
],
},
description: "Output formats",
},
onlyMainContent: {
type: "boolean",
description:
"Only return main content excluding headers, navs, footers",
default: true,
},
includeTags: {
type: "array",
items: { type: "string" },
description: "Tags to include in output",
},
excludeTags: {
type: "array",
items: { type: "string" },
description: "Tags to exclude from output",
},
waitFor: {
type: "number",
description: "Delay in milliseconds before fetching content",
default: 0,
},
mobile: {
type: "boolean",
description: "Emulate mobile device",
default: false,
},
location: {
type: "object",
properties: {
country: {
type: "string",
description: "ISO 3166-1 alpha-2 country code",
},
languages: {
type: "array",
items: { type: "string" },
description: "Preferred languages/locales",
},
},
},
blockAds: {
type: "boolean",
description: "Enable ad/cookie popup blocking",
default: true,
},
},
required: ["url"],
},
};
}
/**
* Execute the scrape operation
*/
async execute(args: ScrapeUrlArgs) {
const response = await retryRequest(
() => this.axiosInstance.post("/scrape", args),
this.errorConfig
);
return {
content: [
{
type: "text",
text: JSON.stringify(response.data, null, 2),
},
],
};
}
/**
* Validate the scrape operation arguments
*/
validate(args: unknown): args is ScrapeUrlArgs {
if (typeof args !== "object" || args === null) {
return false;
}
const { url, jsonOptions, formats } = args as any;
if (typeof url !== "string") {
return false;
}
if (jsonOptions !== undefined) {
if (
typeof jsonOptions !== "object" ||
jsonOptions === null ||
typeof jsonOptions.prompt !== "string"
) {
return false;
}
}
if (formats !== undefined) {
if (
!Array.isArray(formats) ||
!formats.every((f) => typeof f === "string")
) {
return false;
}
}
return true;
}
}