camofox-mcp 1.0.0

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 (59) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +201 -0
  3. package/dist/client.d.ts +33 -0
  4. package/dist/client.d.ts.map +1 -0
  5. package/dist/client.js +224 -0
  6. package/dist/client.js.map +1 -0
  7. package/dist/config.d.ts +3 -0
  8. package/dist/config.d.ts.map +1 -0
  9. package/dist/config.js +41 -0
  10. package/dist/config.js.map +1 -0
  11. package/dist/errors.d.ts +23 -0
  12. package/dist/errors.d.ts.map +1 -0
  13. package/dist/errors.js +46 -0
  14. package/dist/errors.js.map +1 -0
  15. package/dist/index.d.ts +3 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +32 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/server.d.ts +12 -0
  20. package/dist/server.d.ts.map +1 -0
  21. package/dist/server.js +27 -0
  22. package/dist/server.js.map +1 -0
  23. package/dist/state.d.ts +11 -0
  24. package/dist/state.d.ts.map +1 -0
  25. package/dist/state.js +54 -0
  26. package/dist/state.js.map +1 -0
  27. package/dist/tools/health.d.ts +4 -0
  28. package/dist/tools/health.d.ts.map +1 -0
  29. package/dist/tools/health.js +21 -0
  30. package/dist/tools/health.js.map +1 -0
  31. package/dist/tools/interaction.d.ts +5 -0
  32. package/dist/tools/interaction.d.ts.map +1 -0
  33. package/dist/tools/interaction.js +105 -0
  34. package/dist/tools/interaction.js.map +1 -0
  35. package/dist/tools/navigation.d.ts +4 -0
  36. package/dist/tools/navigation.d.ts.map +1 -0
  37. package/dist/tools/navigation.js +70 -0
  38. package/dist/tools/navigation.js.map +1 -0
  39. package/dist/tools/observation.d.ts +4 -0
  40. package/dist/tools/observation.d.ts.map +1 -0
  41. package/dist/tools/observation.js +54 -0
  42. package/dist/tools/observation.js.map +1 -0
  43. package/dist/tools/search.d.ts +4 -0
  44. package/dist/tools/search.d.ts.map +1 -0
  45. package/dist/tools/search.js +52 -0
  46. package/dist/tools/search.js.map +1 -0
  47. package/dist/tools/session.d.ts +4 -0
  48. package/dist/tools/session.d.ts.map +1 -0
  49. package/dist/tools/session.js +42 -0
  50. package/dist/tools/session.js.map +1 -0
  51. package/dist/tools/tabs.d.ts +4 -0
  52. package/dist/tools/tabs.d.ts.map +1 -0
  53. package/dist/tools/tabs.js +65 -0
  54. package/dist/tools/tabs.js.map +1 -0
  55. package/dist/types.d.ts +62 -0
  56. package/dist/types.d.ts.map +1 -0
  57. package/dist/types.js +2 -0
  58. package/dist/types.js.map +1 -0
  59. package/package.json +66 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 CamoFox MCP Contributors
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 ADDED
@@ -0,0 +1,201 @@
1
+ # 🦊 CamoFox MCP
2
+
3
+ **The anti-detection browser MCP server for AI agents.** Navigate, interact, and automate the web without getting blocked.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/camofox-mcp.svg)](https://www.npmjs.com/package/camofox-mcp)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-blue.svg)](https://www.typescriptlang.org/)
8
+ [![Node.js](https://img.shields.io/badge/Node.js-18+-green.svg)](https://nodejs.org/)
9
+ [![MCP](https://img.shields.io/badge/MCP-Compatible-purple.svg)](https://modelcontextprotocol.io/)
10
+
11
+ ---
12
+
13
+ ## Why CamoFox MCP?
14
+
15
+ AI agents using Playwright get **blocked constantly**. CAPTCHAs, fingerprint detection, IP bans — the web fights back against automation.
16
+
17
+ **CamoFox MCP** wraps the [CamoFox anti-detection browser](https://github.com/jo-inc/camofox-browser) as an MCP server, giving your AI agent:
18
+
19
+ - 🛡️ **Anti-detection fingerprinting** — Each tab gets a unique, human-like browser fingerprint
20
+ - ⚡ **Fast, token-efficient snapshots** — Accessibility tree snapshots use 90% fewer tokens than screenshots
21
+ - 🔍 **Built-in search** — Search Google, YouTube, Amazon + 11 more engines without getting blocked
22
+ - 🍪 **Session persistence** — Import cookies, maintain login state across interactions
23
+ - 🎯 **CSS selector fallback** — Target elements even when accessibility refs aren't available
24
+
25
+ ### CamoFox MCP vs Playwright MCP
26
+
27
+ | Feature | CamoFox MCP | Playwright MCP |
28
+ |---------|:-----------:|:--------------:|
29
+ | Anti-detection fingerprinting | ✅ | ❌ |
30
+ | Passes bot detection tests | ✅ | ❌ |
31
+ | Search engine macros (14 engines) | ✅ | ❌ |
32
+ | Accessibility snapshots | ✅ | ✅ |
33
+ | Cookie import/export | ✅ | Limited |
34
+ | Headless support | ✅ | ✅ |
35
+ | Setup complexity | Medium | Easy |
36
+ | Token efficiency | High | High |
37
+
38
+ ### CamoFox MCP vs Other Camoufox MCPs
39
+
40
+ | Feature | CamoFox MCP | whit3rabbit/camoufox-mcp | baixianger/camoufox-mcp |
41
+ |---------|:-----------:|:-----------------------:|:-----------------------:|
42
+ | Tools | 18 | 1 | 33 |
43
+ | Architecture | REST API client | Direct browser | Direct browser |
44
+ | Session persistence | ✅ | ❌ (destroyed per request) | ✅ |
45
+ | Token efficiency | High (snapshots) | Low (raw HTML) | High (snapshots) |
46
+ | Search macros | ✅ (14 engines) | ❌ | ❌ |
47
+ | CSS selector fallback | ✅ | ❌ | ❌ |
48
+ | Active maintenance | ✅ | ❌ (stale 8mo) | ✅ |
49
+ | Press key support | ✅ | ❌ | ✅ |
50
+
51
+ ## Quick Start
52
+
53
+ ### Prerequisites
54
+
55
+ 1. Install and run [CamoFox Browser](https://github.com/jo-inc/camofox-browser):
56
+ ```bash
57
+ # Follow CamoFox installation guide
58
+ # CamoFox must be running on port 9377 (default)
59
+ ```
60
+
61
+ ### VS Code / Cursor / Claude Desktop
62
+
63
+ Add to your MCP configuration:
64
+
65
+ ```json
66
+ {
67
+ "camofox": {
68
+ "command": "node",
69
+ "args": ["/path/to/camofox-mcp/dist/index.js"],
70
+ "env": {
71
+ "CAMOFOX_URL": "http://localhost:9377"
72
+ },
73
+ "type": "stdio"
74
+ }
75
+ }
76
+ ```
77
+
78
+ ### From Source
79
+
80
+ ```bash
81
+ git clone https://github.com/redf0x1/camofox-mcp.git
82
+ cd camofox-mcp
83
+ npm install
84
+ npm run build
85
+ ```
86
+
87
+ ## Tools (18)
88
+
89
+ ### Tab Management
90
+ | Tool | Description |
91
+ |------|-------------|
92
+ | `create_tab` | Create a new tab with anti-detection fingerprinting |
93
+ | `close_tab` | Close a tab and release resources |
94
+ | `list_tabs` | List all open tabs with URLs and titles |
95
+
96
+ ### Navigation
97
+ | Tool | Description |
98
+ |------|-------------|
99
+ | `navigate` | Navigate to a URL, waits for page load |
100
+ | `go_back` | Browser back button |
101
+ | `go_forward` | Browser forward button |
102
+ | `refresh` | Reload current page |
103
+
104
+ ### Interaction
105
+ | Tool | Description |
106
+ |------|-------------|
107
+ | `click` | Click element by ref (from snapshot) or CSS selector |
108
+ | `type_text` | Type text into input fields by ref or CSS selector |
109
+ | `press_key` | Press keyboard keys (Enter, Tab, Escape, etc.) |
110
+ | `scroll` | Scroll page up or down by pixel amount |
111
+
112
+ ### Observation
113
+ | Tool | Description |
114
+ |------|-------------|
115
+ | `snapshot` | Get accessibility tree — PRIMARY way to read pages. Token-efficient |
116
+ | `screenshot` | Take visual screenshot as base64 PNG |
117
+ | `get_links` | Get all hyperlinks with URLs and text |
118
+
119
+ ### Search
120
+ | Tool | Description |
121
+ |------|-------------|
122
+ | `web_search` | Search via 14 engines: Google, YouTube, Amazon, Bing, DuckDuckGo, Reddit, GitHub, StackOverflow, Wikipedia, Twitter, LinkedIn, Facebook, Instagram, TikTok |
123
+
124
+ ### Session
125
+ | Tool | Description |
126
+ |------|-------------|
127
+ | `import_cookies` | Import cookies for authenticated sessions |
128
+ | `get_stats` | Get session statistics and performance metrics |
129
+ | `server_status` | Check CamoFox server health and connection |
130
+
131
+ ## Configuration
132
+
133
+ ### Environment Variables
134
+
135
+ | Variable | Default | Description |
136
+ |----------|---------|-------------|
137
+ | `CAMOFOX_URL` | `http://localhost:9377` | CamoFox server URL |
138
+ | `CAMOFOX_TIMEOUT` | `30000` | Request timeout in ms |
139
+ | `CAMOFOX_API_KEY` | — | API key (if CamoFox requires auth) |
140
+
141
+ ## Architecture
142
+
143
+ ```
144
+ AI Agent (Claude, GPT, etc.)
145
+
146
+ │ MCP Protocol (stdio)
147
+
148
+ ┌─────────────────┐
149
+ │ CamoFox MCP │ ← This package
150
+ │ (TypeScript) │
151
+ └────────┬────────┘
152
+
153
+ │ REST API (HTTP)
154
+
155
+ ┌─────────────────┐
156
+ │ CamoFox Server │ ← Anti-detection browser
157
+ │ (Port 9377) │
158
+ └────────┬────────┘
159
+
160
+ │ Browser Engine
161
+
162
+ ┌─────────────────┐
163
+ │ Camoufox │ ← Firefox-based, fingerprint spoofing
164
+ │ (Firefox) │
165
+ └─────────────────┘
166
+ ```
167
+
168
+ ## How It Works
169
+
170
+ 1. **Your AI agent** sends MCP tool calls (e.g., `create_tab`, `navigate`, `snapshot`)
171
+ 2. **CamoFox MCP** translates these into REST API calls to the CamoFox server
172
+ 3. **CamoFox server** manages a Camoufox browser with anti-detection features
173
+ 4. **Each tab** gets a unique fingerprint — different user agent, screen size, WebGL, fonts, etc.
174
+ 5. **Websites see** what appears to be a normal human browser, not automation
175
+
176
+ ## Anti-Detection Features
177
+
178
+ CamoFox (via [Camoufox](https://github.com/jo-inc/camofox-browser)) provides:
179
+
180
+ - ✅ Unique browser fingerprint per tab
181
+ - ✅ Human-like user agent rotation
182
+ - ✅ WebGL fingerprint spoofing
183
+ - ✅ Canvas fingerprint protection
184
+ - ✅ Screen resolution randomization
185
+ - ✅ Font enumeration protection
186
+ - ✅ Navigator properties masking
187
+ - ✅ Timezone/locale consistency
188
+
189
+ ## Contributing
190
+
191
+ Contributions are welcome! Please open an issue or submit a PR.
192
+
193
+ ## License
194
+
195
+ [MIT](LICENSE)
196
+
197
+ ## Acknowledgments
198
+
199
+ - [CamoFox Browser](https://github.com/jo-inc/camofox-browser) — The anti-detection browser this MCP wraps
200
+ - [Camoufox](https://camoufox.com/) — Firefox-based anti-detection browser engine
201
+ - [Model Context Protocol](https://modelcontextprotocol.io/) — The protocol standard by Anthropic
@@ -0,0 +1,33 @@
1
+ import type { ClickParams, ClickResponse, Config, CreateTabParams, HealthResponse, LinkResponse, NavigateResponse, SnapshotResponse, StatsResponse, TabResponse } from "./types.js";
2
+ export declare class CamofoxClient {
3
+ private readonly baseUrl;
4
+ private readonly timeout;
5
+ private readonly apiKey?;
6
+ constructor(config: Config);
7
+ healthCheck(): Promise<HealthResponse>;
8
+ createTab(params: CreateTabParams): Promise<TabResponse>;
9
+ closeTab(tabId: string, userId: string): Promise<void>;
10
+ navigate(tabId: string, url: string, userId: string): Promise<NavigateResponse>;
11
+ navigateMacro(tabId: string, macro: string, query: string, userId: string): Promise<NavigateResponse>;
12
+ goBack(tabId: string, userId: string): Promise<void>;
13
+ goForward(tabId: string, userId: string): Promise<void>;
14
+ refresh(tabId: string, userId: string): Promise<void>;
15
+ click(tabId: string, params: ClickParams, userId: string): Promise<ClickResponse>;
16
+ typeText(tabId: string, locator: {
17
+ ref?: string;
18
+ selector?: string;
19
+ }, text: string, userId: string): Promise<void>;
20
+ pressKey(tabId: string, key: string, userId: string): Promise<void>;
21
+ scroll(tabId: string, direction: string, amount: number | undefined, userId: string): Promise<void>;
22
+ snapshot(tabId: string, userId: string): Promise<SnapshotResponse>;
23
+ screenshot(tabId: string, userId: string): Promise<Buffer>;
24
+ getLinks(tabId: string, userId: string): Promise<LinkResponse>;
25
+ getStats(tabId: string, userId: string): Promise<StatsResponse>;
26
+ importCookies(userId: string, cookies: string): Promise<void>;
27
+ private requestJson;
28
+ private requestBinary;
29
+ private requestNoContent;
30
+ private request;
31
+ private buildHttpError;
32
+ }
33
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,WAAW,EACX,aAAa,EACb,MAAM,EACN,eAAe,EACf,cAAc,EACd,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAChB,aAAa,EACb,WAAW,EACZ,MAAM,YAAY,CAAC;AAOpB,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IAEjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IAEjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAS;gBAErB,MAAM,EAAE,MAAM;IAMpB,WAAW,IAAI,OAAO,CAAC,cAAc,CAAC;IAItC,SAAS,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,WAAW,CAAC;IAsBxD,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOtD,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAY/E,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAYrG,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOpD,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOvD,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOrD,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAYjF,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOlH,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOnE,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOnG,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAelE,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAU1D,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAiB9D,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAS/D,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAQrD,WAAW;YAQX,aAAa;YAKb,gBAAgB;YAIhB,OAAO;YAmDP,cAAc;CA2B7B"}
package/dist/client.js ADDED
@@ -0,0 +1,224 @@
1
+ import { AppError } from "./errors.js";
2
+ export class CamofoxClient {
3
+ baseUrl;
4
+ timeout;
5
+ apiKey;
6
+ constructor(config) {
7
+ this.baseUrl = config.camofoxUrl.replace(/\/$/, "");
8
+ this.timeout = config.timeout;
9
+ this.apiKey = config.apiKey;
10
+ }
11
+ async healthCheck() {
12
+ return this.requestJson("/health", { method: "GET" });
13
+ }
14
+ async createTab(params) {
15
+ const response = await this.requestJson("/tabs", {
16
+ method: "POST",
17
+ body: JSON.stringify(params)
18
+ });
19
+ const tabId = response.tabId ??
20
+ response.id ??
21
+ (response.tab?.id ?? undefined);
22
+ if (!tabId) {
23
+ throw new AppError("INTERNAL_ERROR", "CamoFox did not return a valid tab ID");
24
+ }
25
+ return {
26
+ tabId,
27
+ url: response.url ?? params.url ?? "about:blank",
28
+ title: response.title
29
+ };
30
+ }
31
+ async closeTab(tabId, userId) {
32
+ await this.requestNoContent(`/tabs/${encodeURIComponent(tabId)}`, {
33
+ method: "DELETE",
34
+ body: JSON.stringify({ userId })
35
+ });
36
+ }
37
+ async navigate(tabId, url, userId) {
38
+ const response = await this.requestJson(`/tabs/${encodeURIComponent(tabId)}/navigate`, {
39
+ method: "POST",
40
+ body: JSON.stringify({ url, userId })
41
+ });
42
+ return {
43
+ url: response.url ?? url,
44
+ title: response.title
45
+ };
46
+ }
47
+ async navigateMacro(tabId, macro, query, userId) {
48
+ const response = await this.requestJson(`/tabs/${encodeURIComponent(tabId)}/navigate`, {
49
+ method: "POST",
50
+ body: JSON.stringify({ macro, query, userId })
51
+ });
52
+ return {
53
+ url: response.url ?? "",
54
+ title: response.title
55
+ };
56
+ }
57
+ async goBack(tabId, userId) {
58
+ await this.requestNoContent(`/tabs/${encodeURIComponent(tabId)}/back`, {
59
+ method: "POST",
60
+ body: JSON.stringify({ userId })
61
+ });
62
+ }
63
+ async goForward(tabId, userId) {
64
+ await this.requestNoContent(`/tabs/${encodeURIComponent(tabId)}/forward`, {
65
+ method: "POST",
66
+ body: JSON.stringify({ userId })
67
+ });
68
+ }
69
+ async refresh(tabId, userId) {
70
+ await this.requestNoContent(`/tabs/${encodeURIComponent(tabId)}/refresh`, {
71
+ method: "POST",
72
+ body: JSON.stringify({ userId })
73
+ });
74
+ }
75
+ async click(tabId, params, userId) {
76
+ const response = await this.requestJson(`/tabs/${encodeURIComponent(tabId)}/click`, {
77
+ method: "POST",
78
+ body: JSON.stringify({ ...params, userId })
79
+ });
80
+ return {
81
+ success: response.success ?? true,
82
+ navigated: response.navigated
83
+ };
84
+ }
85
+ async typeText(tabId, locator, text, userId) {
86
+ await this.requestNoContent(`/tabs/${encodeURIComponent(tabId)}/type`, {
87
+ method: "POST",
88
+ body: JSON.stringify({ ...locator, text, userId })
89
+ });
90
+ }
91
+ async pressKey(tabId, key, userId) {
92
+ await this.requestNoContent(`/tabs/${encodeURIComponent(tabId)}/press`, {
93
+ method: "POST",
94
+ body: JSON.stringify({ key, userId })
95
+ });
96
+ }
97
+ async scroll(tabId, direction, amount, userId) {
98
+ await this.requestNoContent(`/tabs/${encodeURIComponent(tabId)}/scroll`, {
99
+ method: "POST",
100
+ body: JSON.stringify({ direction, amount, userId })
101
+ });
102
+ }
103
+ async snapshot(tabId, userId) {
104
+ const response = await this.requestJson(`/tabs/${encodeURIComponent(tabId)}/snapshot?userId=${encodeURIComponent(userId)}`, {
105
+ method: "GET"
106
+ });
107
+ return {
108
+ url: response.url ?? "",
109
+ snapshot: response.snapshot ?? "",
110
+ refsCount: response.refsCount ?? 0
111
+ };
112
+ }
113
+ async screenshot(tabId, userId) {
114
+ const binary = await this.requestBinary(`/tabs/${encodeURIComponent(tabId)}/screenshot?userId=${encodeURIComponent(userId)}`, {
115
+ method: "GET"
116
+ });
117
+ return Buffer.from(binary);
118
+ }
119
+ async getLinks(tabId, userId) {
120
+ const response = await this.requestJson(`/tabs/${encodeURIComponent(tabId)}/links?userId=${encodeURIComponent(userId)}`, {
121
+ method: "GET"
122
+ });
123
+ const links = Array.isArray(response.links) ? response.links : [];
124
+ return {
125
+ links: links.map((item) => ({
126
+ text: String(item.text ?? ""),
127
+ href: String(item.href ?? "")
128
+ }))
129
+ };
130
+ }
131
+ async getStats(tabId, userId) {
132
+ return this.requestJson(`/tabs/${encodeURIComponent(tabId)}/stats?userId=${encodeURIComponent(userId)}`, {
133
+ method: "GET"
134
+ });
135
+ }
136
+ async importCookies(userId, cookies) {
137
+ await this.requestNoContent(`/sessions/${encodeURIComponent(userId)}/cookies`, {
138
+ method: "POST",
139
+ body: JSON.stringify({ cookies }),
140
+ requireApiKey: true
141
+ });
142
+ }
143
+ async requestJson(path, init) {
144
+ const response = await this.request(path, init);
145
+ if (response.status === 204) {
146
+ return {};
147
+ }
148
+ return (await response.json());
149
+ }
150
+ async requestBinary(path, init) {
151
+ const response = await this.request(path, init);
152
+ return response.arrayBuffer();
153
+ }
154
+ async requestNoContent(path, init) {
155
+ await this.request(path, init);
156
+ }
157
+ async request(path, init) {
158
+ const controller = new AbortController();
159
+ const timer = setTimeout(() => controller.abort(), this.timeout);
160
+ try {
161
+ if (init.requireApiKey && !this.apiKey) {
162
+ throw new AppError("API_KEY_REQUIRED", "CAMOFOX_API_KEY is required for this operation");
163
+ }
164
+ const headers = {
165
+ "content-type": "application/json"
166
+ };
167
+ if (this.apiKey) {
168
+ headers["x-api-key"] = this.apiKey;
169
+ headers.authorization = `Bearer ${this.apiKey}`;
170
+ }
171
+ const response = await fetch(`${this.baseUrl}${path}`, {
172
+ ...init,
173
+ headers: {
174
+ ...headers,
175
+ ...init.headers
176
+ },
177
+ signal: controller.signal
178
+ });
179
+ if (!response.ok) {
180
+ throw await this.buildHttpError(response);
181
+ }
182
+ return response;
183
+ }
184
+ catch (error) {
185
+ if (error instanceof AppError) {
186
+ throw error;
187
+ }
188
+ if (error instanceof DOMException && error.name === "AbortError") {
189
+ throw new AppError("TIMEOUT", `CamoFox API request timed out after ${this.timeout}ms`);
190
+ }
191
+ if (error instanceof Error) {
192
+ throw new AppError("CONNECTION_REFUSED", `Failed to connect to CamoFox API: ${error.message}`);
193
+ }
194
+ throw new AppError("INTERNAL_ERROR", "Unknown error while calling CamoFox API");
195
+ }
196
+ finally {
197
+ clearTimeout(timer);
198
+ }
199
+ }
200
+ async buildHttpError(response) {
201
+ let message = `CamoFox API request failed with ${response.status}`;
202
+ const rawBody = await response.text();
203
+ if (rawBody) {
204
+ try {
205
+ const body = JSON.parse(rawBody);
206
+ message = body.error ?? body.message ?? rawBody;
207
+ }
208
+ catch {
209
+ message = rawBody;
210
+ }
211
+ }
212
+ if (response.status === 404) {
213
+ return new AppError("TAB_NOT_FOUND", message, response.status);
214
+ }
215
+ if (response.status === 400 && /element|ref|selector/i.test(message)) {
216
+ return new AppError("ELEMENT_NOT_FOUND", message, response.status);
217
+ }
218
+ if (response.status >= 500) {
219
+ return new AppError("NAVIGATION_FAILED", message, response.status);
220
+ }
221
+ return new AppError("INTERNAL_ERROR", message, response.status);
222
+ }
223
+ }
224
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { type Config } from "./types.js";
2
+ export declare function loadConfig(argv?: string[], env?: NodeJS.ProcessEnv): Config;
3
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,YAAY,CAAC;AA8CzC,wBAAgB,UAAU,CAAC,IAAI,WAAwB,EAAE,GAAG,oBAAc,GAAG,MAAM,CAUlF"}
package/dist/config.js ADDED
@@ -0,0 +1,41 @@
1
+ function parseCliArgs(argv) {
2
+ const args = {};
3
+ for (let i = 0; i < argv.length; i += 1) {
4
+ const current = argv[i];
5
+ const next = argv[i + 1];
6
+ if ((current === "--camofox-url" || current === "--url") && next) {
7
+ args.camofoxUrl = next;
8
+ i += 1;
9
+ continue;
10
+ }
11
+ if ((current === "--api-key" || current === "--key") && next) {
12
+ args.apiKey = next;
13
+ i += 1;
14
+ continue;
15
+ }
16
+ if ((current === "--default-user-id" || current === "--user-id") && next) {
17
+ args.defaultUserId = next;
18
+ i += 1;
19
+ continue;
20
+ }
21
+ if (current === "--timeout" && next) {
22
+ const timeout = Number.parseInt(next, 10);
23
+ if (!Number.isNaN(timeout) && timeout > 0) {
24
+ args.timeout = timeout;
25
+ }
26
+ i += 1;
27
+ }
28
+ }
29
+ return args;
30
+ }
31
+ export function loadConfig(argv = process.argv.slice(2), env = process.env) {
32
+ const cli = parseCliArgs(argv);
33
+ const timeoutFromEnv = Number.parseInt(env.CAMOFOX_TIMEOUT ?? "", 10);
34
+ return {
35
+ camofoxUrl: cli.camofoxUrl ?? env.CAMOFOX_URL ?? "http://localhost:9377",
36
+ apiKey: cli.apiKey ?? env.CAMOFOX_API_KEY,
37
+ defaultUserId: cli.defaultUserId ?? env.CAMOFOX_DEFAULT_USER_ID ?? "default",
38
+ timeout: cli.timeout ?? (Number.isNaN(timeoutFromEnv) ? 30_000 : timeoutFromEnv)
39
+ };
40
+ }
41
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AASA,SAAS,YAAY,CAAC,IAAc;IAClC,MAAM,IAAI,GAAY,EAAE,CAAC;IAEzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACxC,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACxB,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAEzB,IAAI,CAAC,OAAO,KAAK,eAAe,IAAI,OAAO,KAAK,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC;YACjE,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;YACvB,CAAC,IAAI,CAAC,CAAC;YACP,SAAS;QACX,CAAC;QAED,IAAI,CAAC,OAAO,KAAK,WAAW,IAAI,OAAO,KAAK,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC;YAC7D,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;YACnB,CAAC,IAAI,CAAC,CAAC;YACP,SAAS;QACX,CAAC;QAED,IAAI,CAAC,OAAO,KAAK,mBAAmB,IAAI,OAAO,KAAK,WAAW,CAAC,IAAI,IAAI,EAAE,CAAC;YACzE,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;YAC1B,CAAC,IAAI,CAAC,CAAC;YACP,SAAS;QACX,CAAC;QAED,IAAI,OAAO,KAAK,WAAW,IAAI,IAAI,EAAE,CAAC;YACpC,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAC1C,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;gBAC1C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;YACzB,CAAC;YACD,CAAC,IAAI,CAAC,CAAC;QACT,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG;IACxE,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAC/B,MAAM,cAAc,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,eAAe,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;IAEtE,OAAO;QACL,UAAU,EAAE,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,WAAW,IAAI,uBAAuB;QACxE,MAAM,EAAE,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,eAAe;QACzC,aAAa,EAAE,GAAG,CAAC,aAAa,IAAI,GAAG,CAAC,uBAAuB,IAAI,SAAS;QAC5E,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC;KACjF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,23 @@
1
+ export type ErrorCode = "CONNECTION_REFUSED" | "TAB_NOT_FOUND" | "ELEMENT_NOT_FOUND" | "NAVIGATION_FAILED" | "API_KEY_REQUIRED" | "TIMEOUT" | "VALIDATION_ERROR" | "INTERNAL_ERROR";
2
+ export declare class AppError extends Error {
3
+ readonly code: ErrorCode;
4
+ readonly status?: number;
5
+ constructor(code: ErrorCode, message: string, status?: number);
6
+ }
7
+ export interface ToolResult {
8
+ [key: string]: unknown;
9
+ isError?: boolean;
10
+ content: Array<{
11
+ type: "text";
12
+ text: string;
13
+ } | {
14
+ type: "image";
15
+ data: string;
16
+ mimeType: string;
17
+ }>;
18
+ }
19
+ export declare function okResult(data: unknown): ToolResult;
20
+ export declare function imageResult(base64Png: string): ToolResult;
21
+ export declare function normalizeError(error: unknown): AppError;
22
+ export declare function toErrorResult(error: unknown): ToolResult;
23
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,SAAS,GACjB,oBAAoB,GACpB,eAAe,GACf,mBAAmB,GACnB,mBAAmB,GACnB,kBAAkB,GAClB,SAAS,GACT,kBAAkB,GAClB,gBAAgB,CAAC;AAErB,qBAAa,QAAS,SAAQ,KAAK;IACjC,SAAgB,IAAI,EAAE,SAAS,CAAC;IAEhC,SAAgB,MAAM,CAAC,EAAE,MAAM,CAAC;gBAEpB,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM;CAM9D;AAED,MAAM,WAAW,UAAU;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,KAAK,CACV;QACE,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;KACd,GACD;QACE,IAAI,EAAE,OAAO,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;KAClB,CACJ,CAAC;CACH;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,UAAU,CAIlD;AAED,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU,CAIzD;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,QAAQ,CAcvD;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,UAAU,CAYxD"}
package/dist/errors.js ADDED
@@ -0,0 +1,46 @@
1
+ import { ZodError } from "zod";
2
+ export class AppError extends Error {
3
+ code;
4
+ status;
5
+ constructor(code, message, status) {
6
+ super(message);
7
+ this.name = "AppError";
8
+ this.code = code;
9
+ this.status = status;
10
+ }
11
+ }
12
+ export function okResult(data) {
13
+ return {
14
+ content: [{ type: "text", text: JSON.stringify(data) }]
15
+ };
16
+ }
17
+ export function imageResult(base64Png) {
18
+ return {
19
+ content: [{ type: "image", data: base64Png, mimeType: "image/png" }]
20
+ };
21
+ }
22
+ export function normalizeError(error) {
23
+ if (error instanceof AppError) {
24
+ return error;
25
+ }
26
+ if (error instanceof ZodError) {
27
+ return new AppError("VALIDATION_ERROR", error.issues.map((issue) => issue.message).join(", "));
28
+ }
29
+ if (error instanceof Error) {
30
+ return new AppError("INTERNAL_ERROR", error.message);
31
+ }
32
+ return new AppError("INTERNAL_ERROR", "An unknown internal error occurred");
33
+ }
34
+ export function toErrorResult(error) {
35
+ const appError = normalizeError(error);
36
+ const payload = {
37
+ isError: true,
38
+ code: appError.code,
39
+ message: appError.message
40
+ };
41
+ return {
42
+ isError: true,
43
+ content: [{ type: "text", text: JSON.stringify(payload) }]
44
+ };
45
+ }
46
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAC;AAY/B,MAAM,OAAO,QAAS,SAAQ,KAAK;IACjB,IAAI,CAAY;IAEhB,MAAM,CAAU;IAEhC,YAAY,IAAe,EAAE,OAAe,EAAE,MAAe;QAC3D,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF;AAkBD,MAAM,UAAU,QAAQ,CAAC,IAAa;IACpC,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;KACxD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,SAAiB;IAC3C,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;KACrE,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAc;IAC3C,IAAI,KAAK,YAAY,QAAQ,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,KAAK,YAAY,QAAQ,EAAE,CAAC;QAC9B,OAAO,IAAI,QAAQ,CAAC,kBAAkB,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACjG,CAAC;IAED,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,OAAO,IAAI,QAAQ,CAAC,gBAAgB,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IACvD,CAAC;IAED,OAAO,IAAI,QAAQ,CAAC,gBAAgB,EAAE,oCAAoC,CAAC,CAAC;AAC9E,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAc;IAC1C,MAAM,QAAQ,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;IACvC,MAAM,OAAO,GAAG;QACd,OAAO,EAAE,IAAI;QACb,IAAI,EAAE,QAAQ,CAAC,IAAI;QACnB,OAAO,EAAE,QAAQ,CAAC,OAAO;KAC1B,CAAC;IAEF,OAAO;QACL,OAAO,EAAE,IAAI;QACb,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;KAC3D,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}