@browserbridge/bbx 1.6.0 → 1.6.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 +1 -1
- package/packages/agent-client/src/cli.js +264 -0
- package/packages/agent-client/src/command-registry.js +4 -0
- package/packages/agent-client/src/remotes.js +202 -0
- package/packages/mcp-server/src/handlers-capture.js +201 -198
- package/packages/mcp-server/src/handlers-navigation.js +81 -9
- package/packages/mcp-server/src/handlers-page.js +110 -88
- package/packages/mcp-server/src/handlers-utils.js +55 -27
- package/packages/mcp-server/src/handlers.js +52 -10
- package/packages/mcp-server/src/server.js +23 -6
- package/packages/native-host/src/auth-token.js +56 -1
- package/packages/native-host/src/config.js +122 -5
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
DEFAULT_NETWORK_LIMIT,
|
|
6
6
|
METHOD_SET,
|
|
7
7
|
} from '../../protocol/src/index.js';
|
|
8
|
+
import { createBridgeClientForDestination } from '../../agent-client/src/remotes.js';
|
|
8
9
|
import {
|
|
9
10
|
annotateBridgeSummary,
|
|
10
11
|
applyLimitBudgetPreset,
|
|
@@ -65,7 +66,7 @@ export const PAGE_ACTIONS = {
|
|
|
65
66
|
};
|
|
66
67
|
|
|
67
68
|
/**
|
|
68
|
-
* @param {{ action: string, expression?: string, awaitPromise?: boolean, timeoutMs?: number, returnByValue?: boolean, level?: string, clear?: boolean, limit?: number, type?: string, keys?: string[], textBudget?: number, urlPattern?: string, tabId?: number, budgetPreset?: 'quick' | 'normal' | 'deep' }} args
|
|
69
|
+
* @param {{ action: string, expression?: string, awaitPromise?: boolean, timeoutMs?: number, returnByValue?: boolean, level?: string, clear?: boolean, limit?: number, type?: string, keys?: string[], textBudget?: number, urlPattern?: string, tabId?: number, destinationId?: string, budgetPreset?: 'quick' | 'normal' | 'deep' }} args
|
|
69
70
|
* @returns {Promise<ToolResult>}
|
|
70
71
|
*/
|
|
71
72
|
export async function handlePageTool(args) {
|
|
@@ -96,11 +97,12 @@ export async function handlePageTool(args) {
|
|
|
96
97
|
return callBridgeTool(entry.method, entry.params(normalizedArgs), {
|
|
97
98
|
tabId: typeof normalizedArgs.tabId === 'number' ? normalizedArgs.tabId : null,
|
|
98
99
|
tokenBudget: getToolTokenBudget(normalizedArgs),
|
|
100
|
+
destinationId: normalizedArgs.destinationId ?? null,
|
|
99
101
|
});
|
|
100
102
|
}
|
|
101
103
|
|
|
102
104
|
/**
|
|
103
|
-
* @param {{ calls?: Array<{ method?: string, params?: Record<string, unknown>, tabId?: number, budgetPreset?: 'quick' | 'normal' | 'deep' }> }} args
|
|
105
|
+
* @param {{ calls?: Array<{ method?: string, params?: Record<string, unknown>, tabId?: number, destinationId?: string, budgetPreset?: 'quick' | 'normal' | 'deep' }> }} args
|
|
104
106
|
* @returns {Promise<ToolResult>}
|
|
105
107
|
*/
|
|
106
108
|
export async function handleBatchTool(args) {
|
|
@@ -149,20 +151,30 @@ export async function handleBatchTool(args) {
|
|
|
149
151
|
: null
|
|
150
152
|
: null;
|
|
151
153
|
const tokenBudget = getToolTokenBudget(call);
|
|
154
|
+
const destinationId = typeof call.destinationId === 'string' ? call.destinationId : null;
|
|
152
155
|
|
|
153
156
|
const startTime = Date.now();
|
|
157
|
+
const callClient = destinationId
|
|
158
|
+
? await createBridgeClientForDestination(destinationId)
|
|
159
|
+
: client;
|
|
154
160
|
try {
|
|
155
|
-
|
|
161
|
+
if (destinationId) {
|
|
162
|
+
await callClient.connect();
|
|
163
|
+
}
|
|
164
|
+
const response = await requestBridgeWithRetry(callClient, method, call.params || {}, {
|
|
156
165
|
tabId,
|
|
157
166
|
source: REQUEST_SOURCE,
|
|
158
167
|
tokenBudget,
|
|
159
168
|
});
|
|
160
|
-
return
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
169
|
+
return {
|
|
170
|
+
destinationId,
|
|
171
|
+
...summarizeBatchResponseItem({
|
|
172
|
+
method,
|
|
173
|
+
tabId,
|
|
174
|
+
response,
|
|
175
|
+
durationMs: Date.now() - startTime,
|
|
176
|
+
}),
|
|
177
|
+
};
|
|
166
178
|
} catch (error) {
|
|
167
179
|
return summarizeBatchErrorItem({
|
|
168
180
|
method,
|
|
@@ -170,6 +182,10 @@ export async function handleBatchTool(args) {
|
|
|
170
182
|
error,
|
|
171
183
|
durationMs: Date.now() - startTime,
|
|
172
184
|
});
|
|
185
|
+
} finally {
|
|
186
|
+
if (destinationId) {
|
|
187
|
+
await callClient.close();
|
|
188
|
+
}
|
|
173
189
|
}
|
|
174
190
|
})
|
|
175
191
|
);
|
|
@@ -191,7 +207,7 @@ export async function handleBatchTool(args) {
|
|
|
191
207
|
}
|
|
192
208
|
|
|
193
209
|
/**
|
|
194
|
-
* @param {{ method: string, params?: Record<string, unknown>, tabId?: number }} args
|
|
210
|
+
* @param {{ method: string, params?: Record<string, unknown>, tabId?: number, destinationId?: string }} args
|
|
195
211
|
* @returns {Promise<ToolResult>}
|
|
196
212
|
*/
|
|
197
213
|
export async function handleRawCallTool(args) {
|
|
@@ -199,34 +215,37 @@ export async function handleRawCallTool(args) {
|
|
|
199
215
|
return summarizeToolError(`Unknown bridge method "${args.method}".`);
|
|
200
216
|
}
|
|
201
217
|
|
|
202
|
-
return withToolClient(
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
tabId: typeof args.tabId === 'number' ? args.tabId : null,
|
|
209
|
-
source: REQUEST_SOURCE,
|
|
210
|
-
}
|
|
211
|
-
);
|
|
212
|
-
|
|
213
|
-
if (!response.ok) {
|
|
214
|
-
return createToolResult(
|
|
215
|
-
response.error.message,
|
|
218
|
+
return withToolClient(
|
|
219
|
+
async (client) => {
|
|
220
|
+
const response = await requestBridgeWithRetry(
|
|
221
|
+
client,
|
|
222
|
+
/** @type {BridgeMethod} */ (args.method),
|
|
223
|
+
args.params || {},
|
|
216
224
|
{
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
},
|
|
221
|
-
true
|
|
225
|
+
tabId: typeof args.tabId === 'number' ? args.tabId : null,
|
|
226
|
+
source: REQUEST_SOURCE,
|
|
227
|
+
}
|
|
222
228
|
);
|
|
223
|
-
}
|
|
224
229
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
+
if (!response.ok) {
|
|
231
|
+
return createToolResult(
|
|
232
|
+
response.error.message,
|
|
233
|
+
{
|
|
234
|
+
ok: false,
|
|
235
|
+
error: response.error,
|
|
236
|
+
response,
|
|
237
|
+
},
|
|
238
|
+
true
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return createToolResult(`Called ${args.method}.`, {
|
|
243
|
+
ok: true,
|
|
244
|
+
response: response.result,
|
|
245
|
+
});
|
|
246
|
+
},
|
|
247
|
+
{ destinationId: args.destinationId ?? null }
|
|
248
|
+
);
|
|
230
249
|
}
|
|
231
250
|
|
|
232
251
|
/**
|
|
@@ -290,7 +309,7 @@ const INVESTIGATE_SCOPES = {
|
|
|
290
309
|
};
|
|
291
310
|
|
|
292
311
|
/**
|
|
293
|
-
* @param {{ objective: string, scope?: 'quick' | 'normal' | 'deep', tabId?: number, selector?: string }} args
|
|
312
|
+
* @param {{ objective: string, scope?: 'quick' | 'normal' | 'deep', tabId?: number, destinationId?: string, selector?: string }} args
|
|
294
313
|
* @returns {Promise<ToolResult>}
|
|
295
314
|
*/
|
|
296
315
|
export async function handleInvestigateTool(args) {
|
|
@@ -305,62 +324,65 @@ export async function handleInvestigateTool(args) {
|
|
|
305
324
|
return summarizeToolError(`Unsupported investigation scope "${scopeName}".`);
|
|
306
325
|
}
|
|
307
326
|
|
|
308
|
-
return withToolClient(
|
|
309
|
-
|
|
327
|
+
return withToolClient(
|
|
328
|
+
async (client) => {
|
|
329
|
+
const requestedTabId = typeof args.tabId === 'number' ? args.tabId : null;
|
|
310
330
|
|
|
311
|
-
|
|
312
|
-
|
|
331
|
+
/** @type {Array<{ method: string, ok: boolean, summary: string, evidence: unknown, durationMs: number }>} */
|
|
332
|
+
const stepResults = [];
|
|
313
333
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
334
|
+
for (const step of scope.steps) {
|
|
335
|
+
const startTime = Date.now();
|
|
336
|
+
try {
|
|
337
|
+
const response = await requestBridgeWithRetry(client, step.method, step.params(args), {
|
|
338
|
+
tabId: requestedTabId,
|
|
339
|
+
source: REQUEST_SOURCE,
|
|
340
|
+
tokenBudget: null,
|
|
341
|
+
});
|
|
342
|
+
const bridgeSummary = annotateBridgeSummary(
|
|
343
|
+
summarizeBridgeResponse(response, step.method),
|
|
344
|
+
response
|
|
345
|
+
);
|
|
346
|
+
stepResults.push({
|
|
347
|
+
method: step.method,
|
|
348
|
+
ok: bridgeSummary.ok,
|
|
349
|
+
summary: bridgeSummary.summary,
|
|
350
|
+
evidence: bridgeSummary.evidence,
|
|
351
|
+
durationMs: Date.now() - startTime,
|
|
352
|
+
});
|
|
353
|
+
} catch (error) {
|
|
354
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
355
|
+
stepResults.push({
|
|
356
|
+
method: step.method,
|
|
357
|
+
ok: false,
|
|
358
|
+
summary: `ERROR: ${message}`,
|
|
359
|
+
evidence: null,
|
|
360
|
+
durationMs: Date.now() - startTime,
|
|
361
|
+
});
|
|
362
|
+
}
|
|
342
363
|
}
|
|
343
|
-
}
|
|
344
364
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
365
|
+
const failedSteps = stepResults.filter((s) => !s.ok);
|
|
366
|
+
const allOk = failedSteps.length === 0;
|
|
367
|
+
const totalDuration = stepResults.reduce((sum, s) => sum + s.durationMs, 0);
|
|
348
368
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
369
|
+
const summaryText = allOk
|
|
370
|
+
? `Investigation complete (${scope.label}, ${stepResults.length} steps, ${totalDuration}ms). Objective: ${objective}`
|
|
371
|
+
: `Investigation partial (${scope.label}, ${stepResults.length} steps, ${failedSteps.length} failed, ${totalDuration}ms). Objective: ${objective}`;
|
|
352
372
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
373
|
+
return createToolResult(
|
|
374
|
+
summaryText,
|
|
375
|
+
{
|
|
376
|
+
ok: allOk,
|
|
377
|
+
objective,
|
|
378
|
+
scope: scopeName,
|
|
379
|
+
heuristicFallback: true,
|
|
380
|
+
steps: stepResults,
|
|
381
|
+
failedSteps,
|
|
382
|
+
},
|
|
383
|
+
!allOk
|
|
384
|
+
);
|
|
385
|
+
},
|
|
386
|
+
{ destinationId: args.destinationId ?? null }
|
|
387
|
+
);
|
|
366
388
|
}
|
|
@@ -17,6 +17,10 @@ import {
|
|
|
17
17
|
resolveRef,
|
|
18
18
|
withBridgeClient,
|
|
19
19
|
} from '../../agent-client/src/runtime.js';
|
|
20
|
+
import {
|
|
21
|
+
createBridgeClientForDestination,
|
|
22
|
+
listBridgeDestinations,
|
|
23
|
+
} from '../../agent-client/src/remotes.js';
|
|
20
24
|
import { annotateBridgeSummary, summarizeBridgeResponse } from '../../agent-client/src/subagent.js';
|
|
21
25
|
|
|
22
26
|
/** @typedef {import('../../protocol/src/types.js').BridgeMethod} BridgeMethod */
|
|
@@ -130,11 +134,21 @@ export function summarizeToolError(error) {
|
|
|
130
134
|
|
|
131
135
|
/**
|
|
132
136
|
* @param {(client: import('../../agent-client/src/client.js').BridgeClient) => Promise<ToolResult>} callback
|
|
137
|
+
* @param {{ destinationId?: string | null }} [options]
|
|
133
138
|
* @returns {Promise<ToolResult>}
|
|
134
139
|
*/
|
|
135
|
-
export async function withToolClient(callback) {
|
|
140
|
+
export async function withToolClient(callback, options = {}) {
|
|
136
141
|
try {
|
|
137
|
-
|
|
142
|
+
if (!options.destinationId) {
|
|
143
|
+
return await withBridgeClient(callback);
|
|
144
|
+
}
|
|
145
|
+
const client = await createBridgeClientForDestination(options.destinationId);
|
|
146
|
+
await client.connect();
|
|
147
|
+
try {
|
|
148
|
+
return await callback(client);
|
|
149
|
+
} finally {
|
|
150
|
+
await client.close();
|
|
151
|
+
}
|
|
138
152
|
} catch (error) {
|
|
139
153
|
return summarizeToolError(error);
|
|
140
154
|
}
|
|
@@ -306,18 +320,28 @@ export async function requestBridgeWithRetry(client, method, params, options) {
|
|
|
306
320
|
/**
|
|
307
321
|
* @param {BridgeMethod} method
|
|
308
322
|
* @param {Record<string, unknown>} [params={}]
|
|
309
|
-
* @param {{ tabId?: number | null, summaryMethod?: string, tokenBudget?: number | null }} [options]
|
|
323
|
+
* @param {{ tabId?: number | null, summaryMethod?: string, tokenBudget?: number | null, destinationId?: string | null }} [options]
|
|
310
324
|
* @returns {Promise<ToolResult>}
|
|
311
325
|
*/
|
|
312
326
|
export async function callBridgeTool(method, params = {}, options = {}) {
|
|
313
|
-
return withToolClient(
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
327
|
+
return withToolClient(
|
|
328
|
+
async (client) => {
|
|
329
|
+
const response = await requestBridgeWithRetry(client, method, params, {
|
|
330
|
+
tabId: options.tabId ?? null,
|
|
331
|
+
source: REQUEST_SOURCE,
|
|
332
|
+
tokenBudget: options.tokenBudget ?? null,
|
|
333
|
+
});
|
|
334
|
+
return summarizeToolResponse(response, options.summaryMethod || method);
|
|
335
|
+
},
|
|
336
|
+
{ destinationId: options.destinationId ?? null }
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* @returns {Promise<Array<{ id: string, local: boolean, host: string | null, port: number | null }>>}
|
|
342
|
+
*/
|
|
343
|
+
export async function getBridgeDestinations() {
|
|
344
|
+
return listBridgeDestinations();
|
|
321
345
|
}
|
|
322
346
|
|
|
323
347
|
/**
|
|
@@ -333,22 +357,25 @@ export async function callBridgeTool(method, params = {}, options = {}) {
|
|
|
333
357
|
export async function dispatchToolAction(actions, args, toolName) {
|
|
334
358
|
const entry = actions[args.action];
|
|
335
359
|
if (!entry) return summarizeToolError(`Unsupported ${toolName} action "${args.action}".`);
|
|
336
|
-
return withToolClient(
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
360
|
+
return withToolClient(
|
|
361
|
+
async (client) => {
|
|
362
|
+
const requestedTabId = typeof args.tabId === 'number' ? args.tabId : null;
|
|
363
|
+
const ref = entry.ref
|
|
364
|
+
? await resolveToolRef(
|
|
365
|
+
client,
|
|
366
|
+
/** @type {{ elementRef?: string, selector?: string }} */ (args),
|
|
367
|
+
requestedTabId
|
|
368
|
+
)
|
|
369
|
+
: undefined;
|
|
370
|
+
const response = await requestBridgeWithRetry(client, entry.method, entry.params(args, ref), {
|
|
371
|
+
tabId: requestedTabId,
|
|
372
|
+
source: REQUEST_SOURCE,
|
|
373
|
+
tokenBudget: getToolTokenBudget(/** @type {{ budgetPreset?: unknown }} */ (args)),
|
|
374
|
+
});
|
|
375
|
+
return summarizeToolResponse(response, entry.method);
|
|
376
|
+
},
|
|
377
|
+
{ destinationId: typeof args.destinationId === 'string' ? args.destinationId : null }
|
|
378
|
+
);
|
|
352
379
|
}
|
|
353
380
|
|
|
354
381
|
export {
|
|
@@ -357,6 +384,7 @@ export {
|
|
|
357
384
|
requestBridge,
|
|
358
385
|
resolveRef,
|
|
359
386
|
withBridgeClient,
|
|
387
|
+
listBridgeDestinations,
|
|
360
388
|
annotateBridgeSummary,
|
|
361
389
|
summarizeBridgeResponse,
|
|
362
390
|
summarizeBatchErrorItem,
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
createToolResult,
|
|
9
9
|
getDoctorReport,
|
|
10
10
|
getToolTokenBudget,
|
|
11
|
+
getBridgeDestinations,
|
|
11
12
|
applyLimitBudgetPreset,
|
|
12
13
|
summarizeToolError,
|
|
13
14
|
summarizeToolResponse,
|
|
@@ -71,6 +72,22 @@ const HOME_DIR = os.homedir();
|
|
|
71
72
|
export async function handleStatusTool() {
|
|
72
73
|
try {
|
|
73
74
|
const report = await getDoctorReport();
|
|
75
|
+
const destinations = await Promise.all(
|
|
76
|
+
(await getBridgeDestinations()).map(async (destination) => {
|
|
77
|
+
if (destination.local) {
|
|
78
|
+
return {
|
|
79
|
+
...destination,
|
|
80
|
+
reachable: report.daemonReachable,
|
|
81
|
+
extensionConnected: report.extensionConnected,
|
|
82
|
+
accessEnabled: report.accessEnabled,
|
|
83
|
+
routeReady: report.routeReady,
|
|
84
|
+
routeTabId: report.routeTabId,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
const result = await callRemoteHealth(destination.id);
|
|
88
|
+
return { ...destination, ...result };
|
|
89
|
+
})
|
|
90
|
+
);
|
|
74
91
|
const summary =
|
|
75
92
|
report.issues.length === 0
|
|
76
93
|
? 'Browser Bridge is ready.'
|
|
@@ -78,12 +95,25 @@ export async function handleStatusTool() {
|
|
|
78
95
|
return createToolResult(summary, {
|
|
79
96
|
ok: report.issues.length === 0,
|
|
80
97
|
evidence: report,
|
|
98
|
+
destinations,
|
|
81
99
|
});
|
|
82
100
|
} catch (error) {
|
|
83
101
|
return summarizeToolError(error);
|
|
84
102
|
}
|
|
85
103
|
}
|
|
86
104
|
|
|
105
|
+
/**
|
|
106
|
+
* @param {string} destinationId
|
|
107
|
+
* @returns {Promise<Record<string, unknown>>}
|
|
108
|
+
*/
|
|
109
|
+
async function callRemoteHealth(destinationId) {
|
|
110
|
+
const result = await callBridgeTool('health.ping', {}, { destinationId });
|
|
111
|
+
return {
|
|
112
|
+
reachable: result.structuredContent.ok === true,
|
|
113
|
+
health: result.structuredContent,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
87
117
|
/**
|
|
88
118
|
* @returns {Promise<ToolResult>}
|
|
89
119
|
*/
|
|
@@ -138,21 +168,33 @@ export async function handleLogTool(args) {
|
|
|
138
168
|
}
|
|
139
169
|
|
|
140
170
|
/**
|
|
171
|
+
* @param {{ destinationId?: string }} [args]
|
|
141
172
|
* @returns {Promise<ToolResult>}
|
|
142
173
|
*/
|
|
143
|
-
export async function handleHealthTool() {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
174
|
+
export async function handleHealthTool(args = {}) {
|
|
175
|
+
const destinationId = typeof args.destinationId === 'string' ? args.destinationId : null;
|
|
176
|
+
return withToolClient(
|
|
177
|
+
async (client) => {
|
|
178
|
+
const response = await client.request({
|
|
179
|
+
method: 'health.ping',
|
|
180
|
+
meta: { source: REQUEST_SOURCE },
|
|
181
|
+
});
|
|
182
|
+
return summarizeToolResponse(response, 'health.ping');
|
|
183
|
+
},
|
|
184
|
+
{ destinationId }
|
|
185
|
+
);
|
|
151
186
|
}
|
|
152
187
|
|
|
153
188
|
/**
|
|
189
|
+
* @param {{ destinationId?: string }} [args]
|
|
154
190
|
* @returns {Promise<ToolResult>}
|
|
155
191
|
*/
|
|
156
|
-
export async function handleAccessTool() {
|
|
157
|
-
return callBridgeTool(
|
|
192
|
+
export async function handleAccessTool(args = {}) {
|
|
193
|
+
return callBridgeTool(
|
|
194
|
+
'access.request',
|
|
195
|
+
{},
|
|
196
|
+
{
|
|
197
|
+
destinationId: typeof args.destinationId === 'string' ? args.destinationId : null,
|
|
198
|
+
}
|
|
199
|
+
);
|
|
158
200
|
}
|
|
@@ -40,11 +40,13 @@ import {
|
|
|
40
40
|
getMethodsByMaxComplexity,
|
|
41
41
|
} from '../../protocol/src/index.js';
|
|
42
42
|
import { applyWindowsTcpTransportDefaults } from '../../native-host/src/config.js';
|
|
43
|
-
import { MCP_SERVER_INSTRUCTIONS
|
|
43
|
+
import { MCP_SERVER_INSTRUCTIONS } from './guidance.js';
|
|
44
44
|
|
|
45
45
|
export const BUDGET_PRESET_DESCRIPTION = `Budget preset: "quick", "normal", or "deep" (defaults: query ${BUDGET_PRESETS.normal.maxNodes} nodes / depth ${BUDGET_PRESETS.normal.maxDepth} / text ${BUDGET_PRESETS.normal.textBudget}). Numeric fields override the preset when both are provided.`;
|
|
46
46
|
export const TAB_ID_DESCRIPTION =
|
|
47
47
|
'Target a specific tab instead of the active tab in the enabled window.';
|
|
48
|
+
export const DESTINATION_ID_DESCRIPTION =
|
|
49
|
+
'Optional Browser Bridge destination ID from browser_status/browser_tabs; omit for local.';
|
|
48
50
|
|
|
49
51
|
const MCP_SERVER_VERSION = loadPackageVersion();
|
|
50
52
|
|
|
@@ -109,7 +111,9 @@ export function createBridgeMcpServer() {
|
|
|
109
111
|
title: 'Browser Bridge Status',
|
|
110
112
|
description:
|
|
111
113
|
'Check bridge readiness: daemon connectivity, extension state, and window access. Call first to confirm the bridge is usable. If access is not enabled, ask the user to click Enable in the extension popup or side panel, then retry.',
|
|
112
|
-
inputSchema: {
|
|
114
|
+
inputSchema: {
|
|
115
|
+
destinationId: z.string().optional().describe(DESTINATION_ID_DESCRIPTION),
|
|
116
|
+
},
|
|
113
117
|
},
|
|
114
118
|
handleStatusTool
|
|
115
119
|
);
|
|
@@ -155,7 +159,9 @@ export function createBridgeMcpServer() {
|
|
|
155
159
|
{
|
|
156
160
|
title: 'Browser Bridge Health',
|
|
157
161
|
description: 'Ping the bridge to verify daemon and extension connectivity.',
|
|
158
|
-
inputSchema: {
|
|
162
|
+
inputSchema: {
|
|
163
|
+
destinationId: z.string().optional().describe(DESTINATION_ID_DESCRIPTION),
|
|
164
|
+
},
|
|
159
165
|
},
|
|
160
166
|
handleHealthTool
|
|
161
167
|
);
|
|
@@ -173,6 +179,7 @@ export function createBridgeMcpServer() {
|
|
|
173
179
|
url: z.string().optional().describe('URL for create action'),
|
|
174
180
|
active: z.boolean().optional().describe('Focus the new tab (default: true)'),
|
|
175
181
|
tabId: z.number().int().positive().optional().describe('Tab ID (required for close)'),
|
|
182
|
+
destinationId: z.string().optional().describe(DESTINATION_ID_DESCRIPTION),
|
|
176
183
|
},
|
|
177
184
|
},
|
|
178
185
|
handleTabsTool
|
|
@@ -199,6 +206,7 @@ export function createBridgeMcpServer() {
|
|
|
199
206
|
])
|
|
200
207
|
.describe('DOM operation to perform'),
|
|
201
208
|
tabId: z.number().int().positive().optional().describe(TAB_ID_DESCRIPTION),
|
|
209
|
+
destinationId: z.string().optional().describe(DESTINATION_ID_DESCRIPTION),
|
|
202
210
|
budgetPreset: z
|
|
203
211
|
.enum(['quick', 'normal', 'deep'])
|
|
204
212
|
.optional()
|
|
@@ -291,6 +299,7 @@ export function createBridgeMcpServer() {
|
|
|
291
299
|
.enum(['computed', 'matched_rules', 'box_model', 'hit_test'])
|
|
292
300
|
.describe('Style/layout operation to perform'),
|
|
293
301
|
tabId: z.number().int().positive().optional().describe(TAB_ID_DESCRIPTION),
|
|
302
|
+
destinationId: z.string().optional().describe(DESTINATION_ID_DESCRIPTION),
|
|
294
303
|
budgetPreset: z
|
|
295
304
|
.enum(['quick', 'normal', 'deep'])
|
|
296
305
|
.optional()
|
|
@@ -336,6 +345,7 @@ export function createBridgeMcpServer() {
|
|
|
336
345
|
])
|
|
337
346
|
.describe('Page operation to perform'),
|
|
338
347
|
tabId: z.number().int().positive().optional().describe(TAB_ID_DESCRIPTION),
|
|
348
|
+
destinationId: z.string().optional().describe(DESTINATION_ID_DESCRIPTION),
|
|
339
349
|
budgetPreset: z
|
|
340
350
|
.enum(['quick', 'normal', 'deep'])
|
|
341
351
|
.optional()
|
|
@@ -397,6 +407,7 @@ export function createBridgeMcpServer() {
|
|
|
397
407
|
.enum(['navigate', 'reload', 'go_back', 'go_forward', 'scroll', 'resize'])
|
|
398
408
|
.describe('Navigation operation to perform'),
|
|
399
409
|
tabId: z.number().int().positive().optional().describe(TAB_ID_DESCRIPTION),
|
|
410
|
+
destinationId: z.string().optional().describe(DESTINATION_ID_DESCRIPTION),
|
|
400
411
|
budgetPreset: z
|
|
401
412
|
.enum(['quick', 'normal', 'deep'])
|
|
402
413
|
.optional()
|
|
@@ -451,6 +462,7 @@ export function createBridgeMcpServer() {
|
|
|
451
462
|
])
|
|
452
463
|
.describe('Input operation to perform'),
|
|
453
464
|
tabId: z.number().int().positive().optional().describe(TAB_ID_DESCRIPTION),
|
|
465
|
+
destinationId: z.string().optional().describe(DESTINATION_ID_DESCRIPTION),
|
|
454
466
|
budgetPreset: z
|
|
455
467
|
.enum(['quick', 'normal', 'deep'])
|
|
456
468
|
.optional()
|
|
@@ -533,6 +545,7 @@ export function createBridgeMcpServer() {
|
|
|
533
545
|
.enum(['apply_styles', 'apply_dom', 'list', 'rollback', 'commit_baseline'])
|
|
534
546
|
.describe('Patch operation to perform'),
|
|
535
547
|
tabId: z.number().int().positive().optional().describe(TAB_ID_DESCRIPTION),
|
|
548
|
+
destinationId: z.string().optional().describe(DESTINATION_ID_DESCRIPTION),
|
|
536
549
|
budgetPreset: z
|
|
537
550
|
.enum(['quick', 'normal', 'deep'])
|
|
538
551
|
.optional()
|
|
@@ -593,6 +606,7 @@ export function createBridgeMcpServer() {
|
|
|
593
606
|
'element (preferred), region (tight crop), full_page (document-level only), or cdp_* for low-level data'
|
|
594
607
|
),
|
|
595
608
|
tabId: z.number().int().positive().optional().describe(TAB_ID_DESCRIPTION),
|
|
609
|
+
destinationId: z.string().optional().describe(DESTINATION_ID_DESCRIPTION),
|
|
596
610
|
budgetPreset: z
|
|
597
611
|
.enum(['quick', 'normal', 'deep'])
|
|
598
612
|
.optional()
|
|
@@ -638,6 +652,7 @@ export function createBridgeMcpServer() {
|
|
|
638
652
|
.optional()
|
|
639
653
|
.describe('Method params for this call'),
|
|
640
654
|
tabId: z.number().int().positive().optional().describe(TAB_ID_DESCRIPTION),
|
|
655
|
+
destinationId: z.string().optional().describe(DESTINATION_ID_DESCRIPTION),
|
|
641
656
|
budgetPreset: z
|
|
642
657
|
.enum(['quick', 'normal', 'deep'])
|
|
643
658
|
.optional()
|
|
@@ -664,6 +679,7 @@ export function createBridgeMcpServer() {
|
|
|
664
679
|
.optional()
|
|
665
680
|
.describe('Method parameters as object'),
|
|
666
681
|
tabId: z.number().int().positive().optional().describe(TAB_ID_DESCRIPTION),
|
|
682
|
+
destinationId: z.string().optional().describe(DESTINATION_ID_DESCRIPTION),
|
|
667
683
|
},
|
|
668
684
|
},
|
|
669
685
|
handleRawCallTool
|
|
@@ -675,7 +691,9 @@ export function createBridgeMcpServer() {
|
|
|
675
691
|
title: 'Browser Bridge Runtime Context',
|
|
676
692
|
description:
|
|
677
693
|
'Return runtime context: budget presets, method groups, and active limits. Call to discover defaults before inspecting a page.',
|
|
678
|
-
inputSchema: {
|
|
694
|
+
inputSchema: {
|
|
695
|
+
destinationId: z.string().optional().describe(DESTINATION_ID_DESCRIPTION),
|
|
696
|
+
},
|
|
679
697
|
},
|
|
680
698
|
handleSkillTool
|
|
681
699
|
);
|
|
@@ -726,6 +744,7 @@ export function createBridgeMcpServer() {
|
|
|
726
744
|
'"deep" (state + DOM + text + console + network).'
|
|
727
745
|
),
|
|
728
746
|
tabId: z.number().int().positive().optional().describe(TAB_ID_DESCRIPTION),
|
|
747
|
+
destinationId: z.string().optional().describe(DESTINATION_ID_DESCRIPTION),
|
|
729
748
|
selector: z
|
|
730
749
|
.string()
|
|
731
750
|
.optional()
|
|
@@ -735,8 +754,6 @@ export function createBridgeMcpServer() {
|
|
|
735
754
|
handleInvestigateTool
|
|
736
755
|
);
|
|
737
756
|
|
|
738
|
-
registerBridgeMcpGuidance(server);
|
|
739
|
-
|
|
740
757
|
return server;
|
|
741
758
|
}
|
|
742
759
|
|