@kajidog/mcp-tts-voicevox 0.0.5 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +114 -113
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2,128 +2,129 @@
|
|
|
2
2
|
"use strict";
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
4
|
exports.VoicevoxError = void 0;
|
|
5
|
-
exports.initVoicevox = initVoicevox;
|
|
6
5
|
const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
7
6
|
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
8
7
|
const zod_1 = require("zod");
|
|
9
8
|
const voicevox_1 = require("./voicevox");
|
|
10
9
|
const types_1 = require("./voicevox/types");
|
|
11
10
|
Object.defineProperty(exports, "VoicevoxError", { enumerable: true, get: function () { return types_1.VoicevoxError; } });
|
|
12
|
-
/**
|
|
13
|
-
* VOICEVOX音声合成クライアントを初期化します
|
|
14
|
-
* @param config 設定オブジェクト
|
|
15
|
-
* @returns VoicevoxClientのインスタンス
|
|
16
|
-
*/
|
|
17
|
-
function initVoicevox(config) {
|
|
18
|
-
return new voicevox_1.VoicevoxClient(config);
|
|
19
|
-
}
|
|
20
|
-
// デフォルトのVOICEVOXクライアント
|
|
21
|
-
const voicevoxClient = initVoicevox({
|
|
22
|
-
url: process.env.VOICEVOX_URL || "http://localhost:50021",
|
|
23
|
-
defaultSpeaker: Number(process.env.VOICEVOX_DEFAULT_SPEAKER || "1"),
|
|
24
|
-
defaultSpeedScale: Number(process.env.VOICEVOX_DEFAULT_SPEED_SCALE || "1.0"),
|
|
25
|
-
});
|
|
26
11
|
const server = new mcp_js_1.McpServer({
|
|
27
12
|
name: "MCP TTS Voicevox",
|
|
28
|
-
version: "0.0.
|
|
13
|
+
version: "0.0.6",
|
|
29
14
|
description: "A Voicevox server that converts text to speech for playback and saving.",
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
15
|
+
});
|
|
16
|
+
// VoicevoxClientを一度だけインスタンス化
|
|
17
|
+
const voicevoxClient = new voicevox_1.VoicevoxClient({
|
|
18
|
+
url: process.env.VOICEVOX_URL ?? "http://localhost:50021",
|
|
19
|
+
defaultSpeaker: Number(process.env.VOICEVOX_DEFAULT_SPEAKER || "1"),
|
|
20
|
+
defaultSpeedScale: Number(process.env.VOICEVOX_DEFAULT_SPEED_SCALE || "1.0"),
|
|
21
|
+
});
|
|
22
|
+
// 共通のエラーハンドリング関数
|
|
23
|
+
const handleError = (error) => {
|
|
24
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
25
|
+
console.error("エラーが発生しました:", error);
|
|
26
|
+
return {
|
|
27
|
+
content: [{ type: "text", text: `エラー: ${errorMessage}` }],
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
// テキストを音声に変換して再生
|
|
31
|
+
server.tool("speak", "Convert text to speech and play it", {
|
|
32
|
+
text: zod_1.z
|
|
33
|
+
.string()
|
|
34
|
+
.describe("Text to be spoken (if both query and text are provided, query takes precedence)"),
|
|
35
|
+
speaker: zod_1.z
|
|
36
|
+
.number()
|
|
37
|
+
.optional()
|
|
38
|
+
.describe("Speaker ID (optional, used if text is provided)"),
|
|
39
|
+
query: zod_1.z.string().optional().describe("Voice synthesis query"),
|
|
40
|
+
speedScale: zod_1.z
|
|
41
|
+
.number()
|
|
42
|
+
.optional()
|
|
43
|
+
.describe("Playback speed (optional, default is from environment variable)"),
|
|
44
|
+
}, async ({ text, speaker, query, speedScale }) => {
|
|
45
|
+
try {
|
|
46
|
+
if (query) {
|
|
47
|
+
// クエリが提供されている場合はそれを使用
|
|
48
|
+
const audioQuery = JSON.parse(query);
|
|
49
|
+
if (speedScale !== undefined) {
|
|
50
|
+
audioQuery.speedScale = speedScale;
|
|
51
|
+
}
|
|
52
|
+
const result = await voicevoxClient.enqueueAudioGeneration(audioQuery, speaker);
|
|
53
|
+
return {
|
|
54
|
+
content: [{ type: "text", text: result }],
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
// テキストからの通常の発話
|
|
59
|
+
const result = await voicevoxClient.speak(text, speaker, speedScale);
|
|
60
|
+
return {
|
|
61
|
+
content: [{ type: "text", text: result }],
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
return handleError(error);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
// クエリ生成ツール
|
|
70
|
+
server.tool("generate_query", "Generate a query for voice synthesis", {
|
|
71
|
+
text: zod_1.z.string().describe("Text for voice synthesis"),
|
|
72
|
+
speaker: zod_1.z.number().optional().describe("Speaker ID (optional)"),
|
|
73
|
+
speedScale: zod_1.z
|
|
74
|
+
.number()
|
|
75
|
+
.optional()
|
|
76
|
+
.describe("Playback speed (optional, default is from environment variable)"),
|
|
77
|
+
}, async ({ text, speaker, speedScale }) => {
|
|
78
|
+
try {
|
|
79
|
+
const query = await voicevoxClient.generateQuery(text, speaker, speedScale);
|
|
80
|
+
return {
|
|
81
|
+
content: [{ type: "text", text: JSON.stringify(query) }],
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
return handleError(error);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
// 音声ファイル生成ツール
|
|
89
|
+
server.tool("synthesize_file", "Generate an audio file and return its absolute path", {
|
|
90
|
+
text: zod_1.z
|
|
91
|
+
.string()
|
|
92
|
+
.optional()
|
|
93
|
+
.describe("Text for voice synthesis (if both query and text are provided, query takes precedence)"),
|
|
94
|
+
query: zod_1.z.string().optional().describe("Voice synthesis query"),
|
|
95
|
+
speaker: zod_1.z.number().optional().describe("Speaker ID (optional)"),
|
|
96
|
+
output: zod_1.z.string().describe("Output path for the audio file"),
|
|
97
|
+
speedScale: zod_1.z
|
|
98
|
+
.number()
|
|
99
|
+
.optional()
|
|
100
|
+
.describe("Playback speed (optional, default is from environment variable)"),
|
|
101
|
+
}, async ({ text, query, speaker, output, speedScale }) => {
|
|
102
|
+
try {
|
|
103
|
+
if (query) {
|
|
104
|
+
// クエリが提供されている場合はそれを使用
|
|
105
|
+
const audioQuery = JSON.parse(query);
|
|
106
|
+
if (speedScale !== undefined) {
|
|
107
|
+
audioQuery.speedScale = speedScale;
|
|
108
|
+
}
|
|
109
|
+
const filePath = await voicevoxClient.generateAudioFile(audioQuery, output, speaker);
|
|
110
|
+
return {
|
|
111
|
+
content: [{ type: "text", text: filePath }],
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
else if (text) {
|
|
115
|
+
// テキストから音声ファイルを生成
|
|
116
|
+
const filePath = await voicevoxClient.generateAudioFile(text, output, speaker, speedScale);
|
|
117
|
+
return {
|
|
118
|
+
content: [{ type: "text", text: filePath }],
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
throw new Error("queryパラメータとtextパラメータのどちらかを指定してください");
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
return handleError(error);
|
|
127
|
+
}
|
|
127
128
|
});
|
|
128
129
|
server.connect(new stdio_js_1.StdioServerTransport()).catch((error) => {
|
|
129
130
|
console.error("Error connecting to MCP transport:", error);
|