@kajidog/mcp-tts-voicevox
Version:
VOICEVOX integration for MCP - Text-to-Speech server using VOICEVOX engine
134 lines (133 loc) • 5.5 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.VoicevoxError = exports.VoicevoxClient = void 0;
const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
const zod_1 = require("zod");
const voicevox_1 = require("./voicevox");
Object.defineProperty(exports, "VoicevoxClient", { enumerable: true, get: function () { return voicevox_1.VoicevoxClient; } });
const types_1 = require("./voicevox/types");
Object.defineProperty(exports, "VoicevoxError", { enumerable: true, get: function () { return types_1.VoicevoxError; } });
const server = new mcp_js_1.McpServer({
name: "MCP TTS Voicevox",
version: "0.0.8",
description: "A Voicevox server that converts text to speech for playback and saving.",
});
// VoicevoxClientを一度だけインスタンス化
const voicevoxClient = new voicevox_1.VoicevoxClient({
url: process.env.VOICEVOX_URL ?? "http://localhost:50021",
defaultSpeaker: Number(process.env.VOICEVOX_DEFAULT_SPEAKER || "1"),
defaultSpeedScale: Number(process.env.VOICEVOX_DEFAULT_SPEED_SCALE || "1.0"),
});
// 共通のエラーハンドリング関数
const handleError = (error) => {
const errorMessage = error instanceof Error ? error.message : String(error);
console.error("エラーが発生しました:", error);
return {
content: [{ type: "text", text: `エラー: ${errorMessage}` }],
};
};
// テキストを音声に変換して再生
server.tool("speak", "Convert text to speech and play it", {
text: zod_1.z
.string()
.describe("Text to be spoken (if both query and text are provided, query takes precedence)"),
speaker: zod_1.z
.number()
.optional()
.describe("Speaker ID (optional, used if text is provided)"),
query: zod_1.z.string().optional().describe("Voice synthesis query"),
speedScale: zod_1.z
.number()
.optional()
.describe("Playback speed (optional, default is from environment variable)"),
}, async ({ text, speaker, query, speedScale }) => {
try {
if (query) {
// クエリが提供されている場合はそれを使用
const audioQuery = JSON.parse(query);
if (speedScale !== undefined) {
audioQuery.speedScale = speedScale;
}
const result = await voicevoxClient.enqueueAudioGeneration(audioQuery, speaker);
return {
content: [{ type: "text", text: result }],
};
}
else {
// テキストからの通常の発話
const result = await voicevoxClient.speak(text, speaker, speedScale);
return {
content: [{ type: "text", text: result }],
};
}
}
catch (error) {
return handleError(error);
}
});
// クエリ生成ツール
server.tool("generate_query", "Generate a query for voice synthesis", {
text: zod_1.z.string().describe("Text for voice synthesis"),
speaker: zod_1.z.number().optional().describe("Speaker ID (optional)"),
speedScale: zod_1.z
.number()
.optional()
.describe("Playback speed (optional, default is from environment variable)"),
}, async ({ text, speaker, speedScale }) => {
try {
const query = await voicevoxClient.generateQuery(text, speaker, speedScale);
return {
content: [{ type: "text", text: JSON.stringify(query) }],
};
}
catch (error) {
return handleError(error);
}
});
// 音声ファイル生成ツール
server.tool("synthesize_file", "Generate an audio file and return its absolute path", {
text: zod_1.z
.string()
.optional()
.describe("Text for voice synthesis (if both query and text are provided, query takes precedence)"),
query: zod_1.z.string().optional().describe("Voice synthesis query"),
speaker: zod_1.z.number().optional().describe("Speaker ID (optional)"),
output: zod_1.z.string().describe("Output path for the audio file"),
speedScale: zod_1.z
.number()
.optional()
.describe("Playback speed (optional, default is from environment variable)"),
}, async ({ text, query, speaker, output, speedScale }) => {
try {
if (query) {
// クエリが提供されている場合はそれを使用
const audioQuery = JSON.parse(query);
if (speedScale !== undefined) {
audioQuery.speedScale = speedScale;
}
const filePath = await voicevoxClient.generateAudioFile(audioQuery, output, speaker);
return {
content: [{ type: "text", text: filePath }],
};
}
else if (text) {
// テキストから音声ファイルを生成
const filePath = await voicevoxClient.generateAudioFile(text, output, speaker, speedScale);
return {
content: [{ type: "text", text: filePath }],
};
}
else {
throw new Error("queryパラメータとtextパラメータのどちらかを指定してください");
}
}
catch (error) {
return handleError(error);
}
});
server.connect(new stdio_js_1.StdioServerTransport()).catch((error) => {
console.error("Error connecting to MCP transport:", error);
process.exit(1);
});