# Client SDK quickstart

> Install the Python client SDK, send your first message, and stream a response.

Source: https://maincode.com/docs/python-client-sdk-overview
Section: Client SDK · Matilda documentation

---

A small, self-contained Python SDK for building Matilda clients. Async-first (built on `httpx`), fully typed, with typed stream events and zero runtime dependencies beyond `httpx` and the standard library. Requires Python 3.12 or later. This guide covers SDK version 0.3.0.

The SDK follows the OpenAI client shape where it helps: constructor config, resource groups, request options, typed API errors, and async-iterable streaming. It does not expose model or provider selection — Matilda core owns routing, safety, resumable SSE, server-side tool execution, and policy.

## What's included

- **Chat** — non-streaming, full-event streaming, text-only streaming, schema-constrained structured output, and durable stream resume
- **Conversations** — list, retrieve, rename, and set message feedback
- **Files** — upload (single and parallel), retrieve metadata
- **Feedback** — report harmful content and submit response feedback
- **Auth** — managed PKCE browser login, RFC 8628 device flow, token refresh, and persistent token storage
- **API keys** — create, list, and revoke `mc_live_` API keys via SDK methods or the `matilda-key` CLI

## What's not included

- **Local tool-execution loop** — for client-side tool execution (`client_tools`, local approval/sandbox loops, tool-result continuation), use the [agent SDK](https://maincode.com/docs/python-agent-sdk-agent)
- **Session class** — multi-turn conversations are managed via `conversation_id`; see [Multi-turn conversations](https://maincode.com/docs/python-client-sdk-multi-turn)
- **Devices** — push-notification device management is not yet exposed on the Python client surface

## Installation

**pip**

```bash
pip install matilda-client
```

**uv**

```bash
uv add matilda-client
```

`pydantic` is an optional dependency — install it alongside the SDK if you want schema-validated structured output ([Structured output](https://maincode.com/docs/python-client-sdk-structured-output)). The SDK detects pydantic models by duck-typing, so any version works:

```bash
pip install pydantic
```

### Import

```python title="main.py"
from matilda_client import MatildaClient
```

### Auth modules

The standalone auth helpers live in two submodules — the transport-agnostic OAuth protocol core, and the local-machine adapters (loopback receiver, file token store, managed login flows):

```python title="auth.py"
from matilda_client.auth import (
    create_token_manager,
    fetch_auth_server_metadata,
    memory_storage,
)
from matilda_client.auth_local import (
    create_file_token_store,
    create_loopback_receiver,
    run_device_login_flow,
    run_loopback_login_flow,
)
```

## Quick start

### Send a message

```python title="chat.py"
import asyncio
import os

from matilda_client import MatildaClient


async def main():
    async with MatildaClient(token=os.environ["MATILDA_ACCESS_TOKEN"]) as client:
        response = await client.chat.create(input="Summarize this thread.")
        print(response.output_text)


asyncio.run(main())
```

> **Note** — The `token` option above is fine for quick testing, but for production use we recommend the managed auth flows (`login_with_browser` or `login_with_device_flow`), which auto-wire a `TokenManager` with automatic token refresh. See [Authentication](https://maincode.com/docs/python-client-sdk-authentication).

### Stream a response

```python title="stream.py"
import os

from matilda_client import MatildaClient


async def main():
    async with MatildaClient(token=os.environ["MATILDA_ACCESS_TOKEN"]) as client:
        async for event in client.chat.stream(input="Write a short plan."):
            if event.type == "response.output_text.delta":
                print(event.delta, end="", flush=True)
```

### Authenticated: device flow and chat

```python title="device_flow.py"
import asyncio

from matilda_client import MatildaClient


async def main():
    async with MatildaClient() as client:
        # Authenticate via RFC 8628 device flow — prints a code to stderr
        await client.auth.login_with_device_flow(client_id="matilda-code")

        # Token is now managed automatically — no manual header wiring
        response = await client.chat.create(input="Hello, Matilda!")
        print(response.output_text)


asyncio.run(main())
```
