@jshookmcp/jshook 0.1.5 → 0.1.6
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/LICENSE +661 -661
- package/README.md +72 -40
- package/README.zh.md +77 -40
- package/dist/constants.d.ts +1 -0
- package/dist/constants.js +13 -1
- package/dist/modules/analyzer/IntelligentAnalyzer.js +19 -11
- package/dist/modules/browser/BrowserModeManager.d.ts +5 -0
- package/dist/modules/browser/BrowserModeManager.js +96 -10
- package/dist/modules/browser/CamoufoxBrowserManager.d.ts +4 -0
- package/dist/modules/browser/CamoufoxBrowserManager.js +64 -3
- package/dist/modules/browser/TabRegistry.js +3 -2
- package/dist/modules/browser/UnifiedBrowserManager.d.ts +5 -0
- package/dist/modules/browser/UnifiedBrowserManager.js +62 -9
- package/dist/modules/captcha/AICaptchaDetector.js +185 -185
- package/dist/modules/debugger/DebuggerSessionManager.d.ts +4 -0
- package/dist/modules/debugger/DebuggerSessionManager.js +29 -19
- package/dist/modules/debugger/ScriptManager.impl.class.d.ts +4 -0
- package/dist/modules/debugger/ScriptManager.impl.class.js +46 -21
- package/dist/modules/emulator/EnvironmentEmulator.js +2 -2
- package/dist/modules/monitor/NetworkMonitor.impl.d.ts +1 -0
- package/dist/modules/monitor/NetworkMonitor.impl.js +22 -15
- package/dist/modules/monitor/PerformanceMonitor.js +64 -32
- package/dist/modules/process/LinuxProcessManager.d.ts +3 -1
- package/dist/modules/process/LinuxProcessManager.js +7 -3
- package/dist/modules/process/MacProcessManager.d.ts +3 -1
- package/dist/modules/process/MacProcessManager.js +32 -28
- package/dist/modules/process/ProcessManager.impl.d.ts +5 -1
- package/dist/modules/process/ProcessManager.impl.js +54 -13
- package/dist/modules/process/index.d.ts +3 -1
- package/dist/modules/process/index.js +2 -2
- package/dist/modules/process/memory/AuditTrail.d.ts +25 -0
- package/dist/modules/process/memory/AuditTrail.js +44 -0
- package/dist/modules/process/memory/availability.js +49 -49
- package/dist/modules/process/memory/injector.js +185 -185
- package/dist/modules/process/memory/linux/mapsParser.d.ts +16 -0
- package/dist/modules/process/memory/linux/mapsParser.js +28 -0
- package/dist/modules/process/memory/reader.js +50 -50
- package/dist/modules/process/memory/regions.enumerate.js +45 -1
- package/dist/modules/process/memory/regions.protection.js +48 -2
- package/dist/modules/process/memory/scanner.d.ts +4 -1
- package/dist/modules/process/memory/scanner.js +383 -182
- package/dist/modules/process/memory/writer.js +54 -54
- package/dist/native/NativeMemoryManager.impl.d.ts +4 -0
- package/dist/native/NativeMemoryManager.impl.js +72 -24
- package/dist/native/NativeMemoryManager.utils.d.ts +1 -0
- package/dist/native/NativeMemoryManager.utils.js +44 -1
- package/dist/native/scripts/linux/enum-windows.sh +12 -12
- package/dist/native/scripts/macos/enum-windows.applescript +22 -22
- package/dist/native/scripts/windows/enum-windows-by-class.ps1 +51 -51
- package/dist/native/scripts/windows/enum-windows.ps1 +44 -44
- package/dist/native/scripts/windows/inject-dll.ps1 +21 -21
- package/dist/server/MCPServer.search.d.ts +3 -0
- package/dist/server/MCPServer.search.js +21 -2
- package/dist/server/ToolCallContextGuard.d.ts +2 -0
- package/dist/server/ToolCallContextGuard.js +29 -14
- package/dist/server/ToolSearch.js +11 -5
- package/dist/server/domains/browser/definitions.tools.page-core.js +53 -53
- package/dist/server/domains/browser/definitions.tools.runtime.js +40 -40
- package/dist/server/domains/browser/definitions.tools.security.js +76 -76
- package/dist/server/domains/browser/handlers/tab-workflow.js +6 -4
- package/dist/server/domains/maintenance/handlers.extensions.js +46 -26
- package/dist/server/domains/process/definitions.js +20 -7
- package/dist/server/domains/process/handlers.impl.core.runtime.base.d.ts +35 -0
- package/dist/server/domains/process/handlers.impl.core.runtime.base.js +107 -1
- package/dist/server/domains/process/handlers.impl.core.runtime.inject.js +111 -2
- package/dist/server/domains/process/handlers.impl.core.runtime.memory.d.ts +9 -0
- package/dist/server/domains/process/handlers.impl.core.runtime.memory.js +282 -31
- package/dist/server/domains/process/manifest.js +1 -0
- package/dist/server/domains/transform/handlers.impl.transform-base.js +102 -102
- package/dist/server/domains/workflow/handlers.impl.workflow-api.js +14 -4
- package/dist/server/domains/workflow/handlers.impl.workflow-base.js +51 -51
- package/dist/server/registry/discovery.js +17 -12
- package/dist/server/registry/index.js +10 -2
- package/dist/utils/TokenBudgetManager.d.ts +1 -0
- package/dist/utils/TokenBudgetManager.js +22 -0
- package/package.json +5 -1
- package/src/native/scripts/linux/enum-windows.sh +12 -12
- package/src/native/scripts/macos/enum-windows.applescript +22 -22
- package/src/native/scripts/windows/enum-windows-by-class.ps1 +51 -51
- package/src/native/scripts/windows/enum-windows.ps1 +44 -44
- package/src/native/scripts/windows/inject-dll.ps1 +21 -21
|
@@ -28,7 +28,24 @@ function getCombinedTools(ctx) {
|
|
|
28
28
|
}
|
|
29
29
|
return [...tools.values()];
|
|
30
30
|
}
|
|
31
|
-
|
|
31
|
+
const searchEngineCache = new WeakMap();
|
|
32
|
+
export function buildSearchSignature(ctx) {
|
|
33
|
+
const extParts = [];
|
|
34
|
+
for (const [name, record] of ctx.extensionToolsByName) {
|
|
35
|
+
extParts.push(`${name}:${record.domain}`);
|
|
36
|
+
}
|
|
37
|
+
extParts.sort();
|
|
38
|
+
return [
|
|
39
|
+
ctx.currentTier,
|
|
40
|
+
ctx.extensionWorkflowRuntimeById.size,
|
|
41
|
+
extParts.join('|'),
|
|
42
|
+
].join('::');
|
|
43
|
+
}
|
|
44
|
+
export function getSearchEngine(ctx) {
|
|
45
|
+
const signature = buildSearchSignature(ctx);
|
|
46
|
+
const cached = searchEngineCache.get(ctx);
|
|
47
|
+
if (cached && cached.signature === signature)
|
|
48
|
+
return cached.engine;
|
|
32
49
|
const tools = getCombinedTools(ctx);
|
|
33
50
|
const extensionDomains = getExtensionDomainMap(ctx);
|
|
34
51
|
const domainScoreMultipliers = new Map();
|
|
@@ -43,7 +60,9 @@ function getSearchEngine(ctx) {
|
|
|
43
60
|
toolScoreMultipliers.set('run_extension_workflow', 1.35);
|
|
44
61
|
toolScoreMultipliers.set('list_extension_workflows', 1.25);
|
|
45
62
|
}
|
|
46
|
-
|
|
63
|
+
const engine = new ToolSearchEngine(tools, extensionDomains, domainScoreMultipliers, toolScoreMultipliers);
|
|
64
|
+
searchEngineCache.set(ctx, { signature, engine });
|
|
65
|
+
return engine;
|
|
47
66
|
}
|
|
48
67
|
function getToolByName(ctx) {
|
|
49
68
|
return new Map(getCombinedTools(ctx).map((tool) => [tool.name, tool]));
|
|
@@ -8,11 +8,13 @@ interface TabContextProvider {
|
|
|
8
8
|
}
|
|
9
9
|
export declare class ToolCallContextGuard {
|
|
10
10
|
private getProvider;
|
|
11
|
+
private readonly contextSensitiveCache;
|
|
11
12
|
constructor(getProvider: () => TabContextProvider | null);
|
|
12
13
|
isContextSensitive(toolName: string): boolean;
|
|
13
14
|
enrichResponse<T extends {
|
|
14
15
|
content?: unknown[];
|
|
15
16
|
isError?: boolean;
|
|
16
17
|
}>(toolName: string, response: T): T;
|
|
18
|
+
private spliceTabContext;
|
|
17
19
|
}
|
|
18
20
|
export {};
|
|
@@ -14,11 +14,17 @@ const CONTEXT_SENSITIVE_PREFIXES = [
|
|
|
14
14
|
];
|
|
15
15
|
export class ToolCallContextGuard {
|
|
16
16
|
getProvider;
|
|
17
|
+
contextSensitiveCache = new Map();
|
|
17
18
|
constructor(getProvider) {
|
|
18
19
|
this.getProvider = getProvider;
|
|
19
20
|
}
|
|
20
21
|
isContextSensitive(toolName) {
|
|
21
|
-
|
|
22
|
+
const cached = this.contextSensitiveCache.get(toolName);
|
|
23
|
+
if (cached !== undefined)
|
|
24
|
+
return cached;
|
|
25
|
+
const result = CONTEXT_SENSITIVE_PREFIXES.some((p) => toolName.startsWith(p));
|
|
26
|
+
this.contextSensitiveCache.set(toolName, result);
|
|
27
|
+
return result;
|
|
22
28
|
}
|
|
23
29
|
enrichResponse(toolName, response) {
|
|
24
30
|
if (!this.isContextSensitive(toolName))
|
|
@@ -40,21 +46,30 @@ export class ToolCallContextGuard {
|
|
|
40
46
|
typeof c.text === 'string');
|
|
41
47
|
if (!firstText)
|
|
42
48
|
return response;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
52
|
-
|
|
49
|
+
const raw = firstText.text;
|
|
50
|
+
const trimmedStart = raw.trimStart();
|
|
51
|
+
if (trimmedStart.startsWith('{') && trimmedStart.trimEnd().endsWith('}')) {
|
|
52
|
+
try {
|
|
53
|
+
const parsed = JSON.parse(raw);
|
|
54
|
+
if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)) {
|
|
55
|
+
firstText.text = this.spliceTabContext(raw, meta);
|
|
56
|
+
return response;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
logger.debug(`[ContextGuard] Skipped non-JSON response enrichment for ${toolName}`);
|
|
61
|
+
return response;
|
|
53
62
|
}
|
|
54
|
-
}
|
|
55
|
-
catch {
|
|
56
|
-
logger.debug(`[ContextGuard] Skipped non-JSON response enrichment for ${toolName}`);
|
|
57
63
|
}
|
|
58
64
|
return response;
|
|
59
65
|
}
|
|
66
|
+
spliceTabContext(raw, meta) {
|
|
67
|
+
const tabContext = { url: meta.url, title: meta.title, tabIndex: meta.tabIndex, pageId: meta.pageId };
|
|
68
|
+
if (/\n\}\s*$/.test(raw)) {
|
|
69
|
+
const prettyJson = JSON.stringify(tabContext, null, 2).replace(/\n/g, '\n ');
|
|
70
|
+
return raw.replace(/\n\}\s*$/, `,\n "_tabContext": ${prettyJson}\n}`);
|
|
71
|
+
}
|
|
72
|
+
const compactJson = JSON.stringify(tabContext);
|
|
73
|
+
return raw.replace(/\}\s*$/, `,"_tabContext":${compactJson}}`);
|
|
74
|
+
}
|
|
60
75
|
}
|
|
@@ -170,6 +170,7 @@ export class ToolSearchEngine {
|
|
|
170
170
|
const description = tool.description ?? '';
|
|
171
171
|
const shortDescription = extractShortDescription(description);
|
|
172
172
|
const nameTokens = tokenise(tool.name);
|
|
173
|
+
const nameTokenSet = new Set(nameTokens);
|
|
173
174
|
const domainTokens = domain ? tokenise(domain) : [];
|
|
174
175
|
const descTokens = tokenise(description);
|
|
175
176
|
const allTokens = [...nameTokens, ...domainTokens, ...descTokens];
|
|
@@ -180,6 +181,9 @@ export class ToolSearchEngine {
|
|
|
180
181
|
shortDescription,
|
|
181
182
|
tokens: allTokens,
|
|
182
183
|
length: allTokens.length,
|
|
184
|
+
nameTokens,
|
|
185
|
+
nameTokenSet,
|
|
186
|
+
nameTokenCount: nameTokenSet.size,
|
|
183
187
|
};
|
|
184
188
|
this.docs.push(doc);
|
|
185
189
|
totalLength += doc.length;
|
|
@@ -249,11 +253,13 @@ export class ToolSearchEngine {
|
|
|
249
253
|
}
|
|
250
254
|
continue;
|
|
251
255
|
}
|
|
252
|
-
|
|
253
|
-
const
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
256
|
+
let matchedCount = 0;
|
|
257
|
+
for (const qt of queryTokens) {
|
|
258
|
+
if (doc.nameTokenSet.has(qt))
|
|
259
|
+
matchedCount++;
|
|
260
|
+
}
|
|
261
|
+
if (matchedCount > 0 && doc.nameTokenCount > 0 && queryTokenSet.size > 0) {
|
|
262
|
+
const coverage = matchedCount / doc.nameTokenCount;
|
|
257
263
|
const precision = matchedCount / queryTokenSet.size;
|
|
258
264
|
scores[i] *= 1 + 0.5 * coverage * precision;
|
|
259
265
|
}
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
export const browserPageCoreTools = [
|
|
2
2
|
{
|
|
3
3
|
name: 'page_navigate',
|
|
4
|
-
description: `Navigate to a URL
|
|
5
|
-
|
|
6
|
-
Features:
|
|
7
|
-
- Automatic CAPTCHA detection
|
|
8
|
-
- Optional network monitoring (set enableNetworkMonitoring=true to auto-enable)
|
|
9
|
-
- Waits for page load based on waitUntil strategy
|
|
10
|
-
|
|
11
|
-
Network Monitoring:
|
|
12
|
-
If you want to capture network requests, you have two options:
|
|
13
|
-
1. Call network_enable before page_navigate (recommended for full control)
|
|
14
|
-
2. Set enableNetworkMonitoring=true in page_navigate (convenient for quick capture)
|
|
15
|
-
|
|
16
|
-
Example with network monitoring:
|
|
17
|
-
page_navigate(url="https:
|
|
18
|
-
-> Network monitoring auto-enabled
|
|
19
|
-
-> Page loads
|
|
4
|
+
description: `Navigate to a URL
|
|
5
|
+
|
|
6
|
+
Features:
|
|
7
|
+
- Automatic CAPTCHA detection
|
|
8
|
+
- Optional network monitoring (set enableNetworkMonitoring=true to auto-enable)
|
|
9
|
+
- Waits for page load based on waitUntil strategy
|
|
10
|
+
|
|
11
|
+
Network Monitoring:
|
|
12
|
+
If you want to capture network requests, you have two options:
|
|
13
|
+
1. Call network_enable before page_navigate (recommended for full control)
|
|
14
|
+
2. Set enableNetworkMonitoring=true in page_navigate (convenient for quick capture)
|
|
15
|
+
|
|
16
|
+
Example with network monitoring:
|
|
17
|
+
page_navigate(url="https:
|
|
18
|
+
-> Network monitoring auto-enabled
|
|
19
|
+
-> Page loads
|
|
20
20
|
-> Use network_get_requests to see captured requests`,
|
|
21
21
|
inputSchema: {
|
|
22
22
|
type: 'object',
|
|
@@ -109,17 +109,17 @@ page_navigate(url="https:
|
|
|
109
109
|
},
|
|
110
110
|
{
|
|
111
111
|
name: 'dom_get_structure',
|
|
112
|
-
description: `Get page DOM structure (for AI to understand page layout).
|
|
113
|
-
|
|
114
|
-
IMPORTANT: Large DOM structures (>50KB) automatically return summary + detailId.
|
|
115
|
-
|
|
116
|
-
Best Practices:
|
|
117
|
-
1. Use maxDepth=2 for initial exploration (faster, smaller)
|
|
118
|
-
2. Use maxDepth=3 only when needed (may be large)
|
|
119
|
-
3. Set includeText=false to reduce size if text not needed
|
|
120
|
-
|
|
121
|
-
Example:
|
|
122
|
-
dom_get_structure(maxDepth=2, includeText=false)
|
|
112
|
+
description: `Get page DOM structure (for AI to understand page layout).
|
|
113
|
+
|
|
114
|
+
IMPORTANT: Large DOM structures (>50KB) automatically return summary + detailId.
|
|
115
|
+
|
|
116
|
+
Best Practices:
|
|
117
|
+
1. Use maxDepth=2 for initial exploration (faster, smaller)
|
|
118
|
+
2. Use maxDepth=3 only when needed (may be large)
|
|
119
|
+
3. Set includeText=false to reduce size if text not needed
|
|
120
|
+
|
|
121
|
+
Example:
|
|
122
|
+
dom_get_structure(maxDepth=2, includeText=false)
|
|
123
123
|
-> Returns compact structure without text content`,
|
|
124
124
|
inputSchema: {
|
|
125
125
|
type: 'object',
|
|
@@ -276,19 +276,19 @@ dom_get_structure(maxDepth=2, includeText=false)
|
|
|
276
276
|
},
|
|
277
277
|
{
|
|
278
278
|
name: 'page_evaluate',
|
|
279
|
-
description: `Execute JavaScript code in page context and get result.
|
|
280
|
-
|
|
281
|
-
IMPORTANT: Large results (>50KB) automatically return summary + detailId to prevent context overflow.
|
|
282
|
-
Use get_detailed_data(detailId) to retrieve full data if needed.
|
|
283
|
-
|
|
284
|
-
Best Practices:
|
|
285
|
-
- Query specific properties: { hasAcrawler: !!window.byted_acrawler }
|
|
286
|
-
- Return only needed data: Object.keys(window.byted_acrawler)
|
|
287
|
-
- Avoid returning entire objects: window (too large!)
|
|
288
|
-
|
|
289
|
-
Example:
|
|
290
|
-
page_evaluate("({ keys: Object.keys(window.byted_acrawler), type: typeof window.byted_acrawler })")
|
|
291
|
-
-> Returns small summary
|
|
279
|
+
description: `Execute JavaScript code in page context and get result.
|
|
280
|
+
|
|
281
|
+
IMPORTANT: Large results (>50KB) automatically return summary + detailId to prevent context overflow.
|
|
282
|
+
Use get_detailed_data(detailId) to retrieve full data if needed.
|
|
283
|
+
|
|
284
|
+
Best Practices:
|
|
285
|
+
- Query specific properties: { hasAcrawler: !!window.byted_acrawler }
|
|
286
|
+
- Return only needed data: Object.keys(window.byted_acrawler)
|
|
287
|
+
- Avoid returning entire objects: window (too large!)
|
|
288
|
+
|
|
289
|
+
Example:
|
|
290
|
+
page_evaluate("({ keys: Object.keys(window.byted_acrawler), type: typeof window.byted_acrawler })")
|
|
291
|
+
-> Returns small summary
|
|
292
292
|
-> If you need full object, use the returned detailId`,
|
|
293
293
|
inputSchema: {
|
|
294
294
|
type: 'object',
|
|
@@ -369,19 +369,19 @@ page_evaluate("({ keys: Object.keys(window.byted_acrawler), type: typeof window.
|
|
|
369
369
|
},
|
|
370
370
|
{
|
|
371
371
|
name: 'get_script_source',
|
|
372
|
-
description: `Get source code of a specific script.
|
|
373
|
-
|
|
374
|
-
IMPORTANT: Large scripts (>50KB) automatically return summary + detailId.
|
|
375
|
-
Use preview mode first to check script size before fetching full source.
|
|
376
|
-
|
|
377
|
-
Best Practices:
|
|
378
|
-
1. Use preview=true first to see script overview
|
|
379
|
-
2. If script is large, use detailId to get full source
|
|
380
|
-
3. Or use startLine/endLine to get specific sections
|
|
381
|
-
|
|
382
|
-
Example:
|
|
383
|
-
get_script_source(scriptId="abc", preview=true)
|
|
384
|
-
-> Returns: { lines: 5000, size: "500KB", preview: "...", detailId: "..." }
|
|
372
|
+
description: `Get source code of a specific script.
|
|
373
|
+
|
|
374
|
+
IMPORTANT: Large scripts (>50KB) automatically return summary + detailId.
|
|
375
|
+
Use preview mode first to check script size before fetching full source.
|
|
376
|
+
|
|
377
|
+
Best Practices:
|
|
378
|
+
1. Use preview=true first to see script overview
|
|
379
|
+
2. If script is large, use detailId to get full source
|
|
380
|
+
3. Or use startLine/endLine to get specific sections
|
|
381
|
+
|
|
382
|
+
Example:
|
|
383
|
+
get_script_source(scriptId="abc", preview=true)
|
|
384
|
+
-> Returns: { lines: 5000, size: "500KB", preview: "...", detailId: "..." }
|
|
385
385
|
-> Then: get_detailed_data(detailId) to get full source`,
|
|
386
386
|
inputSchema: {
|
|
387
387
|
type: 'object',
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
export const browserRuntimeTools = [
|
|
2
2
|
{
|
|
3
3
|
name: 'get_detailed_data',
|
|
4
|
-
description: ` Retrieve detailed data using detailId token.
|
|
5
|
-
|
|
6
|
-
When tools return large data, they provide a detailId instead of full data to prevent context overflow.
|
|
7
|
-
Use this tool to retrieve the full data or specific parts.
|
|
8
|
-
|
|
9
|
-
Examples:
|
|
10
|
-
- get_detailed_data("detail_abc123") -> Get full data
|
|
11
|
-
- get_detailed_data("detail_abc123", path="frontierSign") -> Get specific property
|
|
4
|
+
description: ` Retrieve detailed data using detailId token.
|
|
5
|
+
|
|
6
|
+
When tools return large data, they provide a detailId instead of full data to prevent context overflow.
|
|
7
|
+
Use this tool to retrieve the full data or specific parts.
|
|
8
|
+
|
|
9
|
+
Examples:
|
|
10
|
+
- get_detailed_data("detail_abc123") -> Get full data
|
|
11
|
+
- get_detailed_data("detail_abc123", path="frontierSign") -> Get specific property
|
|
12
12
|
- get_detailed_data("detail_abc123", path="methods.0") -> Get first method`,
|
|
13
13
|
inputSchema: {
|
|
14
14
|
type: 'object',
|
|
@@ -27,18 +27,18 @@ Examples:
|
|
|
27
27
|
},
|
|
28
28
|
{
|
|
29
29
|
name: 'browser_launch',
|
|
30
|
-
description: `Launch browser instance.
|
|
31
|
-
|
|
32
|
-
Drivers:
|
|
33
|
-
- chrome (default): rebrowser-puppeteer-core, Chromium-based, full CDP support (debugger, network, stealth scripts, etc.)
|
|
34
|
-
- camoufox: Firefox-based anti-detect browser, C++ engine-level fingerprint spoofing.
|
|
35
|
-
Requires binaries first: npx camoufox-js fetch
|
|
36
|
-
Note: CDP tools (debugger, network monitor, etc.) are not available in camoufox mode.
|
|
37
|
-
|
|
38
|
-
Modes:
|
|
39
|
-
- launch (default): launch a local browser instance
|
|
40
|
-
- connect: reuse an existing browser instance
|
|
41
|
-
- chrome: connect via browserURL (http://host:port) or wsEndpoint
|
|
30
|
+
description: `Launch browser instance.
|
|
31
|
+
|
|
32
|
+
Drivers:
|
|
33
|
+
- chrome (default): rebrowser-puppeteer-core, Chromium-based, full CDP support (debugger, network, stealth scripts, etc.)
|
|
34
|
+
- camoufox: Firefox-based anti-detect browser, C++ engine-level fingerprint spoofing.
|
|
35
|
+
Requires binaries first: npx camoufox-js fetch
|
|
36
|
+
Note: CDP tools (debugger, network monitor, etc.) are not available in camoufox mode.
|
|
37
|
+
|
|
38
|
+
Modes:
|
|
39
|
+
- launch (default): launch a local browser instance
|
|
40
|
+
- connect: reuse an existing browser instance
|
|
41
|
+
- chrome: connect via browserURL (http://host:port) or wsEndpoint
|
|
42
42
|
- camoufox: connect via wsEndpoint from camoufox_server_launch`,
|
|
43
43
|
inputSchema: {
|
|
44
44
|
type: 'object',
|
|
@@ -79,16 +79,16 @@ Modes:
|
|
|
79
79
|
},
|
|
80
80
|
{
|
|
81
81
|
name: 'camoufox_server_launch',
|
|
82
|
-
description: `Launch a Camoufox WebSocket server for multi-process / remote connections.
|
|
83
|
-
|
|
84
|
-
Use this when you need concurrent browser instances or want to manage the browser lifecycle separately from the automation client.
|
|
85
|
-
|
|
86
|
-
Steps:
|
|
87
|
-
1. Call camoufox_server_launch → get wsEndpoint
|
|
88
|
-
2. Call browser_launch(driver="camoufox", mode="connect", wsEndpoint=<endpoint>) from one or more sessions
|
|
89
|
-
3. Use page_navigate and other tools normally
|
|
90
|
-
4. Call camoufox_server_close when done
|
|
91
|
-
|
|
82
|
+
description: `Launch a Camoufox WebSocket server for multi-process / remote connections.
|
|
83
|
+
|
|
84
|
+
Use this when you need concurrent browser instances or want to manage the browser lifecycle separately from the automation client.
|
|
85
|
+
|
|
86
|
+
Steps:
|
|
87
|
+
1. Call camoufox_server_launch → get wsEndpoint
|
|
88
|
+
2. Call browser_launch(driver="camoufox", mode="connect", wsEndpoint=<endpoint>) from one or more sessions
|
|
89
|
+
3. Use page_navigate and other tools normally
|
|
90
|
+
4. Call camoufox_server_close when done
|
|
91
|
+
|
|
92
92
|
Requires binaries: npx camoufox-js fetch`,
|
|
93
93
|
inputSchema: {
|
|
94
94
|
type: 'object',
|
|
@@ -133,16 +133,16 @@ Requires binaries: npx camoufox-js fetch`,
|
|
|
133
133
|
},
|
|
134
134
|
{
|
|
135
135
|
name: 'browser_attach',
|
|
136
|
-
description: `Attach to an existing browser instance via Chrome DevTools Protocol (CDP).
|
|
137
|
-
|
|
138
|
-
Use this when a browser is already running with remote debugging enabled.
|
|
139
|
-
Supports both browserURL (http://host:port) and WebSocket endpoint (ws://...).
|
|
140
|
-
|
|
141
|
-
Example:
|
|
142
|
-
- browser_attach(browserURL="http://127.0.0.1:9222")
|
|
143
|
-
- browser_attach(wsEndpoint="ws://127.0.0.1:9222/devtools/browser/xxx")
|
|
144
|
-
- browser_attach(browserURL="http://127.0.0.1:9222", pageIndex=0)
|
|
145
|
-
|
|
136
|
+
description: `Attach to an existing browser instance via Chrome DevTools Protocol (CDP).
|
|
137
|
+
|
|
138
|
+
Use this when a browser is already running with remote debugging enabled.
|
|
139
|
+
Supports both browserURL (http://host:port) and WebSocket endpoint (ws://...).
|
|
140
|
+
|
|
141
|
+
Example:
|
|
142
|
+
- browser_attach(browserURL="http://127.0.0.1:9222")
|
|
143
|
+
- browser_attach(wsEndpoint="ws://127.0.0.1:9222/devtools/browser/xxx")
|
|
144
|
+
- browser_attach(browserURL="http://127.0.0.1:9222", pageIndex=0)
|
|
145
|
+
|
|
146
146
|
After attaching, use page_navigate / page_screenshot / debugger_enable normally.`,
|
|
147
147
|
inputSchema: {
|
|
148
148
|
type: 'object',
|
|
@@ -1,31 +1,31 @@
|
|
|
1
1
|
export const browserSecurityStateTools = [
|
|
2
2
|
{
|
|
3
3
|
name: 'captcha_detect',
|
|
4
|
-
description: `Detect CAPTCHA on the current page using AI vision analysis.
|
|
5
|
-
|
|
6
|
-
Detection process:
|
|
7
|
-
1. Takes a screenshot and analyzes it with AI (Vision LLM)
|
|
8
|
-
2. Applies rule-based detection as fallback if AI unavailable
|
|
9
|
-
3. Returns detection result with confidence score
|
|
10
|
-
|
|
11
|
-
Supported CAPTCHA types:
|
|
12
|
-
- Slider CAPTCHA: drag-to-verify style challenges
|
|
13
|
-
- Image CAPTCHA: select-images challenges
|
|
14
|
-
- reCAPTCHA / hCaptcha
|
|
15
|
-
- Cloudflare Challenge
|
|
16
|
-
- Custom CAPTCHA implementations
|
|
17
|
-
|
|
18
|
-
Response fields:
|
|
19
|
-
- detected: whether CAPTCHA was found
|
|
20
|
-
- type: CAPTCHA type identifier
|
|
21
|
-
- vendor: vendor name if identified
|
|
22
|
-
- confidence: detection confidence (0-100)
|
|
23
|
-
- reasoning: AI analysis explanation
|
|
24
|
-
- screenshot: base64 screenshot (if MCP cannot view images, use external AI)
|
|
25
|
-
- suggestions: recommended next steps
|
|
26
|
-
|
|
27
|
-
Note:
|
|
28
|
-
When the MCP LLM cannot access Vision API directly, the screenshot is provided as base64.
|
|
4
|
+
description: `Detect CAPTCHA on the current page using AI vision analysis.
|
|
5
|
+
|
|
6
|
+
Detection process:
|
|
7
|
+
1. Takes a screenshot and analyzes it with AI (Vision LLM)
|
|
8
|
+
2. Applies rule-based detection as fallback if AI unavailable
|
|
9
|
+
3. Returns detection result with confidence score
|
|
10
|
+
|
|
11
|
+
Supported CAPTCHA types:
|
|
12
|
+
- Slider CAPTCHA: drag-to-verify style challenges
|
|
13
|
+
- Image CAPTCHA: select-images challenges
|
|
14
|
+
- reCAPTCHA / hCaptcha
|
|
15
|
+
- Cloudflare Challenge
|
|
16
|
+
- Custom CAPTCHA implementations
|
|
17
|
+
|
|
18
|
+
Response fields:
|
|
19
|
+
- detected: whether CAPTCHA was found
|
|
20
|
+
- type: CAPTCHA type identifier
|
|
21
|
+
- vendor: vendor name if identified
|
|
22
|
+
- confidence: detection confidence (0-100)
|
|
23
|
+
- reasoning: AI analysis explanation
|
|
24
|
+
- screenshot: base64 screenshot (if MCP cannot view images, use external AI)
|
|
25
|
+
- suggestions: recommended next steps
|
|
26
|
+
|
|
27
|
+
Note:
|
|
28
|
+
When the MCP LLM cannot access Vision API directly, the screenshot is provided as base64.
|
|
29
29
|
Use an external AI (GPT-4o, Claude 3) to analyze the screenshot.`,
|
|
30
30
|
inputSchema: {
|
|
31
31
|
type: 'object',
|
|
@@ -34,14 +34,14 @@ Use an external AI (GPT-4o, Claude 3) to analyze the screenshot.`,
|
|
|
34
34
|
},
|
|
35
35
|
{
|
|
36
36
|
name: 'captcha_wait',
|
|
37
|
-
description: `Wait for the user to manually solve a CAPTCHA.
|
|
38
|
-
|
|
39
|
-
Steps:
|
|
40
|
-
1. CAPTCHA is detected on the page
|
|
41
|
-
2. Browser switches to headed (visible) mode
|
|
42
|
-
3. User solves the CAPTCHA manually
|
|
43
|
-
4. Script resumes automatically after detection
|
|
44
|
-
|
|
37
|
+
description: `Wait for the user to manually solve a CAPTCHA.
|
|
38
|
+
|
|
39
|
+
Steps:
|
|
40
|
+
1. CAPTCHA is detected on the page
|
|
41
|
+
2. Browser switches to headed (visible) mode
|
|
42
|
+
3. User solves the CAPTCHA manually
|
|
43
|
+
4. Script resumes automatically after detection
|
|
44
|
+
|
|
45
45
|
Timeout: default 300000ms (5 minutes)`,
|
|
46
46
|
inputSchema: {
|
|
47
47
|
type: 'object',
|
|
@@ -56,11 +56,11 @@ Timeout: default 300000ms (5 minutes)`,
|
|
|
56
56
|
},
|
|
57
57
|
{
|
|
58
58
|
name: 'captcha_config',
|
|
59
|
-
description: `Configure CAPTCHA detection behavior.
|
|
60
|
-
|
|
61
|
-
Parameters:
|
|
62
|
-
- autoDetectCaptcha: auto-detect CAPTCHA after page_navigate (default: true)
|
|
63
|
-
- autoSwitchHeadless: auto-switch to headed mode when CAPTCHA detected (default: true)
|
|
59
|
+
description: `Configure CAPTCHA detection behavior.
|
|
60
|
+
|
|
61
|
+
Parameters:
|
|
62
|
+
- autoDetectCaptcha: auto-detect CAPTCHA after page_navigate (default: true)
|
|
63
|
+
- autoSwitchHeadless: auto-switch to headed mode when CAPTCHA detected (default: true)
|
|
64
64
|
- captchaTimeout: timeout for waiting user to solve CAPTCHA in ms (default: 300000)`,
|
|
65
65
|
inputSchema: {
|
|
66
66
|
type: 'object',
|
|
@@ -82,21 +82,21 @@ Parameters:
|
|
|
82
82
|
},
|
|
83
83
|
{
|
|
84
84
|
name: 'stealth_inject',
|
|
85
|
-
description: `Inject modern stealth scripts to bypass bot detection.
|
|
86
|
-
|
|
87
|
-
Anti-detection patches:
|
|
88
|
-
1. Hide navigator.webdriver flag
|
|
89
|
-
2. Inject window.chrome object
|
|
90
|
-
3. Restore navigator.plugins
|
|
91
|
-
4. Fix Permissions API behavior
|
|
92
|
-
5. Patch Canvas fingerprinting
|
|
93
|
-
6. Patch WebGL fingerprinting
|
|
94
|
-
7. Restore hardware concurrency
|
|
95
|
-
8. Fix Battery API responses
|
|
96
|
-
9. Fix MediaDevices enumeration
|
|
97
|
-
10. Fix Notification API
|
|
98
|
-
|
|
99
|
-
Compatible with undetected-chromedriver, puppeteer-extra-plugin-stealth, playwright-stealth.
|
|
85
|
+
description: `Inject modern stealth scripts to bypass bot detection.
|
|
86
|
+
|
|
87
|
+
Anti-detection patches:
|
|
88
|
+
1. Hide navigator.webdriver flag
|
|
89
|
+
2. Inject window.chrome object
|
|
90
|
+
3. Restore navigator.plugins
|
|
91
|
+
4. Fix Permissions API behavior
|
|
92
|
+
5. Patch Canvas fingerprinting
|
|
93
|
+
6. Patch WebGL fingerprinting
|
|
94
|
+
7. Restore hardware concurrency
|
|
95
|
+
8. Fix Battery API responses
|
|
96
|
+
9. Fix MediaDevices enumeration
|
|
97
|
+
10. Fix Notification API
|
|
98
|
+
|
|
99
|
+
Compatible with undetected-chromedriver, puppeteer-extra-plugin-stealth, playwright-stealth.
|
|
100
100
|
Call after browser_launch for best results.`,
|
|
101
101
|
inputSchema: {
|
|
102
102
|
type: 'object',
|
|
@@ -105,10 +105,10 @@ Call after browser_launch for best results.`,
|
|
|
105
105
|
},
|
|
106
106
|
{
|
|
107
107
|
name: 'stealth_set_user_agent',
|
|
108
|
-
description: `Set a realistic User-Agent and browser fingerprint for the target platform.
|
|
109
|
-
|
|
110
|
-
Updates navigator.userAgent, navigator.platform, navigator.vendor,
|
|
111
|
-
navigator.hardwareConcurrency, and navigator.deviceMemory consistently
|
|
108
|
+
description: `Set a realistic User-Agent and browser fingerprint for the target platform.
|
|
109
|
+
|
|
110
|
+
Updates navigator.userAgent, navigator.platform, navigator.vendor,
|
|
111
|
+
navigator.hardwareConcurrency, and navigator.deviceMemory consistently
|
|
112
112
|
to avoid fingerprint inconsistencies.`,
|
|
113
113
|
inputSchema: {
|
|
114
114
|
type: 'object',
|
|
@@ -124,17 +124,17 @@ to avoid fingerprint inconsistencies.`,
|
|
|
124
124
|
},
|
|
125
125
|
{
|
|
126
126
|
name: 'browser_list_tabs',
|
|
127
|
-
description: `List all open tabs/pages in the connected browser.
|
|
128
|
-
|
|
129
|
-
Use this after browser_attach to see all available pages/tabs.
|
|
130
|
-
Returns index, URL, and title for each tab.
|
|
131
|
-
|
|
132
|
-
Workflow:
|
|
133
|
-
1. browser_attach(browserURL="http://127.0.0.1:9222")
|
|
134
|
-
2. browser_list_tabs() -> see all tabs with their indexes
|
|
135
|
-
3. browser_select_tab(index=N) -> switch to desired tab
|
|
136
|
-
|
|
137
|
-
Can also connect and list in one call:
|
|
127
|
+
description: `List all open tabs/pages in the connected browser.
|
|
128
|
+
|
|
129
|
+
Use this after browser_attach to see all available pages/tabs.
|
|
130
|
+
Returns index, URL, and title for each tab.
|
|
131
|
+
|
|
132
|
+
Workflow:
|
|
133
|
+
1. browser_attach(browserURL="http://127.0.0.1:9222")
|
|
134
|
+
2. browser_list_tabs() -> see all tabs with their indexes
|
|
135
|
+
3. browser_select_tab(index=N) -> switch to desired tab
|
|
136
|
+
|
|
137
|
+
Can also connect and list in one call:
|
|
138
138
|
browser_list_tabs(browserURL="http://127.0.0.1:9222")`,
|
|
139
139
|
inputSchema: {
|
|
140
140
|
type: 'object',
|
|
@@ -148,14 +148,14 @@ browser_list_tabs(browserURL="http://127.0.0.1:9222")`,
|
|
|
148
148
|
},
|
|
149
149
|
{
|
|
150
150
|
name: 'browser_select_tab',
|
|
151
|
-
description: `Switch the active tab/page by index or URL/title pattern.
|
|
152
|
-
|
|
153
|
-
After browser_list_tabs, use this to activate a specific tab.
|
|
154
|
-
All subsequent page_* tools will operate on the selected tab.
|
|
155
|
-
|
|
156
|
-
Examples:
|
|
157
|
-
- browser_select_tab(index=0) -> first tab
|
|
158
|
-
- browser_select_tab(urlPattern="qwen") -> tab whose URL contains "qwen"
|
|
151
|
+
description: `Switch the active tab/page by index or URL/title pattern.
|
|
152
|
+
|
|
153
|
+
After browser_list_tabs, use this to activate a specific tab.
|
|
154
|
+
All subsequent page_* tools will operate on the selected tab.
|
|
155
|
+
|
|
156
|
+
Examples:
|
|
157
|
+
- browser_select_tab(index=0) -> first tab
|
|
158
|
+
- browser_select_tab(urlPattern="qwen") -> tab whose URL contains "qwen"
|
|
159
159
|
- browser_select_tab(titlePattern="Mini Program") -> tab whose title contains "Mini Program"`,
|
|
160
160
|
inputSchema: {
|
|
161
161
|
type: 'object',
|
|
@@ -148,13 +148,14 @@ export class TabWorkflowHandlers {
|
|
|
148
148
|
await newPage.goto(url, { waitUntil: 'domcontentloaded' });
|
|
149
149
|
const pages = context.pages();
|
|
150
150
|
const idx = pages.indexOf(newPage);
|
|
151
|
+
const pageTitle = await newPage.title();
|
|
151
152
|
const pageId = this.registry.registerPage(newPage, {
|
|
152
153
|
index: idx,
|
|
153
154
|
url: newPage.url(),
|
|
154
|
-
title:
|
|
155
|
+
title: pageTitle,
|
|
155
156
|
});
|
|
156
157
|
this.registry.bindAlias(alias, pageId);
|
|
157
|
-
return this.ok({ alias, index: idx, pageId, url: newPage.url(), title:
|
|
158
|
+
return this.ok({ alias, index: idx, pageId, url: newPage.url(), title: pageTitle });
|
|
158
159
|
}
|
|
159
160
|
const browser = await this.getBrowserFromController();
|
|
160
161
|
if (!browser)
|
|
@@ -163,13 +164,14 @@ export class TabWorkflowHandlers {
|
|
|
163
164
|
await newPage.goto(url, { waitUntil: 'domcontentloaded' });
|
|
164
165
|
const pages = await browser.pages();
|
|
165
166
|
const idx = pages.indexOf(newPage);
|
|
167
|
+
const pageTitle = await newPage.title();
|
|
166
168
|
const pageId = this.registry.registerPage(newPage, {
|
|
167
169
|
index: idx,
|
|
168
170
|
url: newPage.url(),
|
|
169
|
-
title:
|
|
171
|
+
title: pageTitle,
|
|
170
172
|
});
|
|
171
173
|
this.registry.bindAlias(alias, pageId);
|
|
172
|
-
return this.ok({ alias, index: idx, pageId, url: newPage.url(), title:
|
|
174
|
+
return this.ok({ alias, index: idx, pageId, url: newPage.url(), title: pageTitle });
|
|
173
175
|
}
|
|
174
176
|
async navigateAlias(args) {
|
|
175
177
|
const alias = readRequiredString(args.alias);
|