Skip to main content
Glama

voice-io-mcp

Two MCP tools for Claude Code: text_to_speech and speech_to_text. Groq's free hosted endpoints first, a local model when there is no key or Groq is down.

claude mcp add voice-io -e GROQ_API_KEY=your-key -- uvx --python 3.11 --from git+https://github.com/Furkiozknn/voice-io-mcp voice-io-mcp

What it needs, honestly: uv and Claude Code, plus one of two things to make actual audio. Either a free Groq key (console.groq.com/keys, no card), or the local models: voice-io-mcp[local-tts,local-stt], about 6 GB of downloads on Linux because Kokoro pulls in torch (see Setup). With neither, the server still connects and every call answers with an error that says what to add, as in the demo below. Nothing is on PyPI yet, so uv installs from GitHub.

The first result is quick once uv has it: from an empty uv cache uvx took 24.0 and 28.2 s to install and print the version, 5.3 to 5.8 s with a warm cache, and the server answers the client's initialize about 4 to 6 s after it starts (measured 30 September 2026, Windows 11, Python 3.11; docs/demo/kurulum.txt, docs/DENETIM.md). Claude Code waits 30 s for a server to connect by default, so that is the margin. claude mcp list should show voice-io: … βœ“ Connected.

Use it when

Do not use it when

you want Claude Code to read a paragraph aloud or transcribe a voice memo, and would rather not depend on one provider

you need voice cloning, streaming or mp3 output: it writes .wav files and returns whole files (limits)

you have no API key and can spare the disk for local models: both tools still work

you need a long recording transcribed: files are capped at 25 MB

the agent might be tricked into "transcribe the audio at .env": paths are checked before a byte is read or uploaded

a hosted request must never leave the machine: with GROQ_API_KEY set, audio is uploaded to Groq. Leave the key unset to stay fully local

License: MIT Python 3.11+ MCP Server Cost

Every other tool in this ecosystem's nvidia-nim-mcp wraps image/text/vision/safety/embedding models behind a "try a real provider, fall back if it fails" contract. Audio was the one capability nothing covered β€” this fills that gap, same philosophy: a model being slow, rate-limited, or unconfigured should never take a tool down.

⚑ Quick start

Pick one:

# A) Groq's free hosted tier: get a key at console.groq.com/keys (no credit card)
claude mcp add voice-io -e GROQ_API_KEY=your-key -- \
  uvx --python 3.11 --from git+https://github.com/Furkiozknn/voice-io-mcp voice-io-mcp

# B) No key at all: local models. Kokoro pulls in torch: about 6 GB of downloads on Linux,
#    where torch ships CUDA libraries. Model weights come from Hugging Face on first use.
claude mcp add voice-io -- \
  uvx --python 3.11 --from "voice-io-mcp[local-tts,local-stt] @ git+https://github.com/Furkiozknn/voice-io-mcp" voice-io-mcp

In Claude Code, ask "Transcribe ~/Desktop/note.wav" or "Read this paragraph out loud". Audio is written to output/ under the directory Claude Code was started in (set VOICE_IO_OUTPUT_DIR with another -e to change that).

To see what the server can reach before connecting a client, run its health check (it also runs --help and --version):

uvx --python 3.11 --from git+https://github.com/Furkiozknn/voice-io-mcp voice-io-mcp --check

With no key and no extras (what you get from that command) it prints the report shown in the demo and exits 1. It exits 0 when each tool has at least one OK line; with a key set it spends one tiny TTS and one STT request of free-tier quota. A tool call that can't be served fails with isError: true and names both causes, for example Speech-to-text failed (Groq: GROQ_API_KEY not set (environment or .env)) and no local fallback available (install the local-stt extra to enable one). To watch a session as a client sees it, python scripts/probe.py --help (from a clone) starts the server over stdio and prints initialize, tools/list and any --call you give it. Working on the code instead? See Setup.

Related MCP server: MCP TTS Server

πŸ“– Table of Contents

🧰 Tools

Tool

What it does

Hosted tier (Groq, free)

Local fallback

πŸ”Š text_to_speech

Text (up to 4000 characters) β†’ .wav file, saved to output/

