Voice Coach MCP
Claude cannot process audio. This server records from your microphone, analyzes the audio on your computer, and returns compact measurements that Claude turns into concrete coaching:
Mode | What it measures |
🎤 Singing | Pitch accuracy per note (cents), flat/sharp tendency, drift, stability and vibrato. Compares against equal temperament, a key, or a MIDI melody, including wrong, missed and late notes. |
🗣️ English pronunciation | Phoneme-level comparison of what you said against what you meant to read, with per-word scores and frequent confusions (θ → s, v → b, iː → ɪ…). |
🎙️ Public speaking | Words per minute, long pauses, filler words (English and Spanish), pitch monotony and volume variation, with a timestamped transcript. |
A bundled skill turns Claude into a coach: it runs warm-up → exercise → analysis → feedback sessions, gives one concrete focus per take, and keeps a progress log across sessions. Claude replies in your language.
Local and private: audio never leaves your computer (unless you opt into the Azure backend).
Free: open-source models (faster-whisper, wav2vec2) and no API keys.
Tools measure, Claude interprets: every response is compact JSON (≤ 2 KB) with
confidenceandwarnings, so Claude never coaches on bad audio.
Install
You need uv and, for pronunciation, espeak-ng:
brew install uv espeak-ng ffmpeg # macOS (ffmpeg is optional: m4a/aac input)On Linux: install uv, then sudo apt install espeak-ng ffmpeg libportaudio2. Pronunciation
analysis on macOS needs Apple Silicon and macOS 14 or later (a PyTorch requirement).
Claude Code (plugin: server + skill)
claude plugin marketplace add FabianIMV/voice-coach-mcp
claude plugin install voice-coach@voice-coachOr, inside a session: /plugin install voice-coach --marketplace FabianIMV/voice-coach-mcp.
The first start installs the Python dependencies with uv, which can take a minute or two (the
models download later, on first use). If /mcp shows voice-coach as failed right after
installing, reconnect it from /mcp once the installation finishes.
Claude Desktop (extension)
Download voice-coach.mcpb from the latest release
and double-click it (or drag it into Claude Desktop). For the coaching skill, also download
voice-coach-skill.zip and upload it in Settings → Capabilities → Skills.
Any MCP client (manual)
claude mcp add voice-coach --scope user -- uvx --from "voice-coach-mcp[speech,pronunciation]" voice-coach-mcpFor Claude Desktop's claude_desktop_config.json, use absolute paths (Desktop does not inherit
your shell PATH; which uvx prints it):
{
"mcpServers": {
"voice-coach": {
"command": "/opt/homebrew/bin/uvx",
"args": ["--from", "voice-coach-mcp[speech,pronunciation]", "voice-coach-mcp"]
}
}
}Optional: run uvx --from "voice-coach-mcp[speech,pronunciation]" voice-coach-mcp download-models
once, so the first call does not wait for the models (~480 MB Whisper, ~1.3 GB phoneme model).
Microphone permission (macOS)
macOS grants the microphone to the app that launches the server: Claude Desktop, or the
terminal running Claude Code (Terminal, iTerm, Ghostty, VS Code…). If permission is denied,
macOS returns silence instead of an error and record_audio reports
no_microphone_permission. Fix it in System Settings → Privacy & Security → Microphone and
restart that app.
Related MCP server: claude-voice-input
Use it
Just talk to Claude:
"I want to practice singing in tune. I'm a beginner."
"Record 30 seconds of me presenting my project and tell me how many filler words I use."
"Help me pronounce 'th'. Give me sentences to read and score them."
"Analyze this voice memo against melody.mid" (any wav/mp3/m4a path works).
"How am I doing?" (Claude reads your progress log).
Real sessions in Claude Code: a 60-second talk about work, and a singing baseline on one held note.


