How Provider Requirements Are Resolved and Installed in Music Assistant Server

Music Assistant resolves provider requirements by reading each provider's manifest.json, validating installed packages against declared dependencies in load_provider_module, and automatically installing missing libraries using UV's pip installer before importing the provider module.

Music Assistant treats music providers as self-contained plugins with their own Python dependencies. Understanding how provider requirements are resolved and installed is essential for developers extending the platform or troubleshooting dependency conflicts. The server uses a dynamic runtime resolution system that checks manifests and installs packages on-demand rather than bundling all dependencies upfront.

How Provider Requirements Are Declared

Each provider in the Music Assistant server declares its third-party dependencies in a manifest.json file located in the provider's directory.

The manifest.json Structure

The requirements key contains a list of pip-compatible package strings, typically pinned to specific versions:

{
  "domain": "ytmusic",
  "name": "YouTube Music",
  "requirements": [
    "ytmusicapi==1.4.0",
    "google-auth==2.26.2"
  ]
}

According to the source code, when the core system initializes a provider, it reads this manifest from music_assistant/providers/<domain>/manifest.json before attempting to load the Python module.

Runtime Resolution Pipeline

The resolution process occurs in four distinct phases orchestrated by the load_provider_module function in music_assistant/helpers/util.py.

Step 1: Manifest Loading

When a provider is requested, MusicAssistant (defined in music_assistant/mass.py) retrieves the provider's manifest and extracts the requirements list. This list is passed as the second argument to load_provider_module along with the provider's domain identifier.

Step 2: Dependency Validation

The load_provider_module function iterates over each requirement and verifies installation using importlib.metadata:


# music_assistant/helpers/util.py

import importlib.metadata as metadata

async def load_provider_module(domain: str, requirements: list[str]) -> ModuleType:
    for req in requirements:
        pkg_name = req.split("==")[0]
        try:
            installed_version = metadata.version(pkg_name)
            if installed_version != req.split("==")[1]:
                raise metadata.PackageNotFoundError
        except metadata.PackageNotFoundError:
            # Installation triggered here

            pass

If the package is missing or the version mismatches, the function proceeds to installation.

Step 3: UV Installation

For missing or outdated packages, Music Assistant invokes UV (an extremely fast Python package installer) via subprocess:

cmd = [sys.executable, "-m", "uv", "pip", "install", req]
await subprocess.run(cmd, check=True)

This approach ensures deterministic, fast installations without requiring pre-bundled wheels or manual pip commands from the user.

Step 4: Module Import

Once all requirements are satisfied, the provider module is imported dynamically:

return importlib.import_module(f"music_assistant.providers.{domain}")

The fully initialized module is returned to the caller in music_assistant/mass.py, which then instantiates the provider's main class.

Complete Implementation Example

The following pattern demonstrates how the core system loads a provider with automatic dependency resolution:

from music_assistant.helpers.util import load_provider_module

async def initialize_provider(domain: str, manifest: dict):
    # Extract requirements from the provider manifest

    requirements = manifest.get("requirements", [])
    
    # Resolve and install dependencies, then import module

    provider_mod = await load_provider_module(domain, requirements)
    
    # Instantiate the provider class

    return provider_mod.Provider()

Bulk Dependency Management

For deployment scenarios requiring all provider dependencies upfront, the repository includes scripts/gen_requirements_all.py. This script scans every provider's manifest.json, aggregates the requirements arrays, and writes a consolidated requirements_all.txt file:


# Generate consolidated requirements file

python scripts/gen_requirements_all.py

# Install all provider dependencies at once

uv pip install -r requirements_all.txt

Additionally, scripts/parse_manifest_deps.py assists with CI diff-checking to ensure manifest requirements remain synchronized with the codebase.

Summary

  • Declaration: Provider requirements are declared in manifest.json under the requirements key as pinned pip packages.
  • Resolution: The load_provider_module function in music_assistant/helpers/util.py handles runtime validation using importlib.metadata.
  • Installation: Missing packages are installed using UV (uv pip install) via subprocess calls to ensure speed and reliability.
  • Integration: The resolution pipeline is triggered by MusicAssistant in music_assistant/mass.py during provider initialization.
  • Bulk Operations: Use scripts/gen_requirements_all.py to generate a unified requirements file for all providers.

Frequently Asked Questions

What happens if a provider requirement conflicts with core dependencies?

Music Assistant resolves provider requirements in isolation using UV, which respects the project's Python environment constraints. If a version conflict occurs between a provider's pinned requirement and the core system's dependencies, UV will raise a resolution error during the pip install phase, preventing the provider from loading until the conflict is manually resolved in the manifest.

Can providers specify optional or conditional requirements?

According to the source code analysis, the current implementation requires all entries in the manifest.json requirements array to be installed before the provider module imports. There is no built-in support for optional requirements; all listed packages are treated as mandatory and validated during the load_provider_module execution.

How does Music Assistant handle installation failures?

If the subprocess.run call to uv pip install returns a non-zero exit code (for example, when a package is unavailable or network access is restricted), the check=True parameter raises a CalledProcessError. This exception propagates up to the caller in music_assistant/mass.py, causing the provider initialization to fail gracefully with the error logged for diagnostic purposes.

Where are the installed provider packages stored?

Packages installed by UV are placed in the same Python environment running the Music Assistant server process. Since UV operates within the active virtual environment or system Python (depending on deployment), provider dependencies coexist with core dependencies in sys.path, managed by the standard site-packages directory structure.

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 →