@gaiventures/pilotfish-mcp 0.0.0-stage → 0.1.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.
Files changed (4) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +146 -2
  3. package/cli.js +441 -0
  4. package/package.json +50 -4
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 gAI Ventures
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,147 @@
1
- # Temporary Holding Version
1
+ # pilotfish MCP
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ A real Chromium on your own machine for any [MCP](https://modelcontextprotocol.io) agent: Claude Code, OpenAI
4
+ Codex CLI, Cursor, Claude Desktop, VS Code, or your own client. **No account and no API key.** Your agent's own
5
+ model reads each page and decides every step; pilotfish carries out the action, checks it, and reports what
6
+ changed.
7
+
8
+ - **Ref-based tools that prove each action.** `browser_click {ref: "e12"}` refuses (obscured, stale, not
9
+ visible) rather than clicking the wrong thing, and every action returns evidence of what changed.
10
+ - **Cheap to read.** Compact snapshots of the visible screen, only the lines that changed when the agent has
11
+ seen the page a moment ago, and `browser_query` for just the values it needs (read-only JavaScript).
12
+ - **People stay in the loop.** A sign-in, a one-time code or a CAPTCHA comes back as `NEEDS A PERSON`: you do
13
+ it in the browser window, the agent calls `browser_resume` and carries on. Nothing tries to get past it.
14
+ - **Secrets never reach the model.** Values in `PILOTFISH_SECRETS` are typed as `{{name}}` placeholders and
15
+ masked in every result.
16
+ - **Local.** A fresh browser on your machine and your own IP; nothing is kept when it closes. Cookie banners
17
+ are rejected and ads and trackers blocked before the agent sees the page.
18
+
19
+ ## Requirements
20
+
21
+ - Node.js 22 or newer
22
+ - Google Chrome (or another Chromium browser such as Microsoft Edge or Chromium). Set `PILOTFISH_CHROME` to use
23
+ a specific one.
24
+
25
+ ## Setup
26
+
27
+ **Claude Code**
28
+
29
+ ```sh
30
+ claude mcp add pilotfish -- npx -y @gaiventures/pilotfish-mcp
31
+ ```
32
+
33
+ On native Windows (not WSL): `claude mcp add pilotfish -- cmd /c npx -y @gaiventures/pilotfish-mcp`.
34
+ Settings go before the `--` as `-e NAME=value`, e.g. `-e PILOTFISH_HEADLESS=1`.
35
+
36
+ **OpenAI Codex CLI** (`~/.codex/config.toml`)
37
+
38
+ ```toml
39
+ [mcp_servers.pilotfish]
40
+ command = "npx"
41
+ args = ["-y", "@gaiventures/pilotfish-mcp"]
42
+ # browser_resume waits up to 300 s for you; Codex's default per-call limit is 60 s.
43
+ tool_timeout_sec = 330
44
+ # Optional settings:
45
+ # env = { PILOTFISH_HEADLESS = "1", PILOTFISH_ALLOWED_HOSTS = "example.com,*.example.com" }
46
+ ```
47
+
48
+ **Cursor, Claude Desktop, Windsurf and other MCP clients** (Cursor: `~/.cursor/mcp.json` or `.cursor/mcp.json`;
49
+ Claude Desktop: `claude_desktop_config.json`)
50
+
51
+ ```json
52
+ {
53
+ "mcpServers": {
54
+ "pilotfish": {
55
+ "command": "npx",
56
+ "args": ["-y", "@gaiventures/pilotfish-mcp"],
57
+ "env": {
58
+ "PILOTFISH_SECRETS": "{\"shop_password\": {\"value\": \"...\", \"allowedHosts\": [\"shop.example.com\"]}}"
59
+ }
60
+ }
61
+ }
62
+ }
63
+ ```
64
+
65
+ `env` is optional; leave it out when you set nothing. To pin a version, use `@gaiventures/pilotfish-mcp@0.1.0`.
66
+
67
+ The browser opens in a window of its own on your desktop, where you sign in or solve a CAPTCHA when a page
68
+ needs a person (`PILOTFISH_HEADLESS=1` hides it; on a Linux machine with no display it is hidden already).
69
+
70
+ **Streamable HTTP** (one browser shared by every client that connects; binds to 127.0.0.1):
71
+
72
+ ```sh
73
+ npx -y @gaiventures/pilotfish-mcp --http --port 8931 # http://127.0.0.1:8931/mcp
74
+ claude mcp add --transport http pilotfish http://127.0.0.1:8931/mcp
75
+ ```
76
+
77
+ Clients that take a URL instead of a command (`"url": "http://127.0.0.1:8931/mcp"`) connect the same way. A
78
+ loopback server answers only loopback `Host` headers (DNS rebinding). Set `PILOTFISH_MCP_TOKEN` to require
79
+ `Authorization: Bearer <token>`; serving on any other address needs it.
80
+
81
+ ## Tools
82
+
83
+ | Tool | What it does |
84
+ | --- | --- |
85
+ | `browser_navigate` `{url, snapshot?}` | Open an http(s) URL. Returns evidence and the visible screen as a snapshot, with counts of what is above and below. `snapshot: false` leaves the screen out (what happened and the counts only): only for a page the same reply reads with `browser_query` and the agent will not act on. |
86
+ | `browser_snapshot` `{whole_page?}` | The page as a compact tree with refs (`[e12]<button>Search`): three screens around the viewport, or everything with `whole_page`. Each word once: no closing tags, an element's text not repeated on the lines under it, link targets as paths, no generated ids; every word and ref is kept. |
87
+ | `browser_click` `{ref}` | Click by ref; refuses (obscured, stale, not visible) rather than clicking the wrong thing. |
88
+ | `browser_type` `{ref, text, submit?}` | Replace a field's text; `{{name}}` placeholders type configured secrets. |
89
+ | `browser_select` `{ref, values}` | Pick `<select>` option(s) by label or value. |
90
+ | `browser_press` `{key}` | A key or shortcut (`Enter`, `Escape`, `Control+a`). |
91
+ | `browser_scroll` `{direction}` | Scroll about one screen; returns the screen it shows. |
92
+ | `browser_actions` `{actions}` | Up to 10 steps in one call (`click`, `type`, `select`, `press`, `scroll`, `wait` by ref), e.g. a form's fields then submit; each goes through the same checks as its own tool. Stops at the first that fails or after one that moves the page to another address. |
93
+ | `browser_query` `{expression}` | Read just the values you need with a read-only JavaScript expression (JSON, at most 4,000 characters): a results list, prices, counts. It runs in a world of its own where clicks, typing, submits and network writes are refused. The cheapest way to read. |
94
+ | `browser_find` `{query}` | Refs of the elements on the whole page that match the words, best first; partial matches are marked. Several targets can be separated by commas. |
95
+ | `browser_get_text` `{max_chars?, selector?}` | Readable text of the whole page (PDFs too), or of the first element matching `selector` (`main`, `#results`), secrets masked, up to `max_chars` (default 20,000). |
96
+ | `browser_screenshot` `{}` | JPEG of the viewport (off when secrets are configured: the image could show them). |
97
+ | `browser_wait` `{seconds}` | Wait 0.5–10 s, then return what changed. Actions already wait for the requests they start. |
98
+ | `browser_resume` `{timeout_s?}` | After a result said NEEDS A PERSON and you were asked: waits (default 300 s) until the page has moved on, then returns it. |
99
+ | `browser_tabs` `{switch_to?}` | List open tabs; `switch_to: "t2"` makes another tab current. |
100
+ | `browser_close` `{}` | Close the browser; the next call starts a fresh one. Not needed at the end of a task: the browser closes when the client disconnects. |
101
+
102
+ **Each screen once.** The agent's model keeps every result in its context, and a new token costs it far more than
103
+ one it re-reads (a prompt-cache write against a read). So an action on a page the agent was shown a few results back
104
+ (at most 8) returns only the lines that changed (`CHANGES ONLY since the page snapshot N browser results back`), each
105
+ under its unchanged parent line marked `~ `, with what is gone listed by ref. Refs are stable across snapshots, so the
106
+ lines not repeated still work; a change of more than half of the screen gets the whole screen, and
107
+ `browser_snapshot` always does.
108
+
109
+ **Pages only a person can pass.** After every acting tool the page is classified. A sign-in with no credentials, a
110
+ one-time code or 2FA prompt, a device approval, a sign-in link, a passkey, 3-D Secure or a CAPTCHA adds a
111
+ `NEEDS A PERSON (…)` block to the result: what the page needs, and that you should do it in the pilotfish browser
112
+ window; the agent then calls `browser_resume`. Nothing tries to get past it (no passwords or codes it was not given,
113
+ no CAPTCHA solving). A client that supports elicitation asks you itself and the call goes on when you are done. A
114
+ browser check that clears by itself is waited out first (up to 12 s). `BLOCKED:` (the site refused this browser) and
115
+ `STOP:` (a never-automate site's bot check) mean nobody can fix it from the window.
116
+
117
+ **Confirmations.** Irreversible-looking actions (pay, place an order, send, delete) need your yes. A client with
118
+ elicitation asks you; without it such actions are refused with that reason, never read as a "no".
119
+
120
+ ## Settings
121
+
122
+ All optional. No API key is read: the server works the same with none set.
123
+
124
+ | Variable | Default | Meaning |
125
+ | --- | --- | --- |
126
+ | `PILOTFISH_HEADLESS` | `0` where a window can be shown (Windows, macOS, Linux with a display), else `1` | `1` hides the browser window; sign-ins and CAPTCHAs then cannot be done by hand. |
127
+ | `PILOTFISH_ALLOWED_HOSTS` | any public host | Comma-separated hostname globs (`example.com,*.example.com`) the browser may visit and act on. |
128
+ | `PILOTFISH_ALLOW_PRIVATE` | `0` | `1` allows localhost and private networks (development). |
129
+ | `PILOTFISH_SECRETS` | | JSON: `{"name": "value"}` or `{"name": {"value"?, "totp"?, "allowedHosts"?}}`, typed as `{{name}}`; a `totp` seed (base32) types the current 2FA code. Values never reach a model, a result or an error message. |
130
+ | `PILOTFISH_INTERVENTION_TIMEOUT_MS` | `180000` | How long a call waits for your answer to a question asked in the client. |
131
+ | `PILOTFISH_ALLOW_SCREENSHOTS` | on without secrets | `1` allows screenshots even with secrets configured. |
132
+ | `PILOTFISH_CHROME` | auto-detect | The browser executable. |
133
+ | `PILOTFISH_MCP_TOKEN` | | HTTP mode: the required bearer token. |
134
+
135
+ ## What it connects to
136
+
137
+ Only the sites your agent opens, and the public ad-block lists (EasyList, EasyPrivacy, uBlock Origin filters),
138
+ fetched about once a week and cached in `~/.pilotfish/adblock`. No telemetry, no pilotfish servers, no model
139
+ providers.
140
+
141
+ For saved logins, sessions you can come back to, a cloud browser and whole tasks run for you, see the hosted
142
+ pilotfish app: https://pilotfish.gai.ventures (and its MCP,
143
+ [`@gaiventures/pilotfish-mcp-managed`](https://www.npmjs.com/package/@gaiventures/pilotfish-mcp-managed)).
144
+
145
+ ## License
146
+
147
+ MIT