mcpField
S
Spotify MCP Server

Spotify MCP Server

本地服务
github.com/marcelmarais媒体与设计489今天更新

关于 Spotify MCP Server

Spotify MCP 服务,让 Cursor 和 Claude 等 AI 助手通过对话查询音乐并控制播放、管理播放列表。它同时提供曲目、专辑、艺人、播放队列和设备等信息读取工具。

主要功能

  1. 01搜索曲目、专辑、艺人和播放列表
  2. 02读取当前播放与队列信息
  3. 03播放、暂停、恢复和切换曲目
  4. 04创建及编辑播放列表
  5. 05管理收藏曲目与专辑

适用场景

  1. 01根据请求搜索并播放音乐
  2. 02创建主题播放列表并添加曲目
  3. 03查看播放队列或最近播放记录

MCP 相关

该项目实现 MCP 服务,向 MCP 客户端提供 Spotify 搜索、播放控制、播放列表管理及音乐资料读取工具。README 提及可集成 Claude Desktop、Cursor 和 VsCode (Cline)。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

暂未收录安装方式

我们还没有获取到这个服务的安装包或远程地址,请按项目 README 中的说明安装。

代码仓库

工具

还没有获取到工具列表

本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。

详细介绍

README 配图

Spotify MCP 服务

一个轻量级的 模型上下文协议(MCP) 服务,可让 Cursor 和 Claude 等 AI 助手控制 Spotify 播放并管理播放列表。

目录

交互示例

  • “播放 Elvis 的第一首歌”
  • “创建一个融合 Taylor Swift 和 Slipknot 的播放列表”
  • “把我的健身播放列表中的所有电子舞曲曲目复制到工作播放列表”
  • “把音量稍微调低一点”

工具

读取操作
  1. searchSpotify

    • 描述:在 Spotify 上搜索曲目、专辑、艺人或播放列表
    • 参数:
      • query(字符串):搜索词
      • type(字符串):要搜索的项目类型(track、album、artist、playlist)
      • limit(数字,可选):返回结果的最大数量(1-10,默认值:10)
      • offset(数字,可选):要返回的第一个结果的索引(默认值:0)
    • 返回:包含匹配项目 ID、名称和其他详细信息的列表
    • 示例:searchSpotify("bohemian rhapsody", "track", 10)
  2. getNowPlaying

    • 描述:获取 Spotify 当前正在播放的曲目信息,包括设备和音量信息
    • 参数:无
    • 返回:包含曲目名称、艺人、专辑、播放进度、时长、播放状态、设备信息、音量以及随机播放 / 循环播放状态的对象
    • 示例:getNowPlaying()
  3. getMyPlaylists

    • 描述:获取当前用户在 Spotify 上的播放列表
    • 参数:
      • limit(数字,可选):要返回的播放列表最大数量(默认值:20)
      • offset(数字,可选):要返回的第一个播放列表的索引(默认值:0)
    • 返回:包含播放列表 ID、名称、曲目数量和公开状态的数组
    • 示例:getMyPlaylists(10, 0)
  4. getPlaylistTracks

    • 描述:获取指定 Spotify 播放列表中的曲目列表
    • 参数:
      • playlistId(字符串):播放列表的 Spotify ID
      • limit(数字,可选):要返回的曲目最大数量(默认值:100)
      • offset(数字,可选):要返回的第一首曲目的索引(默认值:0)
    • 返回:包含曲目 ID、名称、艺人、专辑、时长和添加日期的数组
    • 示例:getPlaylistTracks("37i9dQZEVXcJZyENOWUFo7")
  5. getRecentlyPlayed

    • 描述:获取 Spotify 上最近播放的曲目列表。
    • 参数:
      • limit(数字,可选):指定要返回的曲目最大数量。
    • 返回:如果找到曲目,则返回格式化的最近播放曲目列表;否则返回消息:“你在 Spotify 上没有最近播放的曲目”。
    • 示例:getRecentlyPlayed({ limit: 10 })
  6. getUsersSavedTracks

    • Description:获取用户“已赞歌曲”库中保存的曲目列表
    • Parameters:
      • limit (number, optional):返回曲目的最大数量(1-50,默认值:50)
      • offset (number, optional):分页偏移量(从 0 开始,默认值:0)
    • Returns:格式化的已保存曲目列表,包含曲目名称、艺人、时长、曲目 ID,以及添加到“已赞歌曲”的时间。显示分页信息(例如,“1-20 of 150”)。
    • Example:getUsersSavedTracks({ limit: 20, offset: 0 })
  7. getQueue

    • Description:获取 Spotify 队列中当前播放的曲目和后续项目
    • Parameters:
      • limit (number, optional):显示的后续项目最大数量(1-50,默认值:10)
    • Returns:当前播放的曲目以及队列中的后续曲目列表
    • Example:getQueue({ limit: 20 })
  8. getAvailableDevices

    • Description:获取用户可用的 Spotify Connect 设备信息
    • Parameters:无
    • Returns:可用设备列表,包含名称、类型、活跃状态、音量和设备 ID
    • Example:getAvailableDevices()
  9. removeUsersSavedTracks

    • Description:从用户的“已赞歌曲”库中移除一首或多首曲目(每次请求最多 40 首)
    • Parameters:
      • trackIds (array):要移除的 Spotify 曲目 ID 数组(最多 40 个)
    • Returns:操作成功确认消息
    • Example:removeUsersSavedTracks({ trackIds: ["4iV5W9uYEdYUVa79Axb7Rh", "1301WleyT98MSxVHPZCA6M"] })
  10. getFollowedArtists

    • Description:获取当前用户关注的艺人
    • Parameters:
      • limit (number, optional):返回艺人的最大数量(1-50,默认值:20)
      • after (string, optional):用于获取下一页的前一次调用游标(最后一个艺人的 ID)
    • Returns:格式化的已关注艺人列表,包含名称和 ID(以及 Spotify 提供的流行度和流派),若还有更多结果,则提供下一页游标
    • Example:getFollowedArtists({ limit: 50 })
