# How to Add New Music Providers to Music Assistant: A Complete Developer Guide

> Learn how to add new music providers to Music Assistant. This developer guide covers creating Python modules and manifest files to extend your music integration.

- Repository: [Music Assistant/server](https://github.com/music-assistant/server)
- Tags: how-to-guide
- Published: 2026-06-15

---

**Adding a new music provider to Music Assistant requires creating a Python module that subclasses the `MusicProvider` base class and a [`manifest.json`](https://github.com/music-assistant/server/blob/main/manifest.json) configuration file, both placed in a new folder under `music_assistant/providers/<your_provider>/`.**

Music Assistant is an open-source music server that aggregates content from multiple sources through a modular provider architecture. To add new music providers to Music Assistant, developers must implement a standardized interface that handles authentication, library synchronization, search, and streaming. This guide walks through the core architecture, required files, and implementation patterns based on the current source code in the `music-assistant/server` repository.

## Understanding the MusicProvider Base Class

All music providers inherit from the **MusicProvider** class defined in [`music_assistant/models/music_provider.py`](https://github.com/music-assistant/server/blob/main/music_assistant/models/music_provider.py). This base class establishes the contract between external music services and Music Assistant's core library.

### Required Methods and Properties

Your provider implementation must override these key methods to declare capabilities and handle data retrieval:

- **`supported_features`** – Returns a list of `ProviderFeature` enum values (e.g., `ProviderFeature.SEARCH`, `ProviderFeature.LIBRARY_TRACKS`, `ProviderFeature.STREAM`) that declare what your provider can do.
- **`setup()`** – Called once during instantiation to handle authentication, token refresh, or initial configuration.
- **`search()`** – Accepts `search_query`, `media_types`, and `limit` parameters; returns a `SearchResults` object containing matching items.
- **`get_library_artists()`**, **`get_library_albums()`**, **`get_library_tracks()`**, **`get_library_playlists()`** – Async generators that yield the respective model objects (Artist, Album, Track, Playlist) from the user's library.
- **`get_artist()`**, **`get_album()`**, **`get_track()`**, **`get_playlist()`** – Fetch full details for a specific item by its provider-specific ID.
- **`get_stream_details()`** – Returns `StreamDetails` containing protocol, URL, and audio format information.
- **`get_audio_stream()`** – Async generator that yields audio bytes for playback, optionally supporting seek positions.

The base class provides a default browse implementation that constructs a virtual folder hierarchy based on your declared `supported_features`. You only need to override `browse(path)` if you require custom navigation logic.

## Creating the Provider Manifest

Every provider must include a **manifest.json** file that describes metadata, configuration requirements, and dependencies. This file enables Music Assistant to discover and load your provider automatically.

### Key Manifest Fields

Place the manifest at `music_assistant/providers/<your_provider>/manifest.json`:

```json
{
  "type": "music",
  "domain": "unique_provider_name",
  "name": "Human Readable Name",
  "description": "Description of the service",
  "codeowners": ["@github_username"],
  "config_entries": [
    {
      "key": "api_key",
      "type": "secure_string",
      "label": "API Key",
      "default": ""
    }
  ],
  "requirements": ["aiohttp==3.9.0", "some-api-client==1.0.0"],
  "documentation": "https://github.com/music-assistant/server/discussions/xxx",
  "multi_instances": false
}

```

- **`type`** – Must be `"music"` for music providers.
- **`domain`** – Unique identifier used internally (e.g., `"spotify"`, `"qobuz"`).
- **`config_entries`** – Array defining configuration fields; types include `string`, `secure_string`, `boolean`, and `integer`.
- **`requirements`** – Pip-style dependencies installed automatically when running [`scripts/setup.sh`](https://github.com/music-assistant/server/blob/main/scripts/setup.sh).
- **`multi_instances`** – Set to `true` if users can configure multiple accounts of this provider.

## Step-by-Step Implementation Guide

Follow these steps to implement a functional music provider that integrates with Music Assistant's library sync, search, and playback systems.

### 1. Create the Provider Folder Structure

Create a new directory for your provider:

```bash
mkdir -p music_assistant/providers/myprovider
touch music_assistant/providers/myprovider/__init__.py

```

Reference the **demo provider** at `music_assistant/providers/_demo_music_provider/` for a working template.

### 2. Implement the MusicProvider Subclass

In [`music_assistant/providers/myprovider/__init__.py`](https://github.com/music-assistant/server/blob/main/music_assistant/providers/myprovider/__init__.py), implement the required methods:

```python
from __future__ import annotations

from music_assistant.models.music_provider import MusicProvider
from music_assistant.models.provider import ProviderFeature
from music_assistant.models.media_items import Artist, Album, Track, SearchResults, StreamDetails
from music_assistant.helpers.util import async_log_exception
import aiohttp

class MyProvider(MusicProvider):
    """Custom music provider implementation."""

    @property
    def supported_features(self) -> list[ProviderFeature]:
        """Declare supported capabilities."""
        return [
            ProviderFeature.SEARCH,
            ProviderFeature.LIBRARY_ARTISTS,
            ProviderFeature.LIBRARY_ALBUMS,
            ProviderFeature.LIBRARY_TRACKS,
            ProviderFeature.STREAM,
        ]

    async def setup(self) -> None:
        """Initialize authentication."""
        self._api_key = self.config.get_value("api_key")
        # Verify credentials or refresh tokens here

    async def search(self, search_query: str, media_types: list, limit: int = 5) -> SearchResults:
        """Execute search against external API."""
        async with aiohttp.ClientSession() as session:
            params = {"q": search_query, "limit": limit, "key": self._api_key}
            async with session.get("https://api.example.com/search", params=params) as resp:
                data = await resp.json()
        
        # Transform API response into Music Assistant models

        return SearchResults(
            artists=[Artist(item_id=item["id"], provider=self.instance_id, name=item["name"]) 
                    for item in data.get("artists", [])],
            # ... populate albums, tracks, playlists

        )

    async def get_library_artists(self):
        """Yield all artists from the user's library."""
        async with aiohttp.ClientSession() as session:
            async with session.get(f"https://api.example.com/library/artists?key={self._api_key}") as resp:
                for item in await resp.json():
                    yield Artist(
                        item_id=item["id"],
                        provider=self.instance_id,
                        name=item["name"],
                        # ... additional metadata

                    )

```

### 3. Implement Streaming Capabilities

To support playback, implement the streaming methods:

```python
    async def get_stream_details(self, item_id: str, media_type) -> StreamDetails:
        """Return stream metadata for a track."""
        return StreamDetails(
            protocol="https",
            url=f"https://api.example.com/stream/{item_id}?key={self._api_key}",
            audio_format={"content_type": "audio/mpeg", "sample_rate": 44100, "bit_depth": 16},
            duration=240,
        )

    async def get_audio_stream(self, streamdetails: StreamDetails, seek_position: int = 0):
        """Yield audio bytes for playback."""
        headers = {"Range": f"bytes={seek_position}-"} if seek_position else {}
        async with aiohttp.ClientSession() as session:
            async with session.get(streamdetails.url, headers=headers) as resp:
                async for chunk in resp.content.iter_any():
                    yield chunk

```

### 4. Install Dependencies and Test

Run the setup script to install requirements from your manifest:

```bash
scripts/setup.sh

```

Music Assistant automatically scans `music_assistant/providers/*` at startup. No manual registration is required. Enable your provider in the UI to test search, library synchronization, and streaming.

## Summary

- **Music Provider Architecture** – All providers inherit from `MusicProvider` in [`music_assistant/models/music_provider.py`](https://github.com/music-assistant/server/blob/main/music_assistant/models/music_provider.py) and implement async methods for search, library retrieval, and streaming.
- **Manifest Requirements** – Every provider requires a [`manifest.json`](https://github.com/music-assistant/server/blob/main/manifest.json) declaring the domain, configuration entries, dependencies, and supported features.
- **Implementation Location** – Provider code lives in `music_assistant/providers/<your_provider>/` with [`__init__.py`](https://github.com/music-assistant/server/blob/main/__init__.py) containing the subclass and [`manifest.json`](https://github.com/music-assistant/server/blob/main/manifest.json) containing metadata.
- **Capability Declaration** – Use the `supported_features` property to declare which methods your provider implements (search, library sync, streaming, etc.).
- **Automatic Discovery** – The server automatically detects new providers in the providers directory; run [`scripts/setup.sh`](https://github.com/music-assistant/server/blob/main/scripts/setup.sh) to install dependencies.

## Frequently Asked Questions

### What methods are required when adding a new music provider to Music Assistant?

You must implement `setup()` for initialization, `supported_features` to declare capabilities, and any methods corresponding to your declared features. If you declare `ProviderFeature.SEARCH`, you must implement `search()`. If you declare `ProviderFeature.LIBRARY_TRACKS`, you must implement `get_library_tracks()`. Streaming requires both `get_stream_details()` and `get_audio_stream()`.

### How do I handle authentication and API keys in my provider?

Implement the `setup()` method to retrieve configuration values via `self.config.get_value(key)` and perform authentication or token validation. Store tokens as instance variables (e.g., `self._token`) for use in other methods. Use `secure_string` type in your manifest for sensitive fields like API keys.

### Can my provider support multiple simultaneous instances?

Yes, set `"multi_instances": true` in your [`manifest.json`](https://github.com/music-assistant/server/blob/main/manifest.json). This allows users to configure the same provider multiple times with different credentials (e.g., multiple Spotify accounts). When `multi_instances` is enabled, Music Assistant creates separate instances of your provider class with unique configuration scopes.

### Where should I add third-party Python dependencies for my provider?

List all pip-installable packages in the `requirements` array within your [`manifest.json`](https://github.com/music-assistant/server/blob/main/manifest.json) using standard specifiers like `"requests==2.32.0"` or `"aiohttp>=3.8.0"`. The [`scripts/setup.sh`](https://github.com/music-assistant/server/blob/main/scripts/setup.sh) command automatically installs these dependencies into the Music Assistant environment when you run it after creating or modifying your provider.