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

> Learn how the FastMCP Server Provider enables Music Assistant MCP integration. Discover its async HTTP/ASGI server, JWT auth, and tag-based permissions for seamless API access.

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

---

**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`](https://github.com/music-assistant/server/blob/main/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`](https://github.com/music-assistant/server/blob/main/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`](https://github.com/music-assistant/server/blob/main/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:

- **Library** ([`tools/library.py`](https://github.com/music-assistant/server/blob/main/tools/library.py)): Catalog browsing, playlists, and tags
- **Player** ([`tools/players.py`](https://github.com/music-assistant/server/blob/main/tools/players.py)): Playback control, volume management, and group operations
- **Media** ([`tools/media.py`](https://github.com/music-assistant/server/blob/main/tools/media.py)): URI resolution and streaming helpers
- **Config** ([`tools/config.py`](https://github.com/music-assistant/server/blob/main/tools/config.py)): Runtime configuration read/write operations
- **Debug** ([`tools/debug.py`](https://github.com/music-assistant/server/blob/main/tools/debug.py)): Live log streaming and health checks

Resource classes in [`resources/player_resources.py`](https://github.com/music-assistant/server/blob/main/resources/player_resources.py) and [`resources/library_resources.py`](https://github.com/music-assistant/server/blob/main/resources/library_resources.py) serialize internal Music Assistant objects into MCP-compliant JSON schemas.

### Security Layer

The **`TagFilterMiddleware`** in [`middleware.py`](https://github.com/music-assistant/server/blob/main/middleware.py) enforces permissions using tags defined in [`tags.py`](https://github.com/music-assistant/server/blob/main/tags.py). The **[`auth.py`](https://github.com/music-assistant/server/blob/main/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`](https://github.com/music-assistant/server/blob/main/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`](https://github.com/music-assistant/server/blob/main/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`](https://github.com/music-assistant/server/blob/main/tags.py) to restrict endpoint access:

```python

# 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:
   ```json
   {
     "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:

```python
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`](https://github.com/music-assistant/server/blob/main/provider.py), delegating to `MCPServerRuntime` in [`server.py`](https://github.com/music-assistant/server/blob/main/server.py)
- **JWT authentication** and **tag-based permissions** secure endpoints via [`auth.py`](https://github.com/music-assistant/server/blob/main/auth.py) and `TagFilterMiddleware` in [`middleware.py`](https://github.com/music-assistant/server/blob/main/middleware.py)
- **Automatic discovery** is enabled through [`http_bridge.py`](https://github.com/music-assistant/server/blob/main/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`](https://github.com/music-assistant/server/blob/main/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`](https://github.com/music-assistant/server/blob/main/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`](https://github.com/music-assistant/server/blob/main/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`](https://github.com/music-assistant/server/blob/main/library.py); player control (playback, queues, grouping) via [`players.py`](https://github.com/music-assistant/server/blob/main/players.py); media resolution and streaming via [`media.py`](https://github.com/music-assistant/server/blob/main/media.py); runtime configuration via [`config.py`](https://github.com/music-assistant/server/blob/main/config.py); and system monitoring via [`debug.py`](https://github.com/music-assistant/server/blob/main/debug.py).