播放 / 创建操作
  1. playMusic

    • Description:开始在 Spotify 上播放曲目、专辑、艺人或播放列表
    • Parameters:
      • uri (string, optional):要播放项目的 Spotify URI(优先于 type 和 id)
      • type (string, optional):要播放项目的类型(track、album、artist、playlist)
      • id (string, optional):要播放项目的 Spotify ID
      • deviceId (string, optional):播放所用设备的 ID
    • Returns:成功状态
    • Example:playMusic({ uri: "spotify:track:6rqhFgbbKwnb9MLmUQDhG6" })
    • Alternative:playMusic({ type: "track", id: "6rqhFgbbKwnb9MLmUQDhG6" })
  2. pausePlayback

    • Description:暂停 Spotify 上当前播放的曲目
    • Parameters:
      • deviceId (string, optional):要暂停的设备 ID
    • Returns:成功状态
    • Example:pausePlayback()
  3. resumePlayback

    • Description:在活跃设备上恢复 Spotify 播放
    • Parameters:
      • deviceId (string, optional):要恢复播放的设备 ID
    • Returns:成功状态
    • Example:resumePlayback()
  4. skipToNext

    • Description:跳到当前播放队列中的下一首曲目
    • Parameters:
      • deviceId (string, optional):设备 ID
    • Returns:成功状态
    • Example:skipToNext()
  5. skipToPrevious

    • Description:跳到当前播放队列中的上一首曲目
    • Parameters:
      • deviceId (string, optional):设备 ID
    • Returns:成功状态
    • Example:skipToPrevious()
  6. createPlaylist

    • 描述:在 Spotify 上创建新播放列表
    • 参数:
      • name (string):新播放列表的名称
      • description (string, optional):播放列表的描述
      • public (boolean, optional):播放列表是否公开(默认值:false)
    • 返回值:包含新播放列表 ID 和 URL 的对象
    • 示例:createPlaylist({ name: "Workout Mix", description: "Songs to get pumped up", public: false })
  7. addTracksToPlaylist

    • 描述:向现有 Spotify 播放列表添加曲目
    • 参数:
      • playlistId (string):播放列表 ID
      • trackUris (array):要添加的曲目 URI 或 ID 数组
      • position (number, optional):插入曲目的位置
    • 返回值:成功状态和快照 ID
    • 示例:addTracksToPlaylist({ playlistId: "3cEYpjA9oz9GiPac4AsH4n", trackUris: ["spotify:track:4iV5W9uYEdYUVa79Axb7Rh"] })
  8. addToQueue

    • 描述:将曲目、专辑、艺人或播放列表添加到当前播放队列
    • 参数:
      • uri (string, optional):要添加到队列的项目的 Spotify URI(优先于 type 和 id)
      • type (string, optional):要加入队列的项目类型(track、album、artist、playlist)
      • id (string, optional):要加入队列的项目的 Spotify ID
      • deviceId (string, optional):要添加队列的设备 ID
    • 返回值:成功状态
    • 示例:addToQueue({ uri: "spotify:track:6rqhFgbbKwnb9MLmUQDhG6" })
    • 替代方式:addToQueue({ type: "track", id: "6rqhFgbbKwnb9MLmUQDhG6" })
  9. setVolume

    • 描述:将播放音量设置为指定百分比(需要 Spotify Premium)
    • 参数:
      • volumePercent (number):要设置的音量(0-100)
      • deviceId (string, optional):要设置音量的设备 ID
    • 返回值:成功状态及新的音量级别
    • 示例:setVolume({ volumePercent: 50 })
  10. adjustVolume

  • 描述:按相对幅度调高或调低播放音量(需要 Spotify Premium)
  • 参数:
    • adjustment (number):音量调整幅度(-100 到 100)。正值表示调高音量,负值表示调低音量。
    • deviceId (string, optional):要调整音量的设备 ID
  • 返回值:显示音量变化的成功状态(例如,“音量从 50% 调高到 60%”)
  • 示例:adjustVolume({ adjustment: 10 })(调高 10%)
  • 示例:adjustVolume({ adjustment: -20 })(调低 20%)
专辑操作
  1. getAlbums

    • 描述:根据 Spotify ID 获取一个或多个专辑的详细信息
    • 参数:
      • albumIds(string|array):单个专辑 ID 或专辑 ID 数组(最多 20 个)
    • 返回:专辑详细信息,包括名称、艺人、发行日期、类型、曲目总数和 ID。查询单张专辑时返回详细视图,查询多张专辑时返回摘要列表。
    • 示例:getAlbums("4aawyAB9vmqN3uQ7FjRGTy") 或 getAlbums(["4aawyAB9vmqN3uQ7FjRGTy", "1DFixLWuPkv3KT3TnV35m3"])
  2. getAlbumTracks

    • 描述:获取指定专辑中的曲目,支持分页
    • 参数:
      • albumId(string):专辑的 Spotify ID
      • limit(number,可选):要返回的曲目数量上限(1-50)
      • offset(number,可选):分页偏移量(从 0 开始计数)
    • 返回:专辑中的曲目列表,包含曲目名称、艺人、时长和 ID,并显示分页信息。
    • 示例:getAlbumTracks("4aawyAB9vmqN3uQ7FjRGTy", 10, 0)
  3. saveOrRemoveAlbumForUser

    • 描述:在用户的“你的音乐”收藏库中保存或移除专辑
    • 参数:
      • albumIds(array):Spotify 专辑 ID 数组(最多 20 个)
      • action(string):要执行的操作:“save”或“remove”
    • 返回:成功状态及确认消息
    • 示例:saveOrRemoveAlbumForUser(["4aawyAB9vmqN3uQ7FjRGTy"], "save")
  4. checkUsersSavedAlbums

    • 描述:检查专辑是否已保存在用户的“你的音乐”收藏库中
    • 参数:
      • albumIds(array):要检查的 Spotify 专辑 ID 数组(最多 20 个)
    • 返回:每张专辑的状态(已保存或未保存)
    • 示例:checkUsersSavedAlbums(["4aawyAB9vmqN3uQ7FjRGTy", "1DFixLWuPkv3KT3TnV35m3"])
播放列表操作
  1. getPlaylist

    • 描述:获取指定 Spotify 播放列表的详细信息,包括曲目数量、描述和所有者
    • 参数:
      • playlistId(字符串):播放列表的 Spotify ID
    • 返回:播放列表名称、所有者、曲目数量、可见性、描述、ID 和 URL
    • 示例:getPlaylist({ playlistId: "37i9dQZEVXcJZyENOWUFo7" })
  2. updatePlaylist

    • 描述:更新 Spotify 播放列表的详细信息(名称、描述、公开/私密、协作)
    • 参数:
      • playlistId(字符串):播放列表的 Spotify ID
      • name(字符串,可选):播放列表的新名称
      • description(字符串,可选):播放列表的新描述
      • public(布尔值,可选):播放列表是否应设为公开
      • collaborative(布尔值,可选):播放列表是否应设为协作(要求 public 为 false)
    • 返回:操作成功确认及已更新字段列表
    • 示例:updatePlaylist({ playlistId: "3cEYpjA9oz9GiPac4AsH4n", name: "New Name", public: true })
  3. removeTracksFromPlaylist

    • 描述:从 Spotify 播放列表中移除一首或多首曲目(每次请求最多 100 首)
    • 参数:
      • playlistId(字符串):播放列表的 Spotify ID
      • trackIds(数组):要移除的 Spotify 曲目 ID 数组(最多 100 个)
      • snapshotId(字符串,可选):播放列表快照 ID,用于指定目标版本
    • 返回:操作成功确认及已移除的曲目数量
    • 示例:removeTracksFromPlaylist({ playlistId: "3cEYpjA9oz9GiPac4AsH4n", trackIds: ["4iV5W9uYEdYUVa79Axb7Rh"] })
  4. reorderPlaylistItems

    • 描述:通过将 Spotify 播放列表中的一段曲目移至新位置来调整顺序
    • 参数:
      • playlistId(字符串):播放列表的 Spotify ID
      • rangeStart(数字):要移动的第一项的位置(索引从 0 开始)
      • insertBefore(数字):要插入项目的位置(索引从 0 开始)
      • rangeLength(数字,可选):要移动的连续项目数量(默认为 1)
      • snapshotId(字符串,可选):播放列表快照 ID,用于指定目标版本
    • 返回:操作成功确认及移动详情
    • 示例:reorderPlaylistItems({ playlistId: "3cEYpjA9oz9GiPac4AsH4n", rangeStart: 2, insertBefore: 0 })

设置

前置条件
  • 最新的 Node.js Current 版本(当前为 v26.8.1;不支持较旧的发布版本系列)
  • Spotify Premium 账户
  • 已注册的 Spotify Developer 应用
