diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index 6d4c016b..333e70a1 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "0.111.0"
+ ".": "0.112.0"
}
diff --git a/.stats.yml b/.stats.yml
index e8ac4eb6..ec91ee34 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1 +1 @@
-configured_endpoints: 169
+configured_endpoints: 172
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0d1c8026..bee4127d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,18 @@
# Changelog
+## [0.112.0](https://github.com/kernel/kernel-node-sdk/compare/v0.111.0...v0.112.0) (2026-09-24)
+
+
+### Features
+
+* Add profiles to browser pool acquire ([0b0f348](https://github.com/kernel/kernel-node-sdk/commit/0b0f348c33f9e9c372b31dbcfd19b505a26057ef))
+* Correct monitor_disconnected description on computed state ([809b9c8](https://github.com/kernel/kernel-node-sdk/commit/809b9c8be2eb8919389bc5369e8a8a3cc5590182))
+* Expose Search rollout access in org entitlements ([68ff158](https://github.com/kernel/kernel-node-sdk/commit/68ff158188ce06e5f7526a324217d945e1970cc3))
+* Filter archived telemetry events by type ([dc46ab2](https://github.com/kernel/kernel-node-sdk/commit/dc46ab213c0333cd16510c789a3fc10cb4bc0383))
+* Proxy custom WebMCP tools in the control plane ([44e5665](https://github.com/kernel/kernel-node-sdk/commit/44e5665b3edd75f94605cca72479e89029225b38))
+* Publish iframe and worker browser target types ([3d555d7](https://github.com/kernel/kernel-node-sdk/commit/3d555d700e9854a2ec1d095d484d916abea4541e))
+* Route browser destinations through selected proxies ([27108aa](https://github.com/kernel/kernel-node-sdk/commit/27108aa04eb3be3f307a696421e33c45071a5584))
+
## [0.111.0](https://github.com/kernel/kernel-node-sdk/compare/v0.110.0...v0.111.0) (2026-09-22)
diff --git a/api.md b/api.md
index bca08e38..dee34db6 100644
--- a/api.md
+++ b/api.md
@@ -307,19 +307,36 @@ Methods:
Types:
-- InvocationFailure
-- InvocationResult
-- InvokeRequest
-- Tool
-- ToolAnnotations
-- ToolFrame
-- ToolSource
-- ToolsResponse
+- CustomToolSource
+- InvocationFailure
+- InvocationResult
+- InvokeRequest
+- Tool
+- ToolAnnotations
+- ToolFrame
+- ToolMetadata
+- ToolSource
+- ToolsResponse
Methods:
-- client.browsers.webmcp.invokeTool(idOrName, { ...params }) -> InvocationResult
-- client.browsers.webmcp.listTools(idOrName) -> ToolsResponse
+- client.browsers.webmcp.invokeTool(idOrName, { ...params }) -> InvocationResult
+- client.browsers.webmcp.listTools(idOrName, { ...params }) -> ToolsResponse
+
+### CustomTools
+
+Types:
+
+- AddRequest
+- CustomToolsResponse
+- Definition
+- Match
+
+Methods:
+
+- client.browsers.webmcp.customTools.list(idOrName) -> CustomToolsResponse
+- client.browsers.webmcp.customTools.add(idOrName, { ...params }) -> CustomToolsResponse
+- client.browsers.webmcp.customTools.remove(id, { ...params }) -> void
# Profiles
diff --git a/package.json b/package.json
index 0930d37e..539bd6d5 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@onkernel/sdk",
- "version": "0.111.0",
+ "version": "0.112.0",
"description": "The official TypeScript library for the Kernel API",
"author": "Kernel <>",
"types": "dist/index.d.ts",
diff --git a/src/resources/browser-pools.ts b/src/resources/browser-pools.ts
index 7444b45a..2f71c1ba 100644
--- a/src/resources/browser-pools.ts
+++ b/src/resources/browser-pools.ts
@@ -1066,6 +1066,13 @@ export interface BrowserPoolAcquireParams {
*/
name?: string;
+ /**
+ * Profile selection for the browser session. Provide either id or name. If
+ * specified, the matching profile will be loaded into the browser session.
+ * Profiles must be created beforehand.
+ */
+ profile?: Shared.BrowserProfile;
+
/**
* Optional URL to navigate the acquired browser to. Overrides the pool's start_url
* for this acquire only. Best-effort: failures to navigate do not fail the
@@ -1200,7 +1207,8 @@ export interface BrowserPoolReleaseParams {
* Defaults to true. A reused browser keeps the configuration it was created with,
* so it does not pick up pool configuration changes made while it was in use.
* Release with `reuse: false`, or flush the pool afterward, to rebuild it with the
- * current configuration.
+ * current configuration. Browsers loaded with an acquire-time profile are always
+ * destroyed and replaced, even when reuse is true.
*/
reuse?: boolean;
}
diff --git a/src/resources/browsers/browsers.ts b/src/resources/browsers/browsers.ts
index b6663d54..63e8380b 100644
--- a/src/resources/browsers/browsers.ts
+++ b/src/resources/browsers/browsers.ts
@@ -109,19 +109,6 @@ import {
TelemetryStreamParams,
TelemetryStreamResponse,
} from './telemetry';
-import * as WebmcpAPI from './webmcp';
-import {
- InvocationFailure,
- InvocationResult,
- InvokeRequest,
- Tool,
- ToolAnnotations,
- ToolFrame,
- ToolSource,
- ToolsResponse,
- Webmcp,
- WebmcpInvokeToolParams,
-} from './webmcp';
import * as FsAPI from './fs/fs';
import {
FCreateDirectoryParams,
@@ -140,6 +127,22 @@ import {
FWriteFileParams,
Fs,
} from './fs/fs';
+import * as WebmcpAPI from './webmcp/webmcp';
+import {
+ CustomToolSource,
+ InvocationFailure,
+ InvocationResult,
+ InvokeRequest,
+ Tool,
+ ToolAnnotations,
+ ToolFrame,
+ ToolMetadata,
+ ToolSource,
+ ToolsResponse,
+ Webmcp,
+ WebmcpInvokeToolParams,
+ WebmcpListToolsParams,
+} from './webmcp/webmcp';
import { APIPromise } from '../../core/api-promise';
import { OffsetPagination, type OffsetPaginationParams, PagePromise } from '../../core/pagination';
import { type Uploadable } from '../../core/uploads';
@@ -375,6 +378,52 @@ export interface BrowserNetworkConfig {
* upstream-proxy and Kernel-managed direct egress and cannot reach into a VPN.
*/
private_hosts?: Array;
+
+ /**
+ * Per-destination proxy routes for a browser session. After setup, a destination
+ * hostname is matched against every route's hosts, regardless of port; route order
+ * does not matter. An exact hostname beats a wildcard, and a longer wildcard
+ * suffix beats a shorter one (for a.b.example.com: "a.b.example.com" >
+ * "_.b.example.com" > "_.example.com"). A host pattern may appear in only one
+ * route. "\*.example.com" matches subdomains only, not example.com. A matched
+ * request selects the route's proxy instead of the session's top-level proxy
+ * (including mode: direct); the route proxy's own bypass_hosts still apply. If the
+ * route proxy becomes unavailable, matched requests fail closed without falling
+ * back. Requests that match no route use the session's default egress from the
+ * top-level proxy field (or the browser default when proxy is omitted: stealth
+ * proxy or direct egress). Routes take effect once the session is created;
+ * start_url and other traffic during browser setup use the top-level proxy.
+ * Setting routes requires proxy v3. Not supported on browser pools.
+ */
+ proxy_routes?: Array;
+}
+
+export namespace BrowserNetworkConfig {
+ export interface ProxyRoute {
+ /**
+ * Exact hostnames or leading \*. wildcard patterns (subdomains only); patterns
+ * cannot include ports, and matching ignores the destination port. Hosts not
+ * matched by any route use the session's top-level proxy (or the browser default
+ * when proxy is omitted).
+ */
+ hosts: Array;
+
+ /**
+ * Select an active non-direct proxy by ID or name. Responses always use ID.
+ */
+ proxy: ProxyRoute.Proxy;
+ }
+
+ export namespace ProxyRoute {
+ /**
+ * Select an active non-direct proxy by ID or name. Responses always use ID.
+ */
+ export interface Proxy {
+ id?: string;
+
+ name?: string;
+ }
+ }
}
/**
@@ -2019,14 +2068,17 @@ export declare namespace Browsers {
export {
Webmcp as Webmcp,
+ type CustomToolSource as CustomToolSource,
type InvocationFailure as InvocationFailure,
type InvocationResult as InvocationResult,
type InvokeRequest as InvokeRequest,
type Tool as Tool,
type ToolAnnotations as ToolAnnotations,
type ToolFrame as ToolFrame,
+ type ToolMetadata as ToolMetadata,
type ToolSource as ToolSource,
type ToolsResponse as ToolsResponse,
type WebmcpInvokeToolParams as WebmcpInvokeToolParams,
+ type WebmcpListToolsParams as WebmcpListToolsParams,
};
}
diff --git a/src/resources/browsers/index.ts b/src/resources/browsers/index.ts
index 19edac39..ed0d11c3 100644
--- a/src/resources/browsers/index.ts
+++ b/src/resources/browsers/index.ts
@@ -152,13 +152,16 @@ export {
} from './telemetry';
export {
Webmcp,
+ type CustomToolSource,
type InvocationFailure,
type InvocationResult,
type InvokeRequest,
type Tool,
type ToolAnnotations,
type ToolFrame,
+ type ToolMetadata,
type ToolSource,
type ToolsResponse,
type WebmcpInvokeToolParams,
-} from './webmcp';
+ type WebmcpListToolsParams,
+} from './webmcp/index';
diff --git a/src/resources/browsers/telemetry.ts b/src/resources/browsers/telemetry.ts
index 100f182e..99f6d4d4 100644
--- a/src/resources/browsers/telemetry.ts
+++ b/src/resources/browsers/telemetry.ts
@@ -16,8 +16,9 @@ export class Telemetry extends APIResource {
/**
* Reads a page of telemetry events for the browser session. To page through
* results, pass the X-Next-Offset value from the previous response as offset and
- * repeat while X-Has-More is true. Returns an empty list when telemetry data is
- * unavailable.
+ * repeat while X-Has-More is true. The category and type filters apply within each
+ * page, so a filtered page may be empty while X-Has-More is true. Returns an empty
+ * list when telemetry data is unavailable.
*
* @example
* ```ts
@@ -2979,7 +2980,14 @@ export interface BrowserEventContext {
/**
* CDP target type of the page that produced the event.
*/
- target_type?: 'page' | 'background_page' | 'service_worker' | 'shared_worker' | 'other';
+ target_type?:
+ | 'page'
+ | 'iframe'
+ | 'worker'
+ | 'background_page'
+ | 'service_worker'
+ | 'shared_worker'
+ | 'other';
/**
* URL relevant to this event — page URL for navigation and page events, request
@@ -3283,8 +3291,12 @@ export namespace BrowserLiveViewDisconnectEvent {
/**
* The CDP connection to Chrome was lost. Telemetry events may be dropped until
- * monitor_reconnected arrives. Treat any in-progress computed state (network_idle,
- * page_layout_settled) as unreliable until then.
+ * monitor_reconnected arrives. In-progress computed state is discarded rather than
+ * paused, so computed events still pending for the current navigation
+ * (network_idle, page_layout_settled, page_navigation_settled) never fire.
+ * monitor_reconnected does not restore them. After reattachment a fresh state
+ * machine starts, so computed events can resume before the next navigation and
+ * carry empty navigation context until one occurs.
*/
export interface BrowserMonitorDisconnectedEvent {
category: 'monitor';
@@ -3769,7 +3781,14 @@ export namespace BrowserPageCrashedEvent {
/**
* CDP target type of the page that produced the event.
*/
- target_type: 'page' | 'background_page' | 'service_worker' | 'shared_worker' | 'other';
+ target_type:
+ | 'page'
+ | 'iframe'
+ | 'worker'
+ | 'background_page'
+ | 'service_worker'
+ | 'shared_worker'
+ | 'other';
/**
* URL the page was on when its renderer process crashed.
@@ -4135,7 +4154,14 @@ export namespace BrowserPageNavigationEvent {
/**
* CDP target type of the page that produced the event.
*/
- target_type?: 'page' | 'background_page' | 'service_worker' | 'shared_worker' | 'other';
+ target_type?:
+ | 'page'
+ | 'iframe'
+ | 'worker'
+ | 'background_page'
+ | 'service_worker'
+ | 'shared_worker'
+ | 'other';
/**
* URL navigated to.
@@ -4222,7 +4248,14 @@ export namespace BrowserPageTabOpenedEvent {
/**
* CDP target type of the page that produced the event.
*/
- target_type?: 'page' | 'background_page' | 'service_worker' | 'shared_worker' | 'other';
+ target_type?:
+ | 'page'
+ | 'iframe'
+ | 'worker'
+ | 'background_page'
+ | 'service_worker'
+ | 'shared_worker'
+ | 'other';
/**
* Initial page title of the new tab.
@@ -4337,15 +4370,16 @@ export namespace BrowserProxyErrorEvent {
/**
* Proxy-layer error code: the X-Kernel-Proxy-Error response header value from a
* branded 5xx error page served by the metro egress host-proxy. Values mirror what
- * the proxy emits: destination_blocked, provider_blacklisted,
- * provider_unreachable, provider_rejected, origin_tls_timeout,
- * origin_response_incomplete, proxy_unavailable, restricted_route_unavailable,
- * upstream_timeout, upstream_dns_failure, upstream_connect_failed. A header value
- * the browser image does not recognize is reported as unknown, with the header
- * value in raw_code.
+ * the proxy emits: destination_blocked, destination_route_unavailable,
+ * provider_blacklisted, provider_unreachable, provider_rejected,
+ * origin_tls_timeout, origin_response_incomplete, proxy_unavailable,
+ * restricted_route_unavailable, upstream_timeout, upstream_dns_failure,
+ * upstream_connect_failed. A header value the browser image does not recognize is
+ * reported as unknown, with the header value in raw_code.
*/
code:
| 'destination_blocked'
+ | 'destination_route_unavailable'
| 'provider_blacklisted'
| 'provider_unreachable'
| 'provider_rejected'
@@ -4830,9 +4864,7 @@ export interface TelemetryEventsParams extends OffsetPaginationParams {
* Read direction. asc (default) reads oldest first, starting from since or the
* offset cursor. desc reads newest first: each request returns one page of up to
* limit records ending at the offset cursor (or until, or the newest archived
- * event); combining desc with since is rejected with a 400. In either direction
- * the category filter applies within the page, so a filtered page may be empty
- * while X-Has-More is true.
+ * event); combining desc with since is rejected with a 400.
*/
order?: string;
@@ -4842,6 +4874,13 @@ export interface TelemetryEventsParams extends OffsetPaginationParams {
*/
since?: string;
+ /**
+ * Restrict results to these event types, such as page_crashed or
+ * captcha_challenge_result. Repeat the parameter for multiple values. Combines
+ * with category: when both are set an event must match both.
+ */
+ type?: Array;
+
/**
* End of the window (exclusive): an RFC-3339 timestamp, or a duration like 5m
* meaning that long ago.
diff --git a/src/resources/browsers/webmcp.ts b/src/resources/browsers/webmcp.ts
index b88f7655..851ddc76 100644
--- a/src/resources/browsers/webmcp.ts
+++ b/src/resources/browsers/webmcp.ts
@@ -1,206 +1,3 @@
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-import { APIResource } from '../../core/resource';
-import { APIPromise } from '../../core/api-promise';
-import { RequestOptions } from '../../internal/request-options';
-import { path } from '../../internal/utils/path';
-
-/**
- * Discover and invoke native page tools across the browser instance.
- */
-export class Webmcp extends APIResource {
- /**
- * Invokes the exact live registration identified by tool_ref. Non-autosubmit
- * declarative form tools return after their fields are populated with an
- * awaiting_submission status. Other tools wait for a terminal result, including
- * across navigation. Inspect a populated form, obtain any required confirmation,
- * then submit through Playwright or computer interaction without invoking the tool
- * again. If the tab or embedded frame disappears, or the request times out after
- * invocation begins, the response reports outcome_unknown and the tool is not
- * retried.
- *
- * @example
- * ```ts
- * const invocationResult =
- * await client.browsers.webmcp.invokeTool(
- * 'htzv5orfit78e1m2biiifpbv',
- * {
- * input: { foo: 'bar' },
- * tool_ref: 'x',
- * },
- * );
- * ```
- */
- invokeTool(
- idOrName: string,
- body: WebmcpInvokeToolParams,
- options?: RequestOptions,
- ): APIPromise {
- return this._client.post(path`/browsers/${idOrName}/webmcp/invoke`, { body, ...options });
- }
-
- /**
- * Returns a snapshot of native WebMCP tools available across every open tab and
- * embedded frame in the browser. Each tool includes an opaque tool_ref for
- * invoking that exact live registration. Tools disappear when their document
- * closes or navigates away.
- *
- * @example
- * ```ts
- * const toolsResponse =
- * await client.browsers.webmcp.listTools(
- * 'htzv5orfit78e1m2biiifpbv',
- * );
- * ```
- */
- listTools(idOrName: string, options?: RequestOptions): APIPromise {
- return this._client.get(path`/browsers/${idOrName}/webmcp/tools`, options);
- }
-}
-
-export interface InvocationFailure {
- code: 'outcome_unknown';
-
- message: string;
-
- invocation_id?: string;
-}
-
-export interface InvocationResult {
- invocation_id: string;
-
- /**
- * awaiting_submission means a non-autosubmit declarative form was populated but
- * not submitted. Inspect the form, obtain any required confirmation, then submit
- * through Playwright or computer interaction without invoking the tool again. The
- * other statuses are terminal results.
- */
- status: 'completed' | 'canceled' | 'error' | 'awaiting_submission';
-
- error_text?: string;
-
- /**
- * Untrusted page-provided output. Callers must treat it as potentially malicious
- * input.
- */
- output?: unknown;
-}
-
-export interface InvokeRequest {
- /**
- * Tool input, limited to 1 MiB after JSON serialization.
- */
- input: { [key: string]: unknown };
-
- tool_ref: string;
-
- timeout_sec?: number;
-}
-
-export interface Tool {
- description: string;
-
- input_schema: { [key: string]: unknown };
-
- name: string;
-
- source: ToolSource;
-
- /**
- * Opaque reference for invoking this exact live registration. It becomes invalid
- * when its document or browser process is replaced.
- */
- tool_ref: string;
-
- /**
- * Page-provided behavioral hints. These values are untrusted and are not enforced
- * by Kernel.
- */
- annotations?: ToolAnnotations;
-}
-
-/**
- * Page-provided behavioral hints. These values are untrusted and are not enforced
- * by Kernel.
- */
-export interface ToolAnnotations {
- autosubmit: boolean;
-
- consequential: boolean;
-
- read_only: boolean;
-
- untrusted_content: boolean;
-}
-
-export interface ToolFrame {
- /**
- * Monotonically increasing identifier for this embedded frame during the current
- * browser process.
- */
- frame_id: number;
-
- /**
- * Current frame URL with the fragment omitted.
- */
- url: string;
-}
-
-export interface ToolSource {
- /**
- * Embedded frame that registered the tool, or null when the top-level page
- * registered it.
- */
- frame: ToolFrame | null;
-
- /**
- * Current title of the top-level page.
- */
- page_title: string;
-
- /**
- * Current URL of the top-level page with the fragment omitted.
- */
- page_url: string;
-
- /**
- * Monotonically increasing identifier for the tab during the current browser
- * process.
- */
- tab_id: number;
-
- /**
- * Monotonically increasing identifier for the browser window during the current
- * browser process.
- */
- window_id: number;
-}
-
-export interface ToolsResponse {
- tools: Array;
-}
-
-export interface WebmcpInvokeToolParams {
- /**
- * Tool input, limited to 1 MiB after JSON serialization.
- */
- input: { [key: string]: unknown };
-
- tool_ref: string;
-
- timeout_sec?: number;
-}
-
-export declare namespace Webmcp {
- export {
- type InvocationFailure as InvocationFailure,
- type InvocationResult as InvocationResult,
- type InvokeRequest as InvokeRequest,
- type Tool as Tool,
- type ToolAnnotations as ToolAnnotations,
- type ToolFrame as ToolFrame,
- type ToolSource as ToolSource,
- type ToolsResponse as ToolsResponse,
- type WebmcpInvokeToolParams as WebmcpInvokeToolParams,
- };
-}
+export * from './webmcp/index';
diff --git a/src/resources/browsers/webmcp/custom-tools.ts b/src/resources/browsers/webmcp/custom-tools.ts
new file mode 100644
index 00000000..cd0f4f69
--- /dev/null
+++ b/src/resources/browsers/webmcp/custom-tools.ts
@@ -0,0 +1,160 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+import { APIResource } from '../../../core/resource';
+import * as WebmcpAPI from './webmcp';
+import { APIPromise } from '../../../core/api-promise';
+import { buildHeaders } from '../../../internal/headers';
+import { RequestOptions } from '../../../internal/request-options';
+import { path } from '../../../internal/utils/path';
+
+/**
+ * Discover and invoke native page tools across the browser instance.
+ */
+export class CustomTools extends APIResource {
+ /**
+ * Returns every registered custom tool with its generated ID, namespace, matcher,
+ * and MCP tool metadata.
+ *
+ * @example
+ * ```ts
+ * const customToolsResponse =
+ * await client.browsers.webmcp.customTools.list(
+ * 'id_or_name',
+ * );
+ * ```
+ */
+ list(idOrName: string, options?: RequestOptions): APIPromise {
+ return this._client.get(path`/browsers/${idOrName}/webmcp/custom-tools`, options);
+ }
+
+ /**
+ * Add a namespaced batch of custom tools. A custom tool can be page-backed or
+ * CDP-backed. Page-backed tools execute in the page via JavaScript. CDP-backed
+ * tools execute via CDP and can use all browser REPL tools (see `/repl`). The
+ * source must evaluate to a non-empty array of definitions with URL matchers, tool
+ * metadata (including an optional output schema), and execute functions. The batch
+ * is added atomically. Matchers apply to top-level documents and nested frames,
+ * including out-of-process iframes; each matching tool is exposed once on the
+ * tab's top-level document and appears in the WebMCP tool snapshot.
+ *
+ * To update one tool, list the tools, delete its ID, and add its replacement. Set
+ * force_overwrite_namespace to replace every existing tool in the namespace
+ * atomically; omitted or false adds tools without replacing existing ones.
+ * Existing invocations continue.
+ *
+ * @example
+ * ```ts
+ * const customToolsResponse =
+ * await client.browsers.webmcp.customTools.add(
+ * 'id_or_name',
+ * { namespace: 'namespace', source: 'source' },
+ * );
+ * ```
+ */
+ add(
+ idOrName: string,
+ body: CustomToolAddParams,
+ options?: RequestOptions,
+ ): APIPromise {
+ return this._client.post(path`/browsers/${idOrName}/webmcp/custom-tools`, { body, ...options });
+ }
+
+ /**
+ * Removes one custom tool by generated ID. An invocation already in progress is
+ * not canceled.
+ *
+ * @example
+ * ```ts
+ * await client.browsers.webmcp.customTools.remove(
+ * 'ct_n10b9798ad53ecc4y69z31e1',
+ * { id_or_name: 'id_or_name' },
+ * );
+ * ```
+ */
+ remove(id: string, params: CustomToolRemoveParams, options?: RequestOptions): APIPromise {
+ const { id_or_name } = params;
+ return this._client.delete(path`/browsers/${id_or_name}/webmcp/custom-tools/${id}`, {
+ ...options,
+ headers: buildHeaders([{ Accept: '*/*' }, options?.headers]),
+ });
+ }
+}
+
+export interface AddRequest {
+ namespace: string;
+
+ /**
+ * JavaScript expression that evaluates to a non-empty array of custom tool
+ * definitions. Limited to 8,000,000 bytes when UTF-8 encoded, so multi-byte
+ * characters reduce the allowed character count.
+ */
+ source: string;
+
+ /**
+ * Atomically replace all existing tools in this namespace with this batch when
+ * true.
+ */
+ force_overwrite_namespace?: boolean;
+}
+
+export interface CustomToolsResponse {
+ tools: Array;
+}
+
+export interface Definition {
+ id: string;
+
+ kind: string;
+
+ match: Match;
+
+ namespace: string;
+
+ /**
+ * Tool metadata follows the
+ * [MCP Tool definition](https://modelcontextprotocol.io/specification/2025-11-25/server/tools#tool)
+ * and the
+ * [WebMCP RegisteredTool definition](https://webmachinelearning.github.io/webmcp/#dictdef-registeredtool).
+ * outputSchema is optional for page and custom tools.
+ */
+ tool: WebmcpAPI.ToolMetadata;
+}
+
+export interface Match {
+ url_patterns: Array;
+}
+
+export interface CustomToolAddParams {
+ namespace: string;
+
+ /**
+ * JavaScript expression that evaluates to a non-empty array of custom tool
+ * definitions. Limited to 8,000,000 bytes when UTF-8 encoded, so multi-byte
+ * characters reduce the allowed character count.
+ */
+ source: string;
+
+ /**
+ * Atomically replace all existing tools in this namespace with this batch when
+ * true.
+ */
+ force_overwrite_namespace?: boolean;
+}
+
+export interface CustomToolRemoveParams {
+ /**
+ * Browser session ID or name
+ */
+ id_or_name: string;
+}
+
+export declare namespace CustomTools {
+ export {
+ type AddRequest as AddRequest,
+ type CustomToolsResponse as CustomToolsResponse,
+ type Definition as Definition,
+ type Match as Match,
+ type CustomToolAddParams as CustomToolAddParams,
+ type CustomToolRemoveParams as CustomToolRemoveParams,
+ };
+}
diff --git a/src/resources/browsers/webmcp/index.ts b/src/resources/browsers/webmcp/index.ts
new file mode 100644
index 00000000..31bd12f2
--- /dev/null
+++ b/src/resources/browsers/webmcp/index.ts
@@ -0,0 +1,26 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+export {
+ CustomTools,
+ type AddRequest,
+ type CustomToolsResponse,
+ type Definition,
+ type Match,
+ type CustomToolAddParams,
+ type CustomToolRemoveParams,
+} from './custom-tools';
+export {
+ Webmcp,
+ type CustomToolSource,
+ type InvocationFailure,
+ type InvocationResult,
+ type InvokeRequest,
+ type Tool,
+ type ToolAnnotations,
+ type ToolFrame,
+ type ToolMetadata,
+ type ToolSource,
+ type ToolsResponse,
+ type WebmcpInvokeToolParams,
+ type WebmcpListToolsParams,
+} from './webmcp';
diff --git a/src/resources/browsers/webmcp/webmcp.ts b/src/resources/browsers/webmcp/webmcp.ts
new file mode 100644
index 00000000..139f9124
--- /dev/null
+++ b/src/resources/browsers/webmcp/webmcp.ts
@@ -0,0 +1,295 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+import { APIResource } from '../../../core/resource';
+import * as CustomToolsAPI from './custom-tools';
+import {
+ AddRequest,
+ CustomToolAddParams,
+ CustomToolRemoveParams,
+ CustomTools,
+ CustomToolsResponse,
+ Definition,
+ Match,
+} from './custom-tools';
+import { APIPromise } from '../../../core/api-promise';
+import { RequestOptions } from '../../../internal/request-options';
+import { path } from '../../../internal/utils/path';
+
+/**
+ * Discover and invoke native page tools across the browser instance.
+ */
+export class Webmcp extends APIResource {
+ customTools: CustomToolsAPI.CustomTools = new CustomToolsAPI.CustomTools(this._client);
+
+ /**
+ * Invokes the exact live registration identified by tool_ref. Non-autosubmit
+ * declarative form tools return after their fields are populated with an
+ * awaiting_submission status. Other tools wait for a terminal result, including
+ * across navigation. Inspect a populated form, obtain any required confirmation,
+ * then submit through Playwright or computer interaction without invoking the tool
+ * again. If the tab or embedded frame disappears, or the request times out after
+ * invocation begins, the response reports outcome_unknown and the tool is not
+ * retried. CDP-backed custom tool outputs above 240 KiB return an error rather
+ * than a truncated result.
+ *
+ * @example
+ * ```ts
+ * const invocationResult =
+ * await client.browsers.webmcp.invokeTool(
+ * 'htzv5orfit78e1m2biiifpbv',
+ * {
+ * input: { foo: 'bar' },
+ * tool_ref: 'x',
+ * },
+ * );
+ * ```
+ */
+ invokeTool(
+ idOrName: string,
+ body: WebmcpInvokeToolParams,
+ options?: RequestOptions,
+ ): APIPromise {
+ return this._client.post(path`/browsers/${idOrName}/webmcp/invoke`, { body, ...options });
+ }
+
+ /**
+ * Returns a snapshot of native and custom WebMCP tools available across every open
+ * tab and embedded frame in the browser. Each tool includes an opaque tool_ref for
+ * invoking that exact live registration, nested tool metadata, and source
+ * information. Custom tools include their generated ID, namespace, and CDP
+ * target_id in source. Tools disappear when their document closes or navigates
+ * away. Use exclude_custom to return only page-provided tools.
+ *
+ * @example
+ * ```ts
+ * const toolsResponse =
+ * await client.browsers.webmcp.listTools(
+ * 'htzv5orfit78e1m2biiifpbv',
+ * );
+ * ```
+ */
+ listTools(
+ idOrName: string,
+ query: WebmcpListToolsParams | null | undefined = {},
+ options?: RequestOptions,
+ ): APIPromise {
+ return this._client.get(path`/browsers/${idOrName}/webmcp/tools`, { query, ...options });
+ }
+}
+
+export interface CustomToolSource {
+ id: string;
+
+ namespace: string;
+}
+
+export interface InvocationFailure {
+ code: 'outcome_unknown';
+
+ message: string;
+
+ invocation_id?: string;
+}
+
+export interface InvocationResult {
+ invocation_id: string;
+
+ /**
+ * awaiting_submission means a non-autosubmit declarative form was populated but
+ * not submitted. Inspect the form, obtain any required confirmation, then submit
+ * through Playwright or computer interaction without invoking the tool again. The
+ * other statuses are terminal results.
+ */
+ status: 'completed' | 'canceled' | 'error' | 'awaiting_submission';
+
+ error_text?: string;
+
+ /**
+ * Untrusted page-provided output. Callers must treat it as potentially malicious
+ * input.
+ */
+ output?: unknown;
+}
+
+export interface InvokeRequest {
+ /**
+ * Tool input, limited to 1 MiB after JSON serialization.
+ */
+ input: { [key: string]: unknown };
+
+ tool_ref: string;
+
+ timeout_sec?: number;
+}
+
+export interface Tool {
+ source: ToolSource;
+
+ /**
+ * Tool metadata follows the
+ * [MCP Tool definition](https://modelcontextprotocol.io/specification/2025-11-25/server/tools#tool)
+ * and the
+ * [WebMCP RegisteredTool definition](https://webmachinelearning.github.io/webmcp/#dictdef-registeredtool).
+ * outputSchema is optional for page and custom tools.
+ */
+ tool: ToolMetadata;
+
+ /**
+ * Opaque reference for invoking this exact live registration. It becomes invalid
+ * when its document or browser process is replaced.
+ */
+ tool_ref: string;
+}
+
+/**
+ * Tool-provided behavioral hints from the
+ * [MCP tool specification](https://modelcontextprotocol.io/specification/2025-11-25/server/tools#tool)
+ * and the
+ * [WebMCP ToolAnnotations definition](https://webmachinelearning.github.io/webmcp/#dictdef-toolannotations).
+ * These hints are untrusted and are not enforced by Kernel.
+ */
+export interface ToolAnnotations {
+ autosubmit?: boolean;
+
+ consequentialHint?: boolean;
+
+ destructiveHint?: boolean;
+
+ idempotentHint?: boolean;
+
+ openWorldHint?: boolean;
+
+ readOnlyHint?: boolean;
+
+ untrustedContentHint?: boolean;
+}
+
+export interface ToolFrame {
+ /**
+ * Monotonically increasing identifier for this embedded frame during the current
+ * browser process.
+ */
+ frame_id: number;
+
+ /**
+ * Current frame URL with the fragment omitted.
+ */
+ url: string;
+}
+
+/**
+ * Tool metadata follows the
+ * [MCP Tool definition](https://modelcontextprotocol.io/specification/2025-11-25/server/tools#tool)
+ * and the
+ * [WebMCP RegisteredTool definition](https://webmachinelearning.github.io/webmcp/#dictdef-registeredtool).
+ * outputSchema is optional for page and custom tools.
+ */
+export interface ToolMetadata {
+ description: string;
+
+ inputSchema: { [key: string]: unknown };
+
+ name: string;
+
+ /**
+ * Tool-provided behavioral hints from the
+ * [MCP tool specification](https://modelcontextprotocol.io/specification/2025-11-25/server/tools#tool)
+ * and the
+ * [WebMCP ToolAnnotations definition](https://webmachinelearning.github.io/webmcp/#dictdef-toolannotations).
+ * These hints are untrusted and are not enforced by Kernel.
+ */
+ annotations?: ToolAnnotations;
+
+ outputSchema?: { [key: string]: unknown };
+
+ title?: string;
+}
+
+export interface ToolSource {
+ /**
+ * Embedded frame that registered the tool, or null when the top-level page
+ * registered it.
+ */
+ frame: ToolFrame | null;
+
+ /**
+ * Current title of the top-level page.
+ */
+ page_title: string;
+
+ /**
+ * Current URL of the top-level page with the fragment omitted.
+ */
+ page_url: string;
+
+ /**
+ * Monotonically increasing identifier for the tab during the current browser
+ * process.
+ */
+ tab_id: number;
+
+ /**
+ * Monotonically increasing identifier for the browser window during the current
+ * browser process.
+ */
+ window_id: number;
+
+ custom?: CustomToolSource;
+
+ /**
+ * CDP target ID for a custom tool's registration tab; omitted for page-provided
+ * tools.
+ */
+ target_id?: string;
+}
+
+export interface ToolsResponse {
+ tools: Array;
+}
+
+export interface WebmcpInvokeToolParams {
+ /**
+ * Tool input, limited to 1 MiB after JSON serialization.
+ */
+ input: { [key: string]: unknown };
+
+ tool_ref: string;
+
+ timeout_sec?: number;
+}
+
+export interface WebmcpListToolsParams {
+ /**
+ * Exclude custom tools when true.
+ */
+ exclude_custom?: boolean;
+}
+
+Webmcp.CustomTools = CustomTools;
+
+export declare namespace Webmcp {
+ export {
+ type CustomToolSource as CustomToolSource,
+ type InvocationFailure as InvocationFailure,
+ type InvocationResult as InvocationResult,
+ type InvokeRequest as InvokeRequest,
+ type Tool as Tool,
+ type ToolAnnotations as ToolAnnotations,
+ type ToolFrame as ToolFrame,
+ type ToolMetadata as ToolMetadata,
+ type ToolSource as ToolSource,
+ type ToolsResponse as ToolsResponse,
+ type WebmcpInvokeToolParams as WebmcpInvokeToolParams,
+ type WebmcpListToolsParams as WebmcpListToolsParams,
+ };
+
+ export {
+ CustomTools as CustomTools,
+ type AddRequest as AddRequest,
+ type CustomToolsResponse as CustomToolsResponse,
+ type Definition as Definition,
+ type Match as Match,
+ type CustomToolAddParams as CustomToolAddParams,
+ type CustomToolRemoveParams as CustomToolRemoveParams,
+ };
+}
diff --git a/src/resources/organization/entitlements.ts b/src/resources/organization/entitlements.ts
index 3c29cf59..ee0ad2c8 100644
--- a/src/resources/organization/entitlements.ts
+++ b/src/resources/organization/entitlements.ts
@@ -58,6 +58,12 @@ export namespace OrgEntitlements {
proxy_bypass_hosts: Features.ProxyBypassHosts;
+ /**
+ * Whether the Search API is enabled for the organization by its rollout feature
+ * flag.
+ */
+ search: Features.Search;
+
/**
* Whether the organization can access vaults, using the same access check as vault
* API routes.
@@ -183,6 +189,17 @@ export namespace OrgEntitlements {
enabled: boolean;
}
+ /**
+ * Whether the Search API is enabled for the organization by its rollout feature
+ * flag.
+ */
+ export interface Search {
+ /**
+ * Whether the organization is entitled to use this feature.
+ */
+ enabled: boolean;
+ }
+
/**
* Whether the organization can access vaults, using the same access check as vault
* API routes.
diff --git a/src/version.ts b/src/version.ts
index 36c76795..142b029c 100644
--- a/src/version.ts
+++ b/src/version.ts
@@ -1 +1 @@
-export const VERSION = '0.111.0'; // x-release-please-version
+export const VERSION = '0.112.0'; // x-release-please-version
diff --git a/tests/api-resources/browser-pools.test.ts b/tests/api-resources/browser-pools.test.ts
index 1b27e325..15dbfc24 100644
--- a/tests/api-resources/browser-pools.test.ts
+++ b/tests/api-resources/browser-pools.test.ts
@@ -30,7 +30,15 @@ describe('resource browserPools', () => {
headless: false,
kiosk_mode: true,
name: 'my-pool',
- network: { private_hosts: ['*.example.ts.net', '100.64.0.0/10'] },
+ network: {
+ private_hosts: ['*.example.ts.net', '100.64.0.0/10'],
+ proxy_routes: [
+ {
+ hosts: ['string'],
+ proxy: { id: 'x', name: 'x' },
+ },
+ ],
+ },
profile: { id: 'id', name: 'name' },
proxy_id: 'proxy_id',
refresh_on_profile_update: true,
diff --git a/tests/api-resources/browsers/browsers.test.ts b/tests/api-resources/browsers/browsers.test.ts
index e126aaff..bc364170 100644
--- a/tests/api-resources/browsers/browsers.test.ts
+++ b/tests/api-resources/browsers/browsers.test.ts
@@ -34,7 +34,15 @@ describe('resource browsers', () => {
kiosk_mode: true,
memory: '8GiB',
name: 'checkout-flow-1',
- network: { private_hosts: ['*.example.ts.net', '100.64.0.0/10'] },
+ network: {
+ private_hosts: ['*.example.ts.net', '100.64.0.0/10'],
+ proxy_routes: [
+ {
+ hosts: ['string'],
+ proxy: { id: 'x', name: 'x' },
+ },
+ ],
+ },
profile: {
id: 'id',
name: 'name',
diff --git a/tests/api-resources/browsers/telemetry.test.ts b/tests/api-resources/browsers/telemetry.test.ts
index 797d2539..1485ed1b 100644
--- a/tests/api-resources/browsers/telemetry.test.ts
+++ b/tests/api-resources/browsers/telemetry.test.ts
@@ -32,6 +32,7 @@ describe('resource telemetry', () => {
offset: 0,
order: 'order',
since: 'since',
+ type: ['string'],
until: 'until',
},
{ path: '/_stainless_unknown_path' },
diff --git a/tests/api-resources/browsers/webmcp/custom-tools.test.ts b/tests/api-resources/browsers/webmcp/custom-tools.test.ts
new file mode 100644
index 00000000..339c97eb
--- /dev/null
+++ b/tests/api-resources/browsers/webmcp/custom-tools.test.ts
@@ -0,0 +1,67 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+import Kernel from '@onkernel/sdk';
+
+const client = new Kernel({
+ apiKey: 'My API Key',
+ baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010',
+});
+
+describe('resource customTools', () => {
+ // Mock server tests are disabled
+ test.skip('list', async () => {
+ const responsePromise = client.browsers.webmcp.customTools.list('id_or_name');
+ const rawResponse = await responsePromise.asResponse();
+ expect(rawResponse).toBeInstanceOf(Response);
+ const response = await responsePromise;
+ expect(response).not.toBeInstanceOf(Response);
+ const dataAndResponse = await responsePromise.withResponse();
+ expect(dataAndResponse.data).toBe(response);
+ expect(dataAndResponse.response).toBe(rawResponse);
+ });
+
+ // Mock server tests are disabled
+ test.skip('add: only required params', async () => {
+ const responsePromise = client.browsers.webmcp.customTools.add('id_or_name', {
+ namespace: 'namespace',
+ source: 'source',
+ });
+ const rawResponse = await responsePromise.asResponse();
+ expect(rawResponse).toBeInstanceOf(Response);
+ const response = await responsePromise;
+ expect(response).not.toBeInstanceOf(Response);
+ const dataAndResponse = await responsePromise.withResponse();
+ expect(dataAndResponse.data).toBe(response);
+ expect(dataAndResponse.response).toBe(rawResponse);
+ });
+
+ // Mock server tests are disabled
+ test.skip('add: required and optional params', async () => {
+ const response = await client.browsers.webmcp.customTools.add('id_or_name', {
+ namespace: 'namespace',
+ source: 'source',
+ force_overwrite_namespace: true,
+ });
+ });
+
+ // Mock server tests are disabled
+ test.skip('remove: only required params', async () => {
+ const responsePromise = client.browsers.webmcp.customTools.remove('ct_n10b9798ad53ecc4y69z31e1', {
+ id_or_name: 'id_or_name',
+ });
+ const rawResponse = await responsePromise.asResponse();
+ expect(rawResponse).toBeInstanceOf(Response);
+ const response = await responsePromise;
+ expect(response).not.toBeInstanceOf(Response);
+ const dataAndResponse = await responsePromise.withResponse();
+ expect(dataAndResponse.data).toBe(response);
+ expect(dataAndResponse.response).toBe(rawResponse);
+ });
+
+ // Mock server tests are disabled
+ test.skip('remove: required and optional params', async () => {
+ const response = await client.browsers.webmcp.customTools.remove('ct_n10b9798ad53ecc4y69z31e1', {
+ id_or_name: 'id_or_name',
+ });
+ });
+});
diff --git a/tests/api-resources/browsers/webmcp.test.ts b/tests/api-resources/browsers/webmcp/webmcp.test.ts
similarity index 78%
rename from tests/api-resources/browsers/webmcp.test.ts
rename to tests/api-resources/browsers/webmcp/webmcp.test.ts
index 7bfb8db4..0d1c4d21 100644
--- a/tests/api-resources/browsers/webmcp.test.ts
+++ b/tests/api-resources/browsers/webmcp/webmcp.test.ts
@@ -43,4 +43,16 @@ describe('resource webmcp', () => {
expect(dataAndResponse.data).toBe(response);
expect(dataAndResponse.response).toBe(rawResponse);
});
+
+ // Mock server tests are disabled
+ test.skip('listTools: request options and params are passed correctly', async () => {
+ // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error
+ await expect(
+ client.browsers.webmcp.listTools(
+ 'htzv5orfit78e1m2biiifpbv',
+ { exclude_custom: true },
+ { path: '/_stainless_unknown_path' },
+ ),
+ ).rejects.toThrow(Kernel.NotFoundError);
+ });
});