Orpheus (canopylabs/orpheus-v1-english)

Kokoro-82M (Apache-2.0)

πŸŽ™οΈ speech_to_text

Audio file β†’ transcript (refuses non-audio extensions, symlinks to non-audio files, directories/FIFOs/devices and files over 25MB before reading a byte)

whisper-large-v3-turbo

faster-whisper (MIT)

πŸ—£οΈ list_voices

List known Groq Orpheus voice names for text_to_speech's voice argument

β€” (static list)

β€”

🩺 check_provider_health

Liveness probe for both hosted endpoints (spends one tiny TTS + one STT request of free-tier quota per call) + local-dependency availability check

both

both

πŸ”„ The fallback chain

Both tools try Groq first only if GROQ_API_KEY is set in .env β€” if it isn't, or if the Groq call fails for any reason, they drop straight to the local model. This is the one meaningful difference from nvidia-nim-mcp's own pattern: every tool here works with zero API keys configured at all, as long as the relevant optional extra is installed β€” a hosted key is a speed/quality upgrade, not a hard requirement.

Both tiers write .wav: Orpheus answers in WAV only, and so does Kokoro (encoding straight to mp3 depends on the local libsndfile build, which isn't guaranteed cross-platform). output_format="mp3" is still accepted for compatibility, and the tool's return message says it was answered with .wav rather than silently substituting formats.

Orpheus also takes at most 200 characters per request. Longer text is split at sentence ends (then at spaces), sent as several requests, and the WAV parts are joined into one file with the standard library's wave module β€” mind the free tier's per-minute request allowance for long passages. If any piece fails, the whole call drops to the local model; no half-spoken file is left behind.

Groq retired playai-tts (deprecation announced 23 December 2025) in favour of Canopy Labs' Orpheus; this server moved with it. The PlayAI voice names (Fritz-PlayAI, …) no longer exist β€” use list_voices for the Orpheus ones (autumn, diana, hannah, austin, daniel, troy; default hannah).

On model names: canopylabs/orpheus-v1-english and whisper-large-v3-turbo follow Groq's public API documentation, but neither was live-verified with a real key while building this repo (no key was available in the build environment). Run check_provider_health once GROQ_API_KEY is set to confirm they're still current β€” Groq's free-tier model lineup shifts over time, the same "don't trust a name from memory" discipline nvidia-nim-mcp documents for its own model list.

βš™οΈ Setup

This is the from-source route: for working on the server, or for keeping the key in a .env file. Using it only? The Quick start is enough.

0. Clone it:

git clone https://github.com/Furkiozknn/voice-io-mcp && cd voice-io-mcp

1. Install the base package (this project uses uv, not bare pip/venv):

uv sync

2. (Optional) Enable Groq's hosted tier. Copy .env.example to .env in the project root and fill it in:

cp .env.example .env
# GROQ_API_KEY=your-key-here

Get one free at console.groq.com/keys β€” no credit card. Without it, both tools go straight to their local fallback. .env is found by looking upward from voice_io.py, so it works for this checkout. For a uvx install, pass the key as an environment variable (claude mcp add … -e GROQ_API_KEY=…), as in the Quick start. A variable that is already set always wins over .env.

.env.example also documents VOICE_IO_OUTPUT_DIR, which controls where generated audio is written. It defaults to output/ under the directory the server is started in β€” never inside the installed package, so a pip installed copy never writes into site-packages.

3. (Optional) Enable the local fallbacks β€” each is an independent extra, install either or both:

uv sync --extra local-tts   # Kokoro-82M β€” also needs the `espeak-ng` system package
uv sync --extra local-stt   # faster-whisper

espeak-ng is used by Kokoro's phonemizer for out-of-distribution English and non-English text; straightforward English text works without it, but full quality/robustness wants it on PATH (apt install espeak-ng / choco install espeak-ng / brew install espeak-ng).

4. Register it as an MCP server with Claude Code (project or user scope):

claude mcp add --transport stdio voice-io -- uv run --project /path/to/this/repo voice-io-mcp

voice-io-mcp is the console command the project installs into its own environment, so this works from any directory. (uv run --project … voice_io.py does not: --project picks the environment, but the script path is still looked up in the directory Claude Code starts the server from.)

5. Run check_provider_health once, after setting GROQ_API_KEY. The model/voice names this server wires in (canopylabs/orpheus-v1-english, whisper-large-v3-turbo) were transcribed from Groq's public docs but never live-verified with a real key while building this β€” confirm they're still current before relying on the hosted tier. Each run sends one real TTS request ("hi") and one transcription of 0.1 s of silence β€” Groq bills a transcription as at least 10 seconds β€” so it spends a little free-tier quota every time; run it when something looks wrong, not before every call. This is the same "don't trust a name from memory" discipline nvidia-nim-mcp documents for its own model list. If a name has drifted, the local fallback still works regardless (once its extra is installed).

▢️ Example usage

"Read this changelog entry out loud"
β†’ text_to_speech  β†’ saved to output/speech_20260901_120000.wav (model: groq/canopylabs/orpheus-v1-english)

"Transcribe this voice memo at C:\Users\me\Desktop\note.wav"
β†’ speech_to_text  β†’ returns the transcript (model: groq/whisper-large-v3-turbo)

"What voices can I use for text_to_speech?"
β†’ list_voices     β†’ returns the known Groq Orpheus voice names, one per line

"Is voice-io's Groq connection actually working right now?"
β†’ check_provider_health β†’ per-endpoint OK/FAIL report, plus whether the local
                           extras are installed

πŸ— Architecture

Single-file MCP server (voice_io.py), same shape as nvidia-nim-mcp's nvidia_image.py and mini-creative-toolkit's toolkit.py β€” one module, @mcp.tool()-decorated functions, no framework beyond the mcp package itself.

  • Hosted calls go through litellm (aspeech / atranscription), the same library nvidia-nim-mcp and model-comparison-harness already use for their own multi-provider chat chains β€” one dependency covering chat, TTS, and STT uniformly across providers, rather than hand-rolling Groq's HTTP shape directly.

  • Local fallbacks are lazy-loaded singletons (loaded once, on first real use, not at import time) guarded by a threading.Lock β€” a lesson carried over from a real bug caught in nvidia-nim-mcp's own local-embedding fallback: without the lock, two concurrent calls could both start loading the same large model at once.

  • The STT health probe builds a valid ~0.1s silent WAV in-memory using only Python's stdlib wave module β€” no binary audio fixture shipped in the repo, no extra dependency just to construct a liveness-check payload.

  • speech_to_text validates before it reads. It reads whatever local path it's given and uploads the bytes to Groq (a third party) β€” so a wrong or maliciously-crafted path (e.g. an agent instructed to "transcribe the audio at .env") must be rejected locally instead of silently uploaded:

    • the extension allow-list (case-insensitive) is checked on the path as given and on the file it finally resolves to, so a symlink such as memo.wav β†’ ~/.env is refused;

    • the resolved file is opened once (O_NOFOLLOW, O_NONBLOCK where the OS has them) and everything else is decided on that open descriptor: it must be a regular file β€” not a directory, FIFO or device β€” and at most 25MB, and at most 25MB + 1 byte is ever read, so a file that grows after the check is still refused;

    • both tiers receive those same validated bytes; nothing reopens the path, so it cannot be swapped between the check and the upload.

  • Errors never carry the key, and stdout stays clean. Captured Groq error text has the API key scrubbed before it's returned or logged. On a stdio server stdout is the protocol channel, so:

    • litellm's "Give Feedback / Get Help" banner, which it otherwise print()s on every failed call, is switched off;

    • while serving, the MCP SDK points fd 1 at stderr;

    • each local-model call flushes Python's stdout buffer before it returns, so a stray print() (Kokoro's phonemizer has one) reaches stderr too. Left in the buffer, it would be written out at exit, after fd 1 points back at the client.

    tests/test_stdio.py checks this on the real server over a pipe.

  • Bounded hosted calls. Each request has a 120 s timeout and one retry (the OpenAI client under litellm would otherwise retry twice, each attempt with its own timeout); after that the local fallback runs.

