内容
# roon-mcp
[](https://www.npmjs.com/package/roon-mcp)
一款用于控制 **Roon** 音乐播放器的 [MCP](https://modelcontextprotocol.io) 服务器,以便 AI 代理可以查找音乐并开始播放。基于官方的 Roon 扩展 API(`node-roon-api` + `node-roon-api-transport` / `node-roon-api-browse`)构建。
---
> **"在 Roon 上播放女性声乐恍惚音乐混合曲(区域:这台电脑)—— 2000 年代荷兰恍惚音乐氛围,就像你在 Amnesia 处于巅峰时期听的那种音乐。从 4 Strings 的 Take Me Away 开始播放。"**
>
> *Claude 在您的音乐库和流媒体服务中搜索,精心挑选曲目,并将它们排队 - 所有这些都来自一个自然语言提示。*
---
## 要求
- Node.js 20+
- 在本地网络上运行的 **Roon Core** 以便配对
- 在安装主机上安装 **git** - `node-roon-api*` 依赖项发布在 GitHub(而非 npm)上,并在安装期间通过 git URL 获取
## MCP 客户端配置
将以下内容添加到您的 MCP 客户端配置文件中。`npx`会在首次运行时获取软件包:
```json
{
"mcpServers": {
"roon": {
"command": "npx",
"args": ["-y", "roon-mcp"],
"env": { "ROON_DEFAULT_ZONE": "办公室" }
}
}
}
```
首次启动时,打开 **Roon → 设置 → 扩展** 并启用 **Roon MCP** 以配对。配对状态记录到标准错误输出;标准输出保留用于 MCP 协议。配对令牌保存在 `~/.config/roon-mcp/config.json`(可通过 `ROON_MCP_CONFIG` 重置),因此扩展程序在重启后保持授权,而不是每次都作为新的“已发现”条目出现。
### 全局安装(可选)
```bash
npm install -g roon-mcp
```
```json
{
"mcpServers": {
"roon": {
"command": "roon-mcp",
"env": { "ROON_DEFAULT_ZONE": "办公室" }
}
}
}
```
## 配置
| 环境变量 | 用途 |
| --- | --- |
| `ROON_DEFAULT_ZONE` | `play_now` / `enqueue_and_play` 在未指定 `zoneId` 时的可选备用目标 - 一个区域/输出 ID 或显示名称子字符串。如果未设置,服务器将备用到唯一的区域、“办公室”区域或当前正在播放的区域;如果仍然无法确定,它将返回 `ZONE_AMBIGUOUS`,以便代理可以询问。 |
| `ROON_MCP_CONFIG` | 持久化配对令牌的可选路径。以 `.json` 结尾的值是文件本身;其他任何值都是保存 `config.json` 的目录。默认为 `$XDG_CONFIG_HOME/roon-mcp/config.json`(即 `~/.config/roon-mcp/config.json`)。 |
## 工具
| 工具 | 用途 |
| --- | --- |
| `list_zones()` | 列出可播放的区域/输出(ID、名称、状态、输出 ID)。 |
| `search_music({ query, type?, limit?, includeStreaming? })` | 将文本查询解析为排名的浏览候选项(不透明的、会话范围的项目密钥)。`type`(`artist` / `album` / `track` / `genre` / `playlist` / `radio`)限制类别;对于非 genre 类型,空类型搜索扩展到所有类别。有关 `type:"genre"` / `type:"artist"` 和 `includeStreaming` 的流媒体搜索,请参见[流媒体搜索](#流媒体搜索-genre-和-artist)。 |
| `get_tracks_for({ itemKey, limit? })` | 将艺术家/专辑/流派/播放列表候选项扩展为具体的可播放曲目。 |
| `play_now({ zoneId?, itemKey, shuffle?, addToQueue? })` | 播放或排队一个搜索候选项。默认情况下替换队列并立即开始播放。传递 `addToQueue: true` 以追加到现有队列。`zoneId` 是可选的(默认为上述)。 |
| `enqueue_and_play({ zoneId?, itemKeys, shuffle? })` | 从精选的项目密钥构建临时队列并启动(**替换**区域的队列);报告已排队/跳过。 |
| `now_playing({ zoneId? })` | 区域当前曲目的快照 - 状态、标题、艺术家、专辑、搜索位置。当没有播放时,`title` / `artist` / `album` 为未定义。 |
| `control_playback({ zoneId?, action })` | 运行传输动词:`pause` / `resume` / `next` / `previous` / `stop` / `playpause`(切换播放/暂停)。 |
| `seek({ zoneId?, seconds, mode? })` | 在当前曲目中搜索。`mode:"absolute"`(默认)搜索到 `seconds`(0 = 开始);`"relative"` 按 `seconds` 移动(负值跳过)。 |
| `set_loop({ zoneId?, mode })` | 设置循环/重复模式:`off` / `all` / `one`。 |
| `set_volume({ zoneId?, level })` | 将区域的音量设置为 `level` 百分比(0-100)。重新调整为每个输出的原生范围;增量输出报告为跳过。 |
| `mute({ zoneId?, muted })` | 静音(`muted: true`)或取消静音(`muted: false`)区域中的每个输出。 |
### 注意
- **流派搜索** 模糊匹配您输入的内容 - “psychedelic trance” 将找到正确的流派,即使名称不完全匹配。默认情况下,结果来自您的音乐库。
- **`includeStreaming: true`** (在 `type:"genre"` 或 `type:"artist"` 上)将搜索扩展到您的流媒体服务,以便您可以播放不在您本地收藏中的艺术家或流派。
- **开始播放后**,`now_playing` 反映刚刚开始播放的曲目,而不是之前播放的曲目。
- **音量** 以百分比(0-100)设置,并在不同区域之间正确工作。
## 假设
- **核心语言:英语。** 类别/操作标签匹配(`Artists`、`Play Now`、`Top Tracks` 等)假设核心语言为英语。
- **来源:本地音乐库 + 配置的流媒体服务。** 服务器通过 Roon 的浏览 API,该 API 路由到您在 Roon 中设置的流媒体服务(Tidal、Qobuz 等)。在 Tidal 上开发和测试 - 其他服务应可使用但未经测试。仅在本地核心上,结果有所不同。
- **队列:替换。** `enqueue_and_play` 启动一个新队列,而不是添加到当前播放的队列中。
- **精选在代理端。** 去除重复/按艺术家限制/排序/修剪保留在代理中;服务器没有精选逻辑。
没有 `save_playlist` 工具:Roon 没有公开的播放列表写入服务,因此持久的播放列表超出了范围。精选的播放列表由 `enqueue_and_play` 提供(临时队列)。
## 日志记录
每个 Roon API 调用(`browse`、`load`、`get_zones`、`change_settings`)都会发出一行结构化日志到 **stderr**(stdout 保留用于 MCP JSON-RPC):
```
[roon-call] {"t":"2026-06-19T18:00:00.000Z","lvl":"info","op":"browse","ms":12,"params":{"hierarchy":"search","item_key":"…"},"result":{"action":"list","count":7}}
```
失败记录 `lvl:"error"` 以及映射的错误代码,重试显示为相同 `op` 的重复行。grep stderr 以 `[roon-call]` 跟踪流程。
## 开发
```bash
npm install # 从 RoonLabs 的 GitHub 拉取 node-roon-api 包
npm run build
npm test # 构建后运行 node:test
npm run dev # tsc --watch
npm run typecheck
```
直接运行构建的服务器:
```bash
npm start
```
### 集成烟雾测试
`scripts/integration.mjs` 通过 stdio 启动构建的服务器(像真正的 MCP 客户端一样),并在您的核心上运行 list → search → expand。听觉步骤是可选的,因此它不会意外地播放音乐:
```bash
npm run build
node scripts/integration.mjs # list_zones + search only (read-only)
ROON_PLAY=1 node scripts/integration.mjs # also play_now a shuffled genre
ROON_ENQUEUE=1 node scripts/integration.mjs # also enqueue a few curated tracks
# overrides: ROON_ZONE="办公室" ROON_QUERY="Tycho"
```
在首次运行(脚本重试 `list_zones` 约 45 秒)时,在 Roon → 设置 → 扩展中启用 **Roon MCP**。
## 发布
```bash
npm run release -- <patch|minor|major>
```
需要在 `main` 分支上具有干净的工作树和匹配的 `## [<version>]` 条目在 [CHANGELOG.md](CHANGELOG.md) 中。脚本运行测试,更新版本号,标记提交,并使用 `npm pack` 验证软件包。然后打印推送和 `npm publish` 命令。
## 许可证
[MIT](LICENSE)