code-tutor-narrator
Provides text-to-speech narration through ElevenLabs, supporting configurable voice IDs, models, synthesis speed, and audio caching for replays.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@code-tutor-narratorWalk me through the main function in app.py"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Code Tutor Narrator
⚠️ Vibe-coded by an AI, start to finish
Every line of this extension was written by Claude (Claude Code, Opus 5), across a handful of conversational sessions. I directed it and listened to the output; I did not write it, and I have not reviewed most of it line by line.
What that means for you:
Treat it as a prototype, not as engineering you can lean on. It works for me, on my machine, for the thing I use it for.
It spawns child processes, reads your settings, and sends the text you narrate to a third-party API. Read the source before you run it — it's ~1000 lines, and that is genuinely the whole review that has happened.
The tests are real and they pass, but they were written by the same AI that wrote the code, so they encode the same assumptions and blind spots.
Design decisions in here were made mid-conversation and may be wrong in ways neither of us noticed.
Issues and PRs are welcome, but no support is promised. If you need something dependable, this isn't it.
Lets an agent drive VS Code like a tutor: scroll to a range of code, highlight it, dim everything else, and narrate it out loud — then read back what you're looking at.
Requires macOS: speech goes through say and playback through afplay.
It exposes an MCP server over loopback HTTP, so Claude Code calls it as ordinary tools rather than shelling out.
Tools
Tool | What it does |
| Scrolls to |
| A planned sequence of |
| Says something aloud without moving the editor. Interrupts narration in progress. |
| Active file, cursor line, current selection, visible line range, and any errors. |
| Drops the highlight and stops narration. |
show_code blocks until narration finishes, so consecutive calls pace themselves
into a walkthrough instead of talking over each other.
show_code or walkthrough?
Chained show_code calls leave an audible gap between beats, and the gap is not TTS
latency — it is the agent's round-trip to compose the next call. Nothing on this side
can shrink it.
walkthrough removes it by taking the whole sequence at once and synthesising beat
N+1 while N is still speaking, so playback is continuous. The trade is adaptivity: you
commit to all the narration before reading any of the code back.
walkthrough— the tour you have already planned, an overview of a file you've read, anything scripted.show_code— you need the returned source of one beat before deciding the next, the user is likely to interrupt, or you're following their cursor.
Mixing them is normal: walkthrough a section, then drop to show_code for a part
worth pausing on. Interrupting a walkthrough stops it and reports which beat it
reached.
Related MCP server: mcdev-mcp
Driving it from an agent
Claude Code should enter through the tutor skill rather than calling these tools
cold — the skill carries the pedagogy; this section covers the mechanics.
Sequence the calls. show_code blocks. Issue one, wait, issue the next. Batching
them into a single parallel block defeats the pacing and produces overlapping audio.
When the beats are already planned, use walkthrough instead of chaining — same
result, no gaps.
Open with editor_state. It reports the active file, cursor line, selection,
visible range, and current diagnostics. If something is selected or the cursor is
parked, start there instead of at line 1.
One idea per call, 5–20 lines. A whole file in one show_code is a wall of audio
with a highlight that means nothing. Use note as the anchor that survives after the
audio has passed — a short label like "the move happens here", not a summary.
Jumping is cheap. Following the difficulty — to a definition and back — is what a human tutor does. Line order is not an obligation.
Speak or write, never both. If narration is playing, don't also paste the same explanation into chat. Written text is the fallback when audio is unavailable, not an accompaniment.
Always clear_highlight at the end, so the editor is handed back clean.
Failure modes. ECONNREFUSED means no VS Code window is open — the server lives in
the extension host and there is nothing to reconnect to. Say so and stop; do not
silently fall back to pasting the walkthrough into chat, and do not retry. A 402 is
voice plan-gating, not a code problem. See Troubleshooting for the rest.
Diagnostics are advisory. The errors array is whatever the language server
currently believes, which on a file full of stubs can be stale or misleading. Don't
narrate them as fact without reading the code.
Install
npm install
npm run package # builds code-tutor-narrator-<version>.vsix
npm run install-ext # installs it into VS CodeThen reload VS Code (Developer: Reload Window) and register it once with Claude Code:
claude mcp add --transport http tutor http://127.0.0.1:51730/mcp --scope userThe server only exists while VS Code is open. If Claude Code reports the tutor
server as unreachable, that just means no window is running.
Raise the tool timeout. walkthrough holds its response open for as long as the
narration lasts, and an HTTP MCP server gets only 60 seconds per request by default —
so a tour of any length reports The operation timed out while the audio carries on
playing. Progress notifications do not extend that window; only config does. Add a
timeout to the server entry in ~/.claude.json:
"tutor": {
"type": "http",
"url": "http://127.0.0.1:51730/mcp",
"timeout": 600000
}Restart Claude Code afterwards — the value is read at connect. Note the separate
five-minute idle timeout for HTTP servers: a single walkthrough that narrates for
longer than that aborts regardless, so keep one call under ~5 minutes of speech, or
raise CLAUDE_CODE_MCP_TOOL_IDLE_TIMEOUT.
Choosing a voice
codeTutor.tts.provider picks the backend. The built-in macOS voices are the
default because they always work, but they are the weakest option.
Provider | Quality | Latency | Cost | Notes |
| Poor → decent | Instant | Free | Decent only with Premium voices installed — see below. Offline. |
| Best | ~75ms (flash) | ~$0.05 / 1k chars | Needs an API key. Audio is cached, so replays are free. |
| Whatever you point it at | Depends | Usually free | Escape hatch for local models (Kokoro, Piper) or another API. |
Free first: install better macOS voices
The stock Samantha is a compact voice, and it sounds like 2005. macOS ships far
better ones, they're just not downloaded by default:
System Settings → Accessibility → Spoken Content → System Voice → Manage Voices
Grab an Enhanced or Premium English voice (Ava, Zoe, and Evan are the good
ones), then set codeTutor.voice to its exact name. Confirm with say -v '?'.
This costs nothing and closes most of the gap.
ElevenLabs
"codeTutor.tts.provider": "elevenlabs",
"codeTutor.elevenlabs.voiceId": "<see below>",
"codeTutor.elevenlabs.modelId": "eleven_flash_v2_5"Voice ids are plan-gated. Voice Library (community) voices are paid-only via the
API. On a free plan they play fine in the web UI and then fail here with
402 paid_plan_required: Free users cannot use library voices via the API — so copying
an id out of the library is the one obvious move that doesn't work. Either use a default
voice, or add a library voice to your workspace, which mints a new id you own. List what
your key can actually reach:
curl -s -H "xi-api-key: $KEY" https://api.elevenlabs.io/v1/voices \
| jq -r '.voices[] | "\(.category)\t\(.voice_id)\t\(.name)"'Anything premade works on the free plan. Buying pay-as-you-go credits does not
lift this: PAYG is a balance, not a tier, and plan-level restrictions come from the
subscription. Starter ($6/mo) is the cheapest plan that unlocks library voices.
Store the key with ⌘⇧P → "Code Tutor: Set ElevenLabs API Key". It goes into the
OS login keychain via VS Code's SecretStorage — deliberately not into
settings.json, which is easy to commit by accident. ELEVENLABS_API_KEY is also
honoured as a fallback.
eleven_flash_v2_5 is the right default here: ~75ms and half the price of
eleven_multilingual_v2, and narration doesn't need the extra expressiveness.
Speaking faster
There are two speed knobs and they are not interchangeable.
codeTutor.elevenlabs.speed changes how the voice is synthesised, and the API caps
it at 1.2 — 1.25 is a 400, not a clamp, so narration fails outright.
codeTutor.playbackRate speeds up the audio after it arrives, via afplay -r with
the high-quality algorithm, so pitch is preserved rather than chipmunked. It has no
1.2 ceiling, costs nothing, and doesn't invalidate the cache — playback speed isn't
part of the cache key, so you can re-tune it as often as you like without paying for
another synthesis. It's the right knob for genuinely fast narration:
"codeTutor.playbackRate": 1.5The two stack, so 1.2 synthesis × 1.5 playback ≈ 1.8× overall. Past roughly 2× the articulation starts to blur, but that's taste rather than a limit.
Budget roughly: continuous speech runs ~800 characters/minute, so a solid hour of talking is around $2.50 — realistically closer to $1/hour once you account for pauses and questions. Synthesised audio is cached by content hash, so re-walking the same code is free.
Local models (free, offline, private)
Point command at anything that reads text on stdin and plays it:
"codeTutor.tts.provider": "command",
"codeTutor.tts.command": "kokoro-tts - --stdout | afplay -"Kokoro-82M is the sweet spot on Apple Silicon — Apache-licensed, runs faster than
real time on CPU, ~100ms, and clearly better than say. It's still short of
ElevenLabs on expressiveness, which matters less for steady narration than it
would for character work.
Settings
Setting | Default | Meaning |
|
| Loopback port for the MCP server. |
|
|
|
| — | Command for the |
|
| macOS |
|
| Words per minute. |
| Rachel | Voice id. Plan-gated — see above. Only applies when the provider is |
|
| Model id. |
|
| Override for a proxy or a test stub. |
|
| 0 is expressive and variable, 1 is flat. |
|
| How closely to match the reference voice. |
|
| Synthesis speed. Must be 0.7–1.2; outside that the API returns 400 and nothing is spoken. |
|
| Local playback speed, applied after synthesis. No 1.2 ceiling — this is the knob for fast narration. |
|
| Cache synthesised audio so replays are free. |
Blank values fall back to the default rather than being sent as empty, so clearing a setting is the same as unsetting it.
Troubleshooting
Symptom | Cause |
| No VS Code window. The server lives inside the extension host; nothing to reconnect to. |
| The call outlived the MCP request window, but the narration is still playing. Never retry — you'd double-trigger audio. Raise the per-server |
A new tool doesn't appear after installing | The MCP client caches |
| Library voice on a free plan. See Choosing a voice. |
| No key stored. Run Code Tutor: Set ElevenLabs API Key, or export |
A settings change does nothing | Stale build. Config is read per call, so if a new setting is ignored the installed VSIX predates it. |
Speech speed setting does nothing |
|
| Cache hit. The key covers provider, voice, model, and speed — but not those two. Set |
Silence, no error, | The command is responsible for playing, not just synthesising. It needs to end in something like |
npm run install-ext installs alongside older versions rather than replacing them —
VS Code runs the highest. To see what is actually installed:
ls -d ~/.vscode/extensions/*code-tutor*Reload the window (Developer: Reload Window) after installing; the extension host does not pick up a new build on its own. Code Tutor: Show server status reports the port and active provider, and the Code Tutor output channel logs each request.
Development
npm run watch # recompile on change
npm test # MCP transport tests + TTS backend testssrc/mcp.ts and src/tts.ts deliberately have no vscode import, which is what
makes them testable outside the extension host — the ElevenLabs client is verified
against a local stub server, so the request shape is covered without a real key or
a single billed character. Everything that touches the editor lives in
src/extension.ts and is covered by the type checker instead.
Without an agent
A cue file is also watched, so you can drive it from a terminal. bin/narrate is a
small bash wrapper around that:
./bin/narrate --file src/main.rs --lines 12-20 --note "the borrow" \
--say "Here we take a reference instead of moving the value."
./bin/narrate --clearIt writes to ~/.claude/tutor/cue.json and speaks with say, configurable through
TUTOR_VOICE, TUTOR_RATE, TUTOR_TTS_CMD, and TUTOR_MUTE. It does not go through
the MCP server at all, so it works without Claude Code.
The agent side
skill/SKILL.md is the Claude Code skill that
teaches an agent how to tutor with these tools — when to narrate, how long a beat should
be, when to stop and ask. Copy it into your skills directory to use it:
mkdir -p ~/.claude/skills/tutor && cp skill/SKILL.md ~/.claude/skills/tutor/The extension is usable without it; you'll just be explaining the tools to your agent yourself each time.
License
MIT — see LICENSE.
This server cannot be installed
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- Alicense-qualityCmaintenanceAn MCP server that gives AI agents structured code understanding and precise code intelligence via local indexing of AST, call graphs, and semantic search.1084Apache 2.0
- AlicenseAqualityAmaintenanceAn MCP server that empowers AI coding agents to work effectively with Minecraft mod development, providing static analysis of decompiled source code and runtime interaction with a running Minecraft instance.313912MIT
- Alicense-qualityDmaintenanceA local MCP server that gives AI coding agents persistent memory and context across sessions.9MIT

MCP Rubber Duckofficial
AlicenseAqualityBmaintenanceAn MCP server that bridges multiple LLMs (OpenAI-compatible APIs and CLI coding agents) for collaborative debugging and diverse AI perspectives.121475MIT
Related MCP Connectors
An MCP server that gives your AI access to the source code and docs of all public github repos
Hosted MCP server connecting claude.ai, ChatGPT and other AI apps to your own computer
Driflyte MCP server which lets AI assistants query topic-specific knowledge from web and GitHub.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/SimonSchick/code-tutor-narrator'
If you have feedback or need assistance with the MCP directory API, please join our Discord server