> ## Documentation Index
> Fetch the complete documentation index at: https://docs.metabind.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# iOS SDK

> Embed an MCP-aware assistant with native SwiftUI rendering in your iOS app

The iOS Assistant SDK is a Swift Package that ships an MCP client, a conversation manager, an LLM provider abstraction, and the native SwiftUI renderer for BindJS. Drop it into your app, configure how it should reach an LLM, and you have a fully functional in-app AI assistant that calls your Metabind tools and renders results as native SwiftUI.

<CardGroup cols={2}>
  <Card title="View on GitHub" icon="github" href="https://github.com/metabindai/metabind-ai-apple">
    `metabind-ai-apple` — the iOS Assistant SDK Swift Package source.
  </Card>

  <Card title="Sample app" icon="github" href="https://github.com/metabindai/metabind-assistant-demo-apple">
    `metabind-assistant-demo-apple` — a complete SwiftUI app embedding the assistant.
  </Card>
</CardGroup>

## Requirements

* iOS 17+
* Xcode 15+
* Swift 5.9+
* A Metabind project with at least one published Type
* Either: a Metabind project token (for the managed Agent proxy), **or** an Anthropic API key (BYOK direct mode)

## Install via Swift Package Manager

In Xcode: **File → Add Package Dependencies** → paste:

```
https://github.com/metabindai/metabind-ai-apple
```

Or in `Package.swift`:

```swift theme={null}
dependencies: [
  .package(url: "https://github.com/metabindai/metabind-ai-apple", from: "0.1.0")
]
```

Add `MetabindAssistant` to your target's dependencies.

## Two ways to configure the LLM

The SDK accepts an `LLMProvider`. Two implementations ship today:

| Provider                | Use when                                                                                                                                                                                                              |
| ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `MetabindAgentProvider` | You want Metabind to manage LLM access. Calls the **Agent proxy** at `agent.metabind.ai`. The proxy holds the LLM key, runs the tool loop server-side, and streams responses back as SSE. Recommended for production. |
| `AnthropicProvider`     | You want to bring your own Anthropic API key (BYOK direct mode) for development or testing. The SDK calls Anthropic directly.                                                                                         |

Custom providers can conform to the public `LLMProvider` protocol if you need to integrate something else.

## Configure with the Agent proxy (recommended)

```swift theme={null}
import MetabindAssistant

let assistant = MetabindAssistant(
  serverURL: URL(string: "https://mcp.metabind.ai/my-org/oak-and-ivory")!,
  serverHeaders: ["Authorization": "Bearer \(projectToken)"],
  provider: MetabindAgentProvider(
    apiKey: projectToken,
    orgId: "my-org",
    projectId: "oak-and-ivory"
  )
)
```

The Agent proxy:

* Authenticates with a Metabind project token (Bearer header).
* Runs the LLM call and the tool loop on the server side. Tool results are streamed back to the client as Server-Sent Events.
* Handles secret-bearing LLM keys server-side, so your iOS binary doesn't ship any third-party provider keys.

## Configure with direct BYOK mode

```swift theme={null}
import MetabindAssistant

let assistant = MetabindAssistant(
  serverURL: URL(string: "https://mcp.metabind.ai/my-org/oak-and-ivory")!,
  serverHeaders: ["Authorization": "Bearer \(projectToken)"],
  provider: AnthropicProvider(
    apiKey: anthropicKey,
    model: "claude-sonnet-4-20250514"
  )
)
```

<Warning>
  Do not ship a real Anthropic API key in a production iOS app — anyone can extract it from the binary. BYOK mode is for development, internal tools, or apps where the key reaches the SDK from an authenticated user-managed source. For production use, prefer the Agent proxy.
</Warning>

## Drop in the chat surface

The SDK ships a default chat UI as a SwiftUI view:

```swift theme={null}
import SwiftUI
import MetabindAssistant

struct AssistantScreen: View {
  let assistant: MetabindAssistant

  var body: some View {
    MetabindAssistantView(assistant: assistant)
      .navigationTitle("Assistant")
  }
}
```

`MetabindAssistantView` renders the conversation UI, handles input, streams responses, and renders Interactive Tool output as native SwiftUI views inline. It respects your app's color scheme, dynamic type, and accessibility settings.

For a fully custom UI, use the lower-level API on `MetabindAssistant` — `assistant.send(...)`, `assistant.conversation`, `assistant.cancel()`, and `assistant.isProcessing`. See [Custom host UI](/guides/assistant-sdk/custom-host-ui).

## Native rendering of tool output

When the assistant calls an Interactive Tool, the result renders as SwiftUI inline:

<Frame>
  <img src="https://mintcdn.com/yapstudios/ZJLavl8Q7LnCwqCq/images/diagrams/rendered-card.svg?fit=max&auto=format&n=ZJLavl8Q7LnCwqCq&q=85&s=ac112567bb312cff16e5c23ef858c699" alt="In a chat turn, a Metabind ProductCard renders inline as a real native component — image, title, price, and shop button — not a WebView." noZoom width="960" height="460" data-path="images/diagrams/rendered-card.svg" />
</Frame>

The card is a SwiftUI view. It animates with your app's transitions, respects dynamic type, and supports VoiceOver. It is *not* a WebView.

## Conversation state

Conversation history is held in memory by the `Conversation` observable on the assistant. You can read `assistant.conversation.messages` directly to render your own UI or to feed the conversation into your app's state. If your app needs persistence across launches, serialize the messages array (e.g., to Core Data, SwiftData, or your backend) and rehydrate on next launch.

## Mock mode for previews

The SDK includes `MockMCPServer` and helpers for SwiftUI previews so you can iterate on chat UI without wiring up a live server:

```swift theme={null}
#Preview {
  MetabindAssistantView(
    assistant: MetabindAssistant(
      server: MockMCPServer(),
      provider: MetabindAgentProvider(apiKey: "preview", orgId: "preview", projectId: "preview")
    )
  )
}
```

## Authentication patterns

* **Backend mints token.** Your backend authenticates the user, mints a Metabind project token, hands it to the iOS app. The SDK passes it to the Agent proxy. Most secure; recommended for production.
* **Static token (dev only).** Hardcoded in the app. Don't ship to production.

## Performance

* The SDK ships compiled Swift; no JavaScript runtime on iOS.
* BindJS layouts compile to SwiftUI views at render time; subsequent renders reuse cached compilation.
* Streaming SSE events from the Agent proxy render as they arrive.

## What you write vs. what the SDK does

| You write                                        | SDK does                                            |
| ------------------------------------------------ | --------------------------------------------------- |
| Project URL + token from your backend            | Connection, auth, retries                           |
| LLM provider config (Agent proxy vs. BYOK)       | Tool calls, schema validation, conversation state   |
| `MetabindAssistantView` placement (or custom UI) | Streaming, message rendering, tool result rendering |

## Related

<CardGroup cols={2}>
  <Card title="Assistant SDK overview" icon="rocket" href="/guides/getting-started/embed-an-assistant">
    Conceptual: when to embed vs. connect to an external host.
  </Card>

  <Card title="LLM provider configuration" icon="brain" href="/guides/assistant-sdk/llm-provider-configuration">
    Agent proxy vs. BYOK; key custody.
  </Card>

  <Card title="Custom host UI" icon="paintbrush" href="/guides/assistant-sdk/custom-host-ui">
    Replace the default chat UI with your own.
  </Card>

  <Card title="Android SDK" icon="android" href="/guides/assistant-sdk/android-sdk">
    The Android equivalent.
  </Card>
</CardGroup>
