openclaw-navigator 5.0.0 → 5.0.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.
Files changed (3) hide show
  1. package/cli.mjs +31 -2
  2. package/mcp.mjs +58 -3
  3. package/package.json +1 -1
package/cli.mjs CHANGED
@@ -469,7 +469,9 @@ function handleRequest(req, res) {
469
469
  if (!bridgeState.connected) {
470
470
  bridgeState.connected = true;
471
471
  bridgeState.connectedAt = Date.now();
472
+ const activeURL = activeTunnelURL ?? `http://localhost:${bridgePort}`;
472
473
  console.log(`\n${GREEN}✓${RESET} ${BOLD}Navigator connected!${RESET}`);
474
+ console.log(` ${DIM}Tunnel: ${activeURL}${RESET}`);
473
475
  }
474
476
  bridgeState.lastHeartbeat = Date.now();
475
477
 
@@ -1625,7 +1627,7 @@ module.exports = {
1625
1627
 
1626
1628
  mkdirSync(mcporterDir, { recursive: true });
1627
1629
  writeFileSync(mcporterConfigPath, JSON.stringify(mcporterConfig, null, 2) + "\n", "utf8");
1628
- ok("Registered MCP server with mcporter (16 browser tools available)");
1630
+ ok("Registered MCP server with mcporter (31 tools: 16 browser + 10 AI + 5 profiling)");
1629
1631
  info(` Config: ${mcporterConfigPath}`);
1630
1632
 
1631
1633
  // Step 3: Install the navigator-bridge skill so the OC agent knows about all tools
@@ -1670,7 +1672,9 @@ module.exports = {
1670
1672
  "mcporter call navigator.navigator_status",
1671
1673
  BT,
1672
1674
  "",
1673
- "## All 16 tools",
1675
+ "## All 31 tools",
1676
+ "",
1677
+ "### Browser Control (16 tools)",
1674
1678
  "",
1675
1679
  "| Tool | What it does |",
1676
1680
  "|------|-------------|",
@@ -1691,6 +1695,31 @@ module.exports = {
1691
1695
  "| `navigator_query_element` | Inspect DOM element |",
1692
1696
  "| `navigator_wait_ready` | Wait for page load |",
1693
1697
  "",
1698
+ "### AI Browser Intelligence (10 tools)",
1699
+ "",
1700
+ "| Tool | What it does |",
1701
+ "|------|-------------|",
1702
+ "| `navigator_analyze_page` | Full page analysis — forms, buttons, inputs, links, tables, modals |",
1703
+ "| `navigator_find_element` | Find element by natural language intent (e.g. 'login button') |",
1704
+ "| `navigator_is_ready` | Smart page readiness — checks spinners, skeletons, pending XHR |",
1705
+ "| `navigator_wait_for_element` | Wait for CSS selector to appear (MutationObserver) |",
1706
+ "| `navigator_extract_data` | Extract structured data — text, table, JSON, list, or HTML |",
1707
+ "| `navigator_smart_fill` | Fill form fields by label/name matching (React-safe) |",
1708
+ "| `navigator_intercept_api` | Capture fetch/XHR calls — see what APIs the page uses |",
1709
+ "| `navigator_set_cookies` | Set cookies on the current domain |",
1710
+ "| `navigator_get_performance` | Core Web Vitals and resource transfer stats |",
1711
+ "| `navigator_get_page_state` | Full page state — URL, title, readyState, analysis, timestamp |",
1712
+ "",
1713
+ "### User Profiling (5 tools)",
1714
+ "",
1715
+ "| Tool | What it does |",
1716
+ "|------|-------------|",
1717
+ "| `navigator_get_page_visits` | Get browsing history (auto-recorded page visits) |",
1718
+ "| `navigator_save_page_summary` | Save AI-generated summary of a page |",
1719
+ "| `navigator_get_page_summaries` | Retrieve saved page summaries |",
1720
+ "| `navigator_get_user_profile` | Get aggregated user interest profile |",
1721
+ "| `navigator_save_user_profile` | Save/update user profile from browsing patterns |",
1722
+ "",
1694
1723
  "## Usage",
1695
1724
  "",
1696
1725
  BT + "bash",
package/mcp.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  /**
4
- * openclaw-navigator MCP server v5.0.0
4
+ * openclaw-navigator MCP server v5.0.1
5
5
  *
6
6
  * Exposes the Navigator bridge HTTP API as MCP tools so the OpenClaw agent
7
7
  * can control the browser natively via its tool schema.
@@ -17,6 +17,9 @@
17
17
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
18
18
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
19
19
  import { ListToolsRequestSchema, CallToolRequestSchema } from "@modelcontextprotocol/sdk/types.js";
20
+ import { readFileSync } from "node:fs";
21
+ import { join } from "node:path";
22
+ import { homedir } from "node:os";
20
23
 
21
24
  // ── Configuration ─────────────────────────────────────────────────────────
22
25
 
@@ -28,25 +31,77 @@ const WAIT_READY_TIMEOUT_MS = 20_000;
28
31
  // All logging to stderr — stdout is reserved for MCP JSON-RPC protocol
29
32
  const log = (...args) => console.error("[navigator-mcp]", ...args);
30
33
 
34
+ // ── Bridge identity — read persistent token for auth ─────────────────────
35
+ // The bridge stores its identity (pairing code + token) in a file that
36
+ // survives restarts. The MCP server reads this to authenticate requests.
37
+
38
+ const BRIDGE_IDENTITY_PATH = join(homedir(), ".openclaw", "bridge-identity.json");
39
+
40
+ function loadBridgeToken() {
41
+ try {
42
+ const data = JSON.parse(readFileSync(BRIDGE_IDENTITY_PATH, "utf8"));
43
+ if (data.token) {
44
+ log(`Loaded bridge token from ${BRIDGE_IDENTITY_PATH}`);
45
+ return data.token;
46
+ }
47
+ } catch {
48
+ log(`No bridge identity at ${BRIDGE_IDENTITY_PATH} — running without auth`);
49
+ }
50
+ return process.env.NAVIGATOR_BRIDGE_TOKEN ?? null;
51
+ }
52
+
53
+ let bridgeToken = loadBridgeToken();
54
+
55
+ /** Build common headers — includes auth when a token is available. */
56
+ function authHeaders() {
57
+ const headers = { "Content-Type": "application/json" };
58
+ if (bridgeToken) {
59
+ headers["Authorization"] = `Bearer ${bridgeToken}`;
60
+ }
61
+ return headers;
62
+ }
63
+
31
64
  // ── HTTP helpers ──────────────────────────────────────────────────────────
32
65
 
33
66
  async function bridgeGet(path) {
34
- const res = await fetch(`${BRIDGE_URL}${path}`);
67
+ const res = await fetch(`${BRIDGE_URL}${path}`, {
68
+ headers: authHeaders(),
69
+ });
35
70
  if (!res.ok) {
71
+ // If 401, try reloading the token (bridge may have restarted with new identity)
72
+ if (res.status === 401 && !bridgeGet._retrying) {
73
+ bridgeGet._retrying = true;
74
+ bridgeToken = loadBridgeToken();
75
+ const retry = await bridgeGet(path);
76
+ bridgeGet._retrying = false;
77
+ return retry;
78
+ }
79
+ bridgeGet._retrying = false;
36
80
  throw new Error(`Bridge GET ${path} returned ${res.status}`);
37
81
  }
82
+ bridgeGet._retrying = false;
38
83
  return res.json();
39
84
  }
40
85
 
41
86
  async function bridgePost(path, body) {
42
87
  const res = await fetch(`${BRIDGE_URL}${path}`, {
43
88
  method: "POST",
44
- headers: { "Content-Type": "application/json" },
89
+ headers: authHeaders(),
45
90
  body: JSON.stringify(body),
46
91
  });
47
92
  if (!res.ok) {
93
+ // If 401, try reloading the token (bridge may have restarted with new identity)
94
+ if (res.status === 401 && !bridgePost._retrying) {
95
+ bridgePost._retrying = true;
96
+ bridgeToken = loadBridgeToken();
97
+ const retry = await bridgePost(path, body);
98
+ bridgePost._retrying = false;
99
+ return retry;
100
+ }
101
+ bridgePost._retrying = false;
48
102
  throw new Error(`Bridge POST ${path} returned ${res.status}`);
49
103
  }
104
+ bridgePost._retrying = false;
50
105
  return res.json();
51
106
  }
52
107
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openclaw-navigator",
3
- "version": "5.0.0",
3
+ "version": "5.0.2",
4
4
  "description": "One-command bridge + tunnel for the Navigator browser — works on any machine, any OS",
5
5
  "keywords": [
6
6
  "browser",