ai-voice-bridge 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 +57 -0
- package/bin/ai-voice-bridge-mcp.js +217 -0
- package/package.json +19 -0
package/README.md
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# ai-voice-bridge
|
|
2
|
+
|
|
3
|
+
npm shim for the [Voice Bridge](https://github.com/Tomorrow-You/voice-bridge) MCP server — multi-engine TTS for AI coding assistants.
|
|
4
|
+
|
|
5
|
+
## What this package does
|
|
6
|
+
|
|
7
|
+
This is a thin Node.js wrapper that bootstraps the Python-based Voice Bridge MCP server. When you run `npx ai-voice-bridge`, it:
|
|
8
|
+
|
|
9
|
+
1. Finds Python 3.10+ on your system
|
|
10
|
+
2. Installs the `ai-voice-bridge[mcp]` pip package if not already present
|
|
11
|
+
3. Launches the MCP server connected to stdio
|
|
12
|
+
|
|
13
|
+
## Requirements
|
|
14
|
+
|
|
15
|
+
- **Node.js 16+** (for npx)
|
|
16
|
+
- **Python 3.10+** with **pip**
|
|
17
|
+
- **Audio player**: macOS has `afplay` built-in. Linux needs `mpv` or `ffmpeg`. Windows needs `ffmpeg` or `mpv`.
|
|
18
|
+
- **Audio output hardware**: speakers or headphones on the local machine
|
|
19
|
+
|
|
20
|
+
**Not supported**: headless servers, Docker containers, SSH sessions, and CI runners lack audio output. The MCP server will start, but `speak` commands will fail silently.
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
### Claude Desktop / Cursor
|
|
25
|
+
|
|
26
|
+
Add to your MCP config:
|
|
27
|
+
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"mcpServers": {
|
|
31
|
+
"voice-bridge": {
|
|
32
|
+
"command": "npx",
|
|
33
|
+
"args": ["ai-voice-bridge"]
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Claude Code
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
claude mcp add voice-bridge -- npx ai-voice-bridge
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Troubleshooting
|
|
46
|
+
|
|
47
|
+
The shim prints diagnostic warnings to stderr on startup:
|
|
48
|
+
|
|
49
|
+
- **`ERROR: Python 3.10+ is required`** — Install Python with platform-specific instructions shown in the error
|
|
50
|
+
- **`ERROR: Found Python 3.x, but Python 3.10+ is required`** — Upgrade your Python installation
|
|
51
|
+
- **`ERROR: pip is not available`** — Install pip (e.g., `sudo apt install python3-pip` on Ubuntu)
|
|
52
|
+
- **`WARNING: No audio player detected`** — Install `mpv` or `ffmpeg` for audio playback
|
|
53
|
+
- **`WARNING: No display server or PulseAudio detected`** — You're likely in a headless environment where audio cannot play
|
|
54
|
+
|
|
55
|
+
## License
|
|
56
|
+
|
|
57
|
+
MIT. See the [main repository](https://github.com/Tomorrow-You/voice-bridge) for details.
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* npm shim for Voice Bridge MCP server.
|
|
5
|
+
*
|
|
6
|
+
* Checks for Python 3.10+, installs the pip package if needed,
|
|
7
|
+
* then launches the MCP server connected to stdio.
|
|
8
|
+
*
|
|
9
|
+
* Usage in Claude Desktop / Cursor config:
|
|
10
|
+
* { "command": "npx", "args": ["ai-voice-bridge"] }
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const { execFileSync, spawn } = require("child_process");
|
|
14
|
+
const os = require("os");
|
|
15
|
+
|
|
16
|
+
const MIN_PYTHON = [3, 10];
|
|
17
|
+
|
|
18
|
+
function warn(msg) {
|
|
19
|
+
process.stderr.write(`[voice-bridge] ${msg}\n`);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function findPython() {
|
|
23
|
+
let bestFound = null; // track any Python we find (even if too old)
|
|
24
|
+
|
|
25
|
+
for (const cmd of ["python3", "python"]) {
|
|
26
|
+
try {
|
|
27
|
+
const version = execFileSync(cmd, ["--version"], {
|
|
28
|
+
encoding: "utf-8",
|
|
29
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
30
|
+
}).trim();
|
|
31
|
+
const match = version.match(/Python (\d+)\.(\d+)/);
|
|
32
|
+
if (match) {
|
|
33
|
+
const major = parseInt(match[1], 10);
|
|
34
|
+
const minor = parseInt(match[2], 10);
|
|
35
|
+
if (
|
|
36
|
+
major > MIN_PYTHON[0] ||
|
|
37
|
+
(major === MIN_PYTHON[0] && minor >= MIN_PYTHON[1])
|
|
38
|
+
) {
|
|
39
|
+
return { cmd, version };
|
|
40
|
+
}
|
|
41
|
+
// Python found but too old
|
|
42
|
+
bestFound = { cmd, version };
|
|
43
|
+
}
|
|
44
|
+
} catch {
|
|
45
|
+
// Command not found, try next
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return bestFound ? { cmd: null, version: bestFound.version } : null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function isPackageInstalled(python) {
|
|
52
|
+
try {
|
|
53
|
+
execFileSync(python, ["-c", "import voice_bridge"], { stdio: "ignore" });
|
|
54
|
+
return true;
|
|
55
|
+
} catch {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function hasPip(python) {
|
|
61
|
+
try {
|
|
62
|
+
execFileSync(python, ["-m", "pip", "--version"], {
|
|
63
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
64
|
+
});
|
|
65
|
+
return true;
|
|
66
|
+
} catch {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function checkAudioEnvironment() {
|
|
72
|
+
const platform = os.platform();
|
|
73
|
+
|
|
74
|
+
if (platform === "darwin") {
|
|
75
|
+
// macOS always has afplay
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const players =
|
|
80
|
+
platform === "win32"
|
|
81
|
+
? ["ffplay", "mpv"]
|
|
82
|
+
: ["mpv", "ffplay", "aplay", "paplay"];
|
|
83
|
+
|
|
84
|
+
for (const player of players) {
|
|
85
|
+
try {
|
|
86
|
+
execFileSync(platform === "win32" ? "where" : "which", [player], {
|
|
87
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
88
|
+
});
|
|
89
|
+
return; // found one
|
|
90
|
+
} catch {
|
|
91
|
+
// not found, try next
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const installHint =
|
|
96
|
+
platform === "win32"
|
|
97
|
+
? "Install ffmpeg (includes ffplay): https://ffmpeg.org/download.html\n" +
|
|
98
|
+
" Or install mpv: https://mpv.io/installation/"
|
|
99
|
+
: "Install an audio player:\n" +
|
|
100
|
+
" Ubuntu/Debian: sudo apt install mpv (or: sudo apt install ffmpeg)\n" +
|
|
101
|
+
" Fedora/RHEL: sudo dnf install mpv\n" +
|
|
102
|
+
" Arch: sudo pacman -S mpv";
|
|
103
|
+
|
|
104
|
+
warn(
|
|
105
|
+
"WARNING: No audio player detected.\n" +
|
|
106
|
+
" Voice Bridge requires mpv, ffplay, or another audio player to produce sound.\n" +
|
|
107
|
+
" The MCP server will start, but speak commands will fail silently.\n\n" +
|
|
108
|
+
` ${installHint}\n`
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
// Check if we're likely headless (no DISPLAY on Linux, no audio device)
|
|
112
|
+
if (platform === "linux" && !process.env.DISPLAY && !process.env.WAYLAND_DISPLAY && !process.env.PULSE_SERVER) {
|
|
113
|
+
warn(
|
|
114
|
+
"WARNING: No display server or PulseAudio detected — this may be a headless environment.\n" +
|
|
115
|
+
" TTS audio playback requires a machine with speakers or audio output.\n" +
|
|
116
|
+
" Remote sessions (SSH, containers, CI) typically cannot play audio.\n"
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function pythonInstallHint() {
|
|
122
|
+
const platform = os.platform();
|
|
123
|
+
if (platform === "darwin") {
|
|
124
|
+
return (
|
|
125
|
+
"Install Python on macOS:\n" +
|
|
126
|
+
" brew install python@3.12 (recommended)\n" +
|
|
127
|
+
" Or download from https://python.org/downloads/"
|
|
128
|
+
);
|
|
129
|
+
} else if (platform === "win32") {
|
|
130
|
+
return (
|
|
131
|
+
"Install Python on Windows:\n" +
|
|
132
|
+
" winget install Python.Python.3.12\n" +
|
|
133
|
+
" Or download from https://python.org/downloads/"
|
|
134
|
+
);
|
|
135
|
+
} else {
|
|
136
|
+
return (
|
|
137
|
+
"Install Python on Linux:\n" +
|
|
138
|
+
" Ubuntu/Debian: sudo apt install python3 python3-pip\n" +
|
|
139
|
+
" Fedora/RHEL: sudo dnf install python3 python3-pip\n" +
|
|
140
|
+
" Arch: sudo pacman -S python python-pip\n" +
|
|
141
|
+
" Or download from https://python.org/downloads/"
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function main() {
|
|
147
|
+
const result = findPython();
|
|
148
|
+
|
|
149
|
+
if (!result || !result.cmd) {
|
|
150
|
+
if (result && result.version) {
|
|
151
|
+
// Python found but too old
|
|
152
|
+
warn(
|
|
153
|
+
`ERROR: Found ${result.version}, but Python ${MIN_PYTHON.join(".")}+ is required.\n\n` +
|
|
154
|
+
` ${pythonInstallHint()}\n`
|
|
155
|
+
);
|
|
156
|
+
} else {
|
|
157
|
+
// No Python at all
|
|
158
|
+
warn(
|
|
159
|
+
`ERROR: Python ${MIN_PYTHON.join(".")}+ is required but not found on this system.\n\n` +
|
|
160
|
+
` ${pythonInstallHint()}\n`
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
process.exit(1);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const python = result.cmd;
|
|
167
|
+
|
|
168
|
+
// Check audio environment before proceeding
|
|
169
|
+
checkAudioEnvironment();
|
|
170
|
+
|
|
171
|
+
if (!isPackageInstalled(python)) {
|
|
172
|
+
if (!hasPip(python)) {
|
|
173
|
+
const platform = os.platform();
|
|
174
|
+
const pipHint =
|
|
175
|
+
platform === "linux"
|
|
176
|
+
? " Ubuntu/Debian: sudo apt install python3-pip\n" +
|
|
177
|
+
" Fedora/RHEL: sudo dnf install python3-pip"
|
|
178
|
+
: ` ${python} -m ensurepip --upgrade`;
|
|
179
|
+
warn(
|
|
180
|
+
"ERROR: pip is not available. Install pip first:\n" +
|
|
181
|
+
` ${pipHint}\n\n` +
|
|
182
|
+
"Then retry, or install manually:\n" +
|
|
183
|
+
` ${python} -m pip install "ai-voice-bridge[mcp]"\n`
|
|
184
|
+
);
|
|
185
|
+
process.exit(1);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
warn("Installing ai-voice-bridge[mcp]...");
|
|
189
|
+
try {
|
|
190
|
+
execFileSync(python, ["-m", "pip", "install", "ai-voice-bridge[mcp]"], {
|
|
191
|
+
stdio: "inherit",
|
|
192
|
+
});
|
|
193
|
+
} catch {
|
|
194
|
+
warn(
|
|
195
|
+
"Failed to install ai-voice-bridge. Try manually:\n" +
|
|
196
|
+
` ${python} -m pip install "ai-voice-bridge[mcp]"\n`
|
|
197
|
+
);
|
|
198
|
+
process.exit(1);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Launch the MCP server, connecting stdio directly
|
|
203
|
+
const child = spawn(python, ["-m", "voice_bridge.mcp.server"], {
|
|
204
|
+
stdio: "inherit",
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
child.on("error", (err) => {
|
|
208
|
+
warn(`Failed to start MCP server: ${err.message}`);
|
|
209
|
+
process.exit(1);
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
child.on("exit", (code) => {
|
|
213
|
+
process.exit(code ?? 0);
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
main();
|
package/package.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ai-voice-bridge",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server for Voice Bridge — multi-engine TTS for AI coding assistants",
|
|
5
|
+
"author": "Tomorrow You LLC",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/Tomorrow-You/voice-bridge"
|
|
10
|
+
},
|
|
11
|
+
"keywords": ["mcp", "tts", "text-to-speech", "claude", "voice", "ai-assistant"],
|
|
12
|
+
"bin": {
|
|
13
|
+
"ai-voice-bridge": "bin/ai-voice-bridge-mcp.js"
|
|
14
|
+
},
|
|
15
|
+
"files": ["bin/", "README.md"],
|
|
16
|
+
"engines": {
|
|
17
|
+
"node": ">=16"
|
|
18
|
+
}
|
|
19
|
+
}
|