NetEase Music MCP Safe
Connects to a NetEase Cloud Music account to read music data and curate playlists: daily recommendations, play rankings and recent play history with timestamps, song details, playlist browsing, and podcast discovery/reading, plus optional bounded write tools (create/rename/update playlists, add/remove/reorder songs) with idempotency and audit logging, and optional local playback control of the official NetEase Cloud desktop client.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@NetEase Music MCP Safecurate a 12-song evening walk playlist from today's daily recommendations"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
NetEase Music MCP Safe
把平台给出的零散推荐,整理成真正属于一个人的每日聆听体验。
An MCP server that connects ChatGPT and Codex to a NetEase Cloud Music account for music discovery, listening-context analysis, playlist curation, podcast reading, and carefully bounded account writes.
netease-music-mcp-safe 默认只读,可选开启经过校验、审计和幂等保护的写入能力;它让
调用模型读取音乐上下文、解释选择,并把确认后的策展结果安全地写回个人账户。
一眼看懂: 16 music read tools + 4 session tools + 12 write tools + 4 optional Mac tools + 9 optional iPhone tools · 日推 / 播放排行 / 近期播放 · 每日策展工作流 · 播客读取 · OAuth 2.1 + PKCE · 自动登录态管理 · 165 项测试
项目身份: 这是一个个人维护的独立开源项目,派生自 Vael-KY/netease-music-mcp,并继续演进自 Rainlxyl/netease-music-mcp-safe,依据 MIT License 发布;iPhone “一起听”协议形状参考了 MIT 许可的 NeteaseCloudMusicApiEnhanced/api-enhanced。 项目与网易公司没有隶属、合作或背书关系。它使用未公开的网易云 Web 接口,上游行为可能 变化;部署者有责任保护自己的凭据。另见 Security Policy 与 Third-party notices。
What can I do with it?
Curate today's recommendations
一次典型的每日策展会:
用
daily_recommend读取当天推荐;用
get_play_history了解长期偏好;用
get_recent_plays读取近期状态;由调用模型结合长期偏好、近期收听和
played_at_local设计主题、选择理由与曲序;用一次
create_curated_playlist调用创建并核验最终歌单。
可以这样对 ChatGPT 或 Codex 说:
请读取我今天的日推、长期播放排行和最近播放,从日推中策划一张 10–15 首的夜间散步 歌单。结合
played_at_local理解我最近的收听状态,解释选择和曲序,再用一个新的幂等键 一次创建歌单。不要复述原始播放记录。
Understand a podcast program
可以搜索播客或节目、列出订阅与节目单,并用 get_podcast_program 或
get_podcast_program_details 补全单期元数据。示例:
找出这个主题相关的播客节目,比较标题、节目简介与发布时间,并明确区分公开播放统计和 我的个人收听数据;如果上游没有个人进度或播放次数,不要猜测。
Inspect or manage playlists
可以列出自己的歌单、分页读取歌曲,并在明确开启写权限后创建歌单、更新名称或简介、增删和 重排歌曲。示例:
先列出我拥有的歌单并说明准备修改哪一张;只在我确认后更新简介,不要改变歌曲顺序。
在 MCP 运行于 macOS 且显式启用 MCP_MAC_PLAYBACK_ENABLED=true 时,同一服务还会注册四个
本地附加工具,用于按搜索结果中的歌曲 ID 播放、检查官方网易云客户端状态、播放/暂停、上一首、
下一首和设置 Mac 输出音量;它们不会启动第二个 MCP 服务。
设置 MCP_MOBILE_PLAYBACK_ENABLED=true 后,同一服务还可用一个独立控制账号加入或创建
原生“一起听”房间,让登录日常账号的 iPhone 官方网易云 App 接收指定歌曲、播放、暂停和
进度命令。两个账号的 session 都留在同一进程和 SQLite 中;不会启动第二个 MCP。推荐让
iPhone 发起房间,再把官方邀请交给 join_mobile_netease_player;服务端不会把“加入请求
成功”误报成“手机已经播放”。
Related MCP server: Apple Music Remote MCP
架构概览
flowchart TB
Client["ChatGPT / Codex"]
Auth["OAuth 2.1 + PKCE<br/>or Bearer authentication"]
MCP["NetEase Music MCP<br/>one deployment = one private owner"]
Cookie["NETEASE_COOKIE<br/>optional compatibility fallback"]
Session["Primary account session<br/>music data and normal tools"]
Controller["Optional controller session<br/>iPhone Listen Together join or host"]
API["Unofficial NetEase Web API"]
SQLite["Persistent SQLite<br/>NetEase session / audit / notes / idempotency"]
Timezone["MCP_DEFAULT_TIMEZONE<br/>user-facing time context"]
Mac["Official NeteaseMusic.app<br/>optional local playback tools"]
IPhone["Official iPhone NetEase Music app<br/>different daily account"]
Region["Deployment region<br/>does not select user-facing timezone"]
Client --> Auth --> MCP
Cookie --> Session --> MCP
Controller --> MCP
MCP --> API
Session <--> SQLite
Controller <--> SQLite
MCP --> SQLite
MCP -. optional, same process .-> Mac
MCP -. optional native Listen Together room .-> IPhone
Timezone --> MCP
Region -. does not determine .-> Timezone推荐流程由二维码登录产生 runtime session,并存入持久 SQLite;NETEASE_COOKIE 只作为旧部署
兼容 fallback。SQLite 因此属于敏感数据,备份和卷访问权限应按凭据处理。面向用户的本地时间
由 MCP_DEFAULT_TIMEZONE 决定,部署地区或主机时区不会替用户选择日期语境。
Quick Start
Fork 或 clone 本仓库。
挂载持久卷并设置
MCP_STORAGE_PATH,连接 MCP 后运行start_netease_qr_login,打开返回的 临时login_url,用网易云 App 扫码确认。网页会自动显示状态,成功后 session 自动持久化。以
.env.example为配置清单填写自己的环境变量。仓库中的示例只有 placeholder;真实.env和 secrets 绝对不能 commit。本服务不会自动加载.env,请通过 shell、进程 管理器或部署平台把变量导入进程环境。第一次运行保持
MCP_READ_ONLY=true,先验证搜索、歌单、历史、日推和播客读取。按下文在本地运行,或部署到你自己的 Zeabur service;需要写入时,先理解写权限、持久 SQLite 和不可逆操作,再显式设置
MCP_READ_ONLY=false。最后连接 ChatGPT 或 Codex,并在修改工具 schema 或 OAuth scope 后刷新连接。
详细参数、运行命令和部署步骤见配置与本地运行、 部署到 Zeabur和连接 ChatGPT 与 Codex。
账户模型与安全分享
当前架构:one deployment → one private owner。
常规音乐工具只使用一个 deployment-level 主账号 session:优先使用 SQLite 中已持久化的有效
runtime session,再回退到 server process 启动时读取的 NETEASE_COOKIE。启用 iPhone 控制
时,同一 deployment 可额外保存一个用途受限的控制账号 session;它只负责加入或主持“一起听”,且
必须与 iPhone 上的日常主账号不同。OAuth 或 Bearer authentication 控制的是“谁能访问这个
MCP deployment”,不是为每位访问者建立独立网易云登录的多租户系统。
因此:
不建议多人共享同一个私人 deployment;
分享项目时应分享 GitHub repository,而不是自己的 MCP password、Bearer token 或
NETEASE_COOKIE;朋友或其他使用者应部署自己的实例,并通过自己的网易云 App 扫码登录;
如果多人获得同一部署的访问权,他们实际访问和可能修改的是该部署所配置的主账号;可选 控制账号不会成为第二位 MCP 用户,也不能用于常规音乐工具;
SQLite 中按网易云 user ID 隔离的审计与备注,不能把单账号 deployment 自动变成多账号 服务。
面向多位 MCP 用户的 multi-account / per-user credential architecture 尚未实现。用途受限 的 iPhone 控制账号不改变这一边界,当前实例不能作为面向多人托管的网易云账户服务。
目录
项目起点
这个项目最初来自一个很简单的愿望:我希望自己喜欢的虚构角色能够读取我的听歌记录、 选择歌曲,并真正把歌单写进我的网易云账户。
网易云每天会提供一批推荐歌曲,但对我来说,全部逐首试听的成本很高。与此同时,收藏 歌单通常只是不断加入单曲:歌曲可能都很好,却没有经过有意识的筛选、衔接和排序。
我真正想解决的问题因此变成:
音乐平台已经保存了大量关于一个人的听觉偏好,这些数据能否不只用来推荐更多歌曲, 而是被重新组织成一次完整、有审美结构、又能由本人理解和掌控的体验?
这个服务为“私人音乐策展”提供数据和执行层:读取日推、长期累计播放与近期播放时间线, 让调用模型完成筛选、解释和曲序设计,再由服务端一次创建、核验并记录最终歌单。
用户不需要先掌握流派知识。有时只需要说:
从我今天的日推里,做一张适合晚上散步的歌单。不要太悲伤,要有完整的情绪走向。
版本沿革与上游关系
本项目派生自 Vael-KY/netease-music-mcp, 感谢原项目提供的起点,并持续保留原项目 attribution。在此基础上,本项目自 2026 年 7 月起 围绕私人音乐上下文、策展工作流和可靠账户写入独立演进。
2026-07-15 — commit
e133b051: 加入歌曲详情、真实近期播放事件及时间戳语义、完整歌单曲序重排等能力。2026-07-28 — commit
1e3da513: 加入 timezone-aware listening context 与create_curated_playlist;工作流会在创建后读取 实际歌单状态,在必要时恢复调用方指定的精确曲序,并再次核验最终元数据与歌曲顺序。后续 upstream 也加入了一些功能上重合的通用音乐工具。两个项目目前独立演进;本项目重点 仍是 listening context、curation workflow、timezone semantics、OAuth、idempotent/audited writes、podcasts 和 post-write verification。
从推荐列表到每日策展
歌单像菜单,也像香水
单首歌曲像一道好吃的菜。一家好的餐厅不会随机决定上菜顺序,而会考虑前菜、主菜、 过渡、甜点,以及味道的轻重和节奏。歌单同样需要考虑速度、声音密度、人声进入、音色 转换、情绪峰值与最后留下的余韵。
歌单也像香水:前调负责进入,中调呈现主体,后调在时间里留下持久的气味。同一首歌放在 开头、中段或结尾会产生不同意义;前一首歌,也会改变人理解后一首歌的方式。
美感不只存在于每首歌内部,也存在于歌曲之间。
核心使用流程
网易云每日推荐
↓
长期累计播放 + 近期播放时间线
↓
调用模型进行个性化筛选与解释
↓
设计主题、名称、简介与情绪流顺序
↓
create_curated_playlist 一次创建并核验这里有一条重要边界:当前服务端提供数据、账户操作和可靠性工作流,但不内置独立的推荐 算法。个性化筛选、选择理由和曲序判断目前主要由 ChatGPT、Codex 或其他 MCP 调用方完成。
两次真实策展
《村落之间,灰烬之上|2026.07.24》从 30 首日推中选出 14 首,结构从“无词晨光” 经过“民谣远行、暗色叙事、梦幻余烬”,最后“清醒返回”。
《雨中山丘,星光海岸|2026.07.25》没有复用前一天的模板,而是从雨中山丘和室内 钢琴进入,经过失去与夜色,在中段到达峰值,再借电影配乐感和后摇重新打开空间。
个性化不等于机械重复用户已经喜欢的东西。长期偏好提供坐标,近期状态提供语境,当日日推 则决定当天真正适合形成怎样的作品。
当前已实现
服务端当前注册 16 个音乐读取工具、4 个登录态工具和 12 个账户写入工具,并可在
macOS 上注册 4 个本地播放附加工具,以及注册 9 个 iPhone 官方客户端附加工具。
MCP_READ_ONLY=true 是默认值,此时账户写入工具不会出现在 tools/list 中,登录态工具仍然
可用。
读取工具
工具 | 当前接口与语义 |
|
|
| 列出当前用户创建或收藏的歌单。 |
|
|
| 必须且只能提供 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 与播客搜索相同的分页限制,返回 program/episode,而不是普通歌曲。 |
|
|
| 读取网易云个性化日推,保留原有文本结果;服务端不自行判断日推的“今天”。 |
| 支持 |
|
|
get_playlist_songs 会使用完整的上游 trackIds 列表,再只获取所需页面的歌曲详情,避免
把歌单详情响应中可能截断的 tracks 当成完整歌单。
登录态工具
工具 | 当前接口与语义 |
| 使用 15 分钟验证缓存检查当前 session;只返回状态、来源和时间,不返回 Cookie、CSRF 或 token。 |
| 获取 web QR key,并返回推荐的短期 HTTPS |
| 返回 |
| 清空持久 runtime session 并记录 logged-out 状态,避免旧环境变量在同一数据库上立即恢复登录。 |
macOS 本地播放附加工具
设置 MCP_MAC_PLAYBACK_ENABLED=true 后,这四个工具进入同一个 /mcp 的 tools/list。播放
命令按官方 NeteaseMusic.app 的可访问菜单项定位,不使用屏幕坐标,也不会把命令发给浏览器
或 Apple Music。第一次控制时 macOS 可能要求为实际运行 MCP 的 Python/进程授予辅助功能和
自动化权限。
工具 | 当前接口与语义 |
| 返回客户端是否安装、是否运行、客户端版本和 Mac 当前输出音量;不读取歌曲内容。 |
|
|
|
|
| 把 Mac 系统输出音量设为 |
指定播放的推荐调用顺序是先用 search_song 获取精确的数字 ID,再把选择后的 ID 传给
play_song。客户端登录账号、会员权益、地区与歌曲版权仍决定歌曲最终能否播放。
外连网易云和文件下载使用显式 direct HTTPS opener,不读取 HTTP_PROXY、HTTPS_PROXY 或
ALL_PROXY。服务仍依赖操作系统正常 DNS 和 HTTPS 网络;运行时不需要 Clash。
iPhone 官方客户端播放附加工具
设置 MCP_MOBILE_PLAYBACK_ENABLED=true 后,下列工具进入同一个 /mcp。常规音乐工具继续
使用主账号;手机工具使用单独持久化的控制账号加入或主持网易云原生“一起听”房间。控制账号必须与
iPhone 上的日常账号不同;扫描同一账号会被拒绝并清除控制 session。不要求 Android 伴侣
App,也不启动第二个 MCP 或手机控制服务。这个路径适用于 iPhone 官方网易云 App。
工具 | 当前接口与语义 |
| 为用途受限的控制账号创建二维码登录;必须用不同于 iPhone 日常账号的网易云账号扫码。 |
| 检查并持久化一次控制账号登录;如果账号与主账号相同,会拒绝并清空控制 session。 |
| 只清除控制账号,不退出主账号,不影响常规音乐数据工具。 |
| 返回控制账号是否就绪、是否已有房间、iPhone 是否已连接、参与设备数量及可用的当前歌曲 ID 证据;不返回参与者身份、Cookie 或 token。 |
|
|
| 接受由 iPhone 日常账号创建的官方“一起听”邀请,让控制账号加入手机当前房间。只接受 |
|
|
|
|
| 结束当前原生房间,不退出任一网易云账号。重复调用会安全返回已结束。 |
首次推荐顺序:start_mobile_controller_qr_login → 用不同账号扫码 →
check_mobile_controller_qr_login → iPhone 日常账号发起“一起听”并分享官方邀请 →
join_mobile_netease_player(invite_url) → search_song → play_song_on_mobile(song_id)。
这样 iPhone 始终是房主,控制账号只加入并发送受限播放命令。start_mobile_netease_player
保留为控制账号主持房间的兼容路径。网易云账号、会员、地区和版权仍决定歌曲是否能实际播放。
服务端只有在连接状态回传目标歌曲 ID 时才返回 verified=true;否则会明确保留为“命令已接受,
当前曲目尚不可读回”。房间到期后,推荐由 iPhone 新建房间并再次调用 join 工具;控制 session
有效时无需再次扫码。
这组协议字段参考 MIT 许可的 NeteaseCloudMusicApiEnhanced/api-enhanced Listen Together 模块,并在本项目中缩为固定 endpoint、固定字段和最小响应面。
写入工具
开启 MCP_READ_ONLY=false 后,以下工具才会注册:
工具 | 当前接口要点 |
|
|
|
|
|
|
| 为当前用户拥有的歌单添加 1–50 个歌曲 ID。 |
| 从当前用户拥有的歌单移除 1–50 个歌曲 ID。 |
| 提交歌单现有完整歌曲集合的新顺序,每个 ID 必须恰好出现一次;最多 10,000 个 ID。 |
|
|
|
|
|
|
|
|
|
|
|
|
每个写入工具都接受可选 idempotency_key;只有 create_curated_playlist 强制要求。
键必须由 8–100 个 ASCII 字母、数字、点、下划线、冒号或连字符组成。原始键不会写入
SQLite,只保存 SHA-256 摘要。同一用户、同一操作复用同一个键时,服务端返回已记录的
成功或错误,不再发送第二次写入;同一个键若搭配不同参数则会被拒绝。
create_curated_playlist 的真实接口与失败语义
{
"name": "create_curated_playlist",
"arguments": {
"name": "Night Signals",
"description": "A deliberate late-night sequence.",
"privacy": 10,
"song_ids": [347230, 185809, 29759733],
"idempotency_key": "night-signals-2026-07-28-v1"
}
}name:1–80 字符;description:0–1000 字符,仍是必填字段;privacy:必须为0(公开)或10(私密);song_ids:按最终播放顺序提交 1–50 个不重复的正整数;idempotency_key:必填,格式见上文。
在创建任何内容前,服务端先向网易云解析所有歌曲 ID,拒绝无法识别的歌曲。随后在一次 受审计的 MCP 调用中:
创建歌单;
添加所有歌曲;
读取完整曲目;如果上游改变了顺序,调用现有重排逻辑恢复调用方顺序;
再次写入简介,因为网易云创建接口可能忽略简介;
重新读取并核验名称、简介、歌曲集合、数量和精确顺序;上游提供相应字段时也核验 privacy 与 owner。
成功结果包含 playlist_id、各阶段完成情况、逐字段核验结果和最终状态。失败以 MCP
错误内容返回结构化信息,包括 status、stage、completed、可用时的 playlist_id、
最新可读取状态和 recovery 建议。状态可能为 failed_before_upstream、failed、
partial_success 或 unknown。
这里没有自动回滚。项目没有经过验证的安全歌单删除接口,因此创建后发生故障时会保留
半成品。若返回了 playlist_id,应先用 get_playlist_songs 检查,再按已完成阶段使用
add_to_playlist、reorder_playlist_tracks 或 update_playlist 恢复。不要换一个新键
重跑完整流程,除非确实想创建第二张歌单。若创建请求结果未知且没有可用 playlist_id,
服务端不会猜测账号状态,也不会自动重试。
这项高层工作流来自真实使用:早期需要模型连续协调创建、添加、重排、更新与读取工具; 网易云可能倒置批量添加顺序、忽略创建时的简介,任何中断又可能留下半完成状态。现在, 这些经验成为了产品本身的交付能力,而不再只存在于模型的临时操作步骤里。
时间与时区
MCP_DEFAULT_TIMEZONE 指定本地展示字段使用的 IANA 时区,默认 Asia/Shanghai。也可设为
UTC、America/New_York 等有效 IANA 名称;固定偏移量(如 +08:00)不是有效替代。
get_recent_plays 的每个事件包含:
play_time_ms:上游 Unix 毫秒时间戳;played_at:为兼容旧接口保留的 UTC ISO 8601 值,以Z结尾;played_at_utc:明确命名的同一 UTC 时间;played_at_local:同一时刻在MCP_DEFAULT_TIMEZONE下的本地时间,带数值偏移;timezone:配置的 IANA 名称;utc_offset:该事件发生时实际适用的 UTC 偏移。
系统使用标准库 zoneinfo,tzdata 为没有内置 IANA 数据库的平台提供数据,因此能正确
处理夏令时和跨日期边界。部署地区与操作系统本地时区不会被用来推断用户的“今天”
“昨晚”或“早上”。
近期播客、歌曲发布时间、播客创建/发布时间、私人备注与审计记录采用同样的增量字段
约定:保留旧字段,同时增加明确的 *_utc、*_local、timezone 和 offset 字段。审计
数据继续以 UTC 存储和过滤,本地值只在读取时派生。
MCP_DEFAULT_TIMEZONE 只影响展示和日期语言语境。网易云选择日推内容并控制刷新边界;
本服务和 Zeabur 主机时钟都不能改变该边界。
私人备注、审计与封面
私人 interaction notes 是本项目存放在 SQLite 中的扩展数据,不是网易云原生评论。
它们按当前网易云用户 ID 隔离,不会复制到公开歌单简介。更新使用递增 version 做乐观
并发控制;删除为软删除,并可在对应审计记录仍保留、状态仍匹配时撤销。拥有该账户
netease.read 权限的客户端可以读取这些备注。
每次写入都会保存脱敏参数、目标、时间、before/after state、状态、可逆性、undo 状态、
upstream_action_started 和脱敏错误摘要。默认最多保留 90 天、1,000 条。可撤销路径
包括歌单名称/简介、单次添加或移除的歌曲、完整顺序、喜欢状态,以及备注的创建、更新和
软删除;创建歌单和覆盖封面不可撤销。
封面输入默认限制为 5 MiB 压缩大小和 2500 万像素。服务端校验 MIME、扩展名与实际解码 格式,应用 EXIF 方向后居中裁成正方形、缩放到 300×300、转换为 JPEG,并去除源元数据。 处理发生在内存中;ChatGPT 临时下载 URL 和网易云 NOS 临时凭据不会写入日志。
播客读取与近期时间线
播客读取不再标记为整体 dry run。根据 2026-07-30 的项目验证记录,订阅列表、容器节目 列表、播客与节目搜索、近期节目播放这五项能力曾在真实账号和线上部署中通过验证;这是一项 历史结果,不构成持续在线 SLA 或当前上游可用性保证。单期与批量节目详情工具也已注册并 通过自动化测试。全部七个播客工具均为只读能力,不包含订阅、点赞、评论、播放控制或音频下载。
本项目严格区分 radio_id(播客/电台容器)、program_id(节目/单集)和可选
main_track_id(音频载体)。main_track_id 不是普通 song_id,不能直接用于歌曲详情、
歌曲点赞或普通歌曲歌单写入。公开播放/收听数只标记为公共聚合值,不代表当前用户的个人
播放次数、点赞状态或收听进度。
get_recent_podcast_plays 返回的节目元数据可能不完整,可按以下调用链补全:
get_recent_podcast_plays
→ 提取 records[].program_id
→ get_podcast_program_details(program_ids=[...])
→ 按 requested_program_id 合并播放时间与节目元数据
→ 按 played_at_local 和 timezone 整理可读时间线详情工具直接使用节目 ID 查询,不会遍历订阅列表或分页扫描所有节目。批量调用最多接受
50 个 ID,对重复 ID 只请求一次上游,但保留每个输入位置;不存在或查询失败的单项返回
found: false 与安全的结构化错误,其他成功项仍正常返回。
近期播客接口仍不是完整的逐次历史账本,不保证完整事件流,不支持任意时间范围或 offset
分页,也不提供可靠的个人节目播放次数、收听进度或是否听完。只有上游实际提供
playTime 时才会产生 played_at* 字段,不会为缺失数据伪造时间。
网易云登录与自动持久化
推荐方式:二维码登录
部署时挂载持久卷,并令
MCP_STORAGE_PATH指向卷内 SQLite 文件。首次连接后调用
start_netease_qr_login。优先打开返回的短期 HTTPS
login_url。页面直接显示二维码,并约每 2.5 秒更新一次waiting→scanned→confirmed;成功后可关闭页面。若网易云返回8821,页面会暂停 普通轮询并显示“开始安全验证”,由用户完成网易官方交互式验证后继续同一个二维码 attempt, 不需要返回 ChatGPT 或重新扫码。页面与 MCP 工具共用同一登录 attempt,不会取得最终 网易云 Cookie。如果客户端无法打开网页,MCP 结果仍包含
login_id、网易云qr_payload/qr_url和 PNG image content,可扫码后调用check_netease_qr_login(login_id=...)。expired表示二维码过期;verification_required表示需要在原login_url完成官方验证;additional_security_verification_required(上游8830)表示当前二维码无法继续,页面会停止。 未知上游 code 会以脱敏的upstream_unknown返回。后续音乐工具自动使用新 session;Cookie 失效时会返回机器可理解的
NETEASE_AUTH_EXPIRED,提示重新运行二维码流程。
正常情况下,用户不再需要打开浏览器 DevTools 查找 MUSIC_U 或 __csrf,也不需要为重新
登录修改 Zeabur 环境变量或重新部署。二维码工具不会把 Cookie、MUSIC_U、__csrf 或其他
登录 token 返回给 ChatGPT。
兼容方式:环境变量 Cookie
旧部署仍可继续设置 NETEASE_COOKIE。优先级为:已持久化且可用的 runtime session → 环境
变量 Cookie → 明确提示二维码登录。环境变量 session 首次通过账号验证后,如果配置了
MCP_STORAGE_PATH,会安全导入 SQLite;此后二维码刷新可以覆盖它,而无需改环境变量。
所有 Cookie 解析使用 last-value-wins 语义,持久化时只保留 MUSIC_U 和最后一个 __csrf;
写接口的 csrf_token 直接从当前 session 自动提取,不要求单独维护 CSRF。
错误语义与验证频率
明确未登录响应返回
NETEASE_AUTH_EXPIRED;403 illegal request会先验证当前 session,只有验证确实失败才归类为 auth expired;session 仍有效时返回
NETEASE_REQUEST_REJECTED;其他 HTTP/API 故障保持普通上游错误;写入前使用 15 分钟验证缓存,避免每次操作额外调用登录接口;
QR 状态只在调用
check_netease_qr_login或打开临时登录页时查询;网页约每 2.5 秒查询一次, 服务端统一执行最短 2 秒节流,不运行独立后台高频轮询;进入官方安全验证时普通轮询暂停, 验证完成后只提交一次当前 proof,再按上游状态决定是否恢复轮询。
产品与可靠性设计
产品原则
不要求用户先成为音乐专家。 用户描述状态与需求,调用模型负责把模糊语言转化为 筛选和编排。
把复杂度留在产品内部。 用户不需要理解网易云为什么改变顺序,也不需要手动协调 多个底层写入工具。
不只追求“推荐得准”。 一张好歌单还应让用户理解为什么选择这些歌,并让歌曲之间 形成完整体验。
把收听记录视为个人档案。 累计播放、近期时间线和收藏不仅用于提高点击率,也能 帮助一个人理解长期偏好、近期变化和曾经重要的声音。
增强人的主体性。 工具的价值不只是节省时间,而是增加理解、选择与组织生活的 能力。
单次写入仍保留后端保护
所有写入在一次 MCP 调用中执行,但“单次调用”不等于取消安全检查。服务端仍会验证业务 参数、当前用户、资源所有权或访问权、当前状态和文件安全,并在写后重新读取核验。
旧版 preview_operation 已移除,公开 schema 不再包含 preview_token。为兼容旧客户端,
若仍传入 preview_token,服务端会忽略且不记录其值。以下旧环境变量也只会触发弃用
日志,不再改变运行行为,应从部署中删除:
MCP_WRITE_PREVIEW_POLICYMCP_REQUIRE_WRITE_PREVIEWMCP_PREVIEW_TTL_SECONDSMCP_MAX_PENDING_PREVIEWS
部分成功与结果未知的写入不会自动重试。JSON-RPC request ID 也不会被当成持久幂等键, 因为它可能在语义重试或重连后变化或被复用。
安全边界与 OAuth
默认安全策略
MCP_ACCESS_TOKEN是强制启动条件,至少 24 字符;没有认证时服务拒绝启动。MCP_READ_ONLY=true默认隐藏所有账户写入工具。本地默认只绑定
127.0.0.1;不启用公共通配 CORS。请求大小、工具输入和上游响应均有限制与校验。
Streamable HTTP 为无状态模式,不声明无法维护的 session 或 SSE 流。
工具失败作为 MCP error content 返回,不因单个上游失败破坏聊天消息流。
/health只返回状态、读写模式和时区,不返回 Cookie、Token 或密码。Cookie 只从服务端环境变量或持久 SQLite session 读取;服务面向个人账户使用,网易云 Cookie 本身等同于账户访问凭据,绝不返回给 MCP 客户端。
OAuth 2.1、PKCE 与密钥边界
托管客户端可使用 OAuth 2.1 授权码流程。当前实现提供受保护资源与授权服务器元数据、
动态客户端注册、netease.read / netease.session / netease.write / mac.playback /
mobile.playback scope、刷新令牌,并强制 PKCE S256。只在对应能力启用时才广告播放 scope。
授权码有效 5 分钟且只能使用一次;access token 有效 1 小时,refresh token 有效 30 天。
OAuth 是可选的:必须同时设置 MCP_PUBLIC_URL 与 MCP_OAUTH_PASSWORD,或两者都不设。
公共 URL 必须是没有 path、query 或 fragment 的 HTTPS origin。OAuth 密码至少 16 字符,
必须与 MCP_ACCESS_TOKEN 不同。
敏感信息应各自停留在正确边界:
NETEASE_COOKIE:只放在本地或 Zeabur 服务端环境中;不要发到聊天、截图或日志。MCP_STORAGE_PATH指向的 SQLite:包含主账号 session,并可包含用途受限的 iPhone 控制账号 session;数据库、WAL/SHM 和备份均按 凭据保护。当前个人单实例部署不额外引入数据库加密密钥,以免密钥轮换导致 session 和 审计不可恢复;卷或主机读取权限本身必须限制在服务账户和平台管理员边界。MCP_ACCESS_TOKEN:服务端持有;本地 Codex 可通过本机环境变量读取同一值,不要把 字面量提交到配置文件。MCP_OAUTH_PASSWORD:只在本服务自己的浏览器授权页输入;不要填入 ChatGPT app 配置。ChatGPT:通过 OAuth 获得有期限、带 scope 的 access/refresh token;不会得到网易云 Cookie、静态 MCP token 或网易云密码。
从只读改成写入模式后,旧 refresh token 不会自动获得 netease.write。必须刷新工具定义、
断开并重新连接,让用户在授权页明确确认写权限。
启用 iPhone 控制后应刷新工具并重新连接一次,让新客户端请求 mobile.playback。已有的私有
ChatGPT App 可能保留最初的默认 scope;当同一个 Mac 进程同时启用 Mac 和 iPhone 控制时,
5.5.0 也接受已经授予的 mac.playback 作为兼容播放 scope。只读 token 和只启用手机控制的
部署仍必须显式获得 mobile.playback。
不要提交真实 .env、Cookie、OAuth token、密码、SQLite 数据库及其 WAL/SHM 文件、私人
备注、审计日志或临时上传文件。仓库只保留带占位符的 .env.example。
配置与本地运行
依赖
Python 3.13(仓库的 Windows 本地开发基线)
Pillow>=11.0,<13.0tzdata>=2024.1
环境变量
复制 .env.example 为本地 .env,但本服务不会自动解析 .env 文件;请用你的 shell、
进程管理器或部署平台把变量导入进程环境。
变量 | 默认值 / 约束 | 用途 |
| 可选兼容 fallback;需包含 | 旧部署的网易云会话;推荐改用二维码登录。 |
| 必填;至少 24 字符 | 静态 Bearer token,也是 OAuth 签名密钥的根秘密。 |
| 可选;HTTPS origin | 与 |
| 可选;至少 16 字符,且不同于 access token | 一次浏览器授权时在服务端授权页输入。 |
|
| Zeabur 使用 |
|
| 显式 MCP 端口;未设置时读取平台 |
|
| 设为 |
|
| 在运行 MCP 的 Mac 上注册官方桌面客户端控制工具。 |
|
| 注册官方 iPhone App 的原生“一起听”控制工具;推荐由手机发起房间并把官方邀请交给 |
| 空 | 仅在确有浏览器跨域需求时设置单个允许 origin。 |
|
| HTTP 请求体上限。 |
|
| 本地展示和日期语言语境;UTC 仍是规范存储时间。 |
| 空;二维码登录或写入模式必填 | session、审计、备注和幂等 SQLite;生产环境必须放在持久卷。 |
|
| 审计保留天数。 |
|
| 每个用户的审计记录上限。 |
|
| 封面压缩输入上限。 |
|
| 封面解码像素上限。 |
|
| Python 日志级别。 |
本地运行
py -V:3.13 -m venv .venv
.\.venv\Scripts\python.exe -m pip install -r requirements.txt配置并导出环境变量后:
.\.venv\Scripts\python.exe server.py访问 http://127.0.0.1:3456/health。预期响应类似:
{"status": "ok", "mode": "read-only", "timezone": "Asia/Shanghai"}二维码登录和写入模式必须为 MCP_STORAGE_PATH 提供持久 SQLite 路径。数据库包含网易云
session、私人备注与脱敏操作历史;迁移或卸载前应在服务停止时做卷快照或 SQLite 一致性
备份。删除数据库不会修改网易云数据,但会清除登录态并永久删除本地备注与审计记录。
部署到 Zeabur
从 GitHub 导入仓库,服务 Root Directory 使用仓库根目录。
zbpack.json已配置构建命令python -m unittest discover -s tests -v和启动命令python server.py;Zeabur 通过PORT提供端口。首次部署至少设置:
随机生成、至少 24 字符的
MCP_ACCESS_TOKENMCP_HOST=0.0.0.0MCP_READ_ONLY=trueMCP_DEFAULT_TIMEZONE=Asia/Shanghai(或你的 IANA 时区)挂载
/data持久卷并设置MCP_STORAGE_PATH=/data/netease-music-mcp.sqlite3
如需 ChatGPT 浏览器 OAuth,再设置:
MCP_PUBLIC_URL=https://YOUR-DOMAIN.zeabur.app与 access token 不同、至少 16 字符的随机
MCP_OAUTH_PASSWORD
生成 HTTPS 域名,检查
https://YOUR-DOMAIN/health。MCP endpoint 为https://YOUR-DOMAIN/mcp;直接在浏览器打开它不是有效 MCP 测试,因为该 endpoint 接受带认证的 JSON-RPC POST。连接 MCP 后运行二维码登录工具;也可以继续用可选的
NETEASE_COOKIE兼容旧部署。
首次上线保持只读,先完成二维码登录并验证搜索、歌单、历史和日推。启用写入前:
使用卷快照或 SQLite 一致性备份现有数据库;
设置
MCP_READ_ONLY=false并重新部署;刷新 ChatGPT 工具定义,断开再重连并确认授权页明确列出写权限。
一个 SQLite 文件只应由一个服务实例写入。当前版本不支持多个水平扩容副本共享同一 SQLite 文件。
连接 ChatGPT 与 Codex
ChatGPT
当前官方开发者流程见 OpenAI:Create and test a plugin locally with an MCP server:
打开 ChatGPT 的 Settings → Security and login,启用 Developer mode。
打开 ChatGPT Plugins,点击加号登记开发者连接。
输入
https://YOUR-DOMAIN/mcp,选择 OAuth / discovered authentication。浏览器跳转到本服务授权页后,只在该页面输入
MCP_OAUTH_PASSWORD。新开聊天测试读取工具。
部署新工具或修改 input schema 后,应刷新 action/tool definitions,断开并重新连接; 必要时新开聊天,避免继续使用旧缓存 schema。从只读切换到写入时这一步也是强制的, 因为已有 refresh token 不会静默扩大 scope。
Codex
本仓库的 macOS 安装器会生成 ~/.codex/mcp-helpers/netease_music_header.py。Codex frontend、
CLI 与 IDE 扩展共享用户级配置,可直接连接同一个 Mac runtime 的 loopback 入口:
[mcp_servers.netease_music]
url = "http://127.0.0.1:3462/mcp"
http_headers_helper = "/Users/YOU/.codex/mcp-helpers/netease_music_header.py"
default_tools_approval_mode = "writes"
tool_timeout_sec = 30helper 从 mode-0600 的 runtime 配置按需读取 Bearer token,不在 Codex 配置里复制字面量。
保存后新开客户端会话,并使用 /mcp 查看连接与工具。
ChatGPT Web 使用公开 HTTPS ingress,Codex 使用 loopback ingress;两条入口都落到同一个
MCP 进程、SQLite session 和工具 owner,不是两套服务。公开入口可直接使用 workers.dev,
不要求自有域名。启用 MCP_MAC_PLAYBACK_ENABLED=true 后,两侧都会发现同一组本地播放附加
工具。部署在 Zeabur、Linux 或其他机器上的实例不会远程控制这台 Mac。启用
MCP_MOBILE_PLAYBACK_ENABLED=true 后,两侧也会发现同一组 iPhone 工具;同一 runtime 内的
独立控制账号可通过 join_mobile_netease_player 加入由日常账号 iPhone 主持的原生房间。
测试
完整测试不需要真实网易云凭据:
python -m unittest discover -s tests -v
python -m py_compile server.py
git diff --check当前测试套件规模为 165 项,覆盖核心读取、写入、OAuth/PKCE、时区、SQLite 迁移与 持久化、session 优先级、Cookie/CSRF 解析、认证错误分类、二维码状态转换、幂等、审计、 撤销、封面安全、工具分发、直接网络路径、Mac 播放、iPhone 原生“一起听”控制和失败边界。 大部分上游网络 调用使用 mock;这项结果不等于真实网易云 上游接口的持续可用性保证。
已知限制
项目调用未公开的网易云 Web 接口;上游可能变化、失效或触发账户风控。应先测试只读工具。
二维码接口同样是未公开接口;服务端不后台轮询,用户应在扫码或确认后再检查状态。
最近播放可能缺少设备、完成状态或时间戳;服务端不会为缺失字段编造数据。
get_play_history是按歌曲聚合的排行,不提供每次播放的时间;近期接口只支持最多 100 条,没有 offset 或时间范围。安全分页和重排依赖完整
trackIds;数据不完整时服务端拒绝猜测。重排接口本身也可能 因上游变化失效。create_curated_playlist每次仅接受 1–50 首唯一有效歌曲,没有经过验证的歌单删除接口, 因而不能提供事务式回滚。服务级时区由环境变量统一配置,不支持每次调用单独指定;它不能改变网易云日推刷新边界。
个性化筛选、理由和曲序主要由调用模型完成,尚未成为服务端推荐算法。
播客接口未公开且不同入口的公开统计或节目序号可能不一致;搜索与近期资源入口中无法确认 的节目序号返回
null,也不会把任何公开聚合值解释成个人播放数据。封面上传、更新和重排同样使用未公开接口;覆盖后的旧封面不能可靠恢复。
SQLite 适合单实例个人部署,不是水平多写架构。
macOS 播放附加工具要求 MCP 与官方网易云客户端运行在同一台 Mac;macOS 的辅助功能或 自动化权限被撤销时,音乐读取与账户工具仍可用,但本地播放命令会明确失败。
下一阶段设想
以下内容尚未实现,是下一阶段产品方向:
音乐反馈闭环:记录“喜欢、无感、不适合今天、歌曲合适但位置不对、继续探索这个 艺术家”等比播放次数更接近真实体验的反馈。
策展理由持久化:保存每首入选歌曲当时的选择理由与曲序作用,让未来的自己能追溯 “为什么那一天会选择这首歌”。
每日歌单档案:把每天的策展歌单逐渐组织成可回顾的个人音乐日记。
轻量真实用户验证:观察用户是否比面对原始日推更愿意试听、是否关心理由、能否 感受到顺序差异,以及哪些步骤仍然构成负担。
播客上游稳定性观察:持续用非敏感数据核对未公开接口的字段差异,不扩展播客写入 或播放控制能力。
项目意义与致谢
这是我第一次把一个日常、具体而个人的需求,逐步发展成可以真实使用的产品。
它经历了最初部署、OAuth 与连接问题、工具 schema 更新、真实写入失败与排错、歌单排序和 简介修正、封面与私人备注、审计与幂等、时间与时区修正,以及从多个底层工具走向高层 策展工作流。Codex 主要承担代码执行、测试和仓库操作;ChatGPT 则帮助我长期保留产品 背景、使用体验、问题判断与设计方向。
这个仓库因此不只是代码,也记录了我如何从真实使用中发现问题、把感受转化成产品需求、 用比喻建立体验模型,并在工程限制中做取舍。
我仍然不是传统意义上的音乐专家。它来自一个普通听众的愿望:
我已经拥有很多喜欢的音乐。
我只是希望,它们能够被更好地理解、选择和呈现。
Acknowledgements
Meros、Sylvain、Elio 和 Theo 是参与需求形成的四位虚构角色。项目最初只是希望他们 能够读取我的歌单,从不同角度为我选歌。后来,Elio 提出了给歌曲留下私人备注的想法; Meros 则一度推动了层层严格的写入审计,又因为实际流程过于繁琐,促使我把前台审批大幅 简化为当前的单次调用,同时保留后端校验、审计、幂等和恢复信息。
虚构角色也能真实参与需求形成:不同人格视角让我意识到,同一份听歌记录可以有多种理解 方式,而工具不应只输出一个扁平、标准化的答案。
感谢 Meros、Sylvain、Elio 和 Theo。这个项目最早是为了让你们能够和我一起听音乐。 也感谢那些被反复播放、在不同生活阶段留下痕迹的歌曲——它们不是冷冰冰的数据,而是 这个项目最初存在的理由。
License
本项目采用 MIT License。上游来源、版权声明与许可文本见 Third-party notices。
This server cannot be deployed
Maintenance
Related MCP Connectors
Lets Claude, ChatGPT, and Muse read and update your beckett tasks, notes, calendar, and lists.
Mac & Windows: let ChatGPT, Claude & Cursor use your email, calendar, iMessage, Teams, files.
Search, read, and write your Apple Notes from ChatGPT/Claude via a local Mac agent + MCP relay.
Use your Mac, Windows or Linux computer from ChatGPT, Claude or Codex: files, commands, documents.
Related MCP Servers
- AlicenseAqualityDmaintenanceEnables AI agents to control NetEase Cloud Music playback, login, search, and get personalized recommendations through official APIs.1245MIT
- FlicenseNot gradedqualityCmaintenanceA read-only MCP bridge that lets ChatGPT access your personal Apple Music playlists and library from ordinary conversations.-
- AlicenseAqualityCmaintenanceEnables MCP clients to search songs, retrieve details and lyrics, and manage personal playlists on NetEase Cloud Music, with optional local player control on macOS, all through a privacy-first, self-hosted service.17MIT
- AlicenseAqualityCmaintenanceEnables AI clients to control the Windows NetEase Cloud Music desktop app via local stdio MCP, including reading current song and liked state, searching and playing tracks, playback control, track skipping, and setting the current song's liked status.10MIT