πŸ›  Development

uv sync --group dev

πŸ§ͺ Testing

uv run pytest                              # the whole suite
uv run pytest tests/test_speech_to_text.py # one module
uv run pytest -q -rs                       # quiet, with skip reasons

Current result on Linux CI: 69 passed, 3 skipped. The 3 skips are the real-model tests described below, and CI's yerel job runs them. On Windows the same suite gives 66 passed, 6 skipped (measured 30 September 2026): the FIFO, /dev/zero and fd-diversion tests only exist on POSIX.

The suite (tests/) mocks every litellm call β€” no GROQ_API_KEY or real network access needed, and nothing in it touches the network. It also exercises the real, unmocked local-fallback code paths against this repo's base test environment (where kokoro/faster-whisper are deliberately not installed, being optional extras), confirming both fallbacks fail closed β€” returning False/None, never raising β€” when their dependency is absent. The three real-model tests in tests/test_local_integration.py skip unless those optional extras are installed; a skip there is expected locally, not a failure. CI (.github/workflows/ci.yml) runs uv run pytest on Python 3.11 and 3.13 on every push/PR, plus a yerel job that installs both extras (and espeak-ng) and runs the real-model tests with skips treated as failures.

Error contract under test: both tools raise ToolError for invalid input (empty text, unknown output_format, a missing, non-audio or oversized file, a NUL byte in the path). They also raise it when no tier could serve the call. Either way the client gets isError: true and the designed message, not a masked "Error executing tool". That message tells "the local extra is not installed" apart from "it is installed but failed, and here's why". If the hosted tier fails and the local one succeeds, the call succeeds and the result names the model that answered. tests/test_stdio.py starts the real server in a subprocess and checks this over JSON-RPC.

What this server can actually do

The expensive question about an MCP server is not what it promises but what it can do on your machine: which credentials it can touch, where it connects, what it runs. Answering that means reading the source, and most people will not.

On every push, mcp-vet from the same account audits this server from source and writes the whole report into the job summary. The verdict depends on the mcp-vet version. The current release says NOT_FLAGGED. The next one (mcp-vet#18), which can see calls made through litellm, says MEDIUM: "local files read near an outbound request" to api.groq.com. That finding is true. speech_to_text exists to upload a file you name to Groq, and the extension, symlink, file-type and size checks above are what keep it to audio. The gate closes at HIGH and above, so an expected MEDIUM stays green. The gate also closes if the tool itself could not run, because "I could not look" should not read as green.

Auditing our own server with our own tool had a side effect worth recording: adding this job surfaced a real false positive in mcp-vet, which was fixed. A tool nobody runs stays right by default.

🚧 Known limitations / roadmap

  • Voice cloning is deliberately out of scope for v1. Kokoro's own upstream ecosystem and other open models (e.g. Chatterbox) support zero-shot voice cloning from a few seconds of reference audio β€” genuinely useful, but also the most misuse-prone capability in this space. If it's added later, it should ship with a mandatory consent-confirmation step and audio watermarking (Chatterbox bundles Perth, a watermarker, for exactly this reason) β€” not as an afterthought.

  • Groq's Gemini-Flash TTS tier was researched but not wired in. Its free tier exists but is restricted to non-commercial/personal use per Google's terms, and its request/response shape wasn't verified during this build β€” a clean second hosted fallback tier to add later once both are confirmed.

  • No streaming. Both tools return a complete file/transcript, not a chunked stream β€” fine for short clips and voice memos, a real limitation for long-form audio.

  • Output is always .wav, on both tiers (see The fallback chain) β€” Orpheus offers nothing else, and Kokoro skips mp3 encoding as a deliberate cross-platform-safety tradeoff.

  • Long text costs several hosted requests β€” one per 200 characters, against the free tier's per-minute allowance; input is capped at 4000 characters (at most 20 requests) per call.

  • The content of an audio-named file is not inspected. A regular file whose name ends in an allowed extension is uploaded as-is. The checks stop a path from pointing somewhere else. They don't stop someone from saving a secret as notes.wav, or hard-linking one to that name, because a hard link is the same file under a second name.

  • check_provider_health spends quota (see Setup step 5). A free probe that only lists Groq's models would prove less: a model can be listed and still refuse the actual request, as playai-tts did until its terms were accepted in the Groq console. The current mcp-vet release also rates a direct HTTP call next to the key as HIGH, which fails this repo's CI gate. It stays a real request until both of those change.

πŸ“„ License

MIT β€” see LICENSE. Kokoro-82M's weights are Apache-2.0; faster-whisper is MIT. Neither is vendored in this repo β€” both are optional dependencies, fetched from their own sources on install/first-use.


More from this ecosystem

All of them in one searchable page: furkiozknn.github.io β€” each card is generated from that repository's own project-meta.json.

Available Tools

4 tools
check_provider_healthA

Check whether Groq's hosted TTS/STT endpoints are currently reachable and whether each local fallback's optional dependency is installed - without running a full local model load (kokoro/faster-whisper can take real time and disk space on first use, which would defeat the point of a quick health check).

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden of behavioral disclosure. It explicitly states the tool avoids loading kokoro/faster-whisper models, which is a key behavioral trait that prevents surprise time/disk costs. It also indicates that the check covers both network reachability and dependency installation, adding useful detail beyond a simple status check.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, well-structured sentence that front-loads the core purpose ('Check whether...') and then adds a parenthetical rationale for avoiding heavy model loads. Every clause earns its place; there is no filler or repetition.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter health check with an output schema, the description covers all necessary context: what is checked, why it avoids model loading, and what aspect of fallback dependencies it verifies. It does not need to explain return values because the output schema exists.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters, so the baseline is 4. The description need not explain parameter meaning because there are none. It focuses instead on the tool's purpose and behavior, which is appropriate here.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific verb ('check') and resource ('Groq's hosted TTS/STT endpoints' and 'local fallback's optional dependency'), and clearly distinguishes itself from the sibling tools by focusing on health/readiness rather than performing TTS/STT operations. It leaves no ambiguity about what the tool does.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description conveys a clear context: this is a quick health check meant to verify reachability and dependency installation before heavier operations. It does not explicitly name sibling alternatives or state 'use before text_to_speech', but the purpose and the warning against model loading imply when it should be used. The absence of explicit exclusions keeps it at a 4 rather than a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_voicesA

List known Groq PlayAI voice names usable with text_to_speech's voice argument. Static list transcribed from Groq's public API docs, not fetched live - like the model names this server wires in, it can drift; check_provider_health confirms the default voice still works, not the full list.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries full behavioral disclosure. It explicitly warns that the list is static, transcribed from public docs, not fetched live, and can drift. It also clarifies the scope of the health check sibling, which is valuable beyond the function's obvious purpose.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and front-loaded with the tool's purpose, followed by essential caveats about staleness and health checking. Every clause adds value; there is no filler or redundant restatement of the tool name.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter tool with an output schema, the description covers the essential context: what the tool lists, where the data comes from, its limitation, and how to verify current functionality via a sibling tool. Nothing important is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters, so the schema already fully covers parameter semantics. The description adds useful context about what the returned voice names are and how they relate to text_to_speech, which meets the baseline for a no-parameter tool.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: it lists known Groq PlayAI voice names for use with text_to_speech's voice argument. It clearly distinguishes this from sibling tools by tying the list directly to another tool's parameter.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear context that this is a static list and advises that check_provider_health only verifies the default voice, not the full list. This implies when to use this tool and when to use the health-check sibling, though it does not explicitly state exclusions for speech_to_text.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

speech_to_textA

Transcribe a local audio file to text.

Tries Groq's whisper-large-v3-turbo first (free tier, no credit card - requires GROQ_API_KEY), falling back to a fully local, keyless model (faster-whisper, MIT) if Groq is unavailable or the key isn't set. The local fallback requires the optional local-stt extra (uv sync --extra local-stt) and auto-downloads its model weights on first use.

Args: audio_path: Absolute path to a local audio file (mp3/wav/m4a/flac/ ogg/webm/mp4/mpeg/mpga), max 25MB. language: Optional ISO-639-1 language hint (e.g. "en"). Ignored by the local fallback, which auto-detects language.

ParametersJSON Schema
NameRequiredDescriptionDefault
languageNo
audio_pathYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full transparency burden. It discloses the Groq-first fallback, the GROQ_API_KEY requirement, the optional local-stt extra, first-use model weight download, and that the local fallback ignores language hints. It does not mention error handling or network assumptions, but the core operational behavior is well covered.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is appropriately concise and front-loaded with the main purpose, followed by a compact Args block. Every sentence adds useful operational or parameter detail; there is no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool has a fallback architecture and conditional setup requirements, and the description covers all of these: provider order, fallback trigger, setup extra, model weight download, and input constraints. Since an output schema exists, the absence of an explicit return-value description is acceptable, and an agent has enough information to invoke the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema provides no descriptions for parameters, so the description must compensate. It fully explains audio_path as an absolute path with supported formats and max size, and language as an optional ISO-639-1 hint with example and fallback-specific behavior.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific action and resource: 'Transcribe a local audio file to text.' This is unambiguous and clearly different from sibling tools like text_to_speech, list_voices, and check_provider_health.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear usage context: it is for local audio files, lists supported formats and the 25MB limit, and explains the optional language hint. It does not explicitly name sibling alternatives or state 'when not to use,' but the transcription versus speech-synthesis distinction is obvious from the sibling names.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

text_to_speechA

Convert text to speech, saved to output/.

Tries Groq's playai-tts first (free tier, no credit card - requires GROQ_API_KEY), falling back to a fully local, keyless model (Kokoro-82M, Apache-2.0) if Groq is unavailable or the key isn't set. The local fallback always produces a .wav file regardless of output_format (Kokoro's native output), and requires the optional local-tts extra (uv sync --extra local-tts) plus the espeak-ng system package for full quality on non-trivial or non-English text.

Args: text: Text to speak. voice: Groq PlayAI voice name (e.g. "Fritz-PlayAI") - ignored by the local fallback, which always uses Kokoro's "af_heart" voice. output_format: "mp3" or "wav". Only honored on the Groq tier.

ParametersJSON Schema
NameRequiredDescriptionDefault
textYes
voiceNoFritz-PlayAI
output_formatNomp3

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so thoroughly: it discloses provider fallback order, that the local fallback always emits .wav regardless of output_format, that voice is ignored on the local tier, and exact prerequisite setup (local-tts extra and espeak-ng).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The content is front-loaded with the one-line summary, followed by dense but relevant provider/fallback details and an Args section. Every sentence adds operational value with no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with no annotations and no parameter descriptions, the description covers provider selection, key requirements, output-directory behavior, and per-parameter semantics. An agent has enough information to invoke it correctly without inspecting sibling tools or external docs.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, but the description manually documents all three parameters: text, voice (with example and fallback behavior), and output_format (with allowed values and the caveat that it is only honored on Groq). This fully compensates for the empty schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Convert text to speech, saved to output/.' This makes the tool's function immediately clear and distinguishes it from siblings such as speech_to_text (reverse direction) and list_voices/check_provider_health (support tools).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It clearly states the primary purpose and the conditions under which each provider path is used: Groq first when available and the key is set, local fallback otherwise. It doesn't explicitly name when-not-to-use cases, but no sibling tool competes for this task, so clearer context would be marginal.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 4 tool updatesv0.1.0
    • First observedcheck_provider_health
    • First observedlist_voices
    • First observedspeech_to_text
    • First observedtext_to_speech

TDQS

A4.7/5.0

Scored across 4 tools

Disambiguation5/5

Each tool has a distinct role: text_to_speech and speech_to_text are inverse operations, list_voices specifically supports voice selection, and check_provider_health handles environment/endpoint diagnostics. There is no meaningful overlap or ambiguity between any two tools.

Naming Consistency4/5

All names are snake_case and readable. text_to_speech and speech_to_text form a consistent directional pair, while list_voices and check_provider_health follow a verb_noun pattern; the slight mix is minor and does not hinder prediction.

Tool Count5/5

Four tools is a reasonable, focused footprint for a voice I/O server: TTS, STT, voice enumeration, and health checks. Each tool earns its place without unnecessary redundancy.

Completeness5/5

The server covers the full core lifecycle of text-to-speech and speech-to-text, plus support for voice discovery and provider/dependency health. No major operations are missing for the stated scope.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers