crawlforge-mcp-server 4.2.11 → 4.2.12
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 +1 -1
- package/server.js +14 -1
- package/src/core/StealthBrowserManager.js +59 -27
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "crawlforge-mcp-server",
|
|
3
|
-
"version": "4.2.
|
|
3
|
+
"version": "4.2.12",
|
|
4
4
|
"description": "CrawlForge MCP Server - Professional Model Context Protocol server with 23 web scraping, crawling, and content processing tools. Defaults to local Ollama for LLM extraction (no API key needed); OpenAI/Anthropic available as opt-in. v4.0 adds Markdown-first output, pre-built site templates, Camoufox stealth engine, and cost transparency.",
|
|
5
5
|
"main": "server.js",
|
|
6
6
|
"bin": {
|
package/server.js
CHANGED
|
@@ -899,7 +899,20 @@ server.registerTool("stealth_mode", {
|
|
|
899
899
|
case 'create_page': {
|
|
900
900
|
if (!contextId) throw new Error('contextId is required for create_page operation');
|
|
901
901
|
const page = await stealthBrowserManager.createStealthPage(contextId);
|
|
902
|
-
|
|
902
|
+
let navigation = null;
|
|
903
|
+
if (urlToTest) {
|
|
904
|
+
// page.goto returns a Playwright Response handle, which is not
|
|
905
|
+
// JSON-serializable — extract just the useful navigation details.
|
|
906
|
+
const response = await page.goto(urlToTest);
|
|
907
|
+
navigation = {
|
|
908
|
+
requestedUrl: urlToTest,
|
|
909
|
+
finalUrl: page.url(),
|
|
910
|
+
status: response ? response.status() : null,
|
|
911
|
+
ok: response ? response.ok() : null,
|
|
912
|
+
title: await page.title().catch(() => null)
|
|
913
|
+
};
|
|
914
|
+
}
|
|
915
|
+
result = { pageCreated: true, contextId, navigation };
|
|
903
916
|
break;
|
|
904
917
|
}
|
|
905
918
|
case 'get_stats':
|
|
@@ -390,8 +390,11 @@ export class StealthBrowserManager {
|
|
|
390
390
|
* Generate advanced browser fingerprint with enhanced randomization
|
|
391
391
|
*/
|
|
392
392
|
generateAdvancedFingerprint(config = {}) {
|
|
393
|
+
// Select the OS once and thread it through UA, headers, and hardware so
|
|
394
|
+
// navigator.platform / sec-ch-ua-platform / userAgent stay consistent.
|
|
395
|
+
const selectedOS = this.selectOS(config);
|
|
393
396
|
const fingerprint = {
|
|
394
|
-
userAgent: this.selectRealisticUserAgent(config),
|
|
397
|
+
userAgent: this.selectRealisticUserAgent(config, selectedOS),
|
|
395
398
|
viewport: config.customViewport || this.selectWeightedViewport(),
|
|
396
399
|
timezone: config.timezone || this.selectTimezone(),
|
|
397
400
|
deviceScaleFactor: this.randomFloat(1, 2, 1),
|
|
@@ -400,13 +403,13 @@ export class StealthBrowserManager {
|
|
|
400
403
|
colorScheme: Math.random() < 0.3 ? 'dark' : 'light',
|
|
401
404
|
reducedMotion: Math.random() < 0.1 ? 'reduce' : 'no-preference',
|
|
402
405
|
forcedColors: Math.random() < 0.05 ? 'active' : 'none',
|
|
403
|
-
headers: this.generateAdvancedHeaders(config),
|
|
406
|
+
headers: this.generateAdvancedHeaders(config, selectedOS),
|
|
404
407
|
webRTC: this.generateWebRTCConfig(config),
|
|
405
408
|
canvas: this.generateAdvancedCanvasFingerprint(),
|
|
406
409
|
webGL: this.generateAdvancedWebGLFingerprint(),
|
|
407
410
|
audioContext: this.generateAudioContextFingerprint(),
|
|
408
411
|
mediaDevices: this.generateMediaDevicesFingerprint(),
|
|
409
|
-
hardware: this.generateHardwareFingerprint(),
|
|
412
|
+
hardware: this.generateHardwareFingerprint(selectedOS),
|
|
410
413
|
fonts: this.generateAdvancedFontList(),
|
|
411
414
|
plugins: this.generateAdvancedPluginList(),
|
|
412
415
|
geolocation: this.generateRealisticGeolocation(),
|
|
@@ -417,10 +420,34 @@ export class StealthBrowserManager {
|
|
|
417
420
|
return fingerprint;
|
|
418
421
|
}
|
|
419
422
|
|
|
423
|
+
/**
|
|
424
|
+
* Choose a single OS ('windows' | 'macos' | 'linux') for a fingerprint.
|
|
425
|
+
* A custom UA pins the OS to whatever that UA reports; a non-random UA pins
|
|
426
|
+
* to windows (the default pool below); otherwise weighted-random.
|
|
427
|
+
*/
|
|
428
|
+
selectOS(config = {}) {
|
|
429
|
+
if (config.customUserAgent) {
|
|
430
|
+
return this.inferOSFromUserAgent(config.customUserAgent);
|
|
431
|
+
}
|
|
432
|
+
if (!config.useRandomUserAgent) {
|
|
433
|
+
return 'windows';
|
|
434
|
+
}
|
|
435
|
+
return this.weightedRandom(this.osDistribution);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* Infer the OS key from a user-agent string.
|
|
440
|
+
*/
|
|
441
|
+
inferOSFromUserAgent(ua = '') {
|
|
442
|
+
if (/Macintosh|Mac OS X/i.test(ua)) return 'macos';
|
|
443
|
+
if (/Linux|X11|CrOS/i.test(ua)) return 'linux';
|
|
444
|
+
return 'windows';
|
|
445
|
+
}
|
|
446
|
+
|
|
420
447
|
/**
|
|
421
448
|
* Select realistic user agent based on market distribution
|
|
422
449
|
*/
|
|
423
|
-
selectRealisticUserAgent(config) {
|
|
450
|
+
selectRealisticUserAgent(config, selectedOS) {
|
|
424
451
|
if (config.customUserAgent) {
|
|
425
452
|
return config.customUserAgent;
|
|
426
453
|
}
|
|
@@ -429,9 +456,10 @@ export class StealthBrowserManager {
|
|
|
429
456
|
return this.userAgentPools.chrome.windows[0];
|
|
430
457
|
}
|
|
431
458
|
|
|
432
|
-
//
|
|
433
|
-
|
|
434
|
-
|
|
459
|
+
// Use the OS chosen once for this fingerprint (falls back to a fresh draw
|
|
460
|
+
// if called without one, preserving the original standalone behavior).
|
|
461
|
+
selectedOS = selectedOS || this.weightedRandom(this.osDistribution);
|
|
462
|
+
|
|
435
463
|
// Select browser based on distribution and OS compatibility
|
|
436
464
|
let availableBrowsers = { ...this.browserDistribution };
|
|
437
465
|
if (selectedOS === 'linux' && availableBrowsers.safari) {
|
|
@@ -469,7 +497,7 @@ export class StealthBrowserManager {
|
|
|
469
497
|
/**
|
|
470
498
|
* Generate advanced HTTP headers with realistic patterns
|
|
471
499
|
*/
|
|
472
|
-
generateAdvancedHeaders(config) {
|
|
500
|
+
generateAdvancedHeaders(config, selectedOS) {
|
|
473
501
|
const headers = {
|
|
474
502
|
'Accept-Language': `${(config.locale || 'en-US').toLowerCase()},en;q=0.9`,
|
|
475
503
|
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
|
|
@@ -481,7 +509,7 @@ export class StealthBrowserManager {
|
|
|
481
509
|
'Sec-Fetch-Site': 'none',
|
|
482
510
|
'Sec-Fetch-User': '?1',
|
|
483
511
|
'sec-ch-ua-mobile': '?0',
|
|
484
|
-
'sec-ch-ua-platform': this.generateSecChUaPlatform()
|
|
512
|
+
'sec-ch-ua-platform': this.generateSecChUaPlatform(selectedOS)
|
|
485
513
|
};
|
|
486
514
|
|
|
487
515
|
// Add sec-ch-ua header
|
|
@@ -522,14 +550,14 @@ export class StealthBrowserManager {
|
|
|
522
550
|
/**
|
|
523
551
|
* Generate sec-ch-ua-platform header
|
|
524
552
|
*/
|
|
525
|
-
generateSecChUaPlatform() {
|
|
553
|
+
generateSecChUaPlatform(selectedOS) {
|
|
526
554
|
const platforms = {
|
|
527
555
|
windows: '"Windows"',
|
|
528
556
|
macos: '"macOS"',
|
|
529
557
|
linux: '"Linux"'
|
|
530
558
|
};
|
|
531
|
-
|
|
532
|
-
|
|
559
|
+
|
|
560
|
+
selectedOS = selectedOS || this.weightedRandom(this.osDistribution);
|
|
533
561
|
return platforms[selectedOS] || '"Windows"';
|
|
534
562
|
}
|
|
535
563
|
|
|
@@ -746,7 +774,9 @@ export class StealthBrowserManager {
|
|
|
746
774
|
/**
|
|
747
775
|
* Generate realistic hardware fingerprint
|
|
748
776
|
*/
|
|
749
|
-
generateHardwareFingerprint() {
|
|
777
|
+
generateHardwareFingerprint(selectedOS) {
|
|
778
|
+
selectedOS = selectedOS || this.weightedRandom(this.osDistribution);
|
|
779
|
+
|
|
750
780
|
const processors = [
|
|
751
781
|
{ cores: 4, threads: 8, name: 'Intel(R) Core(TM) i5-8250U CPU @ 1.60GHz' },
|
|
752
782
|
{ cores: 6, threads: 12, name: 'Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz' },
|
|
@@ -755,31 +785,33 @@ export class StealthBrowserManager {
|
|
|
755
785
|
{ cores: 6, threads: 6, name: 'AMD Ryzen 5 3600 6-Core Processor' },
|
|
756
786
|
{ cores: 8, threads: 16, name: 'AMD Ryzen 7 3700X 8-Core Processor' }
|
|
757
787
|
];
|
|
758
|
-
|
|
788
|
+
|
|
759
789
|
const selectedProcessor = processors[Math.floor(Math.random() * processors.length)];
|
|
760
|
-
|
|
790
|
+
|
|
761
791
|
return {
|
|
762
792
|
hardwareConcurrency: selectedProcessor.threads,
|
|
763
793
|
processor: selectedProcessor.name,
|
|
764
|
-
architecture:
|
|
794
|
+
architecture: 'x86_64',
|
|
765
795
|
memory: Math.floor(Math.random() * 24) + 8, // 8-32 GB
|
|
766
796
|
deviceMemory: Math.pow(2, Math.floor(Math.random() * 3) + 3), // 8, 16, or 32 GB
|
|
767
|
-
platform: this.selectRealisticPlatform()
|
|
797
|
+
platform: this.selectRealisticPlatform(selectedOS)
|
|
768
798
|
};
|
|
769
799
|
}
|
|
770
800
|
|
|
771
801
|
/**
|
|
772
|
-
*
|
|
802
|
+
* Map the chosen OS to its navigator.platform value so it stays consistent
|
|
803
|
+
* with the user-agent and sec-ch-ua-platform header.
|
|
773
804
|
*/
|
|
774
|
-
selectRealisticPlatform() {
|
|
775
|
-
|
|
776
|
-
'
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
805
|
+
selectRealisticPlatform(selectedOS) {
|
|
806
|
+
switch (selectedOS) {
|
|
807
|
+
case 'macos':
|
|
808
|
+
return 'MacIntel';
|
|
809
|
+
case 'linux':
|
|
810
|
+
return 'Linux x86_64';
|
|
811
|
+
case 'windows':
|
|
812
|
+
default:
|
|
813
|
+
return 'Win32';
|
|
814
|
+
}
|
|
783
815
|
}
|
|
784
816
|
|
|
785
817
|
/**
|