Skip to main content

Build browser agents with tools and UI

Agent SDK is a browser-first JavaScript and TypeScript SDK for connecting an LLM, application tools, MCP servers, skills, structured responses, and a chat interface. It uses one lifecycle:

WebMCP compatibility on every supported browser

When a browser provides native document.modelContext, Agent SDK connects native Tools with its Runtime Tool registry. When native WebMCP is unavailable, runtime.attachModelContext() installs a compatible fallback at document.modelContext. Application code can therefore register, discover, and execute Tools through one integration path instead of maintaining separate WebMCP and non-WebMCP implementations.

Agent SDK is not merely a general-purpose WebMCP polyfill. It uses the WebMCP ModelContext and Tool contracts as a compatibility boundary, then provides a broader Agent application framework around them.

WebMCP-compatible foundationAdditional Agent SDK capabilities
Native document.modelContext integrationProvider-independent Runtime, Agent, Session, and Turn lifecycle
Fallback ModelContext when native WebMCP is unavailableDirect Mode and credential-protecting Relay Mode
Tool registration, discovery, and direct executionTool approval, Tool calling loops, ToolGroup, and remote MCP servers
A shared Tool implementation for SDK and browser AgentsSkills, structured output, attachments, Transcript, and Session events
Native and Runtime Tool discovery from one surfaceAgent Chat UI, custom interactions, iframe/popup bridge, and Remote Session
Runtime → Agent → Session → Turn

Use it when an application needs more than a single model request—for example, a support assistant that calls product APIs, an editor assistant that invokes document tools, or an agent whose chat UI and tool providers live in different iframes.

One Tool works with and without native WebMCP

Call attachModelContext() regardless of browser support. The SDK selects the native or fallback path and exposes the selected mode through runtime.getModelContextMode().

const modelContext = runtime.attachModelContext();

modelContext.registerTool({
name: 'get_workspace_status',
title: 'Get workspace status',
description: 'Returns the readiness state of the current workspace.',
inputSchema: {type: 'object', additionalProperties: false, properties: {}},
annotations: {readOnlyHint: true},
execute: () => ({ready: true}),
});

console.log(runtime.getModelContextMode()); // "native" or "fallback"

const tools = await document.modelContext.getTools();
const status = await document.modelContext.executeTool('get_workspace_status', {});

The same registered Tool can be invoked by an SDK Agent through session.send(...) or discovered by a browser Agent through document.modelContext. The fallback covers the Runtime-managed ModelContext Tool surface; it does not attempt to reproduce browser-owned permission UI, navigation behavior, or arbitrary cross-origin Tool discovery.

Compatibility with the current WebMCP draft

This comparison uses the WebMCP Draft Community Group Report dated 21 July 2026. WebMCP remains a Community Group draft, not a W3C Standard, so applications should pin the SDK version and review this table when the draft changes.

Legend: O = compatible, △ = usable with a documented difference or only on the native path, X = not implemented by the SDK fallback.

Current WebMCP surfaceNative WebMCP pathSDK fallback pathOverallCompatibility note
document.modelContextOOOattachModelContext() uses native support or installs the fallback at the same property.
ModelContext as EventTargetOXThe fallback is a plain compatibility object, not an EventTarget.
registerTool(tool) basic registrationOOOName, title, description, schema, annotations, and executor are retained.
registerTool() returns Promise<undefined>XXXThe SDK wrapper currently returns synchronously. Do not depend on await registerTool() matching the draft lifecycle.
Tool name grammar and 128-character limitOOOASCII letters, digits, _, -, and . are accepted; invalid names are rejected.
Draft DOMException type and asynchronous rejection timingInvalid definitions fail, but SDK error class and timing are not guaranteed to match Web IDL exactly.
ModelContextRegisterToolOptions.signalXXXThe SDK uses an internal AbortSignal when mirroring into native WebMCP, but does not accept the caller's registration signal.
ModelContextRegisterToolOptions.exposedToXXXCross-origin exposure policy is not implemented by the SDK registration wrapper.
getTools() local discoveryOOOSDK Runtime Tools are returned alphabetically with stringified inputSchema, window, and origin.
getTools({fromOrigins}) descendant/cross-origin discoveryOXOptions are delegated to a native implementation. Fallback discovery remains inside the attached Runtime.
RegisteredTool fieldsOOOname, title, description, stringified inputSchema, window, origin, and annotations are exposed.
readOnlyHintOOOPreserved through registration and discovery.
untrustedContentHintOOOPreserved through registration and discovery.
toolchange / ontoolchangeOXNative browser events remain available; the fallback does not dispatch the draft event.
Secure Context and fully-active Document enforcementOXNative enforcement belongs to the browser. The fallback does not reproduce the Web IDL security gate.
Permissions Policy tools with default 'self'OXNative enforcement belongs to the browser. Use Tool Provider/bridge allowlists for SDK-managed frames.
Declarative WebMCPThe current draft section is still TODO; there is no stable normative surface to claim compatibility with.

What the SDK intentionally adds beyond WebMCP

These capabilities are Agent SDK extensions. They are not claims of WebMCP standard compatibility.

