cbrowser 7.4.4 → 7.4.7
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/README.md +84 -2
- package/dist/cli.js +83 -1
- package/dist/cli.js.map +1 -1
- package/dist/mcp-server-remote.d.ts +6 -0
- package/dist/mcp-server-remote.d.ts.map +1 -1
- package/dist/mcp-server-remote.js +231 -29
- package/dist/mcp-server-remote.js.map +1 -1
- package/docs/AUTH0-SETUP.md +201 -0
- package/docs/REMOTE-MCP-SERVER.md +65 -17
- package/examples/remote-mcp.ts +137 -0
- package/examples/smart-automation.ts +5 -2
- package/examples/visual-testing.ts +177 -0
- package/package.json +2 -1
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
# Auth0 OAuth Setup for CBrowser MCP Server
|
|
2
|
+
|
|
3
|
+
This guide walks you through setting up Auth0 authentication for the CBrowser Remote MCP Server, enabling integration with claude.ai's custom connector feature.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
### 1. Create Auth0 Account
|
|
8
|
+
|
|
9
|
+
1. Go to [auth0.com](https://auth0.com) and sign up (free tier works)
|
|
10
|
+
2. Create a new tenant (e.g., `cbrowser` or use your existing tenant)
|
|
11
|
+
|
|
12
|
+
### 2. Create an API
|
|
13
|
+
|
|
14
|
+
1. Go to **Applications → APIs**
|
|
15
|
+
2. Click **+ Create API**
|
|
16
|
+
3. Configure:
|
|
17
|
+
- **Name:** `CBrowser MCP API`
|
|
18
|
+
- **Identifier:** `https://cbrowser-mcp.wyldfyre.ai` (your server URL)
|
|
19
|
+
- **Signing Algorithm:** RS256
|
|
20
|
+
4. Click **Create**
|
|
21
|
+
|
|
22
|
+
### 3. Create an Application (Static Registration)
|
|
23
|
+
|
|
24
|
+
For secure integration, we use static client registration:
|
|
25
|
+
|
|
26
|
+
1. Go to **Applications → Applications**
|
|
27
|
+
2. Click **+ Create Application**
|
|
28
|
+
3. Configure:
|
|
29
|
+
- **Name:** `Claude.ai MCP Client`
|
|
30
|
+
- **Type:** Regular Web Application
|
|
31
|
+
4. Click **Create**
|
|
32
|
+
5. In Settings tab, configure:
|
|
33
|
+
- **Allowed Callback URLs:**
|
|
34
|
+
```
|
|
35
|
+
https://claude.ai/api/mcp/auth_callback,
|
|
36
|
+
https://claude.com/api/mcp/auth_callback
|
|
37
|
+
```
|
|
38
|
+
- **Allowed Web Origins:** `https://claude.ai, https://claude.com`
|
|
39
|
+
6. Save Changes
|
|
40
|
+
7. Note down:
|
|
41
|
+
- **Domain** (e.g., `your-tenant.auth0.com`)
|
|
42
|
+
- **Client ID**
|
|
43
|
+
- **Client Secret**
|
|
44
|
+
|
|
45
|
+
### 4. Configure MCP Server
|
|
46
|
+
|
|
47
|
+
Add these environment variables to your systemd service:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
sudo nano /etc/systemd/system/cbrowser-mcp.service
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Add under `[Service]`:
|
|
54
|
+
|
|
55
|
+
```ini
|
|
56
|
+
Environment=AUTH0_DOMAIN=your-tenant.auth0.com
|
|
57
|
+
Environment=AUTH0_AUDIENCE=https://cbrowser-mcp.wyldfyre.ai
|
|
58
|
+
Environment=AUTH0_CLIENT_ID=your-client-id
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Reload and restart:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
sudo systemctl daemon-reload
|
|
65
|
+
sudo systemctl restart cbrowser-mcp
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### 5. Verify Setup
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
# Check protected resource metadata
|
|
72
|
+
curl https://cbrowser-mcp.wyldfyre.ai/.well-known/oauth-protected-resource
|
|
73
|
+
|
|
74
|
+
# Should return:
|
|
75
|
+
{
|
|
76
|
+
"resource": "https://cbrowser-mcp.wyldfyre.ai",
|
|
77
|
+
"authorization_servers": ["https://your-tenant.auth0.com"],
|
|
78
|
+
"bearer_methods_supported": ["header"],
|
|
79
|
+
"scopes_supported": ["openid", "profile", "cbrowser:read", "cbrowser:write"]
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### 6. Connect from Claude.ai
|
|
84
|
+
|
|
85
|
+
1. Go to [claude.ai](https://claude.ai)
|
|
86
|
+
2. Open **Settings → Connectors**
|
|
87
|
+
3. Click **Add custom connector**
|
|
88
|
+
4. Enter: `https://cbrowser-mcp.wyldfyre.ai/mcp`
|
|
89
|
+
5. Claude will:
|
|
90
|
+
- Fetch the OAuth metadata from `/.well-known/oauth-protected-resource`
|
|
91
|
+
- Redirect you to Auth0 for authentication
|
|
92
|
+
- Exchange tokens and connect
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Architecture
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
┌─────────────────┐ ┌────────────────┐ ┌─────────────────┐
|
|
100
|
+
│ Claude.ai │────▶│ Auth0 │────▶│ CBrowser MCP │
|
|
101
|
+
│ │ │ │ │ Server │
|
|
102
|
+
│ 1. Discover │ │ 2. Authorize │ │ │
|
|
103
|
+
│ OAuth metadata │ │ 3. Get token │ │ 4. Validate │
|
|
104
|
+
│ │ │ │ │ JWT │
|
|
105
|
+
└─────────────────┘ └────────────────┘ └─────────────────┘
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Flow Details
|
|
109
|
+
|
|
110
|
+
1. **Discovery**: Claude fetches `/.well-known/oauth-protected-resource` to find Auth0
|
|
111
|
+
2. **Authorization**: User is redirected to Auth0 login
|
|
112
|
+
3. **Token Exchange**: Auth0 issues JWT access token
|
|
113
|
+
4. **API Access**: Claude sends requests with `Authorization: Bearer <jwt>`
|
|
114
|
+
5. **Validation**: CBrowser validates JWT against Auth0 JWKS
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Environment Variables
|
|
119
|
+
|
|
120
|
+
| Variable | Required | Description |
|
|
121
|
+
|----------|----------|-------------|
|
|
122
|
+
| `AUTH0_DOMAIN` | Yes | Your Auth0 tenant domain (e.g., `your-tenant.auth0.com`) |
|
|
123
|
+
| `AUTH0_AUDIENCE` | Yes | API identifier (your server URL) |
|
|
124
|
+
| `AUTH0_CLIENT_ID` | No | Client ID for static registration info |
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Scopes
|
|
129
|
+
|
|
130
|
+
The server supports these OAuth scopes:
|
|
131
|
+
|
|
132
|
+
| Scope | Description |
|
|
133
|
+
|-------|-------------|
|
|
134
|
+
| `openid` | OpenID Connect authentication |
|
|
135
|
+
| `profile` | User profile information |
|
|
136
|
+
| `cbrowser:read` | Read-only access to CBrowser tools |
|
|
137
|
+
| `cbrowser:write` | Full access to CBrowser tools |
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Troubleshooting
|
|
142
|
+
|
|
143
|
+
### "Invalid token" errors
|
|
144
|
+
|
|
145
|
+
1. Check Auth0 domain is correct
|
|
146
|
+
2. Verify audience matches exactly (including trailing slash if needed)
|
|
147
|
+
3. Check token hasn't expired
|
|
148
|
+
|
|
149
|
+
### "OAuth not configured" response
|
|
150
|
+
|
|
151
|
+
1. Ensure `AUTH0_DOMAIN` and `AUTH0_AUDIENCE` are set
|
|
152
|
+
2. Restart the service after config changes
|
|
153
|
+
|
|
154
|
+
### Claude.ai can't connect
|
|
155
|
+
|
|
156
|
+
1. Verify callback URLs include both `claude.ai` and `claude.com`
|
|
157
|
+
2. Check CORS is working (test with browser dev tools)
|
|
158
|
+
3. Ensure `/.well-known/oauth-protected-resource` is accessible
|
|
159
|
+
|
|
160
|
+
### Rate limit errors (429)
|
|
161
|
+
|
|
162
|
+
Auth0 free tier has strict rate limits. CBrowser caches validated tokens for 30 minutes to avoid hitting these limits. If you're still seeing rate limits:
|
|
163
|
+
|
|
164
|
+
1. Upgrade to Auth0 paid tier
|
|
165
|
+
2. Reduce concurrent users
|
|
166
|
+
|
|
167
|
+
### Opaque token instead of JWT
|
|
168
|
+
|
|
169
|
+
If Auth0 returns an opaque (encrypted) token instead of a JWT, CBrowser validates it via Auth0's `/userinfo` endpoint. This works but:
|
|
170
|
+
|
|
171
|
+
1. Ensure API Identifier in Auth0 exactly matches your audience (including trailing slash)
|
|
172
|
+
2. Check the Application is authorized for the API in Auth0
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## Security Best Practices
|
|
177
|
+
|
|
178
|
+
1. **Use static registration** - Don't enable open DCR without IP restrictions
|
|
179
|
+
2. **Restrict callback URLs** - Only allow Claude's official callbacks
|
|
180
|
+
3. **Monitor logs** - Check Auth0 logs for unauthorized access attempts
|
|
181
|
+
4. **Rotate secrets** - Periodically rotate client secrets
|
|
182
|
+
5. **Use scopes** - Implement scope-based access control for sensitive tools
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Dual Authentication
|
|
187
|
+
|
|
188
|
+
The server supports both API keys and OAuth simultaneously:
|
|
189
|
+
|
|
190
|
+
- **API Key**: For Claude Code CLI and programmatic access
|
|
191
|
+
- **OAuth**: For claude.ai web interface
|
|
192
|
+
|
|
193
|
+
Both can be enabled at the same time. The server checks OAuth JWT first, then falls back to API key.
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## Related Documentation
|
|
198
|
+
|
|
199
|
+
- [Auth0 MCP Documentation](https://auth0.com/ai/docs/mcp/)
|
|
200
|
+
- [MCP Authorization Spec](https://spec.modelcontextprotocol.io/specification/architecture/transports/)
|
|
201
|
+
- [RFC 9728 - OAuth Protected Resource Metadata](https://datatracker.ietf.org/doc/html/rfc9728)
|
|
@@ -295,7 +295,7 @@ Create a page rule to bypass caching:
|
|
|
295
295
|
|
|
296
296
|
```bash
|
|
297
297
|
curl https://cbrowser-mcp.yourdomain.com/health
|
|
298
|
-
# {"status":"ok","version":"7.4.
|
|
298
|
+
# {"status":"ok","version":"7.4.6","auth":true,"auth_methods":{"api_key":true,"oauth":true}}
|
|
299
299
|
```
|
|
300
300
|
|
|
301
301
|
### Info Endpoint
|
|
@@ -317,14 +317,34 @@ curl -X POST https://cbrowser-mcp.yourdomain.com/mcp \
|
|
|
317
317
|
|
|
318
318
|
## Step 6: Connect to Claude.ai
|
|
319
319
|
|
|
320
|
-
|
|
321
|
-
2. Open **Settings → Integrations → Custom MCP Servers**
|
|
322
|
-
3. Add new connector:
|
|
323
|
-
- **Name:** CBrowser
|
|
324
|
-
- **URL:** `https://cbrowser-mcp.yourdomain.com/mcp`
|
|
325
|
-
4. Click **Connect**
|
|
320
|
+
### Option A: With Auth0 OAuth (Recommended)
|
|
326
321
|
|
|
327
|
-
|
|
322
|
+
For secure authentication with claude.ai, set up Auth0 OAuth:
|
|
323
|
+
|
|
324
|
+
1. See the [Auth0 Setup Guide](AUTH0-SETUP.md) to configure Auth0
|
|
325
|
+
2. Add Auth0 environment variables to your systemd service:
|
|
326
|
+
```ini
|
|
327
|
+
Environment=AUTH0_DOMAIN=your-tenant.auth0.com
|
|
328
|
+
Environment=AUTH0_AUDIENCE=https://cbrowser-mcp.yourdomain.com/
|
|
329
|
+
```
|
|
330
|
+
3. Restart the service: `sudo systemctl restart cbrowser-mcp`
|
|
331
|
+
4. Go to [claude.ai](https://claude.ai) → **Settings → Connectors**
|
|
332
|
+
5. Click **Add Custom Connector**
|
|
333
|
+
6. Enter URL: `https://cbrowser-mcp.yourdomain.com/mcp`
|
|
334
|
+
7. Enter your Auth0 **Client ID** and **Client Secret** when prompted
|
|
335
|
+
8. Complete the OAuth login flow
|
|
336
|
+
|
|
337
|
+
### Option B: Open Access (Public Demo)
|
|
338
|
+
|
|
339
|
+
For a public demo server without authentication:
|
|
340
|
+
|
|
341
|
+
1. Remove `MCP_API_KEY` from your systemd service
|
|
342
|
+
2. Remove `AUTH0_*` variables
|
|
343
|
+
3. Add rate limiting in nginx (see Security section)
|
|
344
|
+
4. Go to [claude.ai](https://claude.ai) → **Settings → Connectors**
|
|
345
|
+
5. Add URL: `https://cbrowser-mcp.yourdomain.com/mcp`
|
|
346
|
+
|
|
347
|
+
You should see 31+ CBrowser tools become available in Claude.
|
|
328
348
|
|
|
329
349
|
---
|
|
330
350
|
|
|
@@ -340,11 +360,29 @@ sudo ufw allow 443/tcp # HTTPS
|
|
|
340
360
|
sudo ufw enable
|
|
341
361
|
```
|
|
342
362
|
|
|
343
|
-
### Authentication (v7.4.
|
|
363
|
+
### Authentication (v7.4.6+)
|
|
364
|
+
|
|
365
|
+
CBrowser Remote MCP Server supports two authentication methods:
|
|
366
|
+
|
|
367
|
+
#### Method 1: Auth0 OAuth (for claude.ai)
|
|
368
|
+
|
|
369
|
+
Claude.ai requires OAuth 2.1 authentication. Set up Auth0:
|
|
370
|
+
|
|
371
|
+
```bash
|
|
372
|
+
# Auth0 OAuth (enables claude.ai login)
|
|
373
|
+
Environment=AUTH0_DOMAIN=your-tenant.auth0.com
|
|
374
|
+
Environment=AUTH0_AUDIENCE=https://cbrowser-mcp.yourdomain.com/
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
See [Auth0 Setup Guide](AUTH0-SETUP.md) for full configuration.
|
|
344
378
|
|
|
345
|
-
|
|
379
|
+
**OAuth Endpoints:**
|
|
380
|
+
- `/.well-known/oauth-protected-resource` - OAuth metadata discovery
|
|
381
|
+
- `/mcp` - MCP endpoint (requires valid JWT)
|
|
346
382
|
|
|
347
|
-
|
|
383
|
+
#### Method 2: API Key (for Claude Code CLI)
|
|
384
|
+
|
|
385
|
+
For programmatic access and Claude Code CLI:
|
|
348
386
|
|
|
349
387
|
```bash
|
|
350
388
|
# Single API key
|
|
@@ -370,14 +408,24 @@ curl -H "Authorization: Bearer your-api-key" https://your-server/mcp
|
|
|
370
408
|
curl -H "X-API-Key: your-api-key" https://your-server/mcp
|
|
371
409
|
```
|
|
372
410
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
411
|
+
#### Dual Authentication
|
|
412
|
+
|
|
413
|
+
Both methods can be enabled simultaneously:
|
|
414
|
+
- **OAuth** - For claude.ai web interface
|
|
415
|
+
- **API Key** - For Claude Code CLI and scripts
|
|
416
|
+
|
|
417
|
+
**Public Endpoints (no auth required):**
|
|
418
|
+
- `/health` - Server health status
|
|
419
|
+
- `/info` - Server information
|
|
420
|
+
- `/.well-known/oauth-protected-resource` - OAuth metadata
|
|
421
|
+
|
|
422
|
+
**Protected Endpoints:**
|
|
423
|
+
- `/mcp` - MCP endpoint (requires valid auth)
|
|
376
424
|
|
|
377
425
|
**Additional security layers:**
|
|
378
|
-
1.
|
|
379
|
-
2.
|
|
380
|
-
3.
|
|
426
|
+
1. Rate limiting in nginx
|
|
427
|
+
2. Cloudflare WAF rules
|
|
428
|
+
3. IP whitelisting
|
|
381
429
|
|
|
382
430
|
### Rate Limiting
|
|
383
431
|
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CBrowser v7.4.6 Remote MCP Server Examples
|
|
3
|
+
*
|
|
4
|
+
* Demonstrates:
|
|
5
|
+
* - Starting a remote MCP server
|
|
6
|
+
* - Authentication options (API key, OAuth)
|
|
7
|
+
* - Connecting from claude.ai
|
|
8
|
+
*
|
|
9
|
+
* Run the server: npx cbrowser mcp-remote
|
|
10
|
+
* Or with authentication: MCP_API_KEY=your-key npx cbrowser mcp-remote
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { createServer } from "http";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Example: Start Remote MCP Server Programmatically
|
|
17
|
+
*
|
|
18
|
+
* Note: In most cases, use the CLI:
|
|
19
|
+
* npx cbrowser mcp-remote
|
|
20
|
+
*
|
|
21
|
+
* This example shows programmatic configuration.
|
|
22
|
+
*/
|
|
23
|
+
async function startRemoteMCPServer() {
|
|
24
|
+
console.log("=== Remote MCP Server Configuration ===\n");
|
|
25
|
+
|
|
26
|
+
console.log("Environment Variables:\n");
|
|
27
|
+
|
|
28
|
+
console.log("Basic Configuration:");
|
|
29
|
+
console.log(" PORT=3100 # Server port (default: 3000)");
|
|
30
|
+
console.log(" HOST=127.0.0.1 # Bind address");
|
|
31
|
+
console.log(" MCP_SESSION_MODE=stateless # Session handling\n");
|
|
32
|
+
|
|
33
|
+
console.log("API Key Authentication:");
|
|
34
|
+
console.log(" MCP_API_KEY=your-secret-key # Single API key");
|
|
35
|
+
console.log(" MCP_API_KEYS=key1,key2,key3 # Multiple API keys\n");
|
|
36
|
+
|
|
37
|
+
console.log("Auth0 OAuth (for claude.ai):");
|
|
38
|
+
console.log(" AUTH0_DOMAIN=your-tenant.auth0.com");
|
|
39
|
+
console.log(" AUTH0_AUDIENCE=https://your-server.com/\n");
|
|
40
|
+
|
|
41
|
+
console.log("Start command:");
|
|
42
|
+
console.log(" npx cbrowser mcp-remote\n");
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Example: Client Configuration for claude.ai
|
|
47
|
+
*/
|
|
48
|
+
function claudeAISetup() {
|
|
49
|
+
console.log("=== claude.ai Custom Connector Setup ===\n");
|
|
50
|
+
|
|
51
|
+
console.log("Demo Server (rate-limited, no auth):");
|
|
52
|
+
console.log(" URL: https://cbrowser-mcp-demo.wyldfyre.ai/mcp");
|
|
53
|
+
console.log(" Rate limit: 5 requests/minute, burst of 10");
|
|
54
|
+
console.log(" Purpose: Evaluation only\n");
|
|
55
|
+
|
|
56
|
+
console.log("Authenticated Server (full access):");
|
|
57
|
+
console.log(" URL: https://cbrowser-mcp.wyldfyre.ai/mcp");
|
|
58
|
+
console.log(" Auth: Auth0 OAuth 2.1");
|
|
59
|
+
console.log(" Rate limit: None\n");
|
|
60
|
+
|
|
61
|
+
console.log("Setup Steps:");
|
|
62
|
+
console.log(" 1. Go to claude.ai");
|
|
63
|
+
console.log(" 2. Open Settings -> Integrations -> Custom MCP Servers");
|
|
64
|
+
console.log(" 3. Add the server URL");
|
|
65
|
+
console.log(" 4. Complete OAuth login when prompted (for authenticated server)");
|
|
66
|
+
console.log(" 5. You now have 31 browser automation tools!\n");
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Example: API Key Authentication
|
|
71
|
+
*/
|
|
72
|
+
function apiKeyAuth() {
|
|
73
|
+
console.log("=== API Key Authentication ===\n");
|
|
74
|
+
|
|
75
|
+
console.log("Set API key when starting server:");
|
|
76
|
+
console.log(" MCP_API_KEY=your-secret-key npx cbrowser mcp-remote\n");
|
|
77
|
+
|
|
78
|
+
console.log("Client usage (Bearer token - recommended):");
|
|
79
|
+
console.log(' curl -H "Authorization: Bearer your-api-key" https://server/mcp\n');
|
|
80
|
+
|
|
81
|
+
console.log("Client usage (X-API-Key header):");
|
|
82
|
+
console.log(' curl -H "X-API-Key: your-api-key" https://server/mcp\n');
|
|
83
|
+
|
|
84
|
+
console.log("Generate a secure key:");
|
|
85
|
+
console.log(" openssl rand -hex 32\n");
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Example: OAuth Protected Resource Metadata
|
|
90
|
+
*/
|
|
91
|
+
function oauthMetadata() {
|
|
92
|
+
console.log("=== OAuth Protected Resource Metadata ===\n");
|
|
93
|
+
|
|
94
|
+
console.log("Endpoint: /.well-known/oauth-protected-resource\n");
|
|
95
|
+
|
|
96
|
+
console.log("Response example:");
|
|
97
|
+
const metadata = {
|
|
98
|
+
resource: "https://cbrowser-mcp.wyldfyre.ai",
|
|
99
|
+
authorization_servers: ["https://your-tenant.auth0.com"],
|
|
100
|
+
bearer_methods_supported: ["header"],
|
|
101
|
+
scopes_supported: ["openid", "profile", "cbrowser:read", "cbrowser:write"],
|
|
102
|
+
};
|
|
103
|
+
console.log(JSON.stringify(metadata, null, 2));
|
|
104
|
+
console.log();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Example: Health Check
|
|
109
|
+
*/
|
|
110
|
+
function healthCheck() {
|
|
111
|
+
console.log("=== Health Check Endpoint ===\n");
|
|
112
|
+
|
|
113
|
+
console.log("Endpoint: /health\n");
|
|
114
|
+
|
|
115
|
+
console.log("Response example:");
|
|
116
|
+
const health = {
|
|
117
|
+
status: "ok",
|
|
118
|
+
version: "7.4.6",
|
|
119
|
+
auth: true,
|
|
120
|
+
auth_methods: {
|
|
121
|
+
api_key: true,
|
|
122
|
+
oauth: true,
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
console.log(JSON.stringify(health, null, 2));
|
|
126
|
+
console.log();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async function main() {
|
|
130
|
+
await startRemoteMCPServer();
|
|
131
|
+
claudeAISetup();
|
|
132
|
+
apiKeyAuth();
|
|
133
|
+
oauthMetadata();
|
|
134
|
+
healthCheck();
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
main().catch(console.error);
|
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* CBrowser
|
|
2
|
+
* CBrowser v7.x Smart Automation Examples
|
|
3
3
|
*
|
|
4
4
|
* Demonstrates:
|
|
5
5
|
* - Smart click with auto-retry
|
|
6
6
|
* - Natural language assertions
|
|
7
7
|
* - Self-healing selector cache
|
|
8
8
|
* - AI test generation
|
|
9
|
+
* - Modular imports
|
|
9
10
|
*
|
|
10
11
|
* Run with: npx ts-node examples/smart-automation.ts
|
|
12
|
+
* Or: bun run examples/smart-automation.ts
|
|
11
13
|
*/
|
|
12
14
|
|
|
13
|
-
import { CBrowser } from "
|
|
15
|
+
import { CBrowser } from "cbrowser";
|
|
16
|
+
// For local development: import { CBrowser } from "../src/index.js";
|
|
14
17
|
|
|
15
18
|
async function smartClickExample() {
|
|
16
19
|
console.log("=== Smart Click with Auto-Retry ===\n");
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CBrowser v7.x Visual Testing Examples
|
|
3
|
+
*
|
|
4
|
+
* Demonstrates:
|
|
5
|
+
* - AI Visual Regression (v7.0)
|
|
6
|
+
* - Cross-Browser Testing (v7.1)
|
|
7
|
+
* - Responsive Testing (v7.2)
|
|
8
|
+
* - A/B Comparison (v7.3)
|
|
9
|
+
*
|
|
10
|
+
* Run with: npx ts-node examples/visual-testing.ts
|
|
11
|
+
* Or: bun run examples/visual-testing.ts
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { CBrowser } from "cbrowser";
|
|
15
|
+
// Modular imports for tree-shaking:
|
|
16
|
+
// import { runVisualRegression, runCrossBrowserTest, runResponsiveTest, runABComparison } from "cbrowser/visual";
|
|
17
|
+
|
|
18
|
+
async function visualRegressionExample() {
|
|
19
|
+
console.log("=== AI Visual Regression (v7.0) ===\n");
|
|
20
|
+
|
|
21
|
+
const browser = new CBrowser({ headless: true });
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
// Capture a baseline
|
|
25
|
+
const baseline = await browser.captureVisualBaseline(
|
|
26
|
+
"https://example.com",
|
|
27
|
+
"homepage"
|
|
28
|
+
);
|
|
29
|
+
console.log(`Baseline captured: ${baseline.name}`);
|
|
30
|
+
console.log(`Screenshot: ${baseline.screenshotPath}`);
|
|
31
|
+
console.log(`Timestamp: ${baseline.timestamp}`);
|
|
32
|
+
|
|
33
|
+
// Later, compare against baseline
|
|
34
|
+
const result = await browser.runVisualRegression(
|
|
35
|
+
"https://example.com",
|
|
36
|
+
"homepage"
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
console.log(`\nComparison result:`);
|
|
40
|
+
console.log(` Match: ${result.match}`);
|
|
41
|
+
console.log(` Similarity: ${(result.similarity * 100).toFixed(1)}%`);
|
|
42
|
+
console.log(` AI Analysis: ${result.aiAnalysis}`);
|
|
43
|
+
|
|
44
|
+
if (result.differences.length > 0) {
|
|
45
|
+
console.log(`\nDifferences found:`);
|
|
46
|
+
for (const diff of result.differences) {
|
|
47
|
+
console.log(` - ${diff.type}: ${diff.description}`);
|
|
48
|
+
console.log(` Severity: ${diff.severity}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
} finally {
|
|
52
|
+
await browser.close();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async function crossBrowserExample() {
|
|
57
|
+
console.log("\n=== Cross-Browser Testing (v7.1) ===\n");
|
|
58
|
+
|
|
59
|
+
const browser = new CBrowser({ headless: true });
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
// Compare rendering across browsers
|
|
63
|
+
const result = await browser.runCrossBrowserTest("https://example.com", {
|
|
64
|
+
browsers: ["chromium", "firefox", "webkit"],
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
console.log(`URL tested: ${result.url}`);
|
|
68
|
+
console.log(`Browsers: ${result.browsers.join(", ")}`);
|
|
69
|
+
console.log(`Overall match: ${result.overallMatch}`);
|
|
70
|
+
|
|
71
|
+
console.log(`\nBrowser comparisons:`);
|
|
72
|
+
for (const comparison of result.comparisons) {
|
|
73
|
+
console.log(` ${comparison.browserA} vs ${comparison.browserB}:`);
|
|
74
|
+
console.log(` Similarity: ${(comparison.similarity * 100).toFixed(1)}%`);
|
|
75
|
+
console.log(` Differences: ${comparison.differences.length}`);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (result.criticalDifferences.length > 0) {
|
|
79
|
+
console.log(`\nCritical differences:`);
|
|
80
|
+
for (const diff of result.criticalDifferences) {
|
|
81
|
+
console.log(` - ${diff.browser}: ${diff.description}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
} finally {
|
|
85
|
+
await browser.close();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async function responsiveExample() {
|
|
90
|
+
console.log("\n=== Responsive Testing (v7.2) ===\n");
|
|
91
|
+
|
|
92
|
+
const browser = new CBrowser({ headless: true });
|
|
93
|
+
|
|
94
|
+
try {
|
|
95
|
+
// Test across viewport sizes
|
|
96
|
+
const result = await browser.runResponsiveTest("https://example.com", {
|
|
97
|
+
viewports: ["mobile", "tablet", "desktop"],
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
console.log(`URL tested: ${result.url}`);
|
|
101
|
+
console.log(`Viewports tested: ${result.viewports.length}`);
|
|
102
|
+
|
|
103
|
+
console.log(`\nViewport results:`);
|
|
104
|
+
for (const viewport of result.viewports) {
|
|
105
|
+
console.log(` ${viewport.name} (${viewport.width}x${viewport.height}):`);
|
|
106
|
+
console.log(` Layout: ${viewport.layoutType}`);
|
|
107
|
+
console.log(` Issues: ${viewport.issues.length}`);
|
|
108
|
+
|
|
109
|
+
if (viewport.issues.length > 0) {
|
|
110
|
+
for (const issue of viewport.issues) {
|
|
111
|
+
console.log(` - ${issue.type}: ${issue.description}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Breakpoint analysis
|
|
117
|
+
if (result.breakpointIssues.length > 0) {
|
|
118
|
+
console.log(`\nBreakpoint issues:`);
|
|
119
|
+
for (const issue of result.breakpointIssues) {
|
|
120
|
+
console.log(` At ${issue.breakpoint}px: ${issue.description}`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
} finally {
|
|
124
|
+
await browser.close();
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async function abComparisonExample() {
|
|
129
|
+
console.log("\n=== A/B Comparison (v7.3) ===\n");
|
|
130
|
+
|
|
131
|
+
const browser = new CBrowser({ headless: true });
|
|
132
|
+
|
|
133
|
+
try {
|
|
134
|
+
// Compare two URLs (staging vs production, old vs new design)
|
|
135
|
+
const result = await browser.runABComparison(
|
|
136
|
+
"https://staging.example.com",
|
|
137
|
+
"https://example.com",
|
|
138
|
+
{
|
|
139
|
+
labelA: "Staging",
|
|
140
|
+
labelB: "Production",
|
|
141
|
+
}
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
console.log(`Comparison: ${result.labelA} vs ${result.labelB}`);
|
|
145
|
+
console.log(`Overall similarity: ${(result.similarity * 100).toFixed(1)}%`);
|
|
146
|
+
console.log(`Match: ${result.match}`);
|
|
147
|
+
|
|
148
|
+
console.log(`\nDifferences:`);
|
|
149
|
+
for (const diff of result.differences) {
|
|
150
|
+
console.log(` - ${diff.category}: ${diff.description}`);
|
|
151
|
+
console.log(` Severity: ${diff.severity}`);
|
|
152
|
+
console.log(` Location: ${diff.location}`);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// AI summary
|
|
156
|
+
console.log(`\nAI Summary:`);
|
|
157
|
+
console.log(` ${result.aiSummary}`);
|
|
158
|
+
|
|
159
|
+
if (result.recommendations.length > 0) {
|
|
160
|
+
console.log(`\nRecommendations:`);
|
|
161
|
+
for (const rec of result.recommendations) {
|
|
162
|
+
console.log(` - ${rec}`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
} finally {
|
|
166
|
+
await browser.close();
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
async function main() {
|
|
171
|
+
await visualRegressionExample();
|
|
172
|
+
await crossBrowserExample();
|
|
173
|
+
await responsiveExample();
|
|
174
|
+
await abComparisonExample();
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
main().catch(console.error);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cbrowser",
|
|
3
|
-
"version": "7.4.
|
|
3
|
+
"version": "7.4.7",
|
|
4
4
|
"description": "AI-powered browser automation with constitutional safety, AI visual regression, persona testing, and natural language test suites. Modular architecture for visual, testing, analysis, and performance modules.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -89,6 +89,7 @@
|
|
|
89
89
|
},
|
|
90
90
|
"dependencies": {
|
|
91
91
|
"@modelcontextprotocol/sdk": "^1.25.3",
|
|
92
|
+
"jose": "^5.2.0",
|
|
92
93
|
"playwright": "^1.40.0",
|
|
93
94
|
"zod": "^3.25.76"
|
|
94
95
|
},
|