viyv-browser-mcp 0.7.3 → 0.7.5
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 +121 -11
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -75,7 +75,7 @@ var BRIDGE = {
|
|
|
75
75
|
/** Loopback address for bridge */
|
|
76
76
|
TCP_HOST: "127.0.0.1",
|
|
77
77
|
/** Maximum simultaneous MCP Server connections */
|
|
78
|
-
MAX_CONNECTIONS:
|
|
78
|
+
MAX_CONNECTIONS: 100,
|
|
79
79
|
/** TTL for request routing entries (ms) */
|
|
80
80
|
REQUEST_ROUTING_TTL: 6e4
|
|
81
81
|
};
|
|
@@ -124,10 +124,10 @@ function syncNativeHostBinary() {
|
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
126
|
function shouldUpdateBridge(bridgeVersion) {
|
|
127
|
-
return compareSemver("0.7.
|
|
127
|
+
return compareSemver("0.7.5", bridgeVersion) > 0;
|
|
128
128
|
}
|
|
129
129
|
function getPackageVersion() {
|
|
130
|
-
return "0.7.
|
|
130
|
+
return "0.7.5";
|
|
131
131
|
}
|
|
132
132
|
function compareSemver(a, b) {
|
|
133
133
|
const pa = a.split(".").map(Number);
|
|
@@ -317,6 +317,7 @@ var LOG_PREFIX2 = "[viyv-browser:native-host]";
|
|
|
317
317
|
var ROUTING_CLEANUP_INTERVAL = 3e4;
|
|
318
318
|
function startBridge(options) {
|
|
319
319
|
const { port = BRIDGE.TCP_PORT, host = BRIDGE.TCP_HOST, onError } = options;
|
|
320
|
+
const maxConnections = Number(process.env.VIYV_BRIDGE_MAX_CONNECTIONS) || BRIDGE.MAX_CONNECTIONS;
|
|
320
321
|
const mcpConnections = /* @__PURE__ */ new Map();
|
|
321
322
|
const requestOrigin = /* @__PURE__ */ new Map();
|
|
322
323
|
const agentToConn = /* @__PURE__ */ new Map();
|
|
@@ -735,9 +736,9 @@ function startBridge(options) {
|
|
|
735
736
|
});
|
|
736
737
|
}
|
|
737
738
|
function handleMcpConnection(socket, initialData) {
|
|
738
|
-
if (mcpConnections.size >=
|
|
739
|
+
if (mcpConnections.size >= maxConnections) {
|
|
739
740
|
process.stderr.write(
|
|
740
|
-
`${LOG_PREFIX2} Max connections (${
|
|
741
|
+
`${LOG_PREFIX2} Max connections (${maxConnections}) reached, rejecting
|
|
741
742
|
`
|
|
742
743
|
);
|
|
743
744
|
socket.destroy();
|
|
@@ -1024,8 +1025,15 @@ var TOPICS = {
|
|
|
1024
1025
|
- Don't use for: checking text values, verifying form state
|
|
1025
1026
|
- Do use for: layout verification, image content, charts
|
|
1026
1027
|
|
|
1028
|
+
6. indexed_page \u2192 Alternative text-based DOM representation with numbered interactive elements.
|
|
1029
|
+
- Returns [0]<button>Submit</>, [1]<input placeholder=Search/>, etc.
|
|
1030
|
+
- Use indexed_action(snapshotId, index, action) to interact by number
|
|
1031
|
+
- No screenshots needed \u2014 works with text-only LLMs, lower token cost
|
|
1032
|
+
- snapshotId expires on page change \u2014 call indexed_page again if stale
|
|
1033
|
+
|
|
1027
1034
|
Recommended workflow:
|
|
1028
|
-
page_outline \u2192 read_page(section) \u2192 find(specific element) \u2192 click/form_input
|
|
1035
|
+
page_outline \u2192 read_page(section) \u2192 find(specific element) \u2192 click/form_input
|
|
1036
|
+
OR: indexed_page \u2192 indexed_action(click/type/select_option) for lower-cost automation`
|
|
1029
1037
|
},
|
|
1030
1038
|
interaction: {
|
|
1031
1039
|
title: "Interaction \u2014 How to interact with elements",
|
|
@@ -1073,6 +1081,14 @@ file_upload \u2014 For uploading files or dropping files onto elements
|
|
|
1073
1081
|
- Don't click file inputs \u2014 use file_upload instead
|
|
1074
1082
|
- Best for: file inputs, canvas apps (Canva, Figma), custom drop zones
|
|
1075
1083
|
|
|
1084
|
+
indexed_action \u2014 Index-based interaction (alternative to ref-based tools above)
|
|
1085
|
+
- Requires snapshotId from indexed_page
|
|
1086
|
+
- Actions: click, type, select_option, hover, scroll_to
|
|
1087
|
+
- click/hover: CDP dispatch (trusted events, SPA compatible)
|
|
1088
|
+
- type: CDP click to focus + content script value setting
|
|
1089
|
+
- select_option: content script DOM manipulation
|
|
1090
|
+
- Best for: batch automation with text-only LLMs, lower token cost
|
|
1091
|
+
|
|
1076
1092
|
Common patterns:
|
|
1077
1093
|
Single field: find(input) \u2192 form_input(ref, value, submit: true)
|
|
1078
1094
|
Multi-field form: read_page \u2192 form_fill([{ref, value}, ...], submit: true)
|
|
@@ -1081,7 +1097,8 @@ Common patterns:
|
|
|
1081
1097
|
Dropdown: click(select ref) \u2192 key("ArrowDown ArrowDown Enter")
|
|
1082
1098
|
Search: form_input(search input ref, query, submit: true)
|
|
1083
1099
|
File upload: find(file input) \u2192 file_upload(ref, paths)
|
|
1084
|
-
File drop: find(canvas) \u2192 file_upload(ref, paths) or file_upload(coordinate, paths)
|
|
1100
|
+
File drop: find(canvas) \u2192 file_upload(ref, paths) or file_upload(coordinate, paths)
|
|
1101
|
+
Index-based: indexed_page \u2192 indexed_action(click, index=N) \u2192 wait_for(navigation)`
|
|
1085
1102
|
},
|
|
1086
1103
|
navigation: {
|
|
1087
1104
|
title: "Navigation \u2014 How to navigate between pages",
|
|
@@ -1512,7 +1529,7 @@ var CLICK_RETURNS = `{
|
|
|
1512
1529
|
clicked: true
|
|
1513
1530
|
newTab?: { tabId, url } // only if target="_blank" link detected
|
|
1514
1531
|
}`;
|
|
1515
|
-
var CLICK_RELATED = ["form_input", "hover", "drag", "javascript_exec"];
|
|
1532
|
+
var CLICK_RELATED = ["form_input", "hover", "drag", "javascript_exec", "indexed_action"];
|
|
1516
1533
|
|
|
1517
1534
|
// src/tools/core/drag.ts
|
|
1518
1535
|
var DRAG_DESCRIPTION = `Drag from start coordinate to end coordinate.
|
|
@@ -1608,7 +1625,7 @@ var FORM_INPUT_RETURNS = `{
|
|
|
1608
1625
|
navigated?: boolean // if page navigated after submit
|
|
1609
1626
|
url?: string // new URL if navigated
|
|
1610
1627
|
}`;
|
|
1611
|
-
var FORM_INPUT_RELATED = ["click", "type", "find", "read_page"];
|
|
1628
|
+
var FORM_INPUT_RELATED = ["click", "type", "find", "read_page", "indexed_action"];
|
|
1612
1629
|
|
|
1613
1630
|
// src/tools/core/get-page-text.ts
|
|
1614
1631
|
var GET_PAGE_TEXT_DESCRIPTION = `Extract readable text from page. Use query for semantic filtering.
|
|
@@ -1628,6 +1645,66 @@ var GET_PAGE_TEXT_RETURNS = `// Without query:
|
|
|
1628
1645
|
{ sections: [{ index, tag, role, ariaLabel, heading, text, truncated }], truncated: boolean, charCount: number }`;
|
|
1629
1646
|
var GET_PAGE_TEXT_RELATED = ["read_page", "find", "screenshot"];
|
|
1630
1647
|
|
|
1648
|
+
// src/tools/core/indexed-action.ts
|
|
1649
|
+
var INDEXED_ACTION_DESCRIPTION = `Interact with an element by its [index] from indexed_page. Actions: click, type, select_option, hover, scroll_to.
|
|
1650
|
+
Returns: { success, action, index }`;
|
|
1651
|
+
var INDEXED_ACTION_DETAIL = `Act on an indexed element from indexed_page output.
|
|
1652
|
+
|
|
1653
|
+
Actions:
|
|
1654
|
+
- click: Click the element. Supports modifier keys (ctrl, shift, alt, meta).
|
|
1655
|
+
- type: Set text value on input/textarea/contenteditable. Clears existing content.
|
|
1656
|
+
- select_option: Select a dropdown option by text match.
|
|
1657
|
+
- hover: Hover over the element.
|
|
1658
|
+
- scroll_to: Scroll the element into view.
|
|
1659
|
+
|
|
1660
|
+
The snapshotId from indexed_page is required. If the page has changed since indexed_page was called, this tool returns an error \u2014 call indexed_page again to get a fresh snapshot.
|
|
1661
|
+
|
|
1662
|
+
Examples:
|
|
1663
|
+
indexed_action(tabId=1, snapshotId=3, index=2, action="click")
|
|
1664
|
+
indexed_action(tabId=1, snapshotId=3, index=1, action="type", text="hello")
|
|
1665
|
+
indexed_action(tabId=1, snapshotId=3, index=5, action="select_option", option="Option A")`;
|
|
1666
|
+
var INDEXED_ACTION_RETURNS = `{
|
|
1667
|
+
action: string // the action performed
|
|
1668
|
+
index: number // the element index
|
|
1669
|
+
success: boolean // whether the action succeeded
|
|
1670
|
+
value?: string // set value (for type/select_option)
|
|
1671
|
+
tagName?: string // element tag name
|
|
1672
|
+
}`;
|
|
1673
|
+
var INDEXED_ACTION_RELATED = ["indexed_page", "click", "form_input"];
|
|
1674
|
+
|
|
1675
|
+
// src/tools/core/indexed-page.ts
|
|
1676
|
+
var INDEXED_PAGE_DESCRIPTION = `Get page DOM as indexed text. Interactive elements marked [0], [1], etc. Use indexed_action to act by index.
|
|
1677
|
+
Returns: { tree, snapshotId, elementCount, interactiveCount }`;
|
|
1678
|
+
var INDEXED_PAGE_DETAIL = `Alternative to read_page that returns a text-based DOM representation with numbered interactive elements.
|
|
1679
|
+
|
|
1680
|
+
Format example:
|
|
1681
|
+
[0]<a aria-label=Home>Home />
|
|
1682
|
+
[1]<input placeholder=Search />
|
|
1683
|
+
[2]<button>Submit />
|
|
1684
|
+
Some text content
|
|
1685
|
+
[3]<a>Learn more />
|
|
1686
|
+
|
|
1687
|
+
Each [N] marks an interactive element. Use indexed_action with the index number to click, type, or interact.
|
|
1688
|
+
|
|
1689
|
+
Options:
|
|
1690
|
+
- viewportOnly: only include elements visible in the viewport (default: false = full page)
|
|
1691
|
+
- maxChars: limit output size (default 50000)
|
|
1692
|
+
- includeAttributes: additional HTML attributes to include in output
|
|
1693
|
+
|
|
1694
|
+
The returned snapshotId must be passed to indexed_action. It expires after page changes \u2014 call indexed_page again if indexed_action reports a stale snapshot.
|
|
1695
|
+
|
|
1696
|
+
Advantages over read_page:
|
|
1697
|
+
- Lower token cost (no screenshots needed)
|
|
1698
|
+
- Works with text-only LLMs
|
|
1699
|
+
- Direct index-based interaction without ref resolution`;
|
|
1700
|
+
var INDEXED_PAGE_RETURNS = `{
|
|
1701
|
+
tree: string // indexed DOM text
|
|
1702
|
+
snapshotId: number // pass to indexed_action
|
|
1703
|
+
elementCount: number // total elements
|
|
1704
|
+
interactiveCount: number // indexed interactive elements
|
|
1705
|
+
}`;
|
|
1706
|
+
var INDEXED_PAGE_RELATED = ["indexed_action", "read_page", "screenshot"];
|
|
1707
|
+
|
|
1631
1708
|
// src/tools/core/handle-dialog.ts
|
|
1632
1709
|
var HANDLE_DIALOG_DESCRIPTION = `Handle JS dialog (alert/confirm/prompt) or set next auto-handle policy.
|
|
1633
1710
|
Returns: { handled } or { policy_set }`;
|
|
@@ -1762,7 +1839,7 @@ var PAGE_OUTLINE_RETURNS = `{
|
|
|
1762
1839
|
}]
|
|
1763
1840
|
note?: string // only if no landmarks found
|
|
1764
1841
|
}`;
|
|
1765
|
-
var PAGE_OUTLINE_RELATED = ["read_page", "find", "get_page_text"];
|
|
1842
|
+
var PAGE_OUTLINE_RELATED = ["read_page", "find", "get_page_text", "indexed_page"];
|
|
1766
1843
|
|
|
1767
1844
|
// src/tools/core/read-page.ts
|
|
1768
1845
|
var READ_PAGE_DESCRIPTION = `Get page accessibility tree with element refs for interaction. Call page_outline first on unfamiliar pages.
|
|
@@ -1787,7 +1864,7 @@ var READ_PAGE_RETURNS = `{
|
|
|
1787
1864
|
elementCount: number // total elements in tree
|
|
1788
1865
|
truncated: boolean // whether output hit maxChars limit
|
|
1789
1866
|
}`;
|
|
1790
|
-
var READ_PAGE_RELATED = ["page_outline", "find", "get_page_text", "screenshot"];
|
|
1867
|
+
var READ_PAGE_RELATED = ["page_outline", "find", "get_page_text", "screenshot", "indexed_page"];
|
|
1791
1868
|
|
|
1792
1869
|
// src/tools/core/read-table.ts
|
|
1793
1870
|
var READ_TABLE_DESCRIPTION = `Extract HTML table data from web page by ref. Supports <table> and ARIA role="table".
|
|
@@ -3436,6 +3513,37 @@ var readPageTool = {
|
|
|
3436
3513
|
)
|
|
3437
3514
|
})
|
|
3438
3515
|
};
|
|
3516
|
+
var indexedPageTool = {
|
|
3517
|
+
name: "indexed_page",
|
|
3518
|
+
description: INDEXED_PAGE_DESCRIPTION,
|
|
3519
|
+
detail: INDEXED_PAGE_DETAIL,
|
|
3520
|
+
returns: INDEXED_PAGE_RETURNS,
|
|
3521
|
+
category: "core",
|
|
3522
|
+
related: INDEXED_PAGE_RELATED,
|
|
3523
|
+
inputSchema: z.object({
|
|
3524
|
+
tabId: z.coerce.number().describe("Tab ID"),
|
|
3525
|
+
viewportOnly: z.boolean().optional().describe("Only include viewport-visible elements (default: false)"),
|
|
3526
|
+
maxChars: z.coerce.number().optional().describe("Max output characters (default: 50000)"),
|
|
3527
|
+
includeAttributes: z.array(z.string()).optional().describe("Additional HTML attributes to include in output")
|
|
3528
|
+
})
|
|
3529
|
+
};
|
|
3530
|
+
var indexedActionTool = {
|
|
3531
|
+
name: "indexed_action",
|
|
3532
|
+
description: INDEXED_ACTION_DESCRIPTION,
|
|
3533
|
+
detail: INDEXED_ACTION_DETAIL,
|
|
3534
|
+
returns: INDEXED_ACTION_RETURNS,
|
|
3535
|
+
category: "core",
|
|
3536
|
+
related: INDEXED_ACTION_RELATED,
|
|
3537
|
+
inputSchema: z.object({
|
|
3538
|
+
tabId: z.coerce.number().describe("Tab ID"),
|
|
3539
|
+
snapshotId: z.coerce.number().describe("Snapshot ID from indexed_page"),
|
|
3540
|
+
index: z.coerce.number().min(0).describe("Element index from indexed_page output"),
|
|
3541
|
+
action: z.enum(["click", "type", "select_option", "hover", "scroll_to"]).describe("Action to perform on the element"),
|
|
3542
|
+
text: z.string().optional().describe('Text to type (required for action: "type")'),
|
|
3543
|
+
option: z.string().optional().describe('Option text to select (required for action: "select_option")'),
|
|
3544
|
+
modifiers: z.string().optional().describe('Modifier keys for click (e.g. "ctrl+shift")')
|
|
3545
|
+
})
|
|
3546
|
+
};
|
|
3439
3547
|
var findTool = {
|
|
3440
3548
|
name: "find",
|
|
3441
3549
|
description: FIND_DESCRIPTION,
|
|
@@ -4786,6 +4894,8 @@ var allTools = [
|
|
|
4786
4894
|
hoverTool,
|
|
4787
4895
|
dragTool,
|
|
4788
4896
|
readPageTool,
|
|
4897
|
+
indexedPageTool,
|
|
4898
|
+
indexedActionTool,
|
|
4789
4899
|
findTool,
|
|
4790
4900
|
inspectTool,
|
|
4791
4901
|
formInputTool,
|