Create a new AppBridge instance.
MCP client connected to the server (for proxying requests)
Host application identification (name and version)
Features and capabilities the host supports
Optionaloptions: ProtocolOptionsConfiguration options (inherited from Protocol)
OptionalfallbackA handler to invoke for any notification types that do not have their own handler installed.
OptionalfallbackA handler to invoke for any request types that do not have their own handler installed.
OptionaloncloseCallback for when the connection is closed for any reason.
This is invoked when close() is called as well.
OptionalonerrorCallback for when an error occurs.
Note that errors are not necessarily fatal; they are used for reporting any kind of exceptional condition out of band.
OptionalonpingOptional handler for ping requests from the Guest UI.
The Guest UI can send standard MCP ping requests to verify the connection
is alive. The AppBridge automatically responds with an empty object, but this
handler allows the host to observe or log ping activity.
Unlike the other handlers which use setters, this is a direct property assignment. It is optional; if not set, pings are still handled automatically.
Empty params object from the ping request
Optional_meta?: { progressToken?: string | number; [key: string]: unknown }See General fields: _meta for notes on _meta usage.
OptionalprogressToken?: string | numberIf specified, the caller is requesting out-of-band progress notifications for this request (as represented by notifications/progress). The value of this parameter is an opaque token that will be attached to any subsequent notifications. The receiver is not obligated to provide these notifications.
Request metadata (abort signal, session info)
Called when the Guest UI completes initialization.
Set this callback to be notified when the Guest UI has finished its initialization handshake and is ready to receive tool input and other data.
bridge.oninitialized = () => {
console.log("Guest UI ready");
bridge.sendToolInput({ arguments: toolArgs });
};
Register a handler for logging messages from the Guest UI.
The Guest UI sends standard MCP notifications/message (logging) notifications
to report debugging information, errors, warnings, and other telemetry to the
host. The host can display these in a console, log them to a file, or send
them to a monitoring service.
This uses the standard MCP logging notification format, not a UI-specific message type.
Handler that receives logging params
Register a handler for message requests from the Guest UI.
The Guest UI sends ui/message requests when it wants to add a message to
the host's chat interface. This enables interactive apps to communicate with
the user through the conversation thread.
The handler should process the message (add it to the chat) and return a result indicating success or failure. For security, the host should NOT return conversation content or follow-up results to prevent information leakage.
Handler that receives message params and returns a result
bridge.onmessage = async ({ role, content }, extra) => {
try {
await chatManager.addMessage({ role, content, source: "app" });
return {}; // Success
} catch (error) {
console.error("Failed to add message:", error);
return { isError: true };
}
};
Register a handler for external link requests from the Guest UI.
The Guest UI sends ui/open-link requests when it wants to open an external
URL in the host's default browser. The handler should validate the URL and
open it according to the host's security policy and user preferences.
The host MAY:
Handler that receives URL params and returns a result
bridge.onopenlink = async ({ url }, extra) => {
if (!isAllowedDomain(url)) {
console.warn("Blocked external link:", url);
return { isError: true };
}
const confirmed = await showDialog({
message: `Open external link?\n${url}`,
buttons: ["Open", "Cancel"]
});
if (confirmed) {
window.open(url, "_blank", "noopener,noreferrer");
return {};
}
return { isError: true };
};
InternalRegister a handler for sandbox proxy ready notifications.
This is an internal callback used by web-based hosts implementing the
double-iframe sandbox architecture. The sandbox proxy sends
ui/notifications/sandbox-proxy-ready after it loads and is ready to receive
HTML content.
When this fires, the host should call sendSandboxResourceReady with the HTML content to load into the inner sandboxed iframe.
bridge.onsandboxready = async () => {
const resource = await mcpClient.request(
{ method: "resources/read", params: { uri: "ui://my-app" } },
ReadResourceResultSchema
);
bridge.sendSandboxResourceReady({
html: resource.contents[0].text,
sandbox: "allow-scripts"
});
};
Register a handler for size change notifications from the Guest UI.
The Guest UI sends ui/notifications/size-change when its rendered content
size changes, typically via ResizeObserver. Set this callback to dynamically
adjust the iframe container dimensions based on the Guest UI's content.
Note: This is for Guest UI → Host communication. To notify the Guest UI of host viewport changes, use app.App.sendSizeChange.
bridge.onsizechange = ({ width, height }) => {
if (width != null) {
iframe.style.width = `${width}px`;
}
if (height != null) {
iframe.style.height = `${height}px`;
}
};
Asserts that a request handler has not already been set for the given method, in preparation for a new one being automatically installed.
InternalVerify that the guest supports the capability required for the given request method.
InternalVerify that the host supports the capability required for the given notification method.
InternalVerify that a request handler is registered and supported for the given method.
Closes the connection.
Connect to the Guest UI via transport and set up message forwarding.
This method establishes the transport connection and automatically sets up request/notification forwarding based on the MCP server's capabilities. It proxies the following server capabilities to the Guest UI:
After calling connect, wait for the oninitialized callback before sending
tool input and other data to the Guest UI.
Transport layer (typically PostMessageTransport)
Promise resolving when connection is established
If server capabilities are not available. This occurs when
connect() is called before the MCP client has completed its initialization
with the server. Ensure await client.connect() completes before calling
bridge.connect().
const bridge = new AppBridge(mcpClient, hostInfo, capabilities);
const transport = new PostMessageTransport(
iframe.contentWindow!,
iframe.contentWindow!,
);
bridge.oninitialized = () => {
console.log("Guest UI ready");
bridge.sendToolInput({ arguments: toolArgs });
};
await bridge.connect(transport);
Get the Guest UI's capabilities discovered during initialization.
Returns the capabilities that the Guest UI advertised during its
initialization request. Returns undefined if called before
initialization completes.
Guest UI capabilities, or undefined if not yet initialized
bridge.oninitialized = () => {
const caps = bridge.getAppCapabilities();
if (caps?.tools) {
console.log("Guest UI provides tools");
}
};
McpUiAppCapabilities for the capabilities structure
Get the Guest UI's implementation info discovered during initialization.
Returns the Guest UI's name and version as provided in its initialization
request. Returns undefined if called before initialization completes.
Guest UI implementation info, or undefined if not yet initialized
Get the host capabilities passed to the constructor.
Host capabilities object
McpUiHostCapabilities for the capabilities structure
Emits a notification, which is a one-way message that does not expect a response.
Optionaloptions: NotificationOptionsRemoves the notification handler for the given method.
Removes the request handler for the given method.
Sends a request and wait for a response.
Do not use this method to emit notifications! Use notification() instead.
Optionaloptions: RequestOptionsRequest graceful shutdown of the Guest UI.
The host MUST send this request before tearing down the UI resource (before unmounting the iframe). This gives the Guest UI an opportunity to save state, cancel pending operations, or show confirmation dialogs.
The host SHOULD wait for the response before unmounting to prevent data loss.
Empty params object
Optionaloptions: RequestOptionsRequest options (timeout, etc.)
Promise resolving when Guest UI confirms readiness for teardown
InternalSend HTML resource to the sandbox proxy for secure loading.
This is an internal method used by web-based hosts implementing the
double-iframe sandbox architecture. After the sandbox proxy signals readiness
via ui/notifications/sandbox-proxy-ready, the host sends this notification
with the HTML content to load.
HTML content and sandbox configuration:
html: The HTML content to load into the sandboxed iframesandbox: Optional sandbox attribute value (e.g., "allow-scripts")HTML content to load into the inner iframe
Optionalsandbox?: stringOptional override for the inner iframe's sandbox attribute
onsandboxready for handling the sandbox proxy ready notification
Send complete tool arguments to the Guest UI.
The host MUST send this notification after the Guest UI completes initialization (after oninitialized callback fires) and complete tool arguments become available. This notification is sent exactly once and is required before sendToolResult.
Complete tool call arguments
Optionalarguments?: Record<string, unknown>Complete tool call arguments as key-value pairs
bridge.oninitialized = () => {
bridge.sendToolInput({
arguments: { location: "New York", units: "metric" }
});
};
Send tool execution result to the Guest UI.
The host MUST send this notification when tool execution completes successfully, provided the UI is still displayed. If the UI was closed before execution completes, the host MAY skip this notification. This must be sent after sendToolInput.
Standard MCP tool execution result
import { CallToolResultSchema } from '@modelcontextprotocol/sdk/types.js';
const result = await mcpClient.request(
{ method: "tools/call", params: { name: "get_weather", arguments: args } },
CallToolResultSchema
);
bridge.sendToolResult(result);
Registers a handler to invoke when this protocol object receives a notification with the given method.
Note that this will replace any previous notification handler for the same method.
Registers a handler to invoke when this protocol object receives a request with the given method.
Note that this will replace any previous request handler for the same method.
Host-side bridge for communicating with a single Guest UI (App).
AppBridge extends the MCP SDK's Protocol class and acts as a proxy between the host application and a Guest UI running in an iframe. It automatically forwards MCP server capabilities (tools, resources, prompts) to the Guest UI and handles the initialization handshake.
Architecture
Guest UI ↔ AppBridge ↔ Host ↔ MCP Server
The bridge proxies requests from the Guest UI to the MCP server and forwards responses back. It also sends host-initiated notifications like tool input and results to the Guest UI.
Lifecycle
connect()with transport to establish communicationsendToolInput(),sendToolResult(), etc.sendResourceTeardown()before unmounting iframeExample: Basic usage