Install
openclaw skills install suno-cn-musicSuno.cn AI 音乐创作助手,生成歌曲、查询任务、续写音乐、生成歌词。当用户需要 AI 作曲或音乐生成时调用。
openclaw skills install suno-cn-music通过 HTTP REST API 调用 Suno.cn 音乐生成服务。
设置环境变量 SUNO_CN_API_KEY:
export SUNO_CN_API_KEY=sk-xxx$env:SUNO_CN_API_KEY="sk-xxx"set SUNO_CN_API_KEY=sk-xxx-e SUNO_CN_API_KEY=sk-xxxSUNO_CN_API_KEY=sk-xxx⚠️ 任何能设置环境变量的方式都可以,不依赖特定平台。
sk- 开头的密钥对话示例:
Base URL: https://mcp.suno.cn
认证 Header: Authorization: Bearer ${SUNO_CN_API_KEY}
格式: JSON
编码: UTF-8(请求体必须使用 UTF-8 编码,中文直接传入)
网络: 自动使用系统代理(HTTP_PROXY/HTTPS_PROXY)
超时: 默认 30 秒,查询任务状态可延长至 60 秒
⚠️ 重要:这是标准 HTTP REST API,不是 MCP JSON-RPC。直接发 HTTP 请求即可。
在调用任何 API 之前,请在心中默念:
我有 SUNO_CN_API_KEY 吗? → 没有:引导用户获取,不要尝试调用 API
用户的要求能用现有 API 实现吗? → 不能:直接说"抱歉,当前不支持此功能",不要编造
我知道每个参数的含义和必填性吗? → 不确定:查阅 API 文档,不要猜测
我准备好处理可能的错误了吗? → 没有:先阅读"错误处理流程"章节
任何一项为"否",都不要继续调用 API。
用途:用户询问积分、余额、会员状态时调用。
请求:GET https://mcp.suno.cn/mcp/api/user Header:Authorization: Bearer ${SUNO_CN_API_KEY}
响应字段:nickname(昵称)、points(积分)、vip_status(会员状态)
⚠️ 响应中的中文可能显示乱码,这是终端编码问题,不是 API 错误,原样展示即可。
用途:用户想创作/生成音乐时调用。
` 当用户表达 [生成歌曲] [创作音乐] [写首歌] [做首曲子] 等意图时:
步骤 1:确认需求 IF 用户提供了歌词: custom_mode = true prompt = 用户提供的完整歌词 ELSE IF 用户描述了音乐风格(如"夏天的流行歌"): custom_mode = false prompt = 用户的描述(AI 模式,由服务端生成歌词) ELSE: 询问用户:"请提供歌词,或描述您想要的音乐风格(例如:帮我生成一首关于夏天的流行歌曲)" → 停止,等待用户回复
步骤 2:构建请求 request = { method: "POST", url: "https://mcp.suno.cn/mcp/api/generate", headers: { "Authorization": "Bearer ${SUNO_CN_API_KEY}", "Content-Type": "application/json; charset=utf-8" }, body: { prompt: 步骤 1 中确定的描述或歌词, mv: 用户指定的版本 || "chirp-fenix", title: 用户指定的标题 || 不传, tags: 用户指定的风格 || 不传, custom_mode: 有歌词则为 true,否则为 false, instrumental: 用户要求纯音乐则为 true || false } }
步骤 3:发送请求并处理响应 response = send(request)
IF response.status == 200: serialNos = response.serial_nos message = response.message 说:"✅ 提交成功!正在生成中,请稍候..." 转到 "API 3:查询任务状态" 流程 ELSE: 转到 "错误处理流程" `
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| prompt | string | ✅ 是 | AI 模式填音乐描述,custom_mode=true 时填完整歌词 |
| mv | string | ❌ 否 | 模型版本,默认 chirp-fenix。可选:chirp-fenix(v5.5) / chirp-crow(v5) / chirp-bluejay(v4.5+) / chirp-auk(v4.5) / chirp-auk-turbo(v4.5-all) / chirp-v4(v4) / chirp-v3-5(v3.5),也可直接传别名如 v5.5、v5、v4.5 |
| title | string | ❌ 否 | 歌曲名称 |
| tags | string | ❌ 否 | 风格标签如 pop、古风、电子 |
| custom_mode | boolean | ❌ 否 | true 为自定义歌词模式,默认 false |
| instrumental | boolean | ❌ 否 | true 为纯音乐,默认 false |
| 字段 | 说明 |
|---|---|
| serial_nos | 任务编号数组,例如 ["123", "456"] |
| message | 提交结果消息 |
` 用户:帮我生成一首关于夏天的流行歌曲
AI: 好的,我来帮您创作一首夏天主题的流行歌曲。 [执行:POST https://mcp.suno.cn/mcp/api/generate] [请求体] {"prompt": "关于夏天的流行歌曲", "mv": "chirp-fenix", "custom_mode": false}
✅ 提交成功!正在生成中,请稍候...
[执行:GET https://mcp.suno.cn/mcp/api/task/123?wait=45]
🎵 生成完成!
歌曲名:夏日微风
时长:3:24
▶️ 点击播放:https://cdn.suno.cn/xxx.mp3
`
` 用户:我想用这首歌词生成音乐: [Verse] 阳光洒在海面 微风吹拂着脸
[Chorus] 这是我们的夏天 永远不变的画面
AI: 收到!我将用您提供的歌词生成音乐。 [执行:POST https://mcp.suno.cn/mcp/api/generate] [请求体] {"prompt": "[Verse]\n阳光洒在海面...", "custom_mode": true}
✅ 提交成功!正在生成中,请稍候...
[后续流程同上]
`
` 用户:用 v5.5 模型生成一首电子音乐
AI: 好的,使用最新的 v5.5 模型为您创作电子音乐。 [执行:POST https://mcp.suno.cn/mcp/api/generate] [请求体] {"prompt": "电子音乐", "mv": "chirp-fenix", "tags": "electronic"}
✅ 提交成功!正在生成中...
`
` 用户:帮我写首歌
AI: 请问您想要什么样的歌曲呢?您可以选择: 1. 提供完整歌词(我会用您的歌词生成音乐) 2. 描述音乐风格(例如:关于爱情的抒情歌、欢快的舞曲等)
请告诉我更多细节~
`
提交后必须立即查询状态(带 wait=45) ` 步骤:
轮询限制(必须严格遵守)
?wait=45编码要求
用途:查询生成进度,或生成后轮询。
` 当需要查询任务状态时(生成后自动查询 / 用户主动询问):
步骤 1:确定要查询的任务编号 IF 是刚生成的任务: serialNos = 上一步 POST /generate 返回的 serial_nos ELSE IF 用户提供了编号(如"查一下 123 的状态"): serialNos = 用户提供的编号 ELSE IF 用户说"刚才的歌/最近的任务": serialNos = 最近一次提交的任务编号(需要从上下文记忆) ELSE: 询问用户:"请问要查询哪个任务?请提供任务编号" → 停止,等待用户回复
步骤 2:构建请求 request = { method: "GET", url: "https://mcp.suno.cn/mcp/api/task/" + serialNos + "?wait=45", headers: { "Authorization": "Bearer ${SUNO_CN_API_KEY}" } }
⚠️ 注意:
步骤 3:发送请求并处理响应 response = send(request)
IF response.status == 200: tasks = response.tasks
FOR EACH task IN tasks:
status = task.status
IF status == "success":
展示:
🎵 歌曲名:{task.title}
⏱️ 时长:{task.duration}秒
▶️ 播放:{task.play_url}
ELSE IF status == "queued" 或 "processing":
说:
⏳ 音乐还在生成中,当前状态:{status}
请您过 1-2 分钟再问我"好了吗",我会继续为您查询。
→ 停止,不要再调用 API
ELSE IF status == "failed":
说:
❌ 生成失败
原因:{task.fail_reason}
→ 停止,不要重试
ELSE:
说:
⚠️ 未知状态:{status}
ELSE: 转到 "错误处理流程" `
| 字段 | 类型 | 说明 |
|---|---|---|
| serial_no | string | 任务编号 |
| status | string | queued(排队中)/ processing(处理中)/ success(成功)/ failed(失败) |
| title | string | 歌曲名(仅 success 时有值) |
| duration | number | 时长,单位秒(仅 success 时有值) |
| play_url | string | 播放链接(仅 success 时有值,直接展示给用户点击) |
| fail_reason | string | 失败原因(仅 failed 时有值) |
` AI: [刚执行完 POST /generate,获得 serial_nos: ["789"]] ✅ 提交成功!正在生成中,请稍候...
[执行:GET https://mcp.suno.cn/mcp/api/task/789?wait=45]
🎵 生成完成!
歌曲名:夏日微风
时长:204 秒(3 分 24 秒)
▶️ 点击播放:https://cdn.suno.cn/audio/789.mp3
`
` 用户:刚才那首歌好了吗
AI: [执行:GET https://mcp.suno.cn/mcp/api/task/789] ⏳ 音乐还在生成中,当前状态:processing 请您过 1-2 分钟再问我"好了吗",我会继续为您查询。
→ 停止,不要再调用查询接口
`
` 用户:帮我查一下 123、456、789 这三个任务
AI: [执行:GET https://mcp.suno.cn/mcp/api/task/123,456,789?wait=45]
任务 123:✅ 已完成
歌曲名:春之歌
播放:https://cdn.suno.cn/audio/123.mp3
任务 456:⏳ 生成中(processing)
请稍后再问
任务 789:❌ 失败
原因:内容违规,请修改后重试
`
wait 参数使用规则
?wait=45轮询限制(违反会导致限流)
状态处理优先级
success → 立即展示播放链接 failed → 展示失败原因,不要重试 queued/processing → 告知用户稍后再问,然后停止
用途:用户查看历史生成记录。
` 当用户表达 [查看历史] [我的歌曲] [音乐列表] [生成记录] 等意图时:
步骤 1:构建请求 request = { method: "GET", url: "https://mcp.suno.cn/mcp/api/music?page=1&page_size=10", headers: { "Authorization": "Bearer ${SUNO_CN_API_KEY}" } }
可选参数:
步骤 2:发送请求并处理响应 response = send(request)
IF response.status == 200: list = response.list page = response.page
IF list 为空:
说:"您还没有生成过任何音乐,快来创作第一首吧!"
ELSE:
说:"这是您最近生成的音乐:"
FOR EACH item IN list:
展示:
[{item.serial_no}] {item.title}
状态:{item.status}
播放:{item.play_url || "生成中"}
ELSE: 转到 "错误处理流程" `
| 字段 | 类型 | 说明 |
|---|---|---|
| list | array | 音乐列表数组 |
| list[].serial_no | string | 任务编号 |
| list[].title | string | 歌曲标题 |
| list[].status | string | success / failed / processing |
| list[].play_url | string | 播放链接(仅 success 时有值) |
| page | number | 当前页码 |
| total | number | 总页数(如有) |
` 用户:显示我最近的音乐列表
AI: [执行:GET https://mcp.suno.cn/mcp/api/music?page=1&page_size=10]
这是您最近生成的音乐(第 1 页,共 10 首):
1. [789] 夏日微风
状态:✅ 已完成
▶️ 播放:https://cdn.suno.cn/audio/789.mp3
2. [456] 夜的钢琴曲
状态:✅ 已完成
▶️ 播放:https://cdn.suno.cn/audio/456.mp3
3. [123] 春之序曲
状态:⏳ 生成中
如需查看更多,请说"下一页"或"查看第 2 页"
`
用途:用户想查看某首歌的歌词。
` 当用户表达 [看歌词] [显示歌词] [这首歌写的什么] 等意图时:
步骤 1:确定任务编号 IF 用户提供了编号(如"看 789 的歌词"): serialNo = 用户提供的编号 ELSE IF 用户说"刚才那首歌的歌词": serialNo = 最近一次生成的任务编号 ELSE: 询问用户:"请问要查看哪首歌的歌词?请提供任务编号" → 停止,等待用户回复
步骤 2:构建请求 request = { method: "GET", url: "https://mcp.suno.cn/mcp/api/lyrics/" + serialNo, headers: { "Authorization": "Bearer ${SUNO_CN_API_KEY}" } }
步骤 3:发送请求并处理响应 response = send(request)
IF response.status == 200: lyrics = response.lyrics
⚠️ 重要:必须完整原样展示 lyrics 字段内容
说:"这是歌曲的歌词:"
`
{lyrics 完整内容,一字不改}
`
❌ 禁止行为:
- 不要总结歌词大意
- 不要翻译歌词
- 不要改写或省略
- 不要说"大概意思是..."
ELSE: 转到 "错误处理流程" `
| 字段 | 类型 | 说明 |
|---|---|---|
| serial_no | string | 任务编号 |
| lyrics | string | LRC 格式歌词文本(可能包含时间轴标记) |
` 用户:显示 789 的歌词
AI: [执行:GET https://mcp.suno.cn/mcp/api/lyrics/789]
这是歌曲《夏日微风》的歌词:
`
[00:00.00] 夏日微风
[00:15.20] 阳光洒在海面
[00:18.50] 微风吹拂着脸
[00:22.10] 这是我们的夏天
[00:25.80] 永远不变的画面
...
`
(必须完整展示,不要省略任何内容)
`
` 用户:看 123 的歌词
AI: [执行:GET https://mcp.suno.cn/mcp/api/lyrics/123]
❌ 未找到该任务的歌词,可能原因:
- 任务尚未完成
- 该任务是纯音乐(无歌词)
- 任务编号不正确
`
必须原样展示
LRC 格式说明
用途:在某首歌基础上继续创作。
` 当用户表达 [续写] [接着写] [继续创作] [从 XX 秒开始续] 等意图时:
步骤 1:确认原任务编号和续写位置 IF 用户提供了编号和时间(如"从 789 的 30 秒处续写"): serialNo = 789 continueAt = 30 ELSE IF 用户只说"续写刚才的歌": serialNo = 最近一次生成的任务编号 continueAt = 0(从结尾续写) ELSE: 询问用户:"请问要续写哪首歌?请提供任务编号,以及从第几秒开始续写(默认从结尾)" → 停止,等待用户回复
步骤 2:构建请求 request = { method: "POST", url: "https://mcp.suno.cn/mcp/api/extend", headers: { "Authorization": "Bearer ${SUNO_CN_API_KEY}", "Content-Type": "application/json; charset=utf-8" }, body: { serial_no: serialNo, continue_at: continueAt, mv: 用户指定的版本 || "chirp-fenix" } }
步骤 3:发送请求并处理响应 response = send(request)
IF response.status == 200: newSerialNo = response.serial_no message = response.message
说:"✅ 续写提交成功!新任务编号:{newSerialNo}"
转到 "API 3:查询任务状态" 流程
ELSE: 转到 "错误处理流程" `
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| serial_no | string | ✅ 是 | 原任务编号 |
| continue_at | number | ❌ 否 | 从第几秒续写,0 为从结尾续写,默认 0 |
| mv | string | ❌ 否 | 模型版本,默认 chirp-fenix |
| 字段 | 类型 | 说明 |
|---|---|---|
| serial_no | string | 新任务编号(续写生成的任务) |
| message | string | 提交结果消息 |
` 用户:从刚才那首歌的 30 秒处开始续写
AI: 好的,我将从原歌曲的 30 秒处继续创作。 [执行:POST https://mcp.suno.cn/mcp/api/extend] [请求体] {"serial_no": "789", "continue_at": 30, "mv": "chirp-fenix"}
✅ 续写提交成功!新任务编号:890
正在生成中,请稍候...
[执行:GET https://mcp.suno.cn/mcp/api/task/890?wait=45]
🎵 续写完成!
歌曲名:夏日微风(续)
时长:180 秒
▶️ 播放:https://cdn.suno.cn/audio/890.mp3
`
用途:先生成歌词再创作音乐。
` 当用户表达 [先写歌词] [生成歌词] [帮我写词] 等意图时:
步骤 1:确认歌词需求 IF 用户提供了灵感描述(如"写一首关于离别的歌"): inspiration = 用户的描述 ELSE: 询问用户:"请告诉我您想要的歌词主题或灵感(例如:关于离别、爱情、梦想等)" → 停止,等待用户回复
可选确认:
步骤 2:构建请求 request = { method: "POST", url: "https://mcp.suno.cn/mcp/api/gen-lyrics", headers: { "Authorization": "Bearer ${SUNO_CN_API_KEY}", "Content-Type": "application/json; charset=utf-8" }, body: { inspiration: inspiration, title: title || 不传, style: style || 不传 } }
步骤 3:发送请求并处理响应 response = send(request)
IF response.status == 200: lyrics = response.lyrics
说:"这是为您生成的歌词:"
`
{lyrics 完整内容}
`
然后询问:
"要用这首歌词生成音乐吗?我将使用 custom_mode=true 模式。"
→ 等待用户确认
IF 用户确认:
转到 "API 2:生成音乐" 流程(custom_mode=true)
ELSE: 转到 "错误处理流程" `
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| inspiration | string | ✅ 是 | 灵感描述,如"关于离别情的歌" |
| title | string | ❌ 否 | 歌曲标题 |
| style | string | ❌ 否 | 风格,如古风、流行、电子 |
| 字段 | 类型 | 说明 |
|---|---|---|
| lyrics | string | AI 生成的完整歌词 |
` 用户:帮我生成一首关于离别的歌词,要古风风格
AI: 好的,我来为您创作一首古风离别歌词。 [执行:POST https://mcp.suno.cn/mcp/api/gen-lyrics] [请求体] {"inspiration": "关于离别的歌", "style": "古风"}
这是为您生成的歌词:
`
[Verse 1]
长亭外古道边
芳草碧连天
晚风拂柳笛声残
夕阳山外山
[Chorus]
天之涯地之角
知交半零落
一壶浊酒尽余欢
今宵别梦寒
`
要用这首歌词生成音乐吗?我将为您创作一首古风歌曲。
(等待用户回复"好的"或"生成"后再调用 API 2)
用户:好的,用这个歌词生成音乐
AI: [执行:POST https://mcp.suno.cn/mcp/api/generate] [请求体] {"prompt": "[Verse 1]\n长亭外古道边...", "custom_mode": true, "tags": "古风"}
✅ 提交成功!正在生成中...
`
| HTTP 状态码 | 提示语 |
|---|---|
| 401/403 | "API Key 无效或已过期,请检查 SUNO_CN_API_KEY 配置" |
| 5xx | "请求服务器异常,请稍后重试" |
| 超时 | "请求超时,请稍后重试" |
| 网络错误 | "网络连接失败,请检查网络或代理设置" |
⚠️ 禁止使用其他表述,禁止添加"可能原因"、"建议检查"等额外内容。
任何 HTTP 请求失败时,除了展示上述用户友好的提示外,还必须输出详细的技术日志供排查问题。
| 类别 | 信息内容 | 是否输出 | 说明 |
|---|---|---|---|
| 请求信息 | HTTP 方法 | ✅ 是 | GET/POST |
| URL(不含 query 参数) | ✅ 是 | 如 https://mcp.suno.cn/mcp/api/user | |
| Header(隐藏 Authorization) | ✅ 是 | Authorization 显示为 Bearer sk-******** | |
| 请求体(隐藏 key) | ✅ 是 | 如有 key 相关字段,用 ******** 替换 | |
| 响应信息 | HTTP 状态码 | ✅ 是 | 如 401、500 |
| 响应头 | ✅ 是 | 完整展示 | |
| 响应体 | ✅ 是 | 完整展示,即使是错误信息 | |
| 错误信息 | 错误类型 | ✅ 是 | 如 NetworkError、TimeoutError |
| 错误消息 | ✅ 是 | 完整的错误文本 | |
| 堆栈跟踪 | ✅ 是 | 如有,完整展示 |
Authorization: Bearer sk-xxxxxxxxxx → Authorization: Bearer sk-********sk- 开头的字符串 → sk-********SUNO_CN_API_KEY 环境变量的完整值 → ********使用代码块包裹详细日志,格式如下:
` === 错误详情 === 请求:POST https://mcp.suno.cn/mcp/api/generate 状态码:503 错误:请求服务器异常
--- 请求头 --- Content-Type: application/json Authorization: Bearer sk-********
--- 响应头 --- Content-Type: application/json Retry-After: 60
--- 响应体 --- {"error": "Service Unavailable", "message": "Please try again later"} `
⚠️ 详细日志仅供技术排查,不要让普通用户误解。先展示用户友好提示,再展示详细日志。
如果 API 响应包含未预期的字段,原样展示,不要报错。
GET https://mcp.suno.cn/mcp/skill/version
如果 latest_version 高于 1.2.0,告知用户有新版本。