@mytai20100/opencode-browser 0.0.1

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/dist/index.js ADDED
@@ -0,0 +1,1285 @@
1
+ #!/usr/bin/env node
2
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
5
+ import { WebSocketServer, WebSocket } from "ws";
6
+ const wss = new WebSocketServer({
7
+ port: 3002,
8
+ host: "0.0.0.0",
9
+ verifyClient: () => true,
10
+ });
11
+ console.error("WebSocket server started on port 3002");
12
+ // Keep connections alive with server-side ping every 25s
13
+ const SERVER_PING_INTERVAL = 25000;
14
+ wss.on("connection", (ws) => {
15
+ console.error("Extension connected");
16
+ ws.isAlive = true;
17
+ ws.on("pong", () => { ws.isAlive = true; });
18
+ ws.on("message", (data) => {
19
+ try {
20
+ const msg = JSON.parse(data.toString());
21
+ // Ignore keep-alive pings from extension
22
+ if (msg.type === "ping")
23
+ return;
24
+ }
25
+ catch (e) { }
26
+ });
27
+ ws.on("close", () => { console.error("Extension disconnected"); });
28
+ });
29
+ // Server-side heartbeat: ping all clients, drop dead ones
30
+ const heartbeat = setInterval(() => {
31
+ wss.clients.forEach((ws) => {
32
+ if (ws.isAlive === false) {
33
+ console.error("Dropping dead connection");
34
+ return ws.terminate();
35
+ }
36
+ ws.isAlive = false;
37
+ ws.ping();
38
+ });
39
+ }, SERVER_PING_INTERVAL);
40
+ const server = new Server({
41
+ name: "opencode-brower",
42
+ version: "opencode beta-2a",
43
+ }, {
44
+ capabilities: {
45
+ tools: {},
46
+ },
47
+ });
48
+ async function callExtension(method, params) {
49
+ return new Promise((resolve, reject) => {
50
+ const id = Math.random().toString(36).substring(7);
51
+ const message = JSON.stringify({ id, method, params });
52
+ let sent = false;
53
+ wss.clients.forEach((client) => {
54
+ if (client.readyState === WebSocket.OPEN) {
55
+ sent = true;
56
+ const listener = (data) => {
57
+ try {
58
+ const response = JSON.parse(data.toString());
59
+ // Ignore keep-alive pings
60
+ if (response.type === "ping")
61
+ return;
62
+ if (response.id === id) {
63
+ client.removeListener("message", listener);
64
+ if (response.error)
65
+ reject(new Error(response.error));
66
+ else
67
+ resolve(response.result);
68
+ }
69
+ }
70
+ catch (e) { }
71
+ };
72
+ client.on("message", listener);
73
+ client.send(message);
74
+ }
75
+ });
76
+ if (!sent) {
77
+ reject(new Error("No extension connected"));
78
+ return;
79
+ }
80
+ setTimeout(() => {
81
+ reject(new Error("Timeout waiting for extension response"));
82
+ }, 30000);
83
+ });
84
+ }
85
+ const TOOLS = [
86
+ // TABS VIEWING & QUERYING
87
+ {
88
+ name: "chrome_list_tabs",
89
+ description: "List all open tabs in Chrome with their id, title, url, active status, window, pinned, muted, audible states",
90
+ inputSchema: { type: "object", properties: {} },
91
+ },
92
+ {
93
+ name: "chrome_get_active_tab",
94
+ description: "Get info about the currently active tab",
95
+ inputSchema: { type: "object", properties: {} },
96
+ },
97
+ {
98
+ name: "chrome_get_tab_info",
99
+ description: "Get detailed info about a specific tab by its id",
100
+ inputSchema: {
101
+ type: "object",
102
+ properties: { tabId: { type: "number", description: "Tab ID" } },
103
+ required: ["tabId"],
104
+ },
105
+ },
106
+ {
107
+ name: "chrome_search_tabs",
108
+ description: "Search open tabs by title or URL keyword",
109
+ inputSchema: {
110
+ type: "object",
111
+ properties: { query: { type: "string", description: "Search term" } },
112
+ required: ["query"],
113
+ },
114
+ },
115
+ // TAB MANAGEMENT
116
+ {
117
+ name: "chrome_navigate",
118
+ description: "Navigate a tab to a URL. Optionally specify tabId; defaults to active tab",
119
+ inputSchema: {
120
+ type: "object",
121
+ properties: {
122
+ url: { type: "string" },
123
+ tabId: { type: "number", description: "Target tab ID (optional)" },
124
+ },
125
+ required: ["url"],
126
+ },
127
+ },
128
+ {
129
+ name: "chrome_new_tab",
130
+ description: "Open a new tab, optionally with a URL",
131
+ inputSchema: {
132
+ type: "object",
133
+ properties: {
134
+ url: { type: "string" },
135
+ active: { type: "boolean", description: "Make it active (default true)" },
136
+ },
137
+ },
138
+ },
139
+ {
140
+ name: "chrome_close_tab",
141
+ description: "Close a tab by id (defaults to active tab)",
142
+ inputSchema: {
143
+ type: "object",
144
+ properties: { tabId: { type: "number" } },
145
+ },
146
+ },
147
+ {
148
+ name: "chrome_close_tabs",
149
+ description: "Close multiple tabs by their ids",
150
+ inputSchema: {
151
+ type: "object",
152
+ properties: {
153
+ tabIds: { type: "array", items: { type: "number" }, description: "Array of tab IDs" },
154
+ },
155
+ required: ["tabIds"],
156
+ },
157
+ },
158
+ {
159
+ name: "chrome_switch_tab",
160
+ description: "Switch to (focus) a specific tab by id",
161
+ inputSchema: {
162
+ type: "object",
163
+ properties: { tabId: { type: "number" } },
164
+ required: ["tabId"],
165
+ },
166
+ },
167
+ {
168
+ name: "chrome_duplicate_tab",
169
+ description: "Duplicate a tab (defaults to active tab)",
170
+ inputSchema: {
171
+ type: "object",
172
+ properties: { tabId: { type: "number" } },
173
+ },
174
+ },
175
+ {
176
+ name: "chrome_pin_tab",
177
+ description: "Pin or unpin a tab",
178
+ inputSchema: {
179
+ type: "object",
180
+ properties: {
181
+ tabId: { type: "number" },
182
+ pinned: { type: "boolean", description: "true to pin, false to unpin (default true)" },
183
+ },
184
+ },
185
+ },
186
+ {
187
+ name: "chrome_mute_tab",
188
+ description: "Mute or unmute a tab",
189
+ inputSchema: {
190
+ type: "object",
191
+ properties: {
192
+ tabId: { type: "number" },
193
+ muted: { type: "boolean", description: "true to mute, false to unmute (default true)" },
194
+ },
195
+ },
196
+ },
197
+ {
198
+ name: "chrome_reload_tab",
199
+ description: "Reload a tab",
200
+ inputSchema: {
201
+ type: "object",
202
+ properties: {
203
+ tabId: { type: "number" },
204
+ bypassCache: { type: "boolean" },
205
+ },
206
+ },
207
+ },
208
+ {
209
+ name: "chrome_move_tab",
210
+ description: "Move a tab to a different position or window",
211
+ inputSchema: {
212
+ type: "object",
213
+ properties: {
214
+ tabId: { type: "number" },
215
+ index: { type: "number" },
216
+ windowId: { type: "number" },
217
+ },
218
+ required: ["tabId", "index"],
219
+ },
220
+ },
221
+ // WINDOWS
222
+ {
223
+ name: "chrome_list_windows",
224
+ description: "List all open Chrome windows with their id, state, focused, tab count",
225
+ inputSchema: { type: "object", properties: {} },
226
+ },
227
+ {
228
+ name: "chrome_new_window",
229
+ description: "Open a new browser window",
230
+ inputSchema: {
231
+ type: "object",
232
+ properties: {
233
+ url: { type: "string" },
234
+ incognito: { type: "boolean" },
235
+ state: { type: "string", enum: ["normal", "minimized", "maximized", "fullscreen"] },
236
+ },
237
+ },
238
+ },
239
+ {
240
+ name: "chrome_close_window",
241
+ description: "Close a browser window",
242
+ inputSchema: {
243
+ type: "object",
244
+ properties: { windowId: { type: "number" } },
245
+ required: ["windowId"],
246
+ },
247
+ },
248
+ // SCREENSHOT
249
+ {
250
+ name: "chrome_screenshot",
251
+ description: "Take a screenshot of the visible area of the current tab. Returns a base64 data URL.",
252
+ inputSchema: {
253
+ type: "object",
254
+ properties: {
255
+ format: { type: "string", enum: ["png", "jpeg"] },
256
+ quality: { type: "number", description: "JPEG quality 0-100" },
257
+ windowId: { type: "number" },
258
+ },
259
+ },
260
+ },
261
+ // PAGE INTERACTION
262
+ {
263
+ name: "chrome_click",
264
+ description: "Click an element by CSS selector in the current (or specified) tab",
265
+ inputSchema: {
266
+ type: "object",
267
+ properties: {
268
+ selector: { type: "string" },
269
+ tabId: { type: "number" },
270
+ },
271
+ required: ["selector"],
272
+ },
273
+ },
274
+ {
275
+ name: "chrome_type",
276
+ description: "Type text into an input element by CSS selector",
277
+ inputSchema: {
278
+ type: "object",
279
+ properties: {
280
+ selector: { type: "string" },
281
+ text: { type: "string" },
282
+ tabId: { type: "number" },
283
+ simulate: { type: "boolean", description: "Simulate key-by-key typing (default false)" },
284
+ },
285
+ required: ["selector", "text"],
286
+ },
287
+ },
288
+ {
289
+ name: "chrome_hover",
290
+ description: "Hover over an element by CSS selector",
291
+ inputSchema: {
292
+ type: "object",
293
+ properties: { selector: { type: "string" }, tabId: { type: "number" } },
294
+ required: ["selector"],
295
+ },
296
+ },
297
+ {
298
+ name: "chrome_select",
299
+ description: "Select an option in a <select> element",
300
+ inputSchema: {
301
+ type: "object",
302
+ properties: {
303
+ selector: { type: "string" },
304
+ value: { type: "string" },
305
+ tabId: { type: "number" },
306
+ },
307
+ required: ["selector", "value"],
308
+ },
309
+ },
310
+ {
311
+ name: "chrome_scroll",
312
+ description: "Scroll the page or an element by x/y pixels",
313
+ inputSchema: {
314
+ type: "object",
315
+ properties: {
316
+ x: { type: "number" },
317
+ y: { type: "number" },
318
+ selector: { type: "string", description: "Scroll a specific element (optional)" },
319
+ tabId: { type: "number" },
320
+ },
321
+ },
322
+ },
323
+ {
324
+ name: "chrome_scroll_to",
325
+ description: "Scroll an element into view by CSS selector",
326
+ inputSchema: {
327
+ type: "object",
328
+ properties: { selector: { type: "string" }, tabId: { type: "number" } },
329
+ required: ["selector"],
330
+ },
331
+ },
332
+ {
333
+ name: "chrome_key_press",
334
+ description: "Dispatch a keyboard event (e.g. 'Enter', 'Escape', 'Tab') on the page or element",
335
+ inputSchema: {
336
+ type: "object",
337
+ properties: {
338
+ key: { type: "string", description: "Key name e.g. 'Enter', 'Escape', 'ArrowDown'" },
339
+ selector: { type: "string", description: "Target element (optional, defaults to focused element)" },
340
+ tabId: { type: "number" },
341
+ },
342
+ required: ["key"],
343
+ },
344
+ },
345
+ {
346
+ name: "chrome_wait_for_element",
347
+ description: "Wait until a CSS selector appears in the DOM",
348
+ inputSchema: {
349
+ type: "object",
350
+ properties: {
351
+ selector: { type: "string" },
352
+ timeout: { type: "number", description: "Max wait in ms (default 5000)" },
353
+ tabId: { type: "number" },
354
+ },
355
+ required: ["selector"],
356
+ },
357
+ },
358
+ // PAGE CONTENT
359
+ {
360
+ name: "chrome_get_content",
361
+ description: "Get the visible text content of the current (or specified) tab's page",
362
+ inputSchema: {
363
+ type: "object",
364
+ properties: { tabId: { type: "number" } },
365
+ },
366
+ },
367
+ {
368
+ name: "chrome_get_html",
369
+ description: "Get the outer HTML of an element (or full page if no selector given)",
370
+ inputSchema: {
371
+ type: "object",
372
+ properties: {
373
+ selector: { type: "string" },
374
+ tabId: { type: "number" },
375
+ },
376
+ },
377
+ },
378
+ {
379
+ name: "chrome_get_element_info",
380
+ description: "Get detailed info about a DOM element: tag, id, class, text, attributes, bounding box, visibility",
381
+ inputSchema: {
382
+ type: "object",
383
+ properties: { selector: { type: "string" }, tabId: { type: "number" } },
384
+ required: ["selector"],
385
+ },
386
+ },
387
+ {
388
+ name: "chrome_find_elements",
389
+ description: "Find all elements matching a CSS selector and return their properties",
390
+ inputSchema: {
391
+ type: "object",
392
+ properties: {
393
+ selector: { type: "string" },
394
+ limit: { type: "number", description: "Max results (default 50)" },
395
+ tabId: { type: "number" },
396
+ },
397
+ required: ["selector"],
398
+ },
399
+ },
400
+ {
401
+ name: "chrome_get_page_info",
402
+ description: "Get page metadata: title, URL, scroll position, viewport size, links, meta description",
403
+ inputSchema: {
404
+ type: "object",
405
+ properties: { tabId: { type: "number" } },
406
+ },
407
+ },
408
+ {
409
+ name: "chrome_execute_script",
410
+ description: "Execute arbitrary JavaScript in the current (or specified) tab with full DOM access",
411
+ inputSchema: {
412
+ type: "object",
413
+ properties: {
414
+ code: { type: "string" },
415
+ tabId: { type: "number" },
416
+ allFrames: { type: "boolean" },
417
+ },
418
+ required: ["code"],
419
+ },
420
+ },
421
+ // NAVIGATION HISTORY
422
+ {
423
+ name: "chrome_go_back",
424
+ description: "Navigate back in the current tab's history",
425
+ inputSchema: {
426
+ type: "object",
427
+ properties: { tabId: { type: "number" } },
428
+ },
429
+ },
430
+ {
431
+ name: "chrome_go_forward",
432
+ description: "Navigate forward in the current tab's history",
433
+ inputSchema: {
434
+ type: "object",
435
+ properties: { tabId: { type: "number" } },
436
+ },
437
+ },
438
+ {
439
+ name: "chrome_go_home",
440
+ description: "Navigate the active tab to the new tab page",
441
+ inputSchema: { type: "object", properties: {} },
442
+ },
443
+ // COOKIES
444
+ {
445
+ name: "chrome_get_cookies",
446
+ description: "Get all cookies for a given URL",
447
+ inputSchema: {
448
+ type: "object",
449
+ properties: { url: { type: "string" } },
450
+ required: ["url"],
451
+ },
452
+ },
453
+ {
454
+ name: "chrome_set_cookie",
455
+ description: "Set a cookie for a URL",
456
+ inputSchema: {
457
+ type: "object",
458
+ properties: {
459
+ url: { type: "string" },
460
+ name: { type: "string" },
461
+ value: { type: "string" },
462
+ domain: { type: "string" },
463
+ path: { type: "string" },
464
+ secure: { type: "boolean" },
465
+ httpOnly: { type: "boolean" },
466
+ },
467
+ required: ["url", "name", "value"],
468
+ },
469
+ },
470
+ {
471
+ name: "chrome_delete_cookie",
472
+ description: "Delete a specific cookie",
473
+ inputSchema: {
474
+ type: "object",
475
+ properties: { url: { type: "string" }, name: { type: "string" } },
476
+ required: ["url", "name"],
477
+ },
478
+ },
479
+ // LOCAL STORAGE
480
+ {
481
+ name: "chrome_get_local_storage",
482
+ description: "Get localStorage value(s) from the current page",
483
+ inputSchema: {
484
+ type: "object",
485
+ properties: {
486
+ key: { type: "string", description: "Specific key (omit to get all)" },
487
+ tabId: { type: "number" },
488
+ },
489
+ },
490
+ },
491
+ {
492
+ name: "chrome_set_local_storage",
493
+ description: "Set a localStorage value on the current page",
494
+ inputSchema: {
495
+ type: "object",
496
+ properties: {
497
+ key: { type: "string" },
498
+ value: { type: "string" },
499
+ tabId: { type: "number" },
500
+ },
501
+ required: ["key", "value"],
502
+ },
503
+ },
504
+ {
505
+ name: "chrome_clear_local_storage",
506
+ description: "Clear all localStorage on the current page",
507
+ inputSchema: {
508
+ type: "object",
509
+ properties: { tabId: { type: "number" } },
510
+ },
511
+ },
512
+ // HISTORY & BOOKMARKS
513
+ {
514
+ name: "chrome_get_history",
515
+ description: "Search browser history by text query",
516
+ inputSchema: {
517
+ type: "object",
518
+ properties: {
519
+ query: { type: "string" },
520
+ maxResults: { type: "number" },
521
+ startTime: { type: "number", description: "Start time in ms epoch" },
522
+ },
523
+ },
524
+ },
525
+ {
526
+ name: "chrome_add_bookmark",
527
+ description: "Add a bookmark",
528
+ inputSchema: {
529
+ type: "object",
530
+ properties: {
531
+ title: { type: "string" },
532
+ url: { type: "string" },
533
+ parentId: { type: "string" },
534
+ },
535
+ required: ["title", "url"],
536
+ },
537
+ },
538
+ {
539
+ name: "chrome_search_bookmarks",
540
+ description: "Search bookmarks by title or URL",
541
+ inputSchema: {
542
+ type: "object",
543
+ properties: {
544
+ query: { type: "string" },
545
+ limit: { type: "number" },
546
+ },
547
+ required: ["query"],
548
+ },
549
+ },
550
+ {
551
+ name: "chrome_get_bookmarks",
552
+ description: "Get all bookmarks in a flat list",
553
+ inputSchema: { type: "object", properties: {} },
554
+ },
555
+ // DOWNLOADS
556
+ {
557
+ name: "chrome_download",
558
+ description: "Download a file from a URL",
559
+ inputSchema: {
560
+ type: "object",
561
+ properties: {
562
+ url: { type: "string" },
563
+ filename: { type: "string" },
564
+ saveAs: { type: "boolean" },
565
+ },
566
+ required: ["url"],
567
+ },
568
+ },
569
+ {
570
+ name: "chrome_list_downloads",
571
+ description: "List recent downloads",
572
+ inputSchema: {
573
+ type: "object",
574
+ properties: {
575
+ limit: { type: "number" },
576
+ state: { type: "string", enum: ["in_progress", "interrupted", "complete"] },
577
+ },
578
+ },
579
+ },
580
+ // TAB GROUPS
581
+ {
582
+ name: "chrome_group_tabs",
583
+ description: "Group tabs together, optionally with a title and color",
584
+ inputSchema: {
585
+ type: "object",
586
+ properties: {
587
+ tabIds: { type: "array", items: { type: "number" } },
588
+ title: { type: "string" },
589
+ color: {
590
+ type: "string",
591
+ enum: ["grey", "blue", "red", "yellow", "green", "pink", "purple", "cyan", "orange"],
592
+ },
593
+ },
594
+ required: ["tabIds"],
595
+ },
596
+ },
597
+ {
598
+ name: "chrome_ungroup_tabs",
599
+ description: "Ungroup tabs",
600
+ inputSchema: {
601
+ type: "object",
602
+ properties: { tabIds: { type: "array", items: { type: "number" } } },
603
+ required: ["tabIds"],
604
+ },
605
+ },
606
+ // NOTIFICATIONS
607
+ {
608
+ name: "chrome_notify",
609
+ description: "Show a desktop notification",
610
+ inputSchema: {
611
+ type: "object",
612
+ properties: {
613
+ title: { type: "string" },
614
+ message: { type: "string" },
615
+ },
616
+ required: ["message"],
617
+ },
618
+ },
619
+ // ZOOM
620
+ {
621
+ name: "chrome_set_zoom",
622
+ description: "Set zoom level of a tab (1.0 = 100%)",
623
+ inputSchema: {
624
+ type: "object",
625
+ properties: {
626
+ zoom: { type: "number" },
627
+ tabId: { type: "number" },
628
+ },
629
+ required: ["zoom"],
630
+ },
631
+ },
632
+ {
633
+ name: "chrome_get_zoom",
634
+ description: "Get current zoom level of a tab",
635
+ inputSchema: {
636
+ type: "object",
637
+ properties: { tabId: { type: "number" } },
638
+ },
639
+ },
640
+ // CLIPBOARD
641
+ {
642
+ name: "chrome_write_clipboard",
643
+ description: "Write text to the clipboard",
644
+ inputSchema: {
645
+ type: "object",
646
+ properties: { text: { type: "string" }, tabId: { type: "number" } },
647
+ required: ["text"],
648
+ },
649
+ },
650
+ {
651
+ name: "chrome_read_clipboard",
652
+ description: "Read text from the clipboard",
653
+ inputSchema: {
654
+ type: "object",
655
+ properties: { tabId: { type: "number" } },
656
+ },
657
+ },
658
+ // EXTENSION META
659
+ {
660
+ name: "chrome_get_extension_info",
661
+ description: "Get info about the Opencode Brower extension itself",
662
+ inputSchema: { type: "object", properties: {} },
663
+ },
664
+ // DEVTOOLS / DEBUGGER (CDP)
665
+ {
666
+ name: "chrome_debug_attach",
667
+ description: "Attach Chrome DevTools Protocol debugger to a tab. Enables Console, Network, Runtime, Performance domains for capturing logs and requests.",
668
+ inputSchema: {
669
+ type: "object",
670
+ properties: { tabId: { type: "number" } },
671
+ },
672
+ },
673
+ {
674
+ name: "chrome_debug_detach",
675
+ description: "Detach the debugger from a tab",
676
+ inputSchema: {
677
+ type: "object",
678
+ properties: { tabId: { type: "number" } },
679
+ },
680
+ },
681
+ {
682
+ name: "chrome_debug_get_logs",
683
+ description: "Get captured console logs from a debugged tab (console.log, warn, error, info)",
684
+ inputSchema: {
685
+ type: "object",
686
+ properties: {
687
+ tabId: { type: "number" },
688
+ limit: { type: "number", description: "Max number of logs to return (default 100)" },
689
+ level: { type: "string", description: "Filter by level: log, warn, error, info" },
690
+ },
691
+ },
692
+ },
693
+ {
694
+ name: "chrome_debug_clear_logs",
695
+ description: "Clear captured console logs for a tab",
696
+ inputSchema: {
697
+ type: "object",
698
+ properties: { tabId: { type: "number" } },
699
+ },
700
+ },
701
+ {
702
+ name: "chrome_debug_get_network",
703
+ description: "Get captured network requests (XHR, Fetch, etc.) from a debugged tab",
704
+ inputSchema: {
705
+ type: "object",
706
+ properties: {
707
+ tabId: { type: "number" },
708
+ limit: { type: "number", description: "Max results (default 100)" },
709
+ filter: { type: "string", description: "Filter URLs containing this string" },
710
+ },
711
+ },
712
+ },
713
+ {
714
+ name: "chrome_debug_clear_network",
715
+ description: "Clear captured network log for a tab",
716
+ inputSchema: {
717
+ type: "object",
718
+ properties: { tabId: { type: "number" } },
719
+ },
720
+ },
721
+ {
722
+ name: "chrome_debug_get_response_body",
723
+ description: "Get the response body of a captured network request by requestId",
724
+ inputSchema: {
725
+ type: "object",
726
+ properties: {
727
+ requestId: { type: "string" },
728
+ tabId: { type: "number" },
729
+ },
730
+ required: ["requestId"],
731
+ },
732
+ },
733
+ {
734
+ name: "chrome_debug_eval",
735
+ description: "Evaluate JavaScript in the page context via CDP Runtime.evaluate (bypasses sandbox, supports await)",
736
+ inputSchema: {
737
+ type: "object",
738
+ properties: {
739
+ code: { type: "string" },
740
+ tabId: { type: "number" },
741
+ },
742
+ required: ["code"],
743
+ },
744
+ },
745
+ {
746
+ name: "chrome_debug_get_performance",
747
+ description: "Get performance metrics from a debugged tab (JS heap, DOM nodes, layout count, etc.)",
748
+ inputSchema: {
749
+ type: "object",
750
+ properties: { tabId: { type: "number" } },
751
+ },
752
+ },
753
+ {
754
+ name: "chrome_debug_get_dom_snapshot",
755
+ description: "Capture a full DOM snapshot including layout, paint order, and bounding rects",
756
+ inputSchema: {
757
+ type: "object",
758
+ properties: { tabId: { type: "number" } },
759
+ },
760
+ },
761
+ {
762
+ name: "chrome_debug_set_breakpoint",
763
+ description: "Set a JavaScript breakpoint by URL and line number via CDP Debugger",
764
+ inputSchema: {
765
+ type: "object",
766
+ properties: {
767
+ url: { type: "string" },
768
+ line: { type: "number" },
769
+ column: { type: "number" },
770
+ tabId: { type: "number" },
771
+ },
772
+ required: ["url", "line"],
773
+ },
774
+ },
775
+ {
776
+ name: "chrome_debug_remove_breakpoint",
777
+ description: "Remove a JavaScript breakpoint by breakpointId",
778
+ inputSchema: {
779
+ type: "object",
780
+ properties: {
781
+ breakpointId: { type: "string" },
782
+ tabId: { type: "number" },
783
+ },
784
+ required: ["breakpointId"],
785
+ },
786
+ },
787
+ {
788
+ name: "chrome_debug_get_cookies",
789
+ description: "Get ALL cookies including HttpOnly ones via CDP Network.getAllCookies",
790
+ inputSchema: {
791
+ type: "object",
792
+ properties: { tabId: { type: "number" } },
793
+ },
794
+ },
795
+ {
796
+ name: "chrome_debug_set_xhr_breakpoint",
797
+ description: "Set an XHR/Fetch breakpoint to pause when a URL pattern is requested",
798
+ inputSchema: {
799
+ type: "object",
800
+ properties: {
801
+ url: { type: "string", description: "URL pattern to break on (empty = all XHR)" },
802
+ tabId: { type: "number" },
803
+ },
804
+ },
805
+ },
806
+ {
807
+ name: "chrome_debug_emulate_device",
808
+ description: "Emulate a mobile device (screen size, user agent, DPR)",
809
+ inputSchema: {
810
+ type: "object",
811
+ properties: {
812
+ width: { type: "number", description: "Screen width in px (default 375)" },
813
+ height: { type: "number", description: "Screen height in px (default 812)" },
814
+ deviceScaleFactor: { type: "number", description: "DPR (default 2)" },
815
+ mobile: { type: "boolean" },
816
+ userAgent: { type: "string" },
817
+ tabId: { type: "number" },
818
+ },
819
+ },
820
+ },
821
+ {
822
+ name: "chrome_debug_emulate_network",
823
+ description: "Throttle network speed to emulate different conditions",
824
+ inputSchema: {
825
+ type: "object",
826
+ properties: {
827
+ preset: { type: "string", enum: ["offline", "slow3g", "fast3g", "none"], description: "Preset throttle condition" },
828
+ offline: { type: "boolean" },
829
+ download: { type: "number", description: "Download in bytes/sec" },
830
+ upload: { type: "number", description: "Upload in bytes/sec" },
831
+ latency: { type: "number", description: "Latency in ms" },
832
+ tabId: { type: "number" },
833
+ },
834
+ },
835
+ },
836
+ {
837
+ name: "chrome_debug_block_urls",
838
+ description: "Block specific URL patterns from loading (ads, tracking, API calls)",
839
+ inputSchema: {
840
+ type: "object",
841
+ properties: {
842
+ urls: { type: "array", items: { type: "string" }, description: "URL patterns to block" },
843
+ tabId: { type: "number" },
844
+ },
845
+ required: ["urls"],
846
+ },
847
+ },
848
+ {
849
+ name: "chrome_debug_get_storage",
850
+ description: "Get DOM storage (localStorage/sessionStorage) for a specific origin via CDP",
851
+ inputSchema: {
852
+ type: "object",
853
+ properties: {
854
+ origin: { type: "string", description: "Security origin e.g. https://example.com" },
855
+ isLocal: { type: "boolean", description: "true = localStorage, false = sessionStorage (default true)" },
856
+ tabId: { type: "number" },
857
+ },
858
+ required: ["origin"],
859
+ },
860
+ },
861
+ {
862
+ name: "chrome_debug_send_command",
863
+ description: "Send a raw Chrome DevTools Protocol (CDP) command for advanced debugging",
864
+ inputSchema: {
865
+ type: "object",
866
+ properties: {
867
+ command: { type: "string", description: "CDP method e.g. 'Network.enable', 'DOM.getDocument'" },
868
+ commandParams: { type: "object", description: "Parameters for the CDP command" },
869
+ tabId: { type: "number" },
870
+ },
871
+ required: ["command"],
872
+ },
873
+ },
874
+ // ACCESSIBILITY
875
+ {
876
+ name: "chrome_get_accessibility_tree",
877
+ description: "Get the full accessibility tree of the page via CDP AX (useful for finding elements by label/role)",
878
+ inputSchema: {
879
+ type: "object",
880
+ properties: {
881
+ tabId: { type: "number" },
882
+ limit: { type: "number", description: "Max nodes to return (default 200)" },
883
+ },
884
+ },
885
+ },
886
+ {
887
+ name: "chrome_find_accessible_nodes",
888
+ description: "Find accessibility nodes by name/label and/or role (button, textbox, link, etc.)",
889
+ inputSchema: {
890
+ type: "object",
891
+ properties: {
892
+ query: { type: "string", description: "Text/label to search for" },
893
+ role: { type: "string", description: "ARIA role to filter by e.g. button, textbox, link" },
894
+ limit: { type: "number" },
895
+ tabId: { type: "number" },
896
+ },
897
+ },
898
+ },
899
+ // VISUAL / OC
900
+ {
901
+ name: "chrome_visual_click",
902
+ description: "Click at specific X/Y screen coordinates via CDP Input (useful when CSS selector is unavailable)",
903
+ inputSchema: {
904
+ type: "object",
905
+ properties: {
906
+ x: { type: "number", description: "X coordinate in pixels" },
907
+ y: { type: "number", description: "Y coordinate in pixels" },
908
+ tabId: { type: "number" },
909
+ },
910
+ required: ["x", "y"],
911
+ },
912
+ },
913
+ {
914
+ name: "chrome_ocr_page",
915
+ description: "Extract all visible text from the page with bounding box coordinates (like OCR)",
916
+ inputSchema: {
917
+ type: "object",
918
+ properties: {
919
+ tabId: { type: "number" },
920
+ limit: { type: "number", description: "Max text nodes (default 500)" },
921
+ },
922
+ },
923
+ },
924
+ {
925
+ name: "chrome_find_text_on_screen",
926
+ description: "Find text on the visible page and return its screen coordinates for visual clicking",
927
+ inputSchema: {
928
+ type: "object",
929
+ properties: {
930
+ query: { type: "string", description: "Text to find on screen" },
931
+ exact: { type: "boolean", description: "Exact match (default false)" },
932
+ tabId: { type: "number" },
933
+ },
934
+ required: ["query"],
935
+ },
936
+ },
937
+ // NETWORK INTERCEPT / MOCK
938
+ {
939
+ name: "chrome_intercept_request",
940
+ description: "Intercept all network requests matching a URL pattern via CDP Fetch. Captured requests available via debug_get_network.",
941
+ inputSchema: {
942
+ type: "object",
943
+ properties: {
944
+ urlPattern: { type: "string", description: "URL pattern to intercept e.g. '*/api/*'" },
945
+ tabId: { type: "number" },
946
+ },
947
+ },
948
+ },
949
+ {
950
+ name: "chrome_mock_response",
951
+ description: "Mock the response of a specific URL with custom status, headers, and body",
952
+ inputSchema: {
953
+ type: "object",
954
+ properties: {
955
+ url: { type: "string", description: "Exact URL to mock" },
956
+ status: { type: "number", description: "HTTP status code (default 200)" },
957
+ headers: { type: "object", description: "Response headers" },
958
+ body: { description: "Response body (string or object)" },
959
+ },
960
+ required: ["url"],
961
+ },
962
+ },
963
+ {
964
+ name: "chrome_modify_headers",
965
+ description: "Automatically modify request headers for all matching requests (add auth tokens, change User-Agent, etc.)",
966
+ inputSchema: {
967
+ type: "object",
968
+ properties: {
969
+ urlPattern: { type: "string", description: "URL pattern to match" },
970
+ headers: { type: "object", description: "Headers to add/override" },
971
+ tabId: { type: "number" },
972
+ },
973
+ required: ["headers"],
974
+ },
975
+ },
976
+ // SESSION
977
+ {
978
+ name: "chrome_save_session",
979
+ description: "Save the current session (cookies + localStorage) for later restoration",
980
+ inputSchema: {
981
+ type: "object",
982
+ properties: {
983
+ name: { type: "string", description: "Session name/key to save as" },
984
+ tabId: { type: "number" },
985
+ },
986
+ required: ["name"],
987
+ },
988
+ },
989
+ {
990
+ name: "chrome_restore_session",
991
+ description: "Restore a previously saved session (cookies + localStorage)",
992
+ inputSchema: {
993
+ type: "object",
994
+ properties: {
995
+ name: { type: "string", description: "Session name/key to restore" },
996
+ tabId: { type: "number" },
997
+ },
998
+ required: ["name"],
999
+ },
1000
+ },
1001
+ // EVENTS & DOM WATCH
1002
+ {
1003
+ name: "chrome_subscribe_events",
1004
+ description: "Subscribe to DOM events (click, input, submit, etc.) and log them for later retrieval via get_workflow_context",
1005
+ inputSchema: {
1006
+ type: "object",
1007
+ properties: {
1008
+ events: {
1009
+ type: "array", items: { type: "string" },
1010
+ description: "List of events to listen to (default: click, input, submit, change, keydown)"
1011
+ },
1012
+ tabId: { type: "number" },
1013
+ },
1014
+ },
1015
+ },
1016
+ {
1017
+ name: "chrome_watch_dom_changes",
1018
+ description: "Watch for DOM mutations (added/removed elements, attribute changes) via MutationObserver",
1019
+ inputSchema: {
1020
+ type: "object",
1021
+ properties: {
1022
+ selector: { type: "string", description: "Root element to observe (default: document.body)" },
1023
+ limit: { type: "number", description: "Max mutations to store (default 500)" },
1024
+ tabId: { type: "number" },
1025
+ },
1026
+ },
1027
+ },
1028
+ // IFRAMES
1029
+ {
1030
+ name: "chrome_list_iframes",
1031
+ description: "List all iframes on the current page with src, id, name, and dimensions",
1032
+ inputSchema: {
1033
+ type: "object",
1034
+ properties: { tabId: { type: "number" } },
1035
+ },
1036
+ },
1037
+ {
1038
+ name: "chrome_switch_iframe",
1039
+ description: "Execute JavaScript code inside a specific iframe by frame index",
1040
+ inputSchema: {
1041
+ type: "object",
1042
+ properties: {
1043
+ frameIndex: { type: "number", description: "Index of the iframe (0-based)" },
1044
+ code: { type: "string", description: "JavaScript to execute inside the iframe" },
1045
+ tabId: { type: "number" },
1046
+ },
1047
+ required: ["frameIndex"],
1048
+ },
1049
+ },
1050
+ // FILE UPLOAD
1051
+ {
1052
+ name: "chrome_upload_file",
1053
+ description: "Set files on a file input element via CDP DOM.setFileInputFiles",
1054
+ inputSchema: {
1055
+ type: "object",
1056
+ properties: {
1057
+ selector: { type: "string", description: "CSS selector of the file input element" },
1058
+ files: { type: "array", items: { type: "string" }, description: "Array of absolute file paths to upload" },
1059
+ tabId: { type: "number" },
1060
+ },
1061
+ required: ["selector", "files"],
1062
+ },
1063
+ },
1064
+ // PERMISSIONS
1065
+ {
1066
+ name: "chrome_grant_permissions",
1067
+ description: "Grant browser permissions to the current origin (geolocation, camera, microphone, notifications, etc.)",
1068
+ inputSchema: {
1069
+ type: "object",
1070
+ properties: {
1071
+ permissions: {
1072
+ type: "array", items: { type: "string" },
1073
+ description: "Permissions to grant e.g. ['geolocation', 'camera', 'microphone', 'notifications']"
1074
+ },
1075
+ tabId: { type: "number" },
1076
+ },
1077
+ required: ["permissions"],
1078
+ },
1079
+ },
1080
+ // VIRTUAL AUTHENTICATOR
1081
+ {
1082
+ name: "chrome_virtual_authenticator",
1083
+ description: "Add/remove a virtual WebAuthn authenticator for testing passkey/FIDO2 flows",
1084
+ inputSchema: {
1085
+ type: "object",
1086
+ properties: {
1087
+ action: { type: "string", enum: ["enable", "add", "remove"], description: "Action to perform" },
1088
+ protocol: { type: "string", enum: ["ctap2", "u2f"], description: "Authenticator protocol (default ctap2)" },
1089
+ transport: { type: "string", enum: ["usb", "nfc", "ble", "internal"], description: "Transport (default usb)" },
1090
+ authenticatorId: { type: "string", description: "ID for remove action" },
1091
+ hasResidentKey: { type: "boolean" },
1092
+ hasUserVerification: { type: "boolean" },
1093
+ isUserVerified: { type: "boolean" },
1094
+ tabId: { type: "number" },
1095
+ },
1096
+ required: ["action"],
1097
+ },
1098
+ },
1099
+ // WORKFLOW CONTEXT
1100
+ {
1101
+ name: "chrome_get_workflow_context",
1102
+ description: "Get a comprehensive snapshot of the current page state: forms, buttons, inputs, event log, mutation log — ideal for AI workflow planning",
1103
+ inputSchema: {
1104
+ type: "object",
1105
+ properties: { tabId: { type: "number" } },
1106
+ },
1107
+ },
1108
+ // HAR EXPORT
1109
+ {
1110
+ name: "chrome_export_har",
1111
+ description: "Export all captured network requests as a HAR (HTTP Archive) file",
1112
+ inputSchema: {
1113
+ type: "object",
1114
+ properties: { tabId: { type: "number" } },
1115
+ },
1116
+ },
1117
+ // REPLAY REQUEST
1118
+ {
1119
+ name: "chrome_replay_request",
1120
+ description: "Re-send any HTTP request with custom method, headers, and body directly from the page context",
1121
+ inputSchema: {
1122
+ type: "object",
1123
+ properties: {
1124
+ url: { type: "string" },
1125
+ method: { type: "string", description: "HTTP method (default GET)" },
1126
+ headers: { type: "object" },
1127
+ body: { type: "string" },
1128
+ tabId: { type: "number" },
1129
+ },
1130
+ required: ["url"],
1131
+ },
1132
+ },
1133
+ // TOOL GRAPH
1134
+ {
1135
+ name: "chrome_get_tool_graph",
1136
+ description: "CALL THIS FIRST before any task. Returns the optimal tool graph: which tools to use for a given intent, their cost, prerequisites, and which tools to AVOID to save tokens. Prevents redundant tool calls.",
1137
+ inputSchema: {
1138
+ type: "object",
1139
+ properties: {
1140
+ intent: { type: "string", description: "What you are trying to do in plain text e.g. 'read page content', 'click a button', 'capture network requests'" },
1141
+ tools: { type: "array", items: { type: "string" }, description: "Optional: filter graph to specific tool names" },
1142
+ },
1143
+ },
1144
+ },
1145
+ ];
1146
+ // TOOL GRAPH (server-side, no extension needed)
1147
+ const TOOL_GRAPH = {
1148
+ // Observation (cheap, always prefer first)
1149
+ chrome_get_active_tab: { description: "Get current tab info", intent: ["what tab am I on", "current url", "current tab"], cost: "low", next: ["chrome_get_content", "chrome_get_page_info", "chrome_screenshot"] },
1150
+ chrome_list_tabs: { description: "List all open tabs", intent: ["how many tabs", "find tab", "list tabs", "all tabs open"], cost: "low", next: ["chrome_switch_tab", "chrome_close_tab"] },
1151
+ chrome_get_page_info: { description: "Title, URL, links, meta", intent: ["page title", "page url", "links on page", "meta description"], cost: "low", next: ["chrome_get_content", "chrome_find_elements"] },
1152
+ chrome_get_content: { description: "Full visible text of page", intent: ["read page", "page text", "what does page say", "extract text", "scrape"], cost: "low", avoid: ["chrome_get_html"] },
1153
+ chrome_get_workflow_context: { description: "Forms, buttons, inputs snapshot — use BEFORE interacting with a page", intent: ["plan interaction", "find form", "find button", "what inputs exist", "how to fill form"], cost: "low", next: ["chrome_click", "chrome_type", "chrome_find_accessible_nodes"] },
1154
+ chrome_find_elements: { description: "Find matching DOM elements", intent: ["find elements", "query selector", "list buttons", "list links"], cost: "low" },
1155
+ chrome_get_element_info: { description: "Info about one element", intent: ["is element visible", "element position", "element attributes"], cost: "low" },
1156
+ chrome_list_iframes: { description: "List all iframes", intent: ["iframes on page", "embedded frames"], cost: "low", next: ["chrome_switch_iframe"] },
1157
+ chrome_get_accessibility_tree: { description: "Full AX tree for finding by label/role", intent: ["find by label", "accessible name", "aria role"], cost: "medium", avoid: ["chrome_find_elements"] },
1158
+ chrome_find_accessible_nodes: { description: "Find AX node by name and role", intent: ["find button by label", "find input by name", "click button named"], cost: "medium", next: ["chrome_visual_click"] },
1159
+ chrome_ocr_page: { description: "All text with bounding boxes", intent: ["find text position", "where is text on screen"], cost: "medium", avoid: ["chrome_screenshot"] },
1160
+ chrome_find_text_on_screen: { description: "Find text and get click coordinates", intent: ["click text", "find text on screen", "where is button"], cost: "medium", next: ["chrome_visual_click"] },
1161
+ // Navigation (medium cost)
1162
+ chrome_navigate: { description: "Go to URL", intent: ["open url", "go to", "navigate to", "open website"], cost: "low", next: ["chrome_wait_for_element", "chrome_get_page_info"] },
1163
+ chrome_new_tab: { description: "Open new tab", intent: ["open new tab", "new tab", "open in new tab"], cost: "low" },
1164
+ chrome_switch_tab: { description: "Focus a tab by ID", intent: ["switch to tab", "go to tab"], cost: "low", requires: ["chrome_list_tabs"] },
1165
+ chrome_go_back: { description: "Browser back", intent: ["go back", "previous page"], cost: "low" },
1166
+ chrome_go_forward: { description: "Browser forward", intent: ["go forward", "next page"], cost: "low" },
1167
+ chrome_reload_tab: { description: "Reload tab", intent: ["reload", "refresh page"], cost: "low" },
1168
+ // Interaction (medium cost — always prefer get_workflow_context first)
1169
+ chrome_click: { description: "Click by CSS selector", intent: ["click button", "click link", "press button"], cost: "low", requires: ["chrome_get_workflow_context"], avoid: ["chrome_visual_click"] },
1170
+ chrome_type: { description: "Type into input by selector", intent: ["type text", "fill input", "enter text in field"], cost: "low", requires: ["chrome_get_workflow_context"] },
1171
+ chrome_key_press: { description: "Press a key (Enter, Escape)", intent: ["press enter", "press escape", "submit form"], cost: "low" },
1172
+ chrome_hover: { description: "Hover over element", intent: ["hover", "mouse over", "tooltip"], cost: "low" },
1173
+ chrome_select: { description: "Select dropdown option", intent: ["select option", "choose dropdown"], cost: "low" },
1174
+ chrome_scroll: { description: "Scroll page by pixels", intent: ["scroll down", "scroll up"], cost: "low" },
1175
+ chrome_wait_for_element: { description: "Wait for element to appear", intent: ["wait for load", "wait for element", "page loading"], cost: "low", next: ["chrome_click", "chrome_get_content"] },
1176
+ chrome_visual_click: { description: "Click by X/Y coordinates", intent: ["click coordinate", "click position"], cost: "medium", avoid: ["chrome_click"], requires: ["chrome_find_text_on_screen"] },
1177
+ chrome_upload_file: { description: "Set files on file input", intent: ["upload file", "attach file"], cost: "medium", requires: ["chrome_debug_attach"] },
1178
+ chrome_switch_iframe: { description: "Execute code inside iframe", intent: ["interact iframe", "iframe content"], cost: "medium", requires: ["chrome_list_iframes"] },
1179
+ // Screenshot (expensive — avoid unless visual check needed)
1180
+ chrome_screenshot: { description: "Screenshot of visible tab", intent: ["take screenshot", "capture page", "see page visually"], cost: "high", avoid: ["chrome_get_content", "chrome_get_page_info"] },
1181
+ // Debug tools (require attach first)
1182
+ chrome_debug_attach: { description: "Attach CDP debugger", intent: ["debug tab", "capture network", "read console", "monitor requests"], cost: "medium", next: ["chrome_debug_get_network", "chrome_debug_get_logs", "chrome_debug_get_performance"] },
1183
+ chrome_debug_get_logs: { description: "Read console logs", intent: ["console log", "js error", "read logs"], cost: "low", requires: ["chrome_debug_attach"] },
1184
+ chrome_debug_get_network: { description: "List captured network requests", intent: ["api calls", "network requests", "xhr", "fetch calls"], cost: "low", requires: ["chrome_debug_attach"] },
1185
+ chrome_debug_get_response_body: { description: "Read response body of request", intent: ["api response", "response body", "what did api return"], cost: "low", requires: ["chrome_debug_attach", "chrome_debug_get_network"] },
1186
+ chrome_debug_eval: { description: "Eval JS via CDP (async-safe)", intent: ["run async js", "await in page", "bypass csp"], cost: "medium", requires: ["chrome_debug_attach"], avoid: ["chrome_execute_script"] },
1187
+ chrome_debug_get_performance: { description: "JS heap, DOM node count, layout metrics", intent: ["performance", "memory usage", "page metrics"], cost: "medium", requires: ["chrome_debug_attach"] },
1188
+ chrome_debug_emulate_device: { description: "Mobile device emulation", intent: ["mobile view", "responsive test", "iphone view"], cost: "medium", requires: ["chrome_debug_attach"] },
1189
+ chrome_debug_emulate_network: { description: "Throttle network", intent: ["slow network", "offline test", "3g simulation"], cost: "medium", requires: ["chrome_debug_attach"] },
1190
+ chrome_debug_block_urls: { description: "Block URL patterns", intent: ["block ads", "block tracker", "block request"], cost: "medium", requires: ["chrome_debug_attach"] },
1191
+ chrome_debug_get_cookies: { description: "Get all cookies incl HttpOnly", intent: ["httponly cookie", "session cookie", "all cookies"], cost: "low", requires: ["chrome_debug_attach"], avoid: ["chrome_get_cookies"] },
1192
+ chrome_intercept_request: { description: "Intercept requests via CDP Fetch", intent: ["intercept api", "intercept request"], cost: "medium", requires: ["chrome_debug_attach"] },
1193
+ chrome_mock_response: { description: "Mock a URL response", intent: ["mock api", "fake response"], cost: "low", requires: ["chrome_intercept_request"] },
1194
+ chrome_modify_headers: { description: "Auto-modify request headers", intent: ["add auth header", "change user agent", "modify request"], cost: "medium", requires: ["chrome_debug_attach"] },
1195
+ chrome_export_har: { description: "Export HAR archive", intent: ["export network log", "har file"], cost: "low", requires: ["chrome_debug_attach", "chrome_debug_get_network"] },
1196
+ chrome_replay_request: { description: "Re-send HTTP request", intent: ["replay api", "resend request", "test api"], cost: "medium" },
1197
+ // Session
1198
+ chrome_save_session: { description: "Save cookies+localStorage", intent: ["save login", "save session", "bookmark session"], cost: "low" },
1199
+ chrome_restore_session: { description: "Restore saved session", intent: ["restore login", "load session"], cost: "low" },
1200
+ // Events / DOM watch
1201
+ chrome_subscribe_events: { description: "Listen to DOM events", intent: ["watch events", "detect clicks", "monitor input"], cost: "low" },
1202
+ chrome_watch_dom_changes: { description: "Watch DOM mutations", intent: ["watch dom", "detect changes", "mutation observer"], cost: "low" },
1203
+ // Permissions / Auth
1204
+ chrome_grant_permissions: { description: "Grant origin permissions", intent: ["allow camera", "allow location", "grant permission"], cost: "medium", requires: ["chrome_debug_attach"] },
1205
+ chrome_virtual_authenticator: { description: "WebAuthn virtual authenticator", intent: ["test passkey", "fido2 test", "webauthn"], cost: "medium", requires: ["chrome_debug_attach"] },
1206
+ // Storage
1207
+ chrome_get_cookies: { description: "Get cookies for URL", intent: ["get cookies", "cookie value"], cost: "low" },
1208
+ chrome_get_local_storage: { description: "Read localStorage", intent: ["localstorage", "local storage value"], cost: "low" },
1209
+ chrome_get_history: { description: "Search browser history", intent: ["browser history", "visited sites"], cost: "low" },
1210
+ };
1211
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
1212
+ return { tools: TOOLS };
1213
+ });
1214
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
1215
+ const { name, arguments: args } = request.params;
1216
+ // Tool Graph: handled server-side, no extension needed
1217
+ if (name === "chrome_get_tool_graph") {
1218
+ const intent = (args?.intent || "").toLowerCase();
1219
+ const filterTools = args?.tools;
1220
+ let graph = filterTools
1221
+ ? Object.fromEntries(filterTools.map(t => [t, TOOL_GRAPH[t]]).filter(([, v]) => v))
1222
+ : TOOL_GRAPH;
1223
+ // If intent provided, score and rank by relevance
1224
+ if (intent) {
1225
+ const scored = Object.entries(graph)
1226
+ .map(([tool, info]) => {
1227
+ const typedInfo = info;
1228
+ const score = typedInfo.intent.reduce((s, kw) => s + (intent.includes(kw) ? 2 : kw.split(" ").some((w) => intent.includes(w)) ? 1 : 0), 0);
1229
+ return { tool, score, info: typedInfo };
1230
+ })
1231
+ .filter(e => e.score > 0)
1232
+ .sort((a, b) => b.score - a.score);
1233
+ const result = {
1234
+ intent,
1235
+ recommended: scored.slice(0, 5).map(e => ({
1236
+ tool: e.tool,
1237
+ description: e.info.description,
1238
+ cost: e.info.cost,
1239
+ requires: e.info.requires || [],
1240
+ next: e.info.next || [],
1241
+ avoid: e.info.avoid || [],
1242
+ })),
1243
+ avoid_these: scored.flatMap(e => e.info.avoid || []).filter((v, i, a) => a.indexOf(v) === i),
1244
+ execution_order: scored
1245
+ .slice(0, 5)
1246
+ .sort((a, b) => {
1247
+ const costs = { low: 0, medium: 1, high: 2 };
1248
+ return costs[a.info.cost] - costs[b.info.cost];
1249
+ })
1250
+ .map(e => e.tool),
1251
+ };
1252
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
1253
+ }
1254
+ // No intent — return full graph summary
1255
+ const summary = Object.entries(graph).map(([tool, info]) => {
1256
+ const typedInfo = info;
1257
+ return {
1258
+ tool,
1259
+ description: typedInfo.description,
1260
+ cost: typedInfo.cost,
1261
+ intent_keywords: typedInfo.intent,
1262
+ requires: typedInfo.requires || [],
1263
+ avoid: typedInfo.avoid || [],
1264
+ next: typedInfo.next || [],
1265
+ };
1266
+ });
1267
+ return { content: [{ type: "text", text: JSON.stringify(summary, null, 2) }] };
1268
+ }
1269
+ try {
1270
+ const method = name.replace(/^chrome_/, "");
1271
+ const result = await callExtension(method, args || {});
1272
+ return { content: [{ type: "text", text: String(result) }] };
1273
+ }
1274
+ catch (error) {
1275
+ return {
1276
+ content: [{ type: "text", text: `Error: ${error.message}` }],
1277
+ isError: true,
1278
+ };
1279
+ }
1280
+ });
1281
+ const transport = new StdioServerTransport();
1282
+ await server.connect(transport);
1283
+ console.error("MCP server connected via Stdio");
1284
+ process.on("exit", () => clearInterval(heartbeat));
1285
+ //# sourceMappingURL=index.js.map