How Music Assistant's Provider System Works: Architecture and Supported Types

Music Assistant uses a unified provider system where every integration inherits from a base Provider class, declares its capabilities via the ProviderFeature enum, and registers through a manifest.json file to supply music catalogues, playback devices, metadata, or plugins.

The music-assistant/server repository implements a modular architecture that separates streaming services, hardware controllers, and metadata sources into distinct provider types. Understanding how this provider system works is essential for developers extending Music Assistant or troubleshooting why a specific integration behaves differently than expected.

The Provider Base Class and Core Architecture

Every integration in Music Assistant begins with the Provider class defined in music_assistant/models/provider.py. This base class stores three critical references: the provider's manifest, its runtime configuration, and a handle to the core MusicAssistant instance.

The base class maintains a private set called self._supported_features that contains ProviderFeature enum values declaring what the integration can do. Developers query these capabilities through two helper methods:

  • supports_feature() – Returns a boolean indicating feature availability.
  • check_feature() – Raises an exception if the feature is unsupported.

When Music Assistant starts, the core reads each provider's manifest.json to build a ProviderManifest object. This manifest specifies the type (via the ProviderType enum), a unique domain identifier (e.g., spotify or sonos), and the development stage (stable or beta). The system then instantiates the provider class, injects the manifest and config, and registers the instance in the global mass.providers registry.

Five Provider Types Supported in Music Assistant

Music Assistant subclasses the base Provider into five concrete families, each identified by a ProviderType enum entry. Here is how they function according to the source:

  • MusicProvider – Defined in music_assistant/models/music_provider.py. These providers supply music catalogues, handle library synchronization, implement search functionality, and return playback details. Typical implementations include Spotify, Tidal, YouTube Music, Plex, and Subsonic.

  • PlayerProvider – Defined in music_assistant/models/player_provider.py. These control playback devices such as speakers and media players, optionally supporting grouping features like Sonos zones or MPD clients.

  • MetadataProvider – Defined in music_assistant/models/metadata_provider.py. These offer supplemental metadata not present in the core music catalogue, including album artwork, lyrics, and advanced track tags from sources like MusicBrainz, TheAudioDB, and LRCLib.

  • AudioAnalysisProvider – Defined in music_assistant/models/audio_analysis_provider.py. These perform computational audio tasks such as loudness detection, acoustic fingerprinting, and similarity matching. Examples include SonicSimilarity and SmartFades.

  • PluginProvider – Defined in music_assistant/models/plugin.py. These implement optional, non-core features that extend Music Assistant's functionality, such as smart playlist generation, scrobbling to Last.fm, or recommendation engines.

Provider Registration and Manifest System

Providers declare themselves to the core through a manifest.json file located in each provider's folder. When Music Assistant boots, it parses these manifests to construct ProviderManifest objects without instantiating the provider code.

The registration flow follows these steps:

  1. The core discovers manifest.json files across the providers/ directory.
  2. It validates the domain uniqueness and maps the type field to the ProviderType enum.
  3. Upon user activation, the core imports the provider module, instantiates the class, and calls loaded_in_mass().
  4. The provider becomes accessible via mass.providers.get_by_domain("domain_name").

Feature Detection and Capability Checking

Providers advertise functionality through the ProviderFeature enum. Common features include SEARCH, LIBRARY_ARTISTS, LIBRARY_ALBUMS, and PLAYLIST_CREATE.

Before invoking provider-specific logic, the core guards calls using feature detection:

spotify = self.mass.providers.get_by_domain("spotify")
if spotify and spotify.supports_feature(ProviderFeature.SEARCH):
    results = await spotify.search("beatles", [MediaType.ARTIST, MediaType.TRACK])

If a provider receives a call for an unsupported feature, it raises NotImplementedError. The core catches this exception and either falls back to alternative providers or returns a default implementation, ensuring the system remains stable even when specific providers lack certain capabilities.

Provider Lifecycle Management

Providers support dynamic configuration changes without requiring a full server restart. The lifecycle hooks in music_assistant/models/provider.py manage this state:

  • loaded_in_mass() – Called immediately after registration. Providers perform async initialization here, such as establishing API sessions or discovering network devices.

  • update_config() – Invoked when a user changes settings via the configuration UI. This updates the stored configuration, optionally reloads the provider, and reapplies logging levels.

  • unload() and unload_with_error() – Clean up resources when a provider is disabled or encounters a fatal error. This includes closing HTTP sessions, stopping background tasks, and removing player registrations.

Implementation Examples

Creating a Minimal Music Provider

To implement a new streaming integration, subclass MusicProvider and declare supported features:


# my_provider/provider.py

from music_assistant.models.music_provider import MusicProvider
from music_assistant_models.enums import ProviderFeature, MediaType

class MyProvider(MusicProvider):
    async def search(self, query: str, media_types: list[MediaType], limit: int = 5):
        # Implement provider-specific search logic

        results = await self._api.search(query, limit)
        return results

    async def get_library_artists(self):
        # Return an async generator of Artist objects

        for artist in await self._api.get_artists():
            yield artist

# Register supported features

SUPPORTED_FEATURES = {
    ProviderFeature.SEARCH,
    ProviderFeature.LIBRARY_ARTISTS,
    ProviderFeature.LIBRARY_ALBUMS,
}

Accessing Providers from Core Logic

Other components interact with providers through the registry:


# Inside a core controller or other provider

player_provider = self.mass.providers.get_by_domain("sonos")
if player_provider:
    await player_provider.on_player_enabled(player_id)

Summary

  • Base Architecture: All providers inherit from Provider in music_assistant/models/provider.py, storing manifests and configuration while exposing supports_feature() for capability checks.
  • Five Types: Music Assistant supports MusicProvider, PlayerProvider, MetadataProvider, AudioAnalysisProvider, and PluginProvider, each defined in corresponding files under music_assistant/models/.
  • Registration: Providers declare themselves via manifest.json, which the core parses to build ProviderManifest objects before instantiation.
  • Lifecycle: Async hooks including loaded_in_mass(), update_config(), and unload() manage initialization, dynamic reconfiguration, and cleanup.

Frequently Asked Questions

What is the difference between a MusicProvider and a PlayerProvider?

A MusicProvider supplies audio content and metadata from sources like Spotify or Plex, handling search and library sync. A PlayerProvider controls physical or virtual playback devices such as Sonos speakers or MPD instances, managing volume, transport controls, and grouping.

How does Music Assistant check if a provider supports a specific feature?

The core calls provider.supports_feature(ProviderFeature.SOME_FEATURE) before invoking capability-specific methods. If a provider receives a call for an unsupported feature, it raises NotImplementedError, which the core catches to handle gracefully or fall back to alternatives.

Can providers be reloaded without restarting Music Assistant?

Yes. When configuration changes occur, the core invokes provider.update_config() to apply new settings. For major changes, the system may call unload() followed by re-instantiation and loaded_in_mass(), allowing providers to reinitialize without a full server restart.

What files are required to create a custom provider?

You need a manifest.json declaring the domain, type, and stage, and a provider.py containing a class that inherits from the appropriate base (e.g., MusicProvider). Optional __init__.py files and dependency directories follow standard Python package structure within the providers/ directory.

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 →