How the FastMCP Server Provider Works for MCP Integration in Music Assistant

The FastMCP Server Provider exposes Music Assistant's internal APIs as a Music Control Protocol (MCP) service by wrapping the FastMCP library in an async HTTP/ASGI server with JWT authentication and tag-based permissions.

The FastMCP server provider in the music-assistant/server repository bridges Music Assistant's Python core with external clients through the Music Control Protocol (MCP). This provider transforms the application's media management and playback capabilities into discoverable, secured endpoints that home automation systems and remote controllers can consume.

Core Architecture Components

MCPServerProvider Entry Point

Located in music_assistant/providers/fastmcp_server/provider.py, the MCPServerProvider class extends PluginProvider. It acts as the lifecycle manager that Music Assistant instantiates during startup, delegating setup, start, and stop events to the underlying runtime while maintaining a reference to the main MusicAssistant (mass) instance.

MCPServerRuntime

The MCPServerRuntime class in server.py wraps a FastMCP FastMCP instance. It mounts sub-servers for library, player, media, config, and debug functionality, then serves the ASGI application. During initialization, it calls build_tag_lookup to construct the permission mapping used by the middleware.

HTTP Bridge for Discovery

The http_bridge.py module provides the mount_into_mass function, which mounts the MCP well-known endpoint (/.well-known/mcp) into Music Assistant's main web server. This enables automatic service discovery, allowing clients to retrieve the MCP URL without hard-coding addresses.

Tools and Resources

Sub-servers expose specific domain functionality through individual FastMCP tools:

Resource classes in resources/player_resources.py and resources/library_resources.py serialize internal Music Assistant objects into MCP-compliant JSON schemas.

Security Layer

The TagFilterMiddleware in middleware.py enforces permissions using tags defined in tags.py. The auth.py module handles JWT token validation, extracting the audience from the Authorization: Bearer … header to determine client identity.

Lifecycle Flow

The FastMCP server provider follows a strict lifecycle managed by the provider pattern:

  1. Initialization: MCPServerProvider(mass, manifest, config) stores the MusicAssistant reference and configuration values from constants.py.

  2. Setup: The provider instantiates MCPServerRuntime, which creates the FastMCP root object, calls build_tag_lookup to map permissions, and registers each sub-server via functions like build_library_server and build_players_server.

  3. Start: The runtime launches the ASGI app in a background task group, beginning TCP socket listening. Simultaneously, http_bridge.mount_into_mass optionally exposes the discovery endpoint.

  4. Request Handling:

    • Authentication: auth.py validates the JWT token and extracts the audience
    • Tag filtering: TagFilterMiddleware checks if the client's enabled_tags set contains required permissions for the requested tool
    • Execution: Valid requests route to the appropriate FastMCP tool, which invokes core APIs like mass.players.play or mass.library.search
  5. Stop: MCPServerRuntime.stop() gracefully closes the listener, cancels pending tasks, and clears the tag-lookup cache.

Tag-Based Permission Model

The permission system uses a declarative mapping in tags.py to restrict endpoint access:


# From tags.py

CONFIG_TO_TAG = {
    "allow_play": {"player", "media"},
    "allow_config": {"config"},
    # Additional mappings...

}

When a request arrives, the middleware looks up the required tags for the requested tool using this mapping. It then verifies that all required tags exist in the client's enabled_tags set. If the client lacks a required tag, the middleware rejects the request with an McpError. This mechanism allows minimal surface exposure to third-party devices while gating privileged operations like configuration changes.

Client Interaction Workflow

A typical client interacts with the FastMCP server provider through the following steps:

  1. Discovery: Perform a GET request to /.well-known/mcp to receive JSON containing the mcp_url

  2. Authentication: Include a valid Music Assistant JWT token in the Authorization: Bearer <token> header

  3. Tool Execution: POST to /mcp/v1/player/play with a JSON payload:

    {
      "player_id": "living_room",
      "uri": "track:12345"
    }
  4. Response Handling: FastMCP returns a JSON-encoded result or an McpError object for failed operations

Implementation Example

The following pattern mirrors the internal plugin manager initialization:

from music_assistant import MusicAssistant
from music_assistant.providers.fastmcp_server import MCPServerProvider

async def start_mcp_server():
    mass = MusicAssistant()
    # Load the MCP provider with manifest and configuration

    mcp_provider = MCPServerProvider(
        mass,
        manifest=mass.manifest_registry.get("fastmcp_server"),
        config=mass.config.get("fastmcp_server", {})
    )
    await mcp_provider.setup()
    await mcp_provider.start()

# Graceful shutdown

async def stop_mcp_server():
    await mcp_provider.stop()

Developers rarely invoke the provider directly unless writing custom startup scripts, as Music Assistant's plugin manager handles instantiation automatically.

Summary

  • The FastMCP server provider wraps Music Assistant's APIs in a FastMCP-based ASGI server located in music_assistant/providers/fastmcp_server/
  • Provider lifecycle is managed through MCPServerProvider in provider.py, delegating to MCPServerRuntime in server.py
  • JWT authentication and tag-based permissions secure endpoints via auth.py and TagFilterMiddleware in middleware.py
  • Automatic discovery is enabled through http_bridge.py mounting the /.well-known/mcp endpoint
  • Modular architecture supports discrete tool registration for library, player, media, config, and debug operations
  • Async-first design ensures non-blocking operation within Music Assistant's existing event loop

Frequently Asked Questions

How does the FastMCP server provider authenticate incoming requests?

The provider validates JWT tokens using the auth.py module, which extracts and verifies the token from the Authorization: Bearer … header against the Music Assistant secret. It extracts the audience claim to determine which permission tags apply to the client session.

What is the purpose of the tag-based permission system in MCP integration?

Tags defined in tags.py and enforced by TagFilterMiddleware create a granular access control layer. The CONFIG_TO_TAG dictionary maps configuration keys like allow_play to endpoint categories (e.g., player and media), enabling administrators to restrict clients to specific operations such as playback while denying configuration changes.

How do external clients discover the MCP server endpoint?

The http_bridge.py module mounts a standardized well-known endpoint at /.well-known/mcp that returns a JSON object containing the mcp_url. Clients query this endpoint on the main Music Assistant web server to dynamically discover the service location, eliminating the need for manual URL configuration.

Which Music Assistant features are exposed through the FastMCP server provider?

Sub-servers in the tools/ directory expose comprehensive functionality: library management (search, playlists, tags) via library.py; player control (playback, queues, grouping) via players.py; media resolution and streaming via media.py; runtime configuration via config.py; and system monitoring via debug.py.

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 →