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 ofProviderFeatureenum 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()– Acceptssearch_query,media_types, andlimitparameters; returns aSearchResultsobject 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()– ReturnsStreamDetailscontaining 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 includestring,secure_string,boolean, andinteger.requirements– Pip-style dependencies installed automatically when runningscripts/setup.sh.multi_instances– Set totrueif 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
MusicProviderinmusic_assistant/models/music_provider.pyand implement async methods for search, library retrieval, and streaming. - Manifest Requirements – Every provider requires a
manifest.jsondeclaring the domain, configuration entries, dependencies, and supported features. - Implementation Location – Provider code lives in
music_assistant/providers/<your_provider>/with__init__.pycontaining the subclass andmanifest.jsoncontaining metadata. - Capability Declaration – Use the
supported_featuresproperty 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.shto 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →