Files
suno-mcp-server/suno-server/dist/handlers.js
T

417 lines
17 KiB
JavaScript

"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.ToolHandlers = void 0;
const schemas = __importStar(require("./schemas"));
const ASYNC_POLLING_PATHS = {
'suno_generate_music': '/generate/record-info?taskId=',
'suno_generate_lyrics': '/lyrics/record-info?taskId=',
'suno_generate_sounds': '/generate/record-info?taskId=',
'suno_extend_music': '/generate/record-info?taskId=',
'suno_replace_section': '/generate/record-info?taskId=',
'suno_upload_and_cover': '/generate/record-info?taskId=',
'suno_upload_and_extend': '/generate/record-info?taskId=',
'suno_add_vocals': '/generate/record-info?taskId=',
'suno_add_instrumental': '/generate/record-info?taskId=',
'suno_generate_mashup': '/generate/record-info?taskId=',
'suno_separate_vocals': '/vocal-removal/record-info?taskId=',
'suno_separate_stems': '/vocal-removal/record-info?taskId=',
'suno_create_video': '/generate/video-info?taskId=',
'suno_create_cover': '/generate/cover-info?taskId=',
'suno_convert_to_wav': '/generate/wav-info?taskId=',
};
function copyDefined(source, target, keys) {
for (const key of keys) {
const value = source[key];
if (value !== undefined) {
target[key] = value;
}
}
}
function isLyricsData(data) {
return data.type === 'LYRICS';
}
function formatLyricsResult(data) {
const status = data.status;
if (status !== 'SUCCESS') {
return JSON.stringify({
taskId: data.taskId,
status,
errorCode: data.errorCode,
errorMessage: data.errorMessage,
}, null, 2);
}
const variants = data.response?.data ?? [];
return JSON.stringify({
taskId: data.taskId,
status,
type: data.type,
variants: variants.map((v, index) => ({
index: index + 1,
title: v.title,
text: v.text,
status: v.status,
errorMessage: v.errorMessage,
})),
}, null, 2);
}
function formatTaskResult(data) {
if (isLyricsData(data)) {
return formatLyricsResult(data);
}
const status = data.status;
if (status !== 'SUCCESS') {
return JSON.stringify({
taskId: data.taskId,
status,
errorCode: data.errorCode,
errorMessage: data.errorMessage,
}, null, 2);
}
const response = data.response;
const tracks = (response?.data ?? response?.sunoData ?? []);
return JSON.stringify({
taskId: data.taskId,
status,
operationType: data.operationType,
tracks: tracks.map((t) => ({
id: t.id,
title: t.title,
tags: t.tags,
duration: t.duration,
prompt: t.prompt,
audio_url: t.audio_url ?? t.audioUrl,
stream_audio_url: t.stream_audio_url ?? t.streamAudioUrl,
image_url: t.image_url ?? t.imageUrl,
})),
}, null, 2);
}
async function runAsyncTask(client, taskName, createPath, payload) {
const createResult = await client.post(createPath, payload);
const taskId = createResult.data.taskId;
const statusPathTemplate = ASYNC_POLLING_PATHS[taskName];
if (!statusPathTemplate) {
return JSON.stringify({ taskId, status: 'PENDING', note: 'Use suno_get_task_status to poll.' }, null, 2);
}
const statusData = await client.pollTaskStatus(taskId, {
statusPath: `${statusPathTemplate}${encodeURIComponent(taskId)}`,
});
return formatTaskResult(statusData);
}
class ToolHandlers {
client;
constructor(client) {
this.client = client;
}
async handle(name, args) {
let resultText;
switch (name) {
case 'suno_generate_music': {
const input = schemas.GenerateMusicSchema.parse(args);
const payload = {
customMode: input.customMode,
instrumental: input.instrumental,
model: input.model,
callBackUrl: input.callBackUrl ?? '',
};
copyDefined(input, payload, [
'prompt',
'style',
'title',
'negativeTags',
'vocalGender',
'styleWeight',
'weirdnessConstraint',
'audioWeight',
'personaId',
'personaModel',
]);
resultText = await runAsyncTask(this.client, name, '/generate', payload);
break;
}
case 'suno_generate_lyrics': {
const input = schemas.GenerateLyricsSchema.parse(args);
resultText = await runAsyncTask(this.client, name, '/lyrics', {
prompt: input.prompt,
callBackUrl: input.callBackUrl ?? '',
});
break;
}
case 'suno_generate_sounds': {
const input = schemas.GenerateSoundsSchema.parse(args);
const payload = {
prompt: input.prompt,
model: input.model,
callBackUrl: input.callBackUrl ?? '',
};
copyDefined(input, payload, ['soundLoop', 'soundTempo', 'soundKey', 'grabLyrics']);
resultText = await runAsyncTask(this.client, name, '/generate/sounds', payload);
break;
}
case 'suno_extend_music': {
const input = schemas.ExtendMusicSchema.parse(args);
const payload = {
audioId: input.audioId,
defaultParamFlag: input.defaultParamFlag,
model: input.model,
callBackUrl: input.callBackUrl ?? '',
};
copyDefined(input, payload, [
'prompt',
'style',
'title',
'continueAt',
'negativeTags',
'vocalGender',
'styleWeight',
'weirdnessConstraint',
'audioWeight',
'personaId',
'personaModel',
]);
resultText = await runAsyncTask(this.client, name, '/generate/extend', payload);
break;
}
case 'suno_replace_section': {
const input = schemas.ReplaceSectionSchema.parse(args);
const payload = {
audioId: input.audioId,
prompt: input.prompt,
start: input.start,
end: input.end,
model: input.model,
callBackUrl: input.callBackUrl ?? '',
};
copyDefined(input, payload, ['replaceAudioUrl', 'customMode', 'style', 'title', 'instrumental']);
resultText = await runAsyncTask(this.client, name, '/generate/replace-section', payload);
break;
}
case 'suno_add_vocals': {
const input = schemas.AddVocalsSchema.parse(args);
const payload = {
audioId: input.audioId,
model: input.model,
callBackUrl: input.callBackUrl ?? '',
};
copyDefined(input, payload, ['prompt', 'customMode', 'style', 'title']);
resultText = await runAsyncTask(this.client, name, '/generate/add-vocals', payload);
break;
}
case 'suno_add_instrumental': {
const input = schemas.AddInstrumentalSchema.parse(args);
const payload = {
audioId: input.audioId,
model: input.model,
callBackUrl: input.callBackUrl ?? '',
};
copyDefined(input, payload, ['prompt', 'customMode', 'style', 'title']);
resultText = await runAsyncTask(this.client, name, '/generate/add-instrumental', payload);
break;
}
case 'suno_upload_and_cover': {
const input = schemas.UploadAndCoverSchema.parse(args);
const payload = {
uploadUrl: input.uploadUrl,
customMode: input.customMode,
instrumental: input.instrumental,
model: input.model,
callBackUrl: input.callBackUrl ?? '',
};
copyDefined(input, payload, [
'prompt',
'style',
'title',
'negativeTags',
'vocalGender',
'styleWeight',
'weirdnessConstraint',
'audioWeight',
'personaId',
'personaModel',
]);
resultText = await runAsyncTask(this.client, name, '/generate/upload-cover', payload);
break;
}
case 'suno_upload_and_extend': {
const input = schemas.UploadAndExtendSchema.parse(args);
const payload = {
uploadUrl: input.uploadUrl,
defaultParamFlag: input.defaultParamFlag,
model: input.model,
callBackUrl: input.callBackUrl ?? '',
};
copyDefined(input, payload, ['prompt', 'style', 'title', 'continueAt']);
resultText = await runAsyncTask(this.client, name, '/generate/upload-extend', payload);
break;
}
case 'suno_generate_mashup': {
const input = schemas.GenerateMashupSchema.parse(args);
const payload = {
uploadUrlList: input.uploadUrlList,
customMode: input.customMode,
prompt: input.prompt,
model: input.model,
callBackUrl: input.callBackUrl ?? '',
};
copyDefined(input, payload, [
'instrumental',
'style',
'title',
'negativeTags',
'vocalGender',
'styleWeight',
'weirdnessConstraint',
'audioWeight',
]);
resultText = await runAsyncTask(this.client, name, '/generate/mashup', payload);
break;
}
case 'suno_separate_vocals': {
const input = schemas.SeparateVocalsSchema.parse(args);
resultText = await runAsyncTask(this.client, name, '/vocal-removal/generate', {
taskId: input.taskId,
audioId: input.audioId,
callBackUrl: input.callBackUrl ?? '',
});
break;
}
case 'suno_separate_stems': {
const input = schemas.SeparateStemsSchema.parse(args);
resultText = await runAsyncTask(this.client, name, '/vocal-removal/generate', {
taskId: input.taskId,
audioId: input.audioId,
type: 'split_stem',
callBackUrl: input.callBackUrl ?? '',
});
break;
}
case 'suno_create_video': {
const input = schemas.CreateVideoSchema.parse(args);
const payload = {
taskId: input.taskId,
audioId: input.audioId,
callBackUrl: input.callBackUrl ?? '',
};
copyDefined(input, payload, ['author', 'domainName']);
resultText = await runAsyncTask(this.client, name, '/generate/video', payload);
break;
}
case 'suno_create_cover': {
const input = schemas.CreateCoverSchema.parse(args);
resultText = await runAsyncTask(this.client, name, '/generate/cover', {
taskId: input.taskId,
audioId: input.audioId,
callBackUrl: input.callBackUrl ?? '',
});
break;
}
case 'suno_convert_to_wav': {
const input = schemas.ConvertToWavSchema.parse(args);
resultText = await runAsyncTask(this.client, name, '/generate/wav', {
taskId: input.taskId,
audioId: input.audioId,
callBackUrl: input.callBackUrl ?? '',
});
break;
}
case 'suno_boost_style': {
const input = schemas.BoostStyleSchema.parse(args);
const result = await this.client.post('/style/generate', {
content: input.content,
});
resultText = result.data.result;
break;
}
case 'suno_generate_persona': {
const input = schemas.GeneratePersonaSchema.parse(args);
const payload = { taskId: input.taskId };
if (input.audioId !== undefined)
payload.audioId = input.audioId;
const result = await this.client.post('/generate/persona', payload);
resultText = JSON.stringify(result.data, null, 2);
break;
}
case 'suno_get_task_status': {
const input = schemas.GetTaskStatusSchema.parse(args);
const data = await this.client.get(`/generate/record-info?taskId=${encodeURIComponent(input.taskId)}`);
resultText = formatTaskResult(data.data);
break;
}
case 'suno_get_timestamped_lyrics': {
const input = schemas.GetTimestampedLyricsSchema.parse(args);
const result = await this.client.get(`/generate/timestamped-lyrics?taskId=${encodeURIComponent(input.taskId)}&audioId=${encodeURIComponent(input.audioId)}`);
resultText = JSON.stringify(result.data, null, 2);
break;
}
case 'suno_get_lyrics_details': {
const input = schemas.GetLyricsDetailsSchema.parse(args);
const result = await this.client.get(`/lyrics/record-info?taskId=${encodeURIComponent(input.taskId)}`);
resultText = formatLyricsResult(result.data);
break;
}
case 'suno_get_wav_details': {
const input = schemas.GetWavDetailsSchema.parse(args);
const result = await this.client.get(`/generate/wav-info?taskId=${encodeURIComponent(input.taskId)}`);
resultText = JSON.stringify(result.data, null, 2);
break;
}
case 'suno_get_vocal_separation_details': {
const input = schemas.GetVocalSeparationDetailsSchema.parse(args);
const result = await this.client.get(`/vocal-removal/record-info?taskId=${encodeURIComponent(input.taskId)}`);
resultText = JSON.stringify(result.data, null, 2);
break;
}
case 'suno_get_video_details': {
const input = schemas.GetVideoDetailsSchema.parse(args);
const result = await this.client.get(`/generate/video-info?taskId=${encodeURIComponent(input.taskId)}`);
resultText = JSON.stringify(result.data, null, 2);
break;
}
case 'suno_get_credits': {
schemas.GetCreditsSchema.parse(args);
const result = await this.client.get('/generate/credit');
resultText = JSON.stringify({ credits: result.data }, null, 2);
break;
}
default:
throw new Error(`Unknown tool: ${name}`);
}
return {
content: [{ type: 'text', text: resultText }],
};
}
}
exports.ToolHandlers = ToolHandlers;
//# sourceMappingURL=handlers.js.map