Guided sessions are also available as MCP prompts: singing_session, pronunciation_session
and speaking_session (in Claude Code: /mcp__voice-coach__singing_session).
Tools
Tool | Purpose |
| Records a 16 kHz mono WAV to |
| Pitch accuracy per note against equal temperament, a key ("A minor", "G major"…) or a MIDI melody. |
| Local transcription with segment and word timestamps. |
| Pace, long pauses, filler words, pitch monotony and volume variation. |
| Phoneme-level English pronunciation scores and errors. |
| Read and append sessions in |
Audio can be a path or the name returned by record_audio. When a result is too long, the most
relevant items are returned and everything else is saved next to the audio (full_details).
{"audio":"examples/audio/c_major_scale.wav","duration_s":7.36,"mode":"equal_temperament",
"summary":{"notes":8,"range":"C4–C5","pct_within_25_cents":75.0,"mean_deviation_cents":-7.8,
"mean_abs_deviation_cents":13.6,"tendency":"centered","drift_cents":-1.0,
"stability":{"stable":7,"vibrato":1,"unstable":0}},
"notes":[{"t":0.4,"dur":0.62,"note":"C4","cents":0,"stability":"stable"},
{"t":1.84,"dur":0.62,"note":"E4","cents":-30,"stability":"stable"},
{"t":4.72,"dur":0.62,"note":"B4","cents":-42,"stability":"stable"},
{"t":5.44,"dur":1.43,"note":"C5","cents":-2,"stability":"vibrato","vibrato_hz":5.5,"vibrato_pp_cents":84}, "…"],
"confidence":{"value":1.0,"level":"high"},"warnings":[]}With a MIDI reference, the server detects
that the melody was sung an octave lower (octave_shift: -1), started 1 s late
(start_offset_ms: 1003), and that one note came in 134 ms late.
{"backend":"wav2vec2-local",
"summary":{"overall_score":90,"words":10,"words_with_errors":3,
"errors":{"substitution":3,"deletion":0,"insertion":0},
"frequent_confusions":[{"expected":"θ","detected":"s","count":2},{"expected":"v","detected":"b","count":1}]},
"words":[{"word":"think","score":75,"t":0.56,"expected":"θ ɪ ŋ k","detected":"s ɪ ŋ k",
"errors":[{"type":"substitution","expected":"θ","detected":"s"}]},
{"word":"very","score":75,"t":0.96,"expected":"v ɛ ɹ i","detected":"b ɛ ɹ i",
"errors":[{"type":"substitution","expected":"v","detected":"b"}]}, "…"],
"confidence":{"value":1.0,"level":"high"},"warnings":[]}{"language":"en",
"pace":{"words":36,"speaking_time_s":14.9,"words_per_minute":145,"wpm_excluding_long_pauses":165},
"pauses":{"threshold_s":0.7,"count":2,"total_s":1.9,"max_s":1.03,"per_minute":8.1,
"items":[{"t":4.42,"dur":1.03,"after":"speaking"},{"t":12.1,"dur":0.83,"after":"normal"}]},
"fillers":{"total":6,"per_minute":24.2,"by_type":{"um":1,"so":1,"uh":1,"you know":1,"like":1,"i mean":1}},
"pitch":{"median_f0_hz":101,"std_semitones":1.53,"monotone":true,"monotone_stretches":[{"t":0.0,"end":12.0}]},
"volume":{"mean_dbfs":-21.2,"std_between_words_db":2.4,"low_variation":true},
"confidence":{"value":1.0,"level":"high"},"warnings":[]}The synthetic voice is very flat, hence monotone: true. A Spanish example is also included.
All example outputs are real responses from the server over stdio, regenerated by
examples/generate_examples.py on synthetic audio; see
examples/outputs/.
How it works
Pitch: pYIN (librosa) finds voiced frames; each frame is refined from its harmonic peaks with parabolic interpolation (~1 cent accuracy from C2 to C6). Notes are split at silences, energy dips and sustained pitch changes; vibrato does not split notes. With a MIDI reference, the octave and offset are found by cross-correlation, notes are aligned with Needleman–Wunsch, and a tempo line
t_sung = a·t_ref + bis fitted to judge each onset.Speech: faster-whisper transcribes with word timestamps (an initial prompt keeps fillers). Pauses are measured from the audio energy, because Whisper stretches word endings into silence. Ambiguous fillers ("like", "so") only count when isolated by a comma or a pause.
Pronunciation: phonemizer + espeak-ng give the expected IPA phonemes; the
facebook/wav2vec2-lv-60-espeak-cv-ftphoneme model gives what was said; both are aligned by edit distance. Normal American English variants (flap, schwa, linking r, glottal stop) are not counted as errors.Quality first: clipping, background noise, silence and missing microphone permission are reported as warnings and lower the confidence.
Known limitations: one voice at a time (accompaniment degrades pitch detection); two identical notes sung in perfect legato count as one; the phoneme model uses sentence context and may occasionally "correct" a mispronounced word; pronunciation assessment is English-only.
Privacy and network access
Everything the plugin runs, writes and downloads:
Runs:
uvstarts the server from the plugin folder (uv run --frozen, pinned byuv.lock); the server usesespeak-ngfor expected phonemes andffmpegonly to read m4a/aac files.Microphone: only while
record_audioruns, for the number of seconds Claude asks for.Writes: recordings and
progress.mdin~/VoiceCoach(orVOICE_COACH_DIR), and an analysis detail file<audio>.<tool>.jsonnext to each analyzed audio (or in~/VoiceCoach/analysisif that folder is read-only). Analyzing the same audio again replaces its detail file; nothing else is overwritten or deleted.Downloads: the Python dependencies from PyPI on first start, then the models from Hugging Face on first use: the faster-whisper model (
Systran/faster-whisper-smallby default) andfacebook/wav2vec2-lv-60-espeak-cv-ft. After that, models load from the local cache.Sends: nothing by default. No telemetry, no accounts, no API keys. Only if you set
VOICE_COACH_PRONUNCIATION_BACKEND=azurewith your ownAZURE_SPEECH_KEYandAZURE_SPEECH_REGIONdoesassess_pronunciationsend that audio and the expected text to Azure Speech in your region.
Configuration
Variable | Default | Purpose |
|
| Recordings, analysis details and |
|
| Maximum |
|
| Tuning reference |
|
| Response size budget |
|
|
|
|
| CTranslate2 settings |
| — | Your own filler-word TOML (see |
|
|
|
|
|
|
| — | Optional Azure Pronunciation Assessment backend ( |
| auto-detected | Path to |
Development
git clone https://github.com/FabianIMV/voice-coach-mcp.git && cd voice-coach-mcp
uv sync --extra speech --extra pronunciation
uv run pytest # fast suite: synthetic audio, simulated microphone
uv run pytest -m models # real Whisper and wav2vec2 models on synthetic speech
uv run ruff check . && uv run ruff format --check .See CONTRIBUTING.md for the design principles and the release process.
src/voice_coach_mcp/
server.py MCP tools and prompts (thin layer)
audio/ loading, recording and quality checks
singing/ pitch tracking, music theory, MIDI reference, pitch accuracy
speech/ transcription, speech metrics, filler lists
pronunciation/ expected phonemes, alignment, wav2vec2 and Azure backends
output.py 2 KB response budget and details file
progress.py progress log
skills/voice-coach/ coaching skill (also bundled in the Python package)
examples/ synthetic audio and real tool outputsLicense and credits
MIT © FabianIMV. Built on faster-whisper, librosa, wav2vec2 phoneme recognition and the official MCP Python SDK. The optional pronunciation extra uses phonemizer and espeak-ng, both GPL-3.0. Example voices were synthesized with espeak-ng and Piper (public-domain LJSpeech voice).
Available Tools
7 toolsanalyze_pitchAIdempotent
Measures the pitch accuracy of sung audio (solo voice, one melodic line).
Args:
audio: audio path (wav/flac/mp3/m4a) or a name returned by record_audio.
reference_midi: optional path to a .mid with the expected melody. Tolerates singing an
octave up/down, starting at another moment and a somewhat different tempo.
key: optional when there is no MIDI, e.g. "A minor", "G major", "F#" (Spanish names such as
"La menor" also work): each note is compared with the nearest note of that scale.
Without it, with the nearest equal-tempered note.
midi_track: index of the MIDI track to use (default: the non-drum track with most notes).
Returns `summary` (notes, range, pct_within_25_cents, signed mean_deviation_cents,
tendency flat/sharp/centered, drift_cents between 1st and 2nd half, stability counts; with
MIDI also missed, extra_notes, wrong_notes, onsets on_time/late/early, octave_shift,
start_offset_ms and relative_tempo >1 = slower) and `notes`: t (s), dur, note or
expected/sung, cents (+ = sharp), stability (stable | vibrato with vibrato_hz and
vibrato_pp_cents | unstable with std_cents), drift_cents within the note and, with MIDI,
onset_ms/onset; reference notes not sung have status=missed and unmatched sung notes
status=extra. If the list does not fit, the most problematic notes are shown and the rest
is in `full_details`.
Inputs: audio (required), key, midi_track, reference_midi. Returns: result
assess_pronunciationAIdempotent
Compares the pronounced phonemes with the expected ones for a text read aloud (English).
Args:
audio: audio path or a name returned by record_audio (up to 60 s; short sentences work best).
expected_text: the exact text that was read.
language: "en-US" (default) or "en-GB".
Returns `summary` (overall_score 0–100, words_with_errors, error counts by type,
frequent_confusions expected→detected) and `words`: word, score, t (s) and, when there are
errors, expected/detected in IPA and errors [{type: substitution|deletion|insertion,
expected, detected}]; `missing` when the word was not said. `phonemes` holds both full
sequences. Word score = 100·(1 − (S + D + 0.5·I)/expected phonemes). Allophonic variants
(flap, schwa, linking r) do not count as errors. The text_mismatch warning means a
different text was probably read. Backend: local wav2vec2, or Azure when
VOICE_COACH_PRONUNCIATION_BACKEND=azure (then the audio is sent to Azure).
Inputs: audio (required), expected_text (required), language. Returns: result
log_progressA
Appends a session to the progress log (~/VoiceCoach/progress.md).
Args:
entry: markdown of the session. It should start with "## YYYY-MM-DD · mode · exercise";
if it does not start with "## ", the date and time are added as the title.
Inputs: entry (required). Returns: result
read_progressARead-onlyIdempotent
Reads the latest sessions from the progress log (~/VoiceCoach/progress.md).
Use it at the start of a session to pick up the previous focus. Returns `file`,
`total_entries` and `entries` (markdown of each session, oldest to newest).
Inputs: entries. Returns: result
record_audioA
Records from the computer's microphone and saves a 16 kHz mono .wav.
Args:
seconds: recording length (max 120 by default). Tell the user before calling.
name: optional file name (without extension); defaults to date and time.
Returns `audio` (path of the .wav), levels (peak/RMS in dBFS, estimated SNR, % clipping),
`confidence` and `warnings`. The `no_microphone_permission` warning means macOS delivered no
audio: the user must enable the microphone for the app in System Settings.
Inputs: seconds (required), name. Returns: result
speech_metricsAIdempotent
Measures pace, pauses, filler words and pitch/volume variation of a speech.
Args:
audio: audio path or a name returned by record_audio.
language: language of the speech ("en" or "es"; filler lists exist for both).
pause_threshold_s: minimum silence between words to count as a long pause.
Returns:
- `pace`: words, speaking_time_s, words_per_minute, wpm_excluding_long_pauses.
- `pauses`: count, total_s, max_s, per_minute and items [{t, dur, after: previous word}].
- `fillers`: total, per_minute, by_type and occurrences [{t, text}]. Ambiguous words
("like", "so") only count when isolated by a comma or a pause.
- `pitch`: median_f0_hz, std_semitones, range_p10_p90_semitones, monotone (std < 2 st) and
monotone_stretches [{t, end}] over 8 s windows.
- `volume`: mean_dbfs, std_between_words_db, range_p10_p90_db, low_variation (std < 3 dB).
- `segments` of the transcript [{t, end, text}].
Inputs: audio (required), language (required), pause_threshold_s. Returns: result
transcribeAIdempotent
Transcribes audio with timestamps (faster-whisper, local).
Args:
audio: audio path or a name returned by record_audio.
language: "en", "es", "en-US", "Spanish"…; auto-detected when omitted.
Returns `language`, `language_prob`, `text`, `segments` [{t, end, text}] and `words`
[{w, t, end}]. If it does not fit, words are dropped first and then segments (everything
stays in `full_details`). The first call downloads the model (VOICE_COACH_WHISPER_MODEL).
Inputs: audio (required), language. Returns: result
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 7 tools
The tools target clearly different tasks: recording, sung pitch analysis, transcription, speech delivery metrics, pronunciation scoring, and progress log read/write. The only mild overlap is pitch measurement appearing in both analyze_pitch (singing, melodic line) and speech_metrics (speech variation), but the descriptions clearly separate singing from speech and read-aloud pronunciation assessment.
Five of the seven tools follow a clear verb_noun pattern (record_audio, analyze_pitch, read_progress, assess_pronunciation, log_progress). The bare verb 'transcribe' and the noun phrase 'speech_metrics' are minor deviations but still readable and unambiguous.
Seven tools is well within the sweet spot for this domain, and each one maps to a distinct stage of the coaching workflow (record, analyze, log, review). Nothing feels padded or redundant.
The surface covers the full loop: capture audio, analyze singing, speech and pronunciation, then read and append progress. The progress log has read/append but no update, delete, or cross-session comparison, which are minor gaps an agent can work around.
Maintenance
Related MCP Connectors
AI voice generation: text-to-speech and voice cloning from any MCP client.
Generate AI music via the Lacuna Music API from MCP clients like Claude Desktop & Code.
Talk to your public-facing AI from any MCP client — Claude, ChatGPT, Cursor, Cline, Windsurf.
Use AI models for chat, image, and video generation from Claude Code and other MCP hosts.
Related MCP Servers
- AlicenseAqualityDmaintenanceThis MCP server enables Claude to speak summaries, announcements, and explanations aloud using text-to-speech — right from your terminal.4MIT
- AlicenseNot gradedqualityFmaintenanceLocal MCP server that enables voice input to Claude by transcribing microphone audio locally using faster-whisper, avoiding cloud services.MIT
- AlicenseNot gradedqualityBmaintenanceGive Claude access to your music library. MixCraft is a hosted MCP server that connects Claude to Apple Music, letting Claude search your library, build playlists, and learn your taste over time.9 npm2MIT
- FlicenseNot gradedqualityDmaintenanceExposes headless Claude Code as a remote MCP server with a voice client, enabling hands-free task execution and session management via OpenAI's Realtime API.-