Add MCP-spec-compliant FastMCP server provider v0.3.17#3858
Open
trudenboy wants to merge 31 commits into
Open
Conversation
Contributor
🔒 Dependency Security Report📦 Modified Dependencies
|
| Name | Skip Reason |
|---|---|
| torch | Dependency not found on PyPI and could not be audited: torch (2.11.0+cpu) |
| torchaudio | Dependency not found on PyPI and could not be audited: torchaudio (2.11.0+cpu) |
| ✅ No known vulnerabilities found |
Automated Security Checks
- ✅ Vulnerability Scan: Passed - No known vulnerabilities
- ✅ Trusted Sources: All packages have verified source repositories
- ✅ Typosquatting Check: No suspicious package names detected
⚠️ License Compatibility: Some licenses may not be compatible- ✅ Supply Chain Risk: Passed - packages appear mature and maintained
Manual Review
Maintainer approval required:
- I have reviewed the changes above and approve these dependency updates
To approve: Comment /approve-dependencies or manually add the dependencies-reviewed label.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR introduces a new fastmcp_server plugin provider that exposes Music Assistant functionality (library/queue/playback/players/playlists/volume/media/metadata) as a FastMCP v3 streamable-HTTP MCP server mounted into MA’s existing aiohttp webserver (plus RFC 9728 well-known metadata support).
Changes:
- Add the
music_assistant.providers.fastmcp_serverprovider: runtime composition, ASGI↔aiohttp bridge, auth verifier, tag-based permission filtering, resources, and prompts. - Add a comprehensive
tests/providers/fastmcp_server/suite covering URI parsing, tags/config, origin allowlisting, middleware enforcement, elicitation, and e2e bridge behavior. - Add
fastmcp>=3.2,<4.0to dependency aggregation (requirements_all.txt) and provider manifest requirements.
Reviewed changes
Copilot reviewed 42 out of 44 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/providers/fastmcp_server/init.py | Test package marker for the new provider test suite. |
| tests/providers/fastmcp_server/conftest.py | Shared fixtures + FakeWebserver for bridge/e2e tests. |
| tests/providers/fastmcp_server/test_annotations.py | Verifies tool annotations/destructive/read-only hints across mounted sub-servers. |
| tests/providers/fastmcp_server/test_auth.py | Unit tests for token verification + audience binding behavior. |
| tests/providers/fastmcp_server/test_config_entries.py | Validates provider ConfigEntry schema and defaults. |
| tests/providers/fastmcp_server/test_constants.py | Sanity checks for constants/key sets. |
| tests/providers/fastmcp_server/test_context.py | Ensures Context-based logging/progress paths execute under FastMCP client. |
| tests/providers/fastmcp_server/test_e2e_http.py | End-to-end bridge tests (streaming chunks, DELETE forwarding, well-known). |
| tests/providers/fastmcp_server/test_e2e_smoke.py | Optional smoke test for building full runtime and listing namespaced tools. |
| tests/providers/fastmcp_server/test_elicitation.py | Confirms destructive-tool elicitation flows (accept/decline/disabled). |
| tests/providers/fastmcp_server/test_middleware.py | Validates TagFilterMiddleware blocks hidden tools/resources/prompts. |
| tests/providers/fastmcp_server/test_models.py | Tests brief model adapters (to_brief_*) and paging clamp logic. |
| tests/providers/fastmcp_server/test_origin.py | Tests origin normalization/allowlist and bridge enforcement + RFC9728 metadata. |
| tests/providers/fastmcp_server/test_tags.py | Tests Tag enum + config-to-tag mapping correctness. |
| tests/providers/fastmcp_server/test_uri.py | Tests parsing/validation of library://, player://, queue:// URIs. |
| requirements_all.txt | Adds fastmcp to the aggregated dependency set used in CI installs. |
| music_assistant/providers/fastmcp_server/init.py | Provider entrypoint (setup, get_config_entries). |
| music_assistant/providers/fastmcp_server/auth.py | TokenVerifier delegating to MA auth + optional RFC8707 audience enforcement. |
| music_assistant/providers/fastmcp_server/config.py | Provider configuration schema (server settings + permission toggles + resource toggles). |
| music_assistant/providers/fastmcp_server/constants.py | Defines config keys and key groupings (permissions/resources/hot-swappable). |
| music_assistant/providers/fastmcp_server/http_bridge.py | ASGI↔aiohttp bridge, origin allowlist enforcement, and RFC9728 well-known endpoint mounting. |
| music_assistant/providers/fastmcp_server/manifest.json | Provider manifest (plugin metadata + FastMCP requirement). |
| music_assistant/providers/fastmcp_server/middleware.py | TagFilterMiddleware to filter listings and block direct invocation of disabled components. |
| music_assistant/providers/fastmcp_server/models.py | Brief response dataclasses for tool outputs. |
| music_assistant/providers/fastmcp_server/prompts.py | Registers canned prompts gated by config toggle. |
| music_assistant/providers/fastmcp_server/provider.py | PluginProvider lifecycle wrapper over MCPServerRuntime + config update handling. |
| music_assistant/providers/fastmcp_server/resources/init.py | Resource registration entrypoint gated by config toggles. |
| music_assistant/providers/fastmcp_server/resources/_uri.py | Parser/validator for MCP resource URIs. |
| music_assistant/providers/fastmcp_server/resources/library_resources.py | Registers library://* read-only resources. |
| music_assistant/providers/fastmcp_server/resources/player_resources.py | Registers player://* and queue://* resources. |
| music_assistant/providers/fastmcp_server/server.py | MCPServerRuntime: composes sub-servers, installs middleware, mounts into MA webserver, hot-swap logic. |
| music_assistant/providers/fastmcp_server/tags.py | Tag enum + mapping from permission config keys to tags. |
| music_assistant/providers/fastmcp_server/tools/init.py | Exports sub-server builder functions. |
| music_assistant/providers/fastmcp_server/tools/_common.py | Shared tool helpers (timeouts, paging clamp, brief adapters, confirmation helper). |
| music_assistant/providers/fastmcp_server/tools/library.py | Library query tools (search/list/get) with ToolAnnotations/timeouts. |
| music_assistant/providers/fastmcp_server/tools/media.py | Favorites/library mutation + announcement + played-marking tools. |
| music_assistant/providers/fastmcp_server/tools/metadata.py | Metadata tools (recommendations, recently played, lyrics). |
| music_assistant/providers/fastmcp_server/tools/playback.py | Playback control tools (play/pause/stop/seek/skip/play_media/play_index). |
| music_assistant/providers/fastmcp_server/tools/players.py | Player listing/inspection + power/group control tools. |
| music_assistant/providers/fastmcp_server/tools/playlists.py | Playlist create/add/remove tools with bulk/per-item progress behavior. |
| music_assistant/providers/fastmcp_server/tools/queue.py | Queue querying/mutation tools (active queue, shuffle, clear, transfer). |
| music_assistant/providers/fastmcp_server/tools/volume.py | Volume control tools (set/up/down/mute/group volume). |
| music_assistant/providers/fastmcp_server/icon.svg | Provider icon asset. |
| music_assistant/providers/fastmcp_server/icon_monochrome.svg | Provider monochrome icon asset. |
Merged
3 tasks
3 tasks
trudenboy
added a commit
to trudenboy/ma-provider-mcp
that referenced
this pull request
May 13, 2026
Per Copilot review on music-assistant/server#3858. MA's real _handle_catch_all in helpers/webserver.py matches a "/mcp/v1/*" registration against both the bare /mcp/v1 (no trailing slash) and any descendant — request.path.startswith(prefix). Aiohttp's /{tail:.*} requires the slash, so build_aiohttp_app's test routing silently missed the wizard-advertised MCP entry-point URL that real clients connect to. Add an explicit route for the bare stem alongside the wildcard and a regression test posting to /mcp/v1 (no trailing slash) that asserts the ASGI app is reached. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
FastMCP Server provider v0.3.17
A new plugin provider that exposes Music Assistant as a Model Context Protocol server, accessible to Claude Code, Codex, ChatGPT Apps SDK, and any other MCP-aware LLM client.
Source: trudenboy/ma-provider-mcp
What this adds
library,queue,playback,players,playlists,volume,media,metadata) with 30+ tools, 3 URI-addressable resources (library://,player://,queue://), and canned prompts./mcp/v1; no second port, no changes to MA core.ToolAnnotations, per-tool timeouts,ctx.elicitconfirmation on destructive ops./mcp/v1/connect. Mints a per-client long-lived MA token via the sanctionedauth.revoke_token/auth.get_user_tokens/auth.create_tokenAPI (no direct DB access from the provider) and renders ready-to-paste config for Claude Desktop, Claude Code, Cursor, Windsurf, VSCode, ChatGPT Connectors, Codex CLI, Gemini CLI, Cline, Zed. The flow is idempotent under repeat use: re-generating revokes the prior client token, the bootstrap is single-use, and staleMCP — wizard *rows are GC'd on each open. Ingress-aware end-to-end (reuses the active WS client's forwarded host + path for the wizard URL and the matchingOriginon POST endpoints), so it works out-of-the-box under Home Assistant add-on ingress with no manualextra_allowed_originsconfig.Config
require_authtruemount_path/mcp/v1require_confirmationtrueclear_queue,remove_*); falls through to the permission flag if the client doesn't support elicitation.enforce_audiencefalseextra_allowed_originsOriginheaders to accept in addition tolocalhost/127.0.0.1/ the MAbase_urlhost /publish_ip. Advanced.connect_external_urlhttp://orhttps://. Advanced.res_library/res_player/res_prompts, which rebuild the resource tree).Tests
193 passing unit/integration tests + e2e bridge loop covering: HTTP / streamable transport (both
/mcp/v1bare and/mcp/v1/…),/.well-known/oauth-protected-resource, Connect Wizard endpoints (/connect,/connect/info,/connect/exchange,/connect/login,/connect/token), origin allowlist + ingress auto-accept, override sanitiser, player brief state /current_itemshape, queue lookahead clamp, library-id resolution for media removes, resource template lookup, resource handler JSON serialisation, hot-swap vs restart routing, wizard token lifecycle (bootstrap single-use, server-side name dedup, wizard-row GC, best-effort revoke under failure modes).Live smoke (against
ghcr.io/music-assistant/server:nightly2.9.0.dev2026050614 with this provider mounted)End-to-end manual smoke driven by an MCP-aware LLM client (Claude Code) and
curlJSON-RPC againsthttp://localhost:8095/mcp/v1. Stand had 1 Web player, Yandex Music music provider, ~880 library tracks.media_remove_from_favoritesagainst a Yandex round-trip (server-side mutation completed)library://artist|album|track|playlist/{id},player://{id},queue://{id}*Briefas JSON textfind_and_play,curate_party_playlist,now_playing_summary/.well-known/oauth-protected-resource/<mount>+ bearerWWW-Authenticatecontrol_volumetoggle: 44 → 39 → 44 tools listed, no restartstate,powered,current_itemmatchplayers/getpayload atplayingand post-stop+clear_queueState after the smoke run: baseline restored (player idle, volume 100, queue empty, no leftover playlist / favorite). Server log clean of unexpected
error/traceback.Screenshots