# How Music Assistant's Provider Architecture (Music, Player, Metadata) Works

> Explore Music Assistant's provider architecture for music playback and metadata. Learn how its modular design integrates libraries and devices for a seamless experience.

- Repository: [Music Assistant/server](https://github.com/music-assistant/server)
- Tags: architecture
- Published: 2026-06-17

---

**Music Assistant uses a modular provider architecture where all external integrations inherit from a common `Provider` base class and implement specialized interfaces for music libraries, playback devices, or metadata enrichment.**

Music Assistant organizes every external integration through a hierarchical provider system defined in the `music-assistant/server` repository. This architecture categorizes integrations into three distinct provider types—MUSIC, PLAYER, and METADATA—each extending a shared foundation that handles configuration, logging, and feature declaration. Understanding this structure is essential for developing new integrations or troubleshooting existing ones.

## The Three Provider Types

Music Assistant splits external services into three specialized domains, each with a dedicated abstract base class.

### Music Provider

The **Music Provider** ([`music_assistant/models/music_provider.py`](https://github.com/music-assistant/server/blob/main/music_assistant/models/music_provider.py)) supplies catalogues of media items and synchronizes user libraries with Music Assistant. These providers handle artists, albums, tracks, playlists, radios, podcasts, and audiobooks.

Key responsibilities include:
- Search and browse operations via `search()` and library methods like `get_library_artists()`
- Library synchronization through the `sync_library()` method, which orchestrates full syncs for specific `MediaType` values
- Stream detail handling for custom audio streams

The `sync_library()` method iterates over provider library methods, creates or updates database items, and tracks processed IDs using `CACHE_CATEGORY_PREV_LIBRARY_IDS` to detect deletions.

### Player Provider

The **Player Provider** ([`music_assistant/models/player_provider.py`](https://github.com/music-assistant/server/blob/main/music_assistant/models/player_provider.py)) controls playback devices including speakers, smart displays, and media players. These providers manage device discovery, grouping, and lifecycle events.

Core functionality includes:
- Device discovery via `discover_players()`
- Exposing a `players` property that returns all `Player` objects belonging to the provider
- Lifecycle callbacks: `on_player_enabled()` and `on_player_disabled()`
- Optional group player creation when `ProviderFeature.CREATE_GROUP_PLAYER` is declared

### Metadata Provider

The **Metadata Provider** ([`music_assistant/models/metadata_provider.py`](https://github.com/music-assistant/server/blob/main/music_assistant/models/metadata_provider.py)) enriches existing media items with supplementary information such as cover art, descriptions, similar items, and recommendations.

These providers operate on a priority basis:
- Each provider declares a `priority` attribute
- Music Assistant queries providers in priority order until one returns a non-`None` result
- Typical methods include `get_album_metadata()`, `get_similar_tracks()`, and `get_top_tracks()`

## The Common Provider Base Class

All provider types inherit from the **`Provider`** class in [`music_assistant/models/provider.py`](https://github.com/music-assistant/server/blob/main/music_assistant/models/provider.py). This base implements shared infrastructure:

**Configuration Handling**
Each provider receives a `ProviderConfig` object during instantiation and can react to changes via `update_config()`.

**Feature Declaration**
Providers expose capabilities through a `supported_features` set containing `ProviderFeature` enum values (defined in [`music_assistant/constants.py`](https://github.com/music-assistant/server/blob/main/music_assistant/constants.py)). The base class provides `supports_feature()` and `check_feature()` methods for runtime capability checks.

**Logging**
Providers receive a dedicated logger whose level is automatically configured based on the provider's settings via `_set_log_level_from_config()`.

**Lifecycle Hooks**
The base class defines `loaded_in_mass()`, `unload()`, and async initialization hooks for startup and cleanup operations.

## How the Provider System Functions

The architecture follows a strict discovery and enforcement pattern:

1. **Discovery & Registration**
   During startup, Music Assistant scans `providers/` directories for [`manifest.json`](https://github.com/music-assistant/server/blob/main/manifest.json) files. Each manifest declares the provider's type (`ProviderType.MUSIC`, `PLAYER`, or `METADATA`), domain, and implemented features.

2. **Instantiation**
   For each manifest, the system creates an instance of the appropriate concrete class, passing the global `MusicAssistant` object, manifest, config, and optional supported features to the constructor.

3. **Feature Enforcement**
   Core actions are guarded by feature checks. For example, `MusicProvider.get_similar_tracks()` is only invoked if the provider declares `ProviderFeature.SIMILAR_TRACKS`. Missing features raise `NotImplementedError` in the base implementation.

4. **Library Synchronization**
   For music providers, the `sync_library()` method orchestrates full synchronizations by iterating over library methods, updating database records, and comparing cached IDs against current sets to detect removals.

5. **Metadata Enrichment**
   When enrichment is needed, Music Assistant iterates over registered metadata providers by priority, stopping at the first successful result.

## Implementation Examples

### Declaring a Music Provider

```python

# my_music_provider/__init__.py

from music_assistant.models.music_provider import MusicProvider
from music_assistant.constants import ProviderFeature

class MyMusicProvider(MusicProvider):
    async def search(self, query: str, media_types: list[MediaType], limit: int = 5):
        # Implementation of your service's search endpoint

        pass

    async def get_library_artists(self):
        # Yield Artist objects from the remote service

        pass

# manifest.json (placed next to the package)

{
  "domain": "my_music",
  "name": "My Music Service",
  "type": "music",
  "stage": "stable",
  "features": [
    "SEARCH",
    "LIBRARY_ARTISTS",
    "LIBRARY_ALBUMS",
    "LIBRARY_TRACKS"
  ]
}

```

### Using Metadata Providers for Album Art

```python
async def enrich_album(album: Album) -> Album:
    # Iterate over all metadata providers by priority

    for prov in mass.providers.get_by_type("metadata"):
        try:
            md = await prov.get_album_metadata(album)
            if md:
                album.metadata = md
                break
        except NotImplementedError:
            continue
    return album

```

## Summary

- Music Assistant's provider architecture centers on three specialized types: **MusicProvider**, **PlayerProvider**, and **MetadataProvider**.
- All providers inherit from the common **`Provider`** base class in [`music_assistant/models/provider.py`](https://github.com/music-assistant/server/blob/main/music_assistant/models/provider.py), which handles configuration, logging, and feature checks.
- Features are declared via the **`ProviderFeature`** enum and enforced at runtime using `supports_feature()` and `check_feature()`.
- **Music providers** synchronize libraries using `sync_library()` and track deletions via cache categories like `CACHE_CATEGORY_PREV_LIBRARY_IDS`.
- **Player providers** manage device lifecycles through `discover_players()` and the `players` property, with optional group player support.
- **Metadata providers** enrich content based on priority ordering, with the first successful result winning.
- New integrations require only a concrete subclass, a manifest JSON file, and proper feature declaration.

## Frequently Asked Questions

### What is the difference between a Music Provider and a Metadata Provider in Music Assistant?

A **Music Provider** supplies the actual catalog of media items (artists, albums, tracks) and handles library synchronization, while a **Metadata Provider** only enriches existing items with supplemental data like cover art, descriptions, or recommendations. Music providers are the source of truth for media existence, whereas metadata providers enhance information about items already in the system.

### How does Music Assistant determine which provider method to call?

Music Assistant checks the **`supported_features`** set exposed by each provider instance. Before calling methods like `get_similar_tracks()` or `create_group_player()`, the core code verifies that the provider declares the corresponding `ProviderFeature` enum value. If the feature is missing, the system either skips the call or catches the `NotImplementedError` raised by the base class.

### What files must I create to implement a new provider in Music Assistant?

You must create a Python class inheriting from the appropriate base (`MusicProvider`, `PlayerProvider`, or `MetadataProvider`) and place it in the `providers/` directory. Additionally, you need a [`manifest.json`](https://github.com/music-assistant/server/blob/main/manifest.json) file declaring the provider's domain, type, and features. The base class in [`music_assistant/models/provider.py`](https://github.com/music-assistant/server/blob/main/music_assistant/models/provider.py) handles configuration and logging automatically.

### How does the Metadata Provider priority system work?

Each **Metadata Provider** declares a `priority` attribute. When Music Assistant needs enrichment data (such as album artwork), it queries providers in descending order of priority. The first provider that returns a non-`None` result wins, and subsequent providers are skipped. This allows high-priority sources (like local databases) to override lower-priority remote services.