Create a new MCP App instance.
App identification (name and version)
Features and capabilities this app provides
Configuration options including autoResize behavior
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.
Convenience handler for tool call requests from the host.
Set this property to register a handler that will be called when the host requests this app to execute a tool. This enables apps to provide their own tools that can be called by the host or LLM.
The app must declare tool capabilities in the constructor to use this handler.
This setter is a convenience wrapper around setRequestHandler() that
automatically handles the request schema and extracts the params for you.
Register handlers before calling connect to avoid missing requests.
Async function that executes the tool and returns the result. The callback will only be invoked if the app declared tool capabilities in the constructor.
app.oncalltool = async (params, extra) => {
if (params.name === "greet") {
const name = params.arguments?.name ?? "World";
return { content: [{ type: "text", text: `Hello, ${name}!` }] };
}
throw new Error(`Unknown tool: ${params.name}`);
};
setRequestHandler for the underlying method
Convenience handler for host context changes (theme, viewport, locale, etc.).
Set this property to register a handler that will be called when the host's context changes, such as theme switching (light/dark), viewport size changes, locale changes, or other environmental updates. Apps should respond by updating their UI accordingly.
This setter is a convenience wrapper around setNotificationHandler() that
automatically handles the notification schema and extracts the params for you.
Register handlers before calling connect to avoid missing notifications.
Function called with the updated host context
app.onhostcontextchanged = (params) => {
if (params.theme === "dark") {
document.body.classList.add("dark-theme");
} else {
document.body.classList.remove("dark-theme");
}
};
Convenience handler for listing available tools.
Set this property to register a handler that will be called when the host requests a list of tools this app provides. This enables dynamic tool discovery by the host or LLM.
The app must declare tool capabilities in the constructor to use this handler.
This setter is a convenience wrapper around setRequestHandler() that
automatically handles the request schema and extracts the params for you.
Register handlers before calling connect to avoid missing requests.
Async function that returns the list of available tools. The callback will only be invoked if the app declared tool capabilities in the constructor.
app.onlisttools = async (params, extra) => {
return {
tools: ["calculate", "convert", "format"]
};
};
Convenience handler for receiving complete tool input from the host.
Set this property to register a handler that will be called when the host sends a tool's complete arguments. This is sent after a tool call begins and before the tool result is available.
This setter is a convenience wrapper around setNotificationHandler() that
automatically handles the notification schema and extracts the params for you.
Register handlers before calling connect to avoid missing notifications.
Function called with the tool input params
// Register before connecting to ensure no notifications are missed
app.ontoolinput = (params) => {
console.log("Tool:", params.arguments);
// Update your UI with the tool arguments
};
await app.connect(transport);
app.setNotificationHandler(
McpUiToolInputNotificationSchema,
(notification) => {
console.log("Tool:", notification.params.arguments);
}
);
Convenience handler for receiving streaming partial tool input from the host.
Set this property to register a handler that will be called as the host streams partial tool arguments during tool call initialization. This enables progressive rendering of tool arguments before they're complete.
This setter is a convenience wrapper around setNotificationHandler() that
automatically handles the notification schema and extracts the params for you.
Register handlers before calling connect to avoid missing notifications.
Function called with each partial tool input update
app.ontoolinputpartial = (params) => {
console.log("Partial args:", params.arguments);
// Update your UI progressively as arguments stream in
};
Convenience handler for receiving tool execution results from the host.
Set this property to register a handler that will be called when the host sends the result of a tool execution. This is sent after the tool completes on the MCP server, allowing your app to display the results or update its state.
This setter is a convenience wrapper around setNotificationHandler() that
automatically handles the notification schema and extracts the params for you.
Register handlers before calling connect to avoid missing notifications.
Function called with the tool result
app.ontoolresult = (params) => {
if (params.content) {
console.log("Tool output:", params.content);
}
if (params.isError) {
console.error("Tool execution failed");
}
};
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 host supports the capability required for the given request method.
InternalVerify that the app supports the capability required for the given notification method.
InternalVerify that the app declared the capability required for the given request method.
Call a tool on the originating MCP server (proxied through the host).
Apps can call tools to fetch fresh data or trigger server-side actions. The host proxies the request to the actual MCP server and returns the result.
Tool name and arguments
Optionaloptions: RequestOptionsRequest options (timeout, etc.)
Tool execution result
If the host rejects the request
Note: Tool-level execution errors are returned in the result with isError: true
rather than throwing exceptions. Always check result.isError to distinguish
between transport failures (thrown) and tool execution failures (returned).
try {
const result = await app.callServerTool({
name: "get_weather",
arguments: { location: "Tokyo" }
});
if (result.isError) {
console.error("Tool returned error:", result.content);
} else {
console.log(result.content);
}
} catch (error) {
console.error("Tool call failed:", error);
}
Closes the connection.
Establish connection with the host and perform initialization handshake.
This method performs the following steps:
ui/initialize request with app info and capabilitiesui/notifications/initialized notificationIf initialization fails, the connection is automatically closed and an error is thrown.
Transport layer (typically PostMessageTransport)
Optionaloptions: RequestOptionsRequest options for the initialize request
const app = new App(
{ name: "MyApp", version: "1.0.0" },
{}
);
try {
await app.connect(new PostMessageTransport(window.parent));
console.log("Connected successfully!");
} catch (error) {
console.error("Failed to connect:", error);
}
Get the host's capabilities discovered during initialization.
Returns the capabilities that the host advertised during the
connect handshake. Returns undefined if called before
connection is established.
Host capabilities, or undefined if not yet connected
await app.connect(transport);
const caps = app.getHostCapabilities();
if (caps === undefined) {
console.error("Not connected");
return;
}
if (caps.serverTools) {
console.log("Host supports server tool calls");
}
Get the host's implementation info discovered during initialization.
Returns the host's name and version as advertised during the
connect handshake. Returns undefined if called before
connection is established.
Host implementation info, or undefined if not yet connected
await app.connect(transport);
const host = app.getHostVersion();
if (host === undefined) {
console.error("Not connected");
return;
}
console.log(`Connected to ${host.name} v${host.version}`);
connect for the initialization handshake
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: RequestOptionsSend log messages to the host for debugging and telemetry.
Logs are not added to the conversation but may be recorded by the host for debugging purposes.
Log level and message
Promise that resolves when the log notification is sent
Send a message to the host's chat interface.
Enables the app to add messages to the conversation thread. Useful for user-initiated messages or app-to-conversation communication.
Message role and content
Message content blocks (text, image, etc.)
Message role, currently only "user" is supported
Optionaloptions: RequestOptionsRequest options (timeout, etc.)
Result indicating success or error (no message content returned)
try {
await app.sendMessage({
role: "user",
content: [{ type: "text", text: "Show me details for item #42" }]
});
} catch (error) {
console.error("Failed to send message:", error);
// Handle error appropriately for your app
}
McpUiMessageRequest for request structure
Request the host to open an external URL in the default browser.
The host may deny this request based on user preferences or security policy. Apps should handle rejection gracefully.
URL to open
URL to open in the host's browser
Optionaloptions: RequestOptionsRequest options (timeout, etc.)
Result indicating success or error
try {
await app.sendOpenLink({ url: "https://docs.example.com" });
} catch (error) {
console.error("Failed to open link:", error);
// Optionally show fallback: display URL for manual copy
}
McpUiOpenLinkRequest for request structure
Notify the host of UI size changes.
Apps can manually report size changes to help the host adjust the container.
If autoResize is enabled (default), this is called automatically.
New width and height in pixels
Optionalheight?: numberNew height in pixels
Optionalwidth?: numberNew width in pixels
Promise that resolves when the notification is sent
McpUiSizeChangeNotification for notification structure
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.
Set up automatic size change notifications using ResizeObserver.
Observes both document.documentElement and document.body for size changes
and automatically sends ui/notifications/size-change notifications to the host.
The notifications are debounced using requestAnimationFrame to avoid duplicates.
Note: This method is automatically called by connect() if the autoResize
option is true (default). You typically don't need to call this manually unless
you disabled autoResize and want to enable it later.
Cleanup function to disconnect the observer
Main class for MCP Apps to communicate with their host.
The App class provides a framework-agnostic way to build interactive MCP Apps that run inside host applications. It extends the MCP SDK's Protocol class and handles the connection lifecycle, initialization handshake, and bidirectional communication with the host.
Architecture
Guest UIs (Apps) act as MCP clients connecting to the host via PostMessageTransport. The host proxies requests to the actual MCP server and forwards responses back to the App.
Lifecycle
connect()to establish transport and perform handshakeInherited Methods
As a subclass of Protocol, App inherits key methods for handling communication:
setRequestHandler()- Register handlers for requests from hostsetNotificationHandler()- Register handlers for notifications from hostSee
Protocol from @modelcontextprotocol/sdk for all inherited methods
Notification Setters
For common notifications, the App class provides convenient setter properties that simplify handler registration:
ontoolinput- Complete tool arguments from hostontoolinputpartial- Streaming partial tool argumentsontoolresult- Tool execution resultsonhostcontextchanged- Host context changes (theme, viewport, etc.)These setters are convenience wrappers around
setNotificationHandler(). Both patterns work; use whichever fits your coding style better.Example: Basic usage with PostMessageTransport
Example: Sending a message to the host's chat