> ## 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 a governed agent with native SwiftUI rendering in your iOS app

The Assistant SDK for iOS ships as the `MetabindAI` product of the `metabind-apple` Swift Package. It includes 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 governed agent inside your own app 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-apple">
    `metabind-apple` — the Apple SDK Swift Package. The Assistant SDK is its `MetabindAI` product.
  </Card>

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

## Requirements

* iOS 17+, macOS 14+, or visionOS 1+
* Swift 5.11+
* 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-apple
```

Or in `Package.swift`:

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

Then add the `MetabindAI` product to your target's dependencies:

```swift theme={null}
.target(name: "YourApp", dependencies: [
  .product(name: "MetabindAI", package: "metabind-apple")
])
```

## 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 MetabindAI

let orgId = "<organizationId>"
let projectId = "<projectId>"

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

`orgId` and `projectId` are your organization's and project's internal IDs, not their slugs. The MCP URL accepts either form, but the Agent proxy accepts only IDs. To look them up, see [Find your organization and project IDs](/guides/getting-started/embed-an-assistant#find-your-organization-and-project-ids).

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 MetabindAI

let assistant = MetabindAssistant(
  serverURL: URL(string: "https://mcp.metabind.ai/\(orgId)/projects/\(projectId)")!,
  serverHeaders: ["Authorization": "Bearer \(projectToken)"],
  provider: AnthropicProvider(
    apiKey: anthropicKey,
    model: "claude-sonnet-4-6"
  )
)
```

<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 MetabindAI

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.

## 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

* Tool results render as native SwiftUI through BindJS — no web views.
* 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>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.