Agent SDK extensionWebMCP draftAgent SDK
Execute a discovered Tool from page JavaScript with executeTool()XO
Accept a Tool name or discovered Tool object for direct executionXO
Accept JSON string or JavaScript object Tool inputXO
Runtime → Agent → Session → Turn lifecycleXO
Provider adapters and multi-step Tool calling loopXO
Per-Turn allowlist and Tool approvalXO
ToolGroup and remote MCP server discoveryXO
Skills and structured model outputXO
Transcript, attachments, Property Bag, snapshot/fork/mergeXO
Agent Chat UI and structured user interactionsXO
iframe/popup Tool Provider and Remote Session bridgeXO
Direct Mode and Backend Relay ModeXO

executeTool() is documented by the Chrome WebMCP Imperative API, but it is not present in the 21 July 2026 Community Group Draft ModelContext IDL. Treat it as a useful browser/SDK extension until the draft adopts or replaces it.

Choose the correct execution path

document.modelContext.executeTool(...) directly runs a Tool. It does not create a Session Turn and does not apply allowedToolNames, Tool approval, provider orchestration, or Transcript recording. Use session.send(...) when those Agent policies and records are required.

What you receive

Entry pointUse it for
tf-agent-sdk/runtimeHeadless Runtime, Agent, Session, Tool, Provider, MCP, Skill, and bridge APIs
tf-agent-sdk/uiThe standard Agent Chat UI
sdk/tf-agent-runtime.jsBrowser global without a module bundler
sdk/tf-agent-chat-ui.jsBrowser global including the chat UI

The package is currently distributed through a private GitHub Release Bundle rather than a public npm registry. Obtain an approved release bundle, unpack it under vendor/tf-agent-sdk, and add it as a local dependency:

{
"dependencies": {
"tf-agent-sdk": "file:./vendor/tf-agent-sdk"
}
}

Then run your package manager's normal install command.

Five-minute example

import {
AiProviderKeys,
ConnectionModes,
LlmModelNames,
createRuntime,
} from 'tf-agent-sdk/runtime';

const runtime = createRuntime({appName: 'Order workspace'});

const agent = runtime.createAgent({
agentId: 'order-assistant',
systemPrompt: 'Help the user check an order. Never invent an order state.',
aiProviderConfig: {
connectionMode: ConnectionModes.DIRECT,
aiProvider: AiProviderKeys.GOOGLE,
model: LlmModelNames.GEMINI_3_5_FLASH,
auth: {kind: 'apiKey', apiKey: import.meta.env.VITE_GEMINI_API_KEY},
},
});

const modelContext = runtime.attachModelContext();
modelContext.registerTool({
name: 'get_order',
title: 'Get order',
description: 'Returns the current state of one order.',
inputSchema: {
type: 'object',
additionalProperties: false,
required: ['orderId'],
properties: {orderId: {type: 'string'}},
},
annotations: {readOnlyHint: true},
async execute({orderId}) {
const response = await fetch(`/api/orders/${encodeURIComponent(orderId)}`);
if (!response.ok) throw new Error(`Order lookup failed: ${response.status}`);
return response.json();
},
});

const session = agent.createSession({sessionId: crypto.randomUUID()});
const result = await session.send('Check order A-1042 and explain its status.');
console.log(result.text);

The important order is createRuntime()runtime.createAgent()agent.createSession()session.send(). A Runtime does not create Sessions directly.

Direct Mode and Relay Mode

Direct Mode is convenient for a personal development environment, but its provider credential is visible to browser developer tools. Do not ship a shared application with a secret embedded in JavaScript.

Use Relay Mode in production. The browser sends the model request to your Backend, and the Backend attaches the provider credential. Apply authentication, per-user quotas, timeouts, request-size limits, and audit logging at that boundary.

Tool design checklist

  • Give every Tool one narrow responsibility and an explicit JSON Schema.
  • Set additionalProperties: false unless unknown inputs are intentional.
  • Mark read-only Tools and require approval for destructive Tools.
  • Return structured data; let the Agent turn it into prose.
  • Treat Tool input as untrusted and enforce authorization inside the Tool implementation.
  • Keep Tool errors actionable without exposing credentials or internal stack traces.

Choosing the next feature

Use Local Tools for functions owned by the current page. Use an MCP server when Tool discovery and execution belong to a remote service. Use a Skill for instructions and Tools that should become available only for relevant Turns. Use bridge and Remote Session APIs when Runtime, UI, or Tool providers must run in separate windows or frames.

Troubleshooting

SymptomCheck
The model answers without calling a ToolMake the Tool description specific and ensure it is registered before send()
Provider request is rejectedCheck provider, model, connection mode, credential, and relay response shape together
A Session loses contextReuse the same Session instead of creating one per message
Browser CORS errorUse Relay Mode or explicitly allow the application origin at the target service
A Tool can access another user's dataEnforce identity and resource authorization in the Tool or Backend, not in the prompt

The source project contains a catalog of 29 focused examples covering Tools, UI placement, bridge configurations, interactions, attachments, and structured output. These examples will be exposed through the Open the Agent SDK Playground to edit and run the examples with the connected browser artifact.