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

Adding a new music provider to Music Assistant requires creating a Python module that subclasses the MusicProvider base class and a 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. 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:

{
  "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.
  • 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:

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, implement the required methods:

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:

    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:

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 and implement async methods for search, library retrieval, and streaming.
  • Manifest Requirements – Every provider requires a 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 containing the subclass and 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 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. 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 using standard specifiers like "requests==2.32.0" or "aiohttp>=3.8.0". The scripts/setup.sh command automatically installs these dependencies into the Music Assistant environment when you run it after creating or modifying your provider.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →