Skip to main content

crates-music-mcp

CI

把你三个音乐 App 的收藏交给 Agent,让它每天替你挑一张对味的歌单。

网易云 · QQ 音乐 · 酷狗 —— 一个 MCP server、28 个工具、一份共享凭证、零原生依赖。

大多数"音乐 MCP"只做一件事:把接口包一层,让模型能搜歌。这个包多做两步—— 先读懂你的耳朵,再替你选歌:

它做什么 具体怎么做的
读 三家「我喜欢 / 收藏」+ 今日推荐全部拉下来,按「歌名 + 歌手」跨平台去重(实测一份池子 1500+ 首)
懂 把候选池交给模型,产出结构化偏好画像:常听歌手、口味、情绪倾向,缓存到本地,下次不用重算
推 按画像权重从池子里挑歌,避开最近 14 天推过的,在目标平台现场搜歌再建单(搜不到就跳过,不硬塞)

全程在你自己机器上跑:没有容器、没有 sidecar、没有云端账号,凭证就是你自己的登录 Cookie。 Windows / Linux 行为一致——三平台的协议都是纯 Python 实现的。

一分钟跑通

推荐:直接从仓库装,不用先克隆:

pip install git+https://github.com/guohangbk/crates-music-mcp.git

如果卡在 Could not connect to server(国内直连 github.com:443 经常被挡),两个办法: 挂代理,或改用 SSH 地址:

pip install "git+ssh://git@github.com/guohangbk/crates-music-mcp.git"

或者克隆下来再装 —— 想改代码、跑自检就用这种:

git clone https://github.com/guohangbk/crates-music-mcp.git   # 连不上就用 git@github.com:guohangbk/crates-music-mcp.git
cd crates-music-mcp
pip install -e .

目前还没发布到 PyPI,所以没有 pip install crates-music-mcp 这条路;上面两种是现在就能用的。

装完得到 4 个命令:

crates-music      # 单 server,全部 27 个工具(默认 stdio)—— 推荐
crates-auth       # 只带登录/凭证工具
crates-profile    # 只带画像工具
crates-playlist   # 只带建单/推荐工具

接到客户端(客户端调用时自动拉起进程,用完即退,不需要常驻、不需要 systemd):

{ "mcpServers": { "music": { "command": "crates-music", "args": [] } } }

Codex 用 TOML:

[mcp_servers.music]
command = "crates-music"
args = []

工具名会带 server 前缀(如 music_create_daily_playlist)。然后就能这样用:

你:看看我最近都听什么,给我建一张今天的歌单
Agent:analyze_music_profile → 画像:偏爱华语流行 + 电子,常听 邓紫棋 / 陈奕迅 / 梁博
       create_daily_playlist(count=40, prompt="今天想安静点")
       → 网易云《20261107-独处时光》40 首 / QQ音乐 40 首 / 酷狗 40 首

28 个工具

登录与凭证(8) login_methods · login_start · login_poll · login_submit · credential_status · credential_refresh · credential_set_cookie · credential_logout

画像与听歌数据(4) analyze_music_profile · get_profile · save_profile · recent_tracks

歌单、搜索、命名与推荐(16) create_daily_playlist · create_qq_playlist · create_ncm_playlist · create_kugou_playlist · liked_songs · ncm_liked_songs · search_songs · playlist_songs · add_songs_to_playlist · recent_played · suggest_playlist_names · daily_recommendations · my_playlists · delete_playlist · recent_recommended_tracks · qq_recent

三个工具容易混,先分清:

工具 返回什么 不是什么
liked_songs(service) 某平台全部收藏(「我喜欢」全量) 不是统计摘要,也不是"最近听的"
recent_played(service) 用户最近听过的歌(网易云听歌排行 / 酷狗听歌历史) 不是我们推荐过的歌;QQ 暂不支持
recent_recommended_tracks / recent_tracks / qq_recent 我们最近 7 天推荐过的歌(建单去重用) 与用户听歌历史无关(qq_recent 这名字是历史遗留,也不专指 QQ)
suggest_playlist_names 起名素材(今天天气/时段/心情/歌手/年代)+ 3 个候选 + 字数预算 它不建单,也不改任何东西;挑好名字再传给 create_*_playlist

登录

平台 方式
QQ 音乐 phone_code(默认)/ mobile_qr / qq_qr / wx_qr
网易云 phone_code(默认)/ cookie / qr
酷狗 phone_code(默认)/ qr

三端都默认手机验证码(纯文本、不用截图扫码、跨设备零差异):

login_start(service="qq_music", method="phone_code", phone="138...")
   → 用户把验证码输入对话框
login_submit(session_id=..., code="123456")

凭证自动续期:QQ 到期前 6 小时按需刷新,网易云距上次续期超 12 小时主动调 /login/refresh; 跨进程 flock 互斥,保证同一份凭证不会被两个进程同时刷新。

登录会话:有效期按真实值上报,进程重启也能续

  • login_start 返回的 expires_in_seconds 是该平台二维码的真实寿命,不是一刀切的会话 TTL (另有 session_ttl_seconds 表示我们最多留多久):

    方式 实测有效期 依据
    网易云 qr 300 s 291 s 仍回 801、306 s 回 800
    QQ qq_qr / wx_qr 120 s 114 s 仍回 SCAN、131 s 回 TIMEOUT
    QQ mobile_qr 300 s(MQTT 监听窗口) 走推送,没有可询的 HTTP 状态
    酷狗 qr ≥480 s 实测 8 分钟仍可用,上报按会话窗口 600 s
  • 会话落盘(state/login_sessions.json):票据是纯数据的那些(网易云/酷狗的 unikey、 QQ 的 qrsig、验证码登录的 phone)会被持久化,MCP 进程重启后 login_poll 照样能续。 QQ mobile_qr 例外——它的登录结果由 MQTT 推送带回来,错过就没了,必须在当前进程里完成。

生成歌单

create_daily_playlist(count=40)                              # 全平台各建一份
create_daily_playlist(count=100, prompt="今天心情不好")      # 主题自动取心情
create_daily_playlist(include="晴天 - 周杰伦", count=20)     # 点名的歌排最前
  • 候选池 = 所有平台「今日推荐 + 全部收藏」去重,避开最近 7 天推过的(avoid_days 可改,给 0 = 不避)
  • 画像权重选曲:命中 top_artists 的歌 rank=2,命中 mood_tendencies 的 rank=1
  • 每首歌在目标平台现场搜索,找不到就跳过(记进 failed,绝不硬塞一首不相干的)
  • 歌单名见下面「歌单命名」

歌单命名

名字是给用户看的,规则只有两条:指定优先、共鸣优先。

场景 例子 名字怎么来
Agent/用户给了名字 传 playlist_name="我的私藏" 直接用(今日歌单也不加日期)
说了内容 「邓紫棋2020年以前的歌」 20261108-邓紫棋2019以前(歌手 + 年代,从话里抄,不查曲目年份)
说了心情 「今天心情不好」 20261108-心情不好
内容和心情都有 「写代码时听邓紫棋2019以前的歌」 内容优先,装得下就拼上心情:邓紫棋2018以前 · 专注工作流
什么都没说 — 随机抽素材(天气/时段/主题池),不做任何"雨天一定叫雨天窗边"的硬绑定
  • 今日歌单带 8 位日期前缀(20261108-),普通建单不带;名字总长 ≤20 字(所以今日歌单的主题只有 11 字)
  • 超长按素材优先级丢:先丢修饰(心情/场景),保住人名与用户指定词
  • 不做同日强幂等:同一天重跑可以出不同名字;只有"随机来源"会避开最近 5 张用过的名字(开头词也避),避免"连着几天叫一样"
  • 想每天有惊喜:让 agent 自己起名 —— 先调 suggest_playlist_names 拿素材和候选,再传给 create_*_playlist(agent 是 AI,比内置规则更懂"今天该叫什么")

生成过的歌单(连曲目)记在 state/recent_playlist_history.json(最近 100 张,只记日常歌单;手动建单不写)。这个台账是"我们最近推过什么"的唯一来源:去重池和 recent_recommended_tracks 都从它派生。

凭证 vault

数据默认落在用户级目录(不写进安装目录):