安装
git clone https://github.com/marcelmarais/spotify-mcp-server.git
cd spotify-mcp-server
npm ci
npm run build
创建 Spotify Developer 应用
  1. 前往 Spotify Developer Dashboard
  2. 使用 Spotify 账户登录
  3. 点击“Create an App”按钮
  4. 填写应用名称和描述
  5. 接受服务条款并点击“Create”
  6. 在新应用的控制面板中,找到 Client ID
  7. 点击“Show Client Secret”以显示 Client Secret
  8. 点击“Edit Settings”并添加 Redirect URI(例如,http://127.0.0.1:8888/callback)
  9. 保存更改
Spotify API 配置

在项目根目录中创建 spotify-config.json 文件(可以复制并修改提供的示例):

# Copy the example config file
cp spotify-config.example.json spotify-config.json

然后使用你的凭据编辑该文件:

{
  "clientId": "your-client-id",
  "clientSecret": "your-client-secret",
  "redirectUri": "http://127.0.0.1:8888/callback"
}
身份验证流程

Spotify API 使用 OAuth 2.0 进行身份验证。请按照以下步骤验证应用:

  1. 运行身份验证脚本:
npm run auth
  1. 脚本将生成一个授权 URL。在 Web 浏览器中打开此 URL。

  2. 系统会提示你登录 Spotify 并授权应用。

  3. 授权后,Spotify 会将你重定向到指定的重定向 URI,并在 URL 中附带一个 code 参数。

  4. 身份验证脚本会自动使用此 code 换取访问令牌和刷新令牌。

  5. 这些令牌会保存到 spotify-config.json 文件中,文件内容将类似于:

{
  "clientId": "your-client-id",
  "clientSecret": "your-client-secret",
  "redirectUri": "http://localhost:8888/callback",
  "accessToken": "BQAi9Pn...kKQ",
  "refreshToken": "AQDQcj...7w",
  "expiresAt": 1677889354671
}

注意:expiresAt 字段是一个 Unix 时间戳(以毫秒为单位),表示访问令牌的过期时间。

  1. 自动刷新令牌:访问令牌过期时(通常在 1 小时后),服务会自动刷新令牌。刷新过程会使用 refreshToken 自动完成,因此你无需手动重新进行身份验证。如果刷新失败,则需要再次运行 npm run auth 进行身份验证。

与 Claude Desktop、Cursor 和 VsCode 集成[通过 Cline model extension]

若要将 MCP 服务用于 Claude Desktop,请将其添加到 Claude 配置中:

{
  "mcpServers": {
    "spotify": {
      "command": "node",
      "args": ["spotify-mcp-server/build/index.js"]
    }
  }
}

对于 Cursor,请前往 Cursor Settings 中的 MCP 选项卡(command + shift + J)。使用以下命令添加服务:

node path/to/spotify-mcp-server/build/index.js

若要正确设置 Cline 的 MCP,请确保 cline_mcp_settings.json 文件配置如下:

{
  "mcpServers": {
    "spotify": {
      "command": "node",
      "args": ["~/../spotify-mcp-server/build/index.js"],
      "autoApprove": ["getListeningHistory", "getNowPlaying"]
    }
  }
}

你可以将其他工具添加到自动批准数组中,以便无需干预即可运行这些工具。

Streamable HTTP

服务默认使用 stdio。若要运行一个可供多个 MCP 客户端通过 HTTP 连接的长期进程,请设置 MCP_TRANSPORT=http:

MCP_TRANSPORT=http MCP_HTTP_PORT=3000 node path/to/spotify-mcp-server/build/index.js

客户端随后可连接到 http://127.0.0.1:3000/mcp。MCP_HTTP_PORT 默认值为 3000,MCP_HTTP_HOST 默认值为 127.0.0.1。在环回地址上,如果请求的 Host 或 Origin 标头指定的地址不是 localhost、127.0.0.1、[::1]、MCP_HTTP_HOST 或绑定地址,请求将被拒绝,以防止 DNS 重绑定。该端点没有身份验证,因此只有在其他地址前方配置了可提供身份验证的服务时,才应绑定到该地址。

OAuth(MCPHub 和其他支持 OAuth 的客户端)

除了设置 MCP_TRANSPORT=http,还要设置 MCP_AUTH=spotify。此时,服务会作为受 OAuth 保护的 MCP 端点(RFC 9728)运行,其授权服务器就是 Spotify:

MCP_TRANSPORT=http MCP_HTTP_PORT=3000 MCP_AUTH=spotify node path/to/spotify-mcp-server/build/index.js
  • 不带 Authorization: Bearer 标头的 POST /mcp 请求会返回 401,并附带指向 /.well-known/oauth-protected-resource 的 WWW-Authenticate 质询。
  • 该元数据文档会将 https://accounts.spotify.com 列为授权服务器(并在 scopes_supported 下列出完整的必需 scope 集合),因此支持 OAuth 的客户端(例如 MCPHub)会发现 Spotify,在浏览器中执行授权码流程,然后使用签发的访问令牌重新连接。
  • Bearer 令牌会在每个请求中用作 Spotify 访问令牌,且不会写入 spotify-config.json——无需运行 npm run auth,也不会存储刷新令牌或设置令牌刷新计时器。客户端轮换令牌时会透明处理。
  • 每个新令牌首次收到请求时(即令牌轮换时),服务都会向 Spotify 验证该令牌(GET /me),并缓存验证结果。如果 Spotify 拒绝该令牌,服务会返回 401,并附带 WWW-Authenticate: Bearer error="invalid_token",以便客户端知道需要重新授权。令牌不会被永久信任:如果 Spotify 后续在已验证令牌的工具调用中返回 401(令牌过期或被撤销),服务会从验证缓存中移除该令牌;下一个请求会重新执行 /me 检查,而不是复用过期结果。Spotify 签发的是不透明令牌(没有 JWKS,也没有公开的内省端点),因此在没有客户端密钥的情况下,/me 检查是最有力的验证方式——它能证明该令牌可用于 Spotify,但无法验证该令牌是否是为此应用签发的(这需要客户端密钥,而此模式有意不持有该密钥)。
  • 此模式不需要 spotify-config.json。stdio 模式不变,仍使用配置文件。

环境变量:

变量默认值用途
MCP_AUTH未设置(stdio/配置文件模式)设置为 spotify 可在 HTTP 传输中启用 Bearer 令牌身份验证
SPOTIFY_RESOURCE_URL根据绑定主机/端口推导受保护资源元数据中的 resource 值。如果服务通过其他地址访问(反向代理、Docker 端口映射),请将其设为 MCP 客户端使用的公开 URL。
SPOTIFY_AUTHORIZATION_SERVERShttps://accounts.spotify.com元数据中的授权服务器 URL,以逗号分隔。

一次性 Spotify 应用设置(与其他流程使用同一控制面板):添加 MCP 客户端用于回调的重定向 URI(例如,本地 MCPHub 控制面板使用 http://127.0.0.1:3000/oauth/callback——Spotify 会拒绝新应用使用 localhost 重定向 URI,因此请使用 127.0.0.1 或 HTTPS URL),并将客户端 ID复制到客户端的 OAuth 配置中。Spotify 不支持动态客户端注册,因此必须手动提供客户端 ID。只有使用 client_secret_basic/client_secret_post 交换授权码的客户端才需要客户端密钥。

请求元数据 scopes_supported 中公布的完整 scope 集合(15 个 scope);如果客户端请求的 scope 较少,需要缺失 scope 的工具将会失败并返回 403。

MCPHub 配置示例:

{
  "mcpServers": {
    "spotify": {
      "type": "streamable-http",
      "url": "http://127.0.0.1:3000/mcp",
      "oauth": {
        "clientId": "your-spotify-client-id",
        "authorizationEndpoint": "https://accounts.spotify.com/authorize",
        "tokenEndpoint": "https://accounts.spotify.com/api/token",
        "redirectUri": "http://127.0.0.1:3000/oauth/callback",
        "scopes": [
          "user-read-private",
          "user-read-email",
          "user-read-playback-state",
          "user-modify-playback-state",
          "user-read-currently-playing",
          "user-read-playback-position",
          "playlist-read-private",
          "playlist-read-collaborative",
          "playlist-modify-private",
          "playlist-modify-public",
          "user-library-read",
          "user-library-modify",
          "user-read-recently-played",
          "user-top-read",
          "user-follow-read"
        ],
        "resource": "http://127.0.0.1:3000"
      }
    }
  }
}
Docker(MCPHub 推荐)

此代码仓库提供了一个 Dockerfile(多阶段构建,node:26-alpine,使用非特权用户)和一个 docker-compose.yml,可在内部 Docker 网络中以受 OAuth 保护的 Streamable HTTP 模式运行服务。不会发布任何主机端口,因此该服务不会暴露在主机的外部接口上;只有位于同一 Docker 网络中的 MCPHub 容器才能通过 http://spotify-mcp:3000/mcp 访问它。只需让 MCPHub 仪表盘/回调 URL 可从公网访问,因为 Spotify 的 redirect_uri 指向 MCPHub。

此镜像不需要客户端密钥、刷新令牌或 spotify-config.json。

  1. 构建并启动服务:

    docker compose up -d --build
    
  2. 在 Spotify Developer Dashboard 中,将 MCPHub 回调 URL 添加为应用的重定向 URI(例如,本地运行 MCPHub 时使用 http://127.0.0.1:3000/oauth/callback——Spotify 会拒绝新应用使用 localhost 重定向 URI——或者使用已部署的 MCPHub 仪表盘域名),并复制 客户端 ID。

  3. 将 MCPHub 连接到该服务。将 url 指向 Docker DNS 名称,并将 resource 设为相同值(该值必须与服务在受保护资源元数据中公布的 SPOTIFY_RESOURCE_URL 一致):

    {
      "mcpServers": {
        "spotify": {
          "type": "streamable-http",
          "url": "http://spotify-mcp:3000/mcp",
          "oauth": {
            "clientId": "your-spotify-client-id",
            "authorizationEndpoint": "https://accounts.spotify.com/authorize",
            "tokenEndpoint": "https://accounts.spotify.com/api/token",
            "redirectUri": "http://127.0.0.1:3000/oauth/callback",
            "scopes": [
              "user-read-private",
              "user-read-email",
              "user-read-playback-state",
              "user-modify-playback-state",
              "user-read-currently-playing",
              "user-read-playback-position",
              "playlist-read-private",
              "playlist-read-collaborative",
              "playlist-modify-private",
              "playlist-modify-public",
              "user-library-read",
              "user-library-modify",
              "user-read-recently-played",
              "user-top-read",
              "user-follow-read"
            ],
            "resource": "http://spotify-mcp:3000"
          }
        }
      }
    }
    

    两个 spotify-mcp 容器必须共享一个 Docker 网络。如果 MCPHub 已在自己的 compose 堆栈中运行,请将它们接入同一网络:在 MCPHub 服务中添加该网络,并在两个 compose 文件中将共享网络声明为 external: true。

    MCPHub 服务(mcphub compose 文件):

    services:
      mcphub:
        networks:
          - mcphub          # its own network (from its existing file)
          - spotify-mcp     # join the Spotify MCP network
    networks:
      spotify-mcp:
        external: true      # the network is created by the other stack
    

    或者,如果你自行管理两者,请使用 docker network create spotify-mcp 创建一次网络,并在两个 compose 文件中将其标记为 external: true——包括此文件中的 spotify-mcp 网络定义——这样两个堆栈都不会尝试创建它。

  4. 在 MCPHub 中,首次调用会在浏览器中触发 Spotify 授权流程;MCPHub 会存储令牌并自动轮换。

如果 MCPHub 通过其他地址(另一台主机、反向代理)访问服务,请在 .env 中将 SPOTIFY_RESOURCE_URL 设为该 URL,并在 MCPHub 的 oauth.resource 中设置相同的值。

容器镜像

CI 工作流会在 lint、类型检查和测试通过后构建 linux/amd64 和 linux/arm64 镜像。拉取请求只会触发构建;推送到默认分支以及在该分支上手动运行时会发布到 ghcr.io/<repository-owner>/<repository-name>(小写),并使用 latest 和 sha-<full-commit-SHA> 标签。对于不可变部署,请固定镜像摘要。

发布时会使用自动生成的 GITHUB_TOKEN,并授予 packages: write 权限;无需个人访问令牌。如果新建的 fork 提示启用 Actions,请按提示操作。首次发布后,请在 Package settings → Change visibility 中将软件包设为公开,以允许匿名拉取。新的 GHCR 软件包默认是私有的(GitHub 文档)。镜像在 /app/LICENSE 中包含上游 MIT 许可证。

开发

该服务使用 MCP TypeScript SDK v2 和 Zod 4,在支持旧版 MCP 客户端的同时提供协议修订版本 2026-07-28。仅支持最新的 Node.js Current 版本(最低为 v26.8.1)。CI 使用最新的 Current 版本。使用 npm ci 安装锁定的依赖项。

npm run lint
npm run typecheck
npm test

测试会使用模拟的 HTTP 响应,测试 MCP 初始化、工具发现、验证和 Spotify 操作。测试无需 Spotify 凭据,也不会更改你的 Spotify 账户。

许可证

依据 MIT 许可证授权。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。