Skip to main content
On iOS and Android, the Assistant SDK ships the same pair: MetabindAssistant, which runs the conversation, and MetabindAssistantView, a default chat surface that handles most cases. When you need full control over the UI (a different layout, a non-chat interaction model, custom branding beyond what theming covers), keep MetabindAssistant and drive your own surface from its public API.

Why go custom

Most teams ship the default UI for the first release and customize later. Cases where custom is right from day one:
  • Your assistant lives inside a non-chat surface — a sidebar, an inline panel, a voice-first interaction.
  • You want UI primitives that don’t fit a chat metaphor — e.g., a multi-pane workspace where the assistant is one component.
  • Your design system mandates components that diverge significantly from the SDK’s chat default.
  • You’re building an agent UI (open-ended task execution) rather than a chat UI.
If your case is “the chat looks fine but I want a different color scheme,” start with theming the default — it covers far more than it appears to.

What the lower-level API gives you

On iOS, the default chat surface is built on a small public API on the MetabindAssistant object: Tool result UI is rendered through the BindJS native renderer. On iOS, each tool call arrives in conversation.messages as a .tool(MCPAppSession) message; MCPAppView(session:) fetches the tool’s UI resource and renders it as native SwiftUI. On Android, each tool call arrives in messages as a TOOL message; pass toolUIContent[message.id] to MetabindToolView, which renders it as Compose, or in a WebView for an HTML resource.

iOS example

MetabindAssistant and its conversation use the Observation framework (@Observable), so SwiftUI updates the view whenever conversation.messages or isProcessing changes. Pass the assistant as a plain property, as above, or hold it in @State if the view creates it. MCPAppView comes from MCPAppsHost, which MetabindAI re-exports.

Android example

On Android, MetabindAssistant exposes StateFlows: messages, isLoading, error, and toolUIContent. Collect them, call send(text) and cancel(), and render each TOOL message’s UI with MetabindToolView:
toolUIContent is keyed by tool call ID, the same ID as the TOOL message, and fills in once the tool’s UI resource loads. The finance demo is a complete custom Android UI built this way. The Android SDK guide lists the full API.

What the default UI does that you’ll need to handle

If you replace the default UI, replicate (or skip) these as needed:

Conversation state observability

The conversation state is the source of truth. Patterns:
  • Read-only views. Render the conversation in a different surface (e.g., a summary sidebar) by subscribing to the same state.
  • Multi-pane layouts. A chat pane on one side, a tool result detail pane on the other — both subscribed to the same state, both displaying different slices.

iOS SDK

Default chat surface and configuration.

Android SDK

Default chat surface and configuration.

LLM provider configuration

Agent proxy vs. BYOK for the LLM call.

Assistant SDK overview

Conceptual: when to embed and what’s in the box.