@kajidog/mcp-tts-voicevox 0.0.12 → 0.1.0
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/README.md +336 -20
- package/dist/index.js +188 -61
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +3 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +179 -0
- package/dist/server.js.map +1 -0
- package/dist/sse.d.ts +4 -0
- package/dist/sse.d.ts.map +1 -0
- package/dist/sse.js +255 -0
- package/dist/sse.js.map +1 -0
- package/dist/stdio.js +2 -190
- package/dist/stdio.js.map +1 -1
- package/dist/voicevox/index.d.ts +40 -3
- package/dist/voicevox/index.d.ts.map +1 -1
- package/dist/voicevox/index.js +83 -52
- package/dist/voicevox/index.js.map +1 -1
- package/dist/voicevox/types.d.ts +4 -0
- package/dist/voicevox/types.d.ts.map +1 -1
- package/package.json +46 -24
package/README.md
CHANGED
|
@@ -9,11 +9,17 @@ VOICEVOX を使用した音声合成 MCP サーバー
|
|
|
9
9
|
- **クロスプラットフォーム対応** - Windows、macOS で動作
|
|
10
10
|
- **マルチ環境対応** - Node.js(ライブラリ/CLI)とブラウザの環境で利用可能
|
|
11
11
|
- **ファイルダウンロード機能** - ブラウザ環境での音声ファイル保存をサポート
|
|
12
|
+
- **Stdio 対応** - 標準入出力による MCP プロトコル通信(Claude Desktop 等で推奨)
|
|
13
|
+
- **SSE 対応** - Server-Sent Events によるリアルタイム対話形式音声再生
|
|
14
|
+
- **StreamableHTTP 対応** - ストリーミング形式での HTTP 通信による高速音声合成
|
|
15
|
+
- **対話形式音声再生** - チャット形式でのリアルタイム音声合成・再生機能
|
|
16
|
+
- **複数話者対応** - セグメント単位での個別話者指定が可能
|
|
17
|
+
- **テキスト自動分割** - 長文の自動分割による安定した音声合成
|
|
12
18
|
|
|
13
19
|
## 必要条件
|
|
14
20
|
|
|
15
|
-
- Node.js
|
|
16
|
-
- [VOICEVOX エンジン](https://voicevox.hiroshiba.jp/)
|
|
21
|
+
- Node.js 18.0.0 以上
|
|
22
|
+
- [VOICEVOX エンジン](https://voicevox.hiroshiba.jp/) または互換エンジン
|
|
17
23
|
|
|
18
24
|
## インストール
|
|
19
25
|
|
|
@@ -25,13 +31,218 @@ npm install -g @kajidog/mcp-tts-voicevox
|
|
|
25
31
|
|
|
26
32
|
### MCP サーバーとして
|
|
27
33
|
|
|
28
|
-
1. VOICEVOX エンジンを起動
|
|
29
|
-
|
|
34
|
+
#### 1. VOICEVOX エンジンを起動
|
|
35
|
+
|
|
36
|
+
VOICEVOX エンジンを起動し、デフォルトポート(`http://localhost:50021`)で待機状態にします。
|
|
37
|
+
|
|
38
|
+
#### 2. MCP サーバーを起動
|
|
39
|
+
|
|
40
|
+
**標準入出力モード(推奨):**
|
|
30
41
|
|
|
31
42
|
```bash
|
|
32
43
|
npx @kajidog/mcp-tts-voicevox
|
|
33
44
|
```
|
|
34
45
|
|
|
46
|
+
**HTTP サーバーモード:**
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# Linux/macOS
|
|
50
|
+
MCP_HTTP_MODE=true npx @kajidog/mcp-tts-voicevox
|
|
51
|
+
|
|
52
|
+
# Windows PowerShell
|
|
53
|
+
$env:MCP_HTTP_MODE='true'; npx @kajidog/mcp-tts-voicevox
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### MCP ツール一覧
|
|
57
|
+
|
|
58
|
+
MCP サーバーは以下のツールを提供します:
|
|
59
|
+
|
|
60
|
+
#### `speak` - テキスト読み上げ
|
|
61
|
+
|
|
62
|
+
テキストを音声に変換して再生します。
|
|
63
|
+
|
|
64
|
+
**パラメータ:**
|
|
65
|
+
|
|
66
|
+
- `text`: 文字列配列、またはテキストと話者ペアの配列
|
|
67
|
+
- `speaker` (オプション): 話者 ID
|
|
68
|
+
- `speedScale` (オプション): 再生速度
|
|
69
|
+
- `query` (オプション): 事前生成済みクエリ
|
|
70
|
+
|
|
71
|
+
**使用例:**
|
|
72
|
+
|
|
73
|
+
```javascript
|
|
74
|
+
// シンプルなテキスト
|
|
75
|
+
{ "text": ["こんにちは", "今日はいい天気ですね"] }
|
|
76
|
+
|
|
77
|
+
// 話者指定
|
|
78
|
+
{ "text": ["こんにちは", "今日はいい天気ですね"], "speaker": 3 }
|
|
79
|
+
|
|
80
|
+
// セグメント別話者指定
|
|
81
|
+
{ "text": [{"text": "こんにちは", "speaker": 1}, {"text": "今日はいい天気ですね", "speaker": 3}] }
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
#### `generate_query` - クエリ生成
|
|
85
|
+
|
|
86
|
+
音声合成用クエリを生成します。
|
|
87
|
+
|
|
88
|
+
**パラメータ:**
|
|
89
|
+
|
|
90
|
+
- `text`: 合成するテキスト
|
|
91
|
+
- `speaker` (オプション): 話者 ID
|
|
92
|
+
- `speedScale` (オプション): 再生速度
|
|
93
|
+
|
|
94
|
+
#### `synthesize_file` - ファイル生成
|
|
95
|
+
|
|
96
|
+
音声ファイルを生成し、パスを返します。
|
|
97
|
+
|
|
98
|
+
**パラメータ:**
|
|
99
|
+
|
|
100
|
+
- `text` (オプション): 合成するテキスト
|
|
101
|
+
- `query` (オプション): 事前生成済みクエリ
|
|
102
|
+
- `output`: 出力ファイルパス
|
|
103
|
+
- `speaker` (オプション): 話者 ID
|
|
104
|
+
- `speedScale` (オプション): 再生速度
|
|
105
|
+
|
|
106
|
+
#### `stop_speaker` - 再生停止
|
|
107
|
+
|
|
108
|
+
現在の音声合成キューをクリアします。
|
|
109
|
+
|
|
110
|
+
#### `get_speakers` - 話者一覧取得
|
|
111
|
+
|
|
112
|
+
利用可能な話者一覧を取得します。
|
|
113
|
+
|
|
114
|
+
#### `get_speaker_detail` - 話者詳細取得
|
|
115
|
+
|
|
116
|
+
指定した UUID の話者詳細情報を取得します。
|
|
117
|
+
|
|
118
|
+
**パラメータ:**
|
|
119
|
+
|
|
120
|
+
- `uuid`: 話者 UUID
|
|
121
|
+
|
|
122
|
+
### 対話形式音声再生の使用例
|
|
123
|
+
|
|
124
|
+
#### StreamableHTTP を使用した対話形式再生
|
|
125
|
+
|
|
126
|
+
```javascript
|
|
127
|
+
// セッション初期化
|
|
128
|
+
const response = await fetch("http://localhost:3000/mcp", {
|
|
129
|
+
method: "POST",
|
|
130
|
+
headers: {
|
|
131
|
+
"Content-Type": "application/json",
|
|
132
|
+
},
|
|
133
|
+
body: JSON.stringify({
|
|
134
|
+
jsonrpc: "2.0",
|
|
135
|
+
method: "initialize",
|
|
136
|
+
params: {
|
|
137
|
+
protocolVersion: "2024-11-05",
|
|
138
|
+
capabilities: {},
|
|
139
|
+
},
|
|
140
|
+
id: 1,
|
|
141
|
+
}),
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
const sessionData = await response.json();
|
|
145
|
+
const sessionId = response.headers.get("mcp-session-id");
|
|
146
|
+
|
|
147
|
+
// 音声合成・再生リクエスト
|
|
148
|
+
const speakResponse = await fetch("http://localhost:3000/mcp", {
|
|
149
|
+
method: "POST",
|
|
150
|
+
headers: {
|
|
151
|
+
"Content-Type": "application/json",
|
|
152
|
+
"mcp-session-id": sessionId,
|
|
153
|
+
},
|
|
154
|
+
body: JSON.stringify({
|
|
155
|
+
jsonrpc: "2.0",
|
|
156
|
+
method: "tools/call",
|
|
157
|
+
params: {
|
|
158
|
+
name: "speak",
|
|
159
|
+
arguments: {
|
|
160
|
+
text: ["こんにちは、対話形式で音声を再生します"],
|
|
161
|
+
speaker: 1,
|
|
162
|
+
speedScale: 1.0,
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
id: 2,
|
|
166
|
+
}),
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
const result = await speakResponse.json();
|
|
170
|
+
console.log("結果:", result);
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
#### 複数話者を使用した対話例
|
|
174
|
+
|
|
175
|
+
```javascript
|
|
176
|
+
// 複数話者での会話例
|
|
177
|
+
const conversationResponse = await fetch("http://localhost:3000/mcp", {
|
|
178
|
+
method: "POST",
|
|
179
|
+
headers: {
|
|
180
|
+
"Content-Type": "application/json",
|
|
181
|
+
"mcp-session-id": sessionId,
|
|
182
|
+
},
|
|
183
|
+
body: JSON.stringify({
|
|
184
|
+
jsonrpc: "2.0",
|
|
185
|
+
method: "tools/call",
|
|
186
|
+
params: {
|
|
187
|
+
name: "speak",
|
|
188
|
+
arguments: {
|
|
189
|
+
text: [
|
|
190
|
+
{ text: "こんにちは!", speaker: 1 },
|
|
191
|
+
{ text: "お元気ですか?", speaker: 3 },
|
|
192
|
+
{ text: "とても元気です!", speaker: 1 },
|
|
193
|
+
],
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
id: 3,
|
|
197
|
+
}),
|
|
198
|
+
});
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
#### SSE を使用した対話形式再生(レガシー)
|
|
202
|
+
|
|
203
|
+
```javascript
|
|
204
|
+
// SSE接続の確立
|
|
205
|
+
const eventSource = new EventSource("http://localhost:3000/sse");
|
|
206
|
+
let sessionId = null;
|
|
207
|
+
|
|
208
|
+
eventSource.onopen = function (event) {
|
|
209
|
+
console.log("SSE接続が確立されました");
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
eventSource.onmessage = function (event) {
|
|
213
|
+
const data = JSON.parse(event.data);
|
|
214
|
+
|
|
215
|
+
if (data.type === "session") {
|
|
216
|
+
sessionId = data.sessionId;
|
|
217
|
+
console.log("セッションID:", sessionId);
|
|
218
|
+
|
|
219
|
+
// 音声合成リクエストを送信
|
|
220
|
+
sendSpeakRequest();
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
async function sendSpeakRequest() {
|
|
225
|
+
await fetch(`http://localhost:3000/messages?sessionId=${sessionId}`, {
|
|
226
|
+
method: "POST",
|
|
227
|
+
headers: {
|
|
228
|
+
"Content-Type": "application/json",
|
|
229
|
+
},
|
|
230
|
+
body: JSON.stringify({
|
|
231
|
+
jsonrpc: "2.0",
|
|
232
|
+
method: "tools/call",
|
|
233
|
+
params: {
|
|
234
|
+
name: "speak",
|
|
235
|
+
arguments: {
|
|
236
|
+
text: ["SSEを使用した音声再生です"],
|
|
237
|
+
speaker: 1,
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
id: 1,
|
|
241
|
+
}),
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
35
246
|
### ライブラリとして
|
|
36
247
|
|
|
37
248
|
プロジェクトに直接インポートして使用することも可能です:
|
|
@@ -55,6 +266,15 @@ const client = new VoicevoxClient({
|
|
|
55
266
|
// テキストを音声に変換して再生
|
|
56
267
|
await client.speak("こんにちは");
|
|
57
268
|
|
|
269
|
+
// 配列でのテキスト読み上げ
|
|
270
|
+
await client.speak(["こんにちは", "今日はいい天気ですね"]);
|
|
271
|
+
|
|
272
|
+
// 話者を個別指定
|
|
273
|
+
await client.speak([
|
|
274
|
+
{ text: "こんにちは", speaker: 1 },
|
|
275
|
+
{ text: "お元気ですか?", speaker: 3 },
|
|
276
|
+
]);
|
|
277
|
+
|
|
58
278
|
// テキストから音声ファイルを生成
|
|
59
279
|
const filePath = await client.generateAudioFile("こんにちは", "./output.wav");
|
|
60
280
|
|
|
@@ -99,21 +319,65 @@ document
|
|
|
99
319
|
});
|
|
100
320
|
```
|
|
101
321
|
|
|
102
|
-
##
|
|
322
|
+
## MCP 設定例
|
|
323
|
+
|
|
324
|
+
### Claude Desktop での設定
|
|
103
325
|
|
|
104
|
-
|
|
105
|
-
- **読み上げ停止** (`stop_speaker`) - 現在の音声合成キューをすべてクリア
|
|
106
|
-
- **クエリ生成** (`generate_query`) - 音声合成用クエリの作成
|
|
107
|
-
- **ファイル生成** (`synthesize_file`) - クエリから音声ファイルを生成
|
|
108
|
-
- **音声ファイルダウンロード** (`generateAudioFile`) - 音声ファイルを生成し、ブラウザでダウンロード
|
|
109
|
-
- **スピーカー一覧取得** (`get_speakers`) - 利用可能なスピーカー一覧を取得
|
|
110
|
-
- **スピーカー詳細取得** (`get_speaker_detail`) - スピーカー ID から詳細情報を取得
|
|
326
|
+
**⚠️ 重要: Claude Desktop の通信モードについて**
|
|
111
327
|
|
|
112
|
-
|
|
328
|
+
Claude Desktop は現在 **Stdio モードのみ** をサポートしており、SSE/HTTP モードは直接サポートされていません。
|
|
329
|
+
|
|
330
|
+
#### 推奨設定(Stdio モード)
|
|
331
|
+
|
|
332
|
+
`claude_desktop_config.json` ファイルに以下の設定を追加:
|
|
333
|
+
|
|
334
|
+
```json
|
|
335
|
+
{
|
|
336
|
+
"mcpServers": {
|
|
337
|
+
"tts-mcp": {
|
|
338
|
+
"command": "npx",
|
|
339
|
+
"args": ["-y", "@kajidog/mcp-tts-voicevox"],
|
|
340
|
+
"env": {
|
|
341
|
+
"VOICEVOX_URL": "http://localhost:50021",
|
|
342
|
+
"VOICEVOX_DEFAULT_SPEAKER": "1"
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
#### SSE モードが必要な場合
|
|
350
|
+
|
|
351
|
+
SSE モードでの音声合成が必要な場合は、`mcp-remote` を使用して SSE↔Stdio 変換を行えます:
|
|
352
|
+
|
|
353
|
+
1. **Claude Desktop 設定**
|
|
354
|
+
|
|
355
|
+
```json
|
|
356
|
+
{
|
|
357
|
+
"mcpServers": {
|
|
358
|
+
"tts-mcp-proxy": {
|
|
359
|
+
"command": "npx",
|
|
360
|
+
"args": ["-y", "mcp-remote", "http://localhost:3000/sse"]
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
```
|
|
113
365
|
|
|
114
|
-
|
|
366
|
+
2. **SSE サーバーの起動**
|
|
115
367
|
|
|
116
|
-
|
|
368
|
+
**Mac/Linux:**
|
|
369
|
+
|
|
370
|
+
```bash
|
|
371
|
+
MCP_HTTP_MODE=true MCP_HTTP_PORT=3000 npx @kajidog/mcp-tts-voicevox
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
**Windows:**
|
|
375
|
+
|
|
376
|
+
```powershell
|
|
377
|
+
$env:MCP_HTTP_MODE='true'; $env:MCP_HTTP_PORT='3000'; npx @kajidog/mcp-tts-voicevox
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
### AivisSpeech での設定例
|
|
117
381
|
|
|
118
382
|
```json
|
|
119
383
|
{
|
|
@@ -130,17 +394,69 @@ document
|
|
|
130
394
|
}
|
|
131
395
|
```
|
|
132
396
|
|
|
397
|
+
### HTTP モードでの設定
|
|
398
|
+
|
|
399
|
+
```json
|
|
400
|
+
{
|
|
401
|
+
"mcpServers": {
|
|
402
|
+
"tts-mcp-http": {
|
|
403
|
+
"command": "npx",
|
|
404
|
+
"args": ["-y", "@kajidog/mcp-tts-voicevox"],
|
|
405
|
+
"env": {
|
|
406
|
+
"MCP_HTTP_MODE": "true",
|
|
407
|
+
"MCP_HTTP_PORT": "3000",
|
|
408
|
+
"MCP_HTTP_HOST": "0.0.0.0",
|
|
409
|
+
"VOICEVOX_URL": "http://localhost:50021",
|
|
410
|
+
"VOICEVOX_DEFAULT_SPEAKER": "1"
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
```
|
|
416
|
+
|
|
133
417
|
## 環境変数
|
|
134
418
|
|
|
419
|
+
### VOICEVOX 設定
|
|
420
|
+
|
|
135
421
|
- `VOICEVOX_URL`: VOICEVOX エンジンの URL(デフォルト: `http://localhost:50021`)
|
|
136
|
-
- `VOICEVOX_DEFAULT_SPEAKER`: デフォルト話者 ID
|
|
137
|
-
- `VOICEVOX_DEFAULT_SPEED_SCALE`:
|
|
422
|
+
- `VOICEVOX_DEFAULT_SPEAKER`: デフォルト話者 ID(デフォルト: `1`)
|
|
423
|
+
- `VOICEVOX_DEFAULT_SPEED_SCALE`: デフォルト再生速度(デフォルト: `1.0`)
|
|
424
|
+
|
|
425
|
+
### サーバー設定
|
|
426
|
+
|
|
427
|
+
- `MCP_HTTP_MODE`: HTTP サーバーモードの有効化(`true` で有効)
|
|
428
|
+
- `MCP_HTTP_PORT`: HTTP サーバーのポート番号(デフォルト: `3000`)
|
|
429
|
+
- `MCP_HTTP_HOST`: HTTP サーバーのホスト(デフォルト: `0.0.0.0`)
|
|
430
|
+
- `NODE_ENV`: 開発モード(`development` で有効)
|
|
431
|
+
|
|
432
|
+
## トラブルシューティング
|
|
138
433
|
|
|
139
|
-
|
|
434
|
+
### よくある問題
|
|
140
435
|
|
|
141
|
-
|
|
142
|
-
|
|
436
|
+
1. **VOICEVOX エンジンが起動していない**
|
|
437
|
+
|
|
438
|
+
```bash
|
|
439
|
+
curl http://localhost:50021/speakers
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
2. **ポートが既に使用されている (EADDRINUSE エラー)**
|
|
443
|
+
|
|
444
|
+
- 別のポート番号を使用するか、既存のプロセスを終了してください
|
|
445
|
+
|
|
446
|
+
3. **MCP クライアントで認識されない**
|
|
447
|
+
|
|
448
|
+
- パッケージのインストールを確認:`npm list -g @kajidog/mcp-tts-voicevox`
|
|
449
|
+
- 設定ファイルの JSON 構文を確認
|
|
450
|
+
|
|
451
|
+
4. **音声が再生されない**
|
|
452
|
+
- システムの音声出力デバイスを確認
|
|
453
|
+
- VOICEVOX エンジンの動作確認:
|
|
454
|
+
```bash
|
|
455
|
+
curl -X POST "http://localhost:50021/audio_query?text=テスト&speaker=1"
|
|
456
|
+
```
|
|
143
457
|
|
|
144
458
|
## ライセンス
|
|
145
459
|
|
|
146
460
|
ISC
|
|
461
|
+
|
|
462
|
+
[](https://mseep.ai/app/kajidog-mcp-tts-voicevox)
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
3
|
// MCP TTS Voicevox エントリーポイント
|
|
4
|
-
// ライブラリとしても使用できるように、クライアントとCLI
|
|
4
|
+
// ライブラリとしても使用できるように、クライアントとCLIのエントリーポイントを分離
|
|
5
5
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
6
|
if (k2 === undefined) k2 = k;
|
|
7
7
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
@@ -41,70 +41,197 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
41
41
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
42
|
// ライブラリとして使用する場合のエクスポート
|
|
43
43
|
__exportStar(require("./client"), exports);
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
const
|
|
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
|
-
|
|
44
|
+
/**
|
|
45
|
+
* 実行環境を判定するユーティリティ
|
|
46
|
+
*/
|
|
47
|
+
class EnvironmentDetector {
|
|
48
|
+
/** ブラウザ環境かどうかを判定 */
|
|
49
|
+
static isBrowser() {
|
|
50
|
+
return (typeof window !== "undefined" && typeof window.document !== "undefined");
|
|
51
|
+
}
|
|
52
|
+
/** Node.js環境かどうかを判定 */
|
|
53
|
+
static isNodejs() {
|
|
54
|
+
return typeof process !== "undefined" && !!process.versions?.node;
|
|
55
|
+
}
|
|
56
|
+
/** CLI実行かどうかを判定 */
|
|
57
|
+
static isCLI() {
|
|
58
|
+
if (!this.isNodejs() || !process.argv)
|
|
59
|
+
return false;
|
|
60
|
+
const isNpmStart = process.env?.npm_lifecycle_event === "start";
|
|
61
|
+
const argv1 = process.argv[1] || "";
|
|
62
|
+
const isDirectExecution = argv1.includes("mcp-tts-voicevox") ||
|
|
63
|
+
argv1.endsWith("dist/index.js") ||
|
|
64
|
+
argv1.endsWith("src/index.ts") ||
|
|
65
|
+
argv1.includes("index.js") ||
|
|
66
|
+
argv1.includes("npx");
|
|
67
|
+
// 環境変数でHTTPモードが明示的に設定されている場合は強制的にCLI実行として扱う
|
|
68
|
+
const isForceMode = process.env?.MCP_HTTP_MODE === "true";
|
|
69
|
+
// npxやCLIからの直接実行を検出
|
|
70
|
+
const isMainModule = require.main === module || process.argv0.includes("node");
|
|
71
|
+
return isNpmStart || isDirectExecution || isForceMode || isMainModule;
|
|
72
|
+
}
|
|
73
|
+
/** NPX経由実行かどうかを判定 */
|
|
74
|
+
static isNpx() {
|
|
75
|
+
if (!this.isNodejs())
|
|
76
|
+
return false;
|
|
77
|
+
return !!(process.env?.npm_execpath &&
|
|
78
|
+
process.argv[1] &&
|
|
79
|
+
!process.argv[1].includes("node_modules"));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* サーバー設定を管理するクラス
|
|
84
|
+
*/
|
|
85
|
+
class ServerConfigManager {
|
|
86
|
+
static getConfig() {
|
|
87
|
+
const env = process.env || {};
|
|
88
|
+
return {
|
|
89
|
+
port: parseInt(env.MCP_HTTP_PORT || "3000", 10),
|
|
90
|
+
host: env.MCP_HTTP_HOST || "0.0.0.0",
|
|
91
|
+
isDevelopment: env.NODE_ENV === "development",
|
|
92
|
+
isHttpMode: env.MCP_HTTP_MODE === "true",
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* HTTP サーバー管理クラス
|
|
98
|
+
*/
|
|
99
|
+
class HttpServerManager {
|
|
100
|
+
static async start(config) {
|
|
101
|
+
try {
|
|
102
|
+
console.error("Starting HTTP server with config:", config);
|
|
103
|
+
const app = await this.loadApp(config.isDevelopment);
|
|
104
|
+
console.error("App loaded successfully");
|
|
105
|
+
const server = await this.loadServer(config.isDevelopment);
|
|
106
|
+
console.error("Server module loaded successfully");
|
|
107
|
+
const serverOptions = {
|
|
108
|
+
fetch: app.fetch,
|
|
109
|
+
port: config.port,
|
|
110
|
+
hostname: config.host,
|
|
111
|
+
};
|
|
112
|
+
console.error("Attempting to start server with options:", serverOptions);
|
|
113
|
+
server.serve(serverOptions, (info) => {
|
|
114
|
+
console.error(`✅ VOICEVOX MCP HTTP server running at http://${info.address}:${info.port}/mcp`);
|
|
115
|
+
console.error(`📡 SSE endpoint (legacy): http://${info.address}:${info.port}/sse`);
|
|
116
|
+
console.error(`🔍 Health check: http://${info.address}:${info.port}/health`);
|
|
117
|
+
});
|
|
118
|
+
// サーバー起動の確認を少し待つ
|
|
119
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
120
|
+
console.error("HTTP server startup completed");
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
console.error("❌ HTTP server startup failed:", error);
|
|
124
|
+
if (error instanceof Error) {
|
|
125
|
+
console.error("Error details:", {
|
|
126
|
+
message: error.message,
|
|
127
|
+
stack: error.stack,
|
|
128
|
+
name: error.name,
|
|
129
|
+
});
|
|
97
130
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
131
|
+
throw new Error(`Failed to start HTTP server: ${error}`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
static async loadApp(isDevelopment) {
|
|
135
|
+
if (isDevelopment) {
|
|
136
|
+
const module = await Promise.resolve().then(() => __importStar(require("./sse")));
|
|
137
|
+
return module.default;
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
return require("./sse").default;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
static async loadServer(isDevelopment) {
|
|
144
|
+
if (isDevelopment) {
|
|
145
|
+
return await Promise.resolve().then(() => __importStar(require("@hono/node-server")));
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
return require("@hono/node-server");
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Stdio サーバー管理クラス
|
|
154
|
+
*/
|
|
155
|
+
class StdioServerManager {
|
|
156
|
+
static async start(config) {
|
|
157
|
+
try {
|
|
158
|
+
if (config.isDevelopment) {
|
|
159
|
+
await Promise.resolve().then(() => __importStar(require("./stdio")));
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
require("./stdio");
|
|
163
|
+
}
|
|
164
|
+
// Stdio サーバーは常に実行中なので、プロセス終了までブロック
|
|
165
|
+
process.on("SIGINT", () => {
|
|
166
|
+
process.exit(0);
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
catch (error) {
|
|
170
|
+
console.error("❌ Stdio server startup failed:", error);
|
|
171
|
+
if (error instanceof Error) {
|
|
172
|
+
console.error("Error details:", {
|
|
173
|
+
message: error.message,
|
|
174
|
+
stack: error.stack,
|
|
175
|
+
name: error.name,
|
|
176
|
+
});
|
|
103
177
|
}
|
|
178
|
+
throw new Error(`Failed to start stdio server: ${error}`);
|
|
104
179
|
}
|
|
105
180
|
}
|
|
106
|
-
|
|
107
|
-
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* メインサーバー管理クラス
|
|
184
|
+
*/
|
|
185
|
+
class MCPServerManager {
|
|
186
|
+
static async start() {
|
|
187
|
+
// 環境チェック
|
|
188
|
+
if (EnvironmentDetector.isBrowser()) {
|
|
189
|
+
console.warn("⚠️ MCP server cannot run in browser environment");
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
if (!EnvironmentDetector.isNodejs()) {
|
|
193
|
+
throw new Error("❌ Node.js environment required");
|
|
194
|
+
}
|
|
195
|
+
// CLI実行またはNPX実行の場合のみサーバーを起動
|
|
196
|
+
const shouldStart = EnvironmentDetector.isCLI() || EnvironmentDetector.isNpx();
|
|
197
|
+
const config = ServerConfigManager.getConfig();
|
|
198
|
+
// HTTPモードの場合のみログを出力
|
|
199
|
+
if (config.isHttpMode) {
|
|
200
|
+
console.error("🔍 Environment detection:", {
|
|
201
|
+
isCLI: EnvironmentDetector.isCLI(),
|
|
202
|
+
isNpx: EnvironmentDetector.isNpx(),
|
|
203
|
+
shouldStart,
|
|
204
|
+
argv1: process.argv[1],
|
|
205
|
+
argv0: process.argv0,
|
|
206
|
+
execPath: process.execPath,
|
|
207
|
+
});
|
|
208
|
+
console.error("⚙️ Server configuration:", config);
|
|
209
|
+
}
|
|
210
|
+
if (!shouldStart) {
|
|
211
|
+
if (config.isHttpMode) {
|
|
212
|
+
console.error("📚 Running as library, server startup skipped");
|
|
213
|
+
}
|
|
214
|
+
return; // ライブラリとして使用されている
|
|
215
|
+
}
|
|
216
|
+
try {
|
|
217
|
+
if (config.isHttpMode) {
|
|
218
|
+
await HttpServerManager.start(config);
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
await StdioServerManager.start(config);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
catch (error) {
|
|
225
|
+
console.error("❌ Server startup failed:", error);
|
|
226
|
+
process.exit(1);
|
|
227
|
+
}
|
|
108
228
|
}
|
|
109
229
|
}
|
|
230
|
+
// Node.js環境での自動起動
|
|
231
|
+
if (EnvironmentDetector.isNodejs()) {
|
|
232
|
+
MCPServerManager.start().catch((error) => {
|
|
233
|
+
console.error("Initialization error:", error);
|
|
234
|
+
// ライブラリとしての利用に支障がないように、エラーは無視
|
|
235
|
+
});
|
|
236
|
+
}
|
|
110
237
|
//# sourceMappingURL=index.js.map
|