Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
58ac2d4
feat: add agent persona and datacenter proxy options
xsvfat Aug 28, 2026
6afb140
refactor: reuse agent persona request state
xsvfat Aug 28, 2026
d79d7e3
fix: enforce agent persona and proxy creation contracts
xsvfat Aug 28, 2026
0bbec1e
fix: preserve sessions on persona conflicts
xsvfat Aug 29, 2026
c1107fc
fix: retain agent personas across retries
xsvfat Aug 29, 2026
81c9b27
fix: validate agent persona lifecycles
xsvfat Aug 29, 2026
a315012
fix: enforce desktop persona dependencies
xsvfat Aug 29, 2026
5b8d9a7
fix: retain agent personas after socket loss
xsvfat Aug 29, 2026
39e40d8
fix: preserve agent persona options
ampagent Sep 2, 2026
e286a15
fix: preserve credential session isolation
ampagent Sep 2, 2026
a9011b1
refactor: clarify agent session scope
ampagent Sep 2, 2026
748dc4d
fix: retain legacy persona options
ampagent Sep 3, 2026
ae8624f
fix: preserve humanlike profile sessions
ampagent Sep 3, 2026
d7a3d4e
fix: retain Agent proxy routing across reconnects
ampagent Sep 3, 2026
b240e77
fix: preserve attached session persona state
ampagent Sep 3, 2026
c4855ab
fix: validate proxy reuse paths
ampagent Sep 3, 2026
1f6e809
Merge main into feat/agent-stealth-parameters
ampagent Sep 4, 2026
2318d63
fix: preserve recording client argument order
ampagent Sep 4, 2026
dac1697
fix: reject recording on attached sessions
ampagent Sep 4, 2026
a3a13ab
fix: reject recording changes on reused sessions
ampagent Sep 4, 2026
bf89108
fix: retain no-proxy session state
ampagent Sep 4, 2026
664bb46
fix(agent): reject legacy OS on session attach
ampagent Sep 4, 2026
e0c49d8
fix(agent): classify attach persona conflicts
ampagent Sep 4, 2026
a0479be
fix(agent): preserve profile OS during session recovery
andyMrtnzP Sep 14, 2026
7177239
Merge remote-tracking branch 'origin/main' into feat/agent-stealth-pa…
Copilot Sep 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 21 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,9 @@ Load a skill explicitly:
}
```

### Residential proxy (`browserless_agent`)
### Built-in proxy (`browserless_agent`)

Pass a top-level `proxy` object on `browserless_agent` to route the session through residential IPs. Use this when targets IP-block datacenter traffic.
Pass a top-level `proxy` object on `browserless_agent` to route the session through datacenter or residential IPs. Datacenter is cheaper per MB; residential is less likely to be blocked.

```jsonc
{
Expand All @@ -90,19 +90,35 @@ Pass a top-level `proxy` object on `browserless_agent` to route the session thro

| Field | Notes |
| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `proxy` | `"residential"` — only value supported today. |
| `proxy` | `"datacenter"` for lower cost or `"residential"` when targets block datacenter traffic. |
| `proxyCountry` | ISO-2 country code (`"us"`, `"de"`). Auto-normalized to lowercase. Non-letter values are rejected. |
| `proxyState` | US state name with whitespace replaced by underscores (`"new_york"`). Paid-plan gated — non-eligible tokens get a 401. |
| `proxyCity` | City target. Paid/enterprise plan gated — non-eligible tokens get a 401. |
| `proxySticky` | Stable IP while the underlying WebSocket stays open. Reconnects (idle drop, network blip, browser crash) allocate a new sticky id and new IP. |
| `proxyLocaleMatch` | Match `navigator` locale to the proxy IP country. |
| `proxyPreset` | Named preset (e.g. `"px_amazon01"`). Available presets are plan-dependent — ask Browserless support for your list. |
| `proxyPreset` | Residential-only named preset (e.g. `"px_amazon01"`). Available presets are plan-dependent — ask Browserless support for your list. |
| `externalProxyServer` | Bring-your-own upstream, e.g. `http://user:pass@host:port`. Must be `http://` or `https://`. |

> **Note:** `proxyCountry` / `proxyState` / `proxyCity` / `proxySticky` / `proxyLocaleMatch` / `proxyPreset` require either `proxy: "residential"` or `externalProxyServer` to be set. The MCP rejects this combination at validation time; without it, the API would silently ignore them.
> **Note:** Geo, sticky, and locale options require either a built-in `proxy` tier or `externalProxyServer`; `proxyPreset` requires `proxy: "residential"`. The MCP rejects unsupported combinations instead of letting the API silently ignore them.

The `proxy` object is read once at session creation. To change it, call `close` and start a new session — the agent client keys sessions on the proxy fingerprint, so passing a different config will land on a fresh WebSocket.

### OS persona (`browserless_agent`)

Agent sessions can opt into a coherent OS persona with top-level creation options:

| Field | Notes |
| ------------------- | ----------------------------------------------------------------------------------------- |
| `emulationOs` | `"windows"`, `"macos"`, `"linux"`, or `"android"`. Enables platform spoofing. |
| `emulatedDevice` | Android device slug; used only with `emulationOs: "android"`. |
| `screen` | Desktop screen in `WIDTHxHEIGHT` form. |
| `deviceScaleFactor` | Desktop device pixel ratio: `1` or `1.25`. |
| `deviceSlot` | Non-negative stable desktop-device slot; the server validates the account-specific range. |

Set persona options on the first call before navigation and reuse the returned
`sessionId` afterward. Persona is fixed for the life of that browser session;
close it before selecting a different persona.

## Configuration

The server is hosted at `https://mcp.browserless.io/mcp`. Authenticate via headers (preferred) or a `?token=` query parameter.
Expand Down
12 changes: 9 additions & 3 deletions src/@types/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ import type {
} from '../tools/crawl.js';
import type { AgentParamsSchema } from '../tools/agent.js';
import type { CreateProfileParams } from '../tools/schemas.js';
import type { ProxyOptionsSchema } from '../lib/agent-client.js';
import type {
PersonaOptionsSchema,
ProxyOptionsSchema,
} from '../lib/agent-client.js';
import type { AuthMethod, McpTransport } from '../lib/attribution.js';

/* ------------------------------------------------------------------ */
Expand Down Expand Up @@ -205,11 +208,13 @@ export interface SnapshotResult {
export interface ActiveSession {
ws: WebSocket;
msgId: number;
// Identity fields: these feed the session-cache key (see getSessionKey).
// Mutating them post-creation would desync the cache, so they're readonly.
// Creation identity fields are immutable. Most feed the session-cache key;
// persona is retained on the handle and checked before reuse.
readonly apiUrl: string;
readonly token: string;
readonly proxy?: ProxyOptions;
/** Persona fixed when the underlying browser session is created. */
readonly persona?: PersonaOptions;
readonly profile?: string;
// When set, this session was opened in profile-creation mode: the WS is bound
// to a creation session from POST /profile rather than a fresh launch. Feeds
Expand Down Expand Up @@ -364,6 +369,7 @@ export type SmartScraperResponse = z.infer<typeof SmartScraperResponseSchema>;
export type FunctionParams = z.infer<typeof FunctionParamsSchema>;
export type ExportParams = z.infer<typeof ExportParamsSchema>;
export type ProxyOptions = z.infer<typeof ProxyOptionsSchema>;
export type PersonaOptions = z.infer<typeof PersonaOptionsSchema>;
export type SearchSource = z.infer<typeof SearchSourceSchema>;
export type SearchCategory = z.infer<typeof SearchCategorySchema>;
export type TimeBasedOptions = z.infer<typeof TimeBasedOptionsSchema>;
Expand Down
Loading