crawlforge-mcp-server 6.19.0 → 6.19.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "crawlforge-mcp-server",
3
- "version": "6.19.0",
3
+ "version": "6.19.2",
4
4
  "mcpName": "io.github.mysleekdesigns/crawlforge-mcp-server",
5
5
  "description": "CrawlForge MCP Server - Professional Model Context Protocol server with 31 web scraping, crawling, deep-research, and autonomous-extraction tools. Returns clean Markdown and structured JSON for Claude, Cursor, and any MCP client. Defaults to local Ollama for LLM extraction (no API key needed); OpenAI/Anthropic available as opt-in. Includes a unified multi-format scrape tool, an autonomous agent, pre-built site templates, and Camoufox stealth browsing.",
6
6
  "main": "server.js",
package/server.js CHANGED
@@ -113,7 +113,7 @@ if (configErrors.length > 0 && config.server.nodeEnv === 'production') {
113
113
  // Create the server
114
114
  const server = new McpServer({
115
115
  name: "crawlforge",
116
- version: "6.19.0",
116
+ version: "6.19.2",
117
117
  description: "Production-ready MCP server with 31 web scraping, crawling, and content processing tools. Features MCP Resources (crawlforge://), Prompts, Sampling fallback, Elicitation, stealth browsing, stateful browser sessions with element refs, deep research, structured extraction, embedded JavaScript state extraction, real Google SERP rank tracking, Reddit search via community archives, change tracking, local-LLM extraction via Ollama, unified multi-format scrape, and autonomous agent tool.",
118
118
  homepage: "https://www.crawlforge.dev",
119
119
  icon: "https://www.crawlforge.dev/icon.png",
@@ -597,7 +597,7 @@ registerToolIfEnabled("serp_rank", {
597
597
  location_code: z.number().optional().describe("Numeric DataForSEO location code (overrides location_name)"),
598
598
  language_code: z.string().optional().describe("Language code (e.g. 'en')"),
599
599
  device: z.enum(["desktop", "mobile"]).optional().describe("Device to emulate"),
600
- depth: z.number().min(10).max(200).optional().describe("How many results to scan, 10-200 (default 20; DataForSEO bills ~$0.002 per 10 and gets slower the deeper it goes)")
600
+ depth: z.number().min(10).max(200).optional().describe("How many results to scan, 10-200 (default 30; DataForSEO bills ~$0.002 per 10 and gets slower the deeper it goes)")
601
601
  },
602
602
  outputSchema: OUTPUT_SCHEMAS.serp_rank
603
603
  }, withAuth("serp_rank", async ({ keyword, target, location_name, location_code, language_code, device, depth }) => {
@@ -399,11 +399,15 @@ export class LocalizationManager extends EventEmitter {
399
399
  // Configure geolocation
400
400
  geolocation: config.geoLocation || this.getCountryCoordinates(targetCountry) || undefined,
401
401
 
402
- // Set HTTP headers
402
+ // Set HTTP headers. A context's extraHTTPHeaders go on every request, so
403
+ // each must be one CORS ignores (a forbidden name: Accept-Encoding, DNT)
404
+ // or safelisted (Accept-Language). Cache-Control is neither: it turned
405
+ // every cross-origin CORS fetch into a preflighted one, which a server
406
+ // answering no OPTIONS refuses — the stealth headers broke Cloudflare's
407
+ // Turnstile the same way (R24).
403
408
  extraHTTPHeaders: {
404
409
  'Accept-Language': config.acceptLanguage,
405
410
  'Accept-Encoding': 'gzip, deflate, br',
406
- 'Cache-Control': 'no-cache',
407
411
  'DNT': '1',
408
412
  ...config.customHeaders,
409
413
  ...browserOptions.extraHTTPHeaders
@@ -963,7 +967,6 @@ export class LocalizationManager extends EventEmitter {
963
967
  return {
964
968
  "Accept-Language": this.generateAcceptLanguageHeader(config.language),
965
969
  "Accept-Encoding": "gzip, deflate, br",
966
- "Cache-Control": "no-cache",
967
970
  "DNT": "1"
968
971
  };
969
972
  }
@@ -12,8 +12,8 @@
12
12
  * POST https://api.dataforseo.com/v3/serp/google/organic/live/advanced
13
13
  *
14
14
  * Cost: US$0.002 per 10 results of `depth` on Live Advanced — measured live,
15
- * not estimated: depth 10 bills $0.002, the depth 20 default bills $0.004, and
16
- * depth 100 bills $0.02. Deeper scans are also slower (see the timeout note
15
+ * not estimated: depth 10 bills $0.002, depth 20 bills $0.004, and depth 100
16
+ * bills $0.02, so the depth 30 default is $0.006. Deeper scans are also slower (see the timeout note
17
17
  * below), so raise `depth` only when a rank below the default is worth paying
18
18
  * for. For high-volume scheduled tracking, DataForSEO's task-based "Standard"
19
19
  * queue (task_post → tasks_ready → task_get) is cheaper; swap the endpoint +
@@ -51,7 +51,7 @@ export class DataForSEOSearchAdapter {
51
51
  * @param {number} [params.locationCode] - Numeric DataForSEO location code (overrides locationName)
52
52
  * @param {string} [params.languageCode='en'] - Language code
53
53
  * @param {('desktop'|'mobile')} [params.device='desktop'] - Device to emulate
54
- * @param {number} [params.depth=20] - How many results to scan (billed per 10)
54
+ * @param {number} [params.depth=30] - How many results to scan (billed per 10)
55
55
  * @returns {Promise<{items: Array<Object>, meta: Object}>} Normalized organic results + metadata
56
56
  */
57
57
  async search(params) {
@@ -61,7 +61,7 @@ export class DataForSEOSearchAdapter {
61
61
  locationCode,
62
62
  languageCode = 'en',
63
63
  device = 'desktop',
64
- depth = 20,
64
+ depth = 30,
65
65
  } = params;
66
66
 
67
67
  if (!keyword) {
@@ -27,7 +27,7 @@ const SerpRankSchema = z.object({
27
27
  // DataForSEO bills per 10 results scanned and gets slower the deeper it goes,
28
28
  // so the default stays shallow: 20 covers Google's first two pages for $0.004.
29
29
  // Raise it (max 200, their cap) when a deeper position is worth the spend.
30
- depth: z.number().int().min(10).max(200).optional().default(20),
30
+ depth: z.number().int().min(10).max(200).optional().default(30),
31
31
  });
32
32
 
33
33
  /** Reduce a domain or URL to a bare, comparable host: "https://www.Example.com/x" → "example.com".