文件 内容
secrets/qq_music.json QQ 音乐完整 Credential(含 refresh_token)
secrets/netease.json 网易云 Cookie
secrets/kugou.json 酷狗 Cookie(token + userid)
state/*_liked.json 各平台收藏快照
state/music_prefer_profile.json 偏好画像
state/recent_music_history.json 最近 14 天推荐历史(去重口径)
state/login_sessions.json 未完成的登录会话(可跨进程续,见上)

覆盖路径用 MUSIC_DATA_DIR(一处决定 secrets/ 与 state/)。

三个平台的上游出处

协议不是凭空写的:网易云、酷狗的签名与加密都是照公开实现逐字复刻的,QQ 直接用现成的纯 Python 库。

平台 上游项目 许可
QQ 音乐 L-1124/QQMusicApi(文档) MIT
网易云 NeteaseCloudMusicApiEnhanced/api-enhanced MIT
酷狗 MakcRe/KuGouMusicApi MIT

依赖与自检

运行依赖只有 mcp / qqmusic-api-python / qrcode / Pillow / httpx / uvicorn, 由 pyproject.toml 声明,pip 自动装齐。

自检:

python tests/test_ncm_native.py                # 网易云:AES/RSA/weapi/eapi 与官方向量
NCM_LIVE=1 python tests/test_ncm_native.py     #   再加真实搜索 / 推荐 / 登录态
python tests/test_kugou_native.py              # 酷狗:签名/RSA/AES 与上游 JS 逐字节对拍
KUGOU_LIVE=1 python tests/test_kugou_native.py #   再加真实搜索 / 歌单 / 曲目 / 二维码
python tests/test_login_resumable.py           # 登录会话:有效期 + 跨进程续(含另起进程验证)

项目结构

music_mcp/
├── app.py              入口:起 MCP server(stdio / http 两种传输,4 个命令都走它)
├── servers.py          MCP 工具定义(21 个):校验参数 → 转给业务层 → 结果 JSON 化
├── compose.py          业务编排:画像加权选曲、跨平台建单、最近 14 天去重
├── login.py            登录会话注册表:发号 / 回收 / 落盘(跨进程可续)
├── vault.py            共享凭证库:三个进程共用一份,读-刷新-回写用 flock 互斥
├── paths.py            数据目录(用户级,MUSIC_DATA_DIR 一处覆盖)
├── qr.py               二维码本地渲染 + 127.0.0.1 回环图片服务
└── platforms/
    ├── __init__.py     平台注册表:枚举 ↔ 实现
    ├── qq.py           QQ 音乐 · 平台层(登录流程、收藏/推荐/搜索/建单)
    ├── netease.py      网易云 · 平台层(同上 + Cookie 续期)
    ├── kugou.py        酷狗 · 平台层(同上)
    └── core/           ← 共用底座 + 各平台协议实现(纯 Python 传输层)
        ├── base.py          平台接口 + 通用结构/工具(Song / LoginStart / normalize / dedupe…)
        ├── aes.py           通用 AES-128/192/256(CBC/ECB + PKCS7,标准库实现)
        ├── ncm_crypto.py    网易云 · 参数加密:weapi(双层 AES + 裸 RSA)/ eapi(AES-ECB + md5)
        ├── ncm_native.py    网易云 · 路由与请求:域名、参数、指纹 Cookie、响应归一
        ├── kugou_crypto.py  酷狗 · 签名/加密:md5 盐值签名、两种 RSA、三处 AES、设备指纹
        └── kugou_native.py  酷狗 · 路由与请求:14 条上游接口

一句话分工:

层 负责 不知道的事
core/*_crypto.py 怎么签名:把参数算成上游要的样子 不知道要调哪个接口
core/*_native.py 打哪个请求:URL / 参数 / 头 / 响应 不知道"我喜欢"是什么
platforms/*.py 业务上要干什么:登录编排、收藏、搜索、建单 不碰签名细节
servers.py 对外暴露哪些工具 任何平台差异

新增一个平台 = 一个 x_crypto.py + 一个 x_native.py(放 core/)+ 一个 x.py(放 platforms/), 再加一行注册。

开发

pip install -e .
python tests/test_stdio.py all    # 冒烟:28 个工具
python tests/test_methods.py      # 登录方式目录 + Cookie 导入 + 凭证状态
python tests/test_analyze_all.py  # 三平台画像(需要本地已有凭证)

CI(.github/workflows/ci.yml)在每次 push / PR 跑 离线自检:

跑什么 为什么是离线
test_ncm_native.py(默认不带 NCM_LIVE=1) 密码学对 FIPS-197 / NIST SP 800-38A 官方向量,不需要账号
test_kugou_native.py(默认不带 KUGOU_LIVE=1) 签名/RSA/AES 对上游 JS 的实际输出,参照值已固化进测试
test_theme_naming.py 命名与台账全是本地逻辑(长度上限、指定优先、随机兜底、去重窗口),不需要网络
test_profile_rank.py / test_methods.py / test_poll_fast.py / test_stdio.py 纯本地逻辑与 stdio 协议
打包检查 构建 wheel/sdist,断言 platforms/core/ 与 LICENSE 都在里面

联网那部分(NCM_LIVE=1 / KUGOU_LIVE=1)故意不进 CI:需要真实账号凭证,而且 CI 机房在境外、 访问国内音乐接口不稳定,跑出来是假红。要验联网就看「自检」那一节,在本地跑。

发布(PyPI)

走 Trusted Publishing(OIDC):仓库里不存任何 token,也不需要本地 twine。 一次性配置(三处,拼错任何一处都会得到 invalid-publisher / 401):

  1. PyPI 账号要有 2FA;TestPyPI 是另一套账号,练手前先注册一个。

  2. 两个站点各配一次 pending publisher(项目还不存在时只能走这个入口): 正式 https://pypi.org/manage/account/publishing/、练手 https://test.pypi.org/manage/account/publishing/。

    字段 填什么
    PyPI Project Name crates-music-mcp
    Owner guohangbk
    Repository name crates-music-mcp
    Workflow name publish.yml(文件名,不是 workflow 里的 name: Publish)
    Environment name 正式 pypi,练手 testpypi
  3. 仓库 Settings → Environments 建 pypi 与 testpypi,名字和上表逐字一致。 pypi 可以加 Required reviewers 做人工审批(加了之后自动触发也会停下来等人点)。

每次发版:

# 1) 先改 pyproject.toml 的 version —— PyPI 不允许覆盖同名版本

# 2) 练手(不污染正式包)
gh workflow run publish.yml -f repository=testpypi
pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ crates-music-mcp

# 3) 正式:打 tag + 发 Release(必须是 published,草稿不触发)
git tag v0.1.1 && git push origin v0.1.1
gh release create v0.1.1 --generate-notes

装上之后(发布到 PyPI 后可用):

uvx --from crates-music-mcp crates-music   # 一条命令跑通,不用先建 venv
pip install crates-music-mcp               # 常规装法

许可证

MIT。三个平台的上游实现同样是 MIT——我们只对齐了协议行为、没有复制它们的代码: 网易云/酷狗的签名与加密都是照公开协议自己实现的,QQ 那个库是以依赖形式引入的。

Metadata

Release files for crates-music-mcp 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for crates-music-mcp 0.1.1
File Size Uploaded Provenance Actions
crates_music_mcp-0.1.1.tar.gz 124.0 kB With provenance Details for crates_music_mcp-0.1.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for crates-music-mcp 0.1.1
File Interpreter ABI Platform Actions
crates_music_mcp-0.1.1-py3-none-any.whl Python 3 none any Details for crates_music_mcp-0.1.1-py3-none-any.whl

Total release size: 242.3 kB

Release files / crates_music_mcp-0.1.1.tar.gz

Download URL crates_music_mcp-0.1.1.tar.gz
Size 124.0 kB
Tags Source
SHA-256 checksum
How to use checksums
71c7ed7677d753e8648addebe5a400c9b0c9d8194edf504024c91563804b461a
BLAKE2b-256 checksum
How to use checksums
12fe8a4df23f288049c5784036d6554c47e8174e0a70b5ca3db508a6c8b4adfa
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 8, 2026.

Transparency log

Release files / crates_music_mcp-0.1.1-py3-none-any.whl

Download URL crates_music_mcp-0.1.1-py3-none-any.whl
Size 118.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2dc34081e10ba92a7382ce2da37eadb01c2f8471ae0bb3a928e85d0f43d3cb32
BLAKE2b-256 checksum
How to use checksums
2ca226c893c3501d651b7eccf3bf8c6128cef67b38a33b53b2ac033dca8abce9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 8, 2026.

Transparency log

Security for crates-music-mcp 0.1.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for crates_music_mcp-0.1.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 8, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page