Ofaudio
FreeNot checkedAn agent-first MCP server for generating and transforming audio (music, speech, sound effects) via ElevenLabs and Mureka, providing tools for transcription, voi
About
An agent-first MCP server for generating and transforming audio (music, speech, sound effects) via ElevenLabs and Mureka, providing tools for transcription, voice cloning, and multi-speaker dialogue.
README
An agent-first MCP server for any audio an AI agent needs — generate (music, sound effects, speech, multi-speaker dialogue) and transform (transcribe, caption, isolate/denoise, voice-convert/dub) — behind one intent-shaped tool surface. It wraps ElevenLabs (speech, dialogue, SFX, voice library/design/cloning, music, transcription, isolation, speech-to-speech) and Mureka (music, lyrics), does the work in-process, and writes files to the local filesystem. Games, audiobooks, podcasts, video, ads, accessibility, localization — all one MCP.
Built to be driven by an agent, never a human clicking a UI. Every generation call returns
a job_id instantly and runs in the background, so an agent can fan out many variants
without blocking, then collect them with check_jobs.
Install
# from a checkout
pip install -e .
ofaudio-mcp # or: python -m ofaudio_mcp
Only hard dependency is the mcp SDK. Python 3.10+.
Configure (environment)
Copy .env.example to .env and fill in your keys (.env is gitignored).
Set at least one provider's key. Keys accept a singular or plural form; the plural
is comma-separated and becomes a multi-account pool (see Parallelism).
| Env var | Default | Purpose |
|---|---|---|
ELEVENLABS_API_KEY / ELEVENLABS_API_KEYS |
— | ElevenLabs key(s) — voice + SFX. Works with a subscription tier or pure pay-as-you-go. |
MUREKA_API_KEY / MUREKA_API_KEYS |
— | Mureka key(s) — music. Prepaid API credits. |
OFAUDIO_OUT_DIR |
./ofaudio-out |
Where audio files are written. |
OFAUDIO_STATE_DIR |
<OUT_DIR>/.state |
Job records (JSON) + presets.json. |
OFAUDIO_TOOLS |
all | Comma-separated tool groups to mount (generate,speakers,voices,account,transform,pronunciation) — fewer tools, less client context. See Context cost. |
OFAUDIO_ELEVENLABS_LANES |
3 |
Concurrent requests per ElevenLabs key. |
OFAUDIO_MUREKA_LANES |
1 |
Concurrent requests per Mureka key (Mureka caps at 1/account). |
OFAUDIO_POLL_INTERVAL |
5 |
Seconds between polls for async (Mureka) jobs. |
OFAUDIO_JOB_TIMEOUT |
300 |
Max seconds to wait for one generation. |
OFAUDIO_MUREKA_MODEL |
auto |
Pin a Mureka model (e.g. the V9 flagship string) once confirmed on a live key. |
OFAUDIO_ELEVENLABS_MODEL |
eleven_v3 |
TTS model; drop to eleven_multilingual_v2 if v3 isn't on the key's tier. |
OFAUDIO_ELEVENLABS_VOICE |
Rachel | Default voice id when a call doesn't specify one. |
ELEVENLABS_BASE_URL / MUREKA_BASE_URL |
official | Override API base URLs. |
A key entry may be label:key to name the lane in logs and job results
(e.g. MUREKA_API_KEYS="acct-a:ak_...,acct-b:ak_...").
Tools
27 tools in six groups (generate, speakers, voices, account, transform,
pronunciation); mount a subset with OFAUDIO_TOOLS. Every parameter is documented in the
tool schema itself, so an agent needs nothing beyond tools/list.
| Tool | What it does |
|---|---|
generate_music(prompt, duration?, instrumental?, reference?, lyrics?, engine?, format?, count?, composition_plan?, store_for_inpainting?, respect_sections_durations?) |
Themes, BGM, songs, instrumentals. Soft-defaults to Mureka (prompt→song writes its own lyrics; pass lyrics for your own; reference = local/URL track → vibe-match; format defaults to lossless flac; count 1–3). engine="elevenlabs" = Eleven Music (composition_plan replaces prompt; store_for_inpainting → song_id) → {job_id} |
generate_lyrics(prompt) |
Write song lyrics from a theme (Mureka) — synchronous {title, lyrics}; review/edit before spending song credits |
transcribe(audio, language?, diarize?, captions?) |
Speech-to-text (ElevenLabs Scribe). audio = local path or a URL (YouTube/TikTok); diarize labels speakers; captions="srt"/"vtt" writes a subtitle file → {text, language_code, words, captions_path?} |
forced_alignment(audio, text, captions?) |
Align a known script to existing audio → exact per-word timings (+ optional SRT/VTT) — for captioning recordings you already have the transcript for |
isolate_audio(audio) |
Remove background noise / isolate the voice → {path} |
convert_voice(audio, voice, remove_background_noise?, format?, seed?) |
Speech-to-speech: re-voice a recording onto another voice, keeping delivery (dubbing/ADR) → {path} |
generate_sfx(prompt, duration_seconds?, loop?, prompt_influence?, model?, engine?, format?) |
One-shots, ambience, seamless loops → {job_id} |
generate_speech(text, voice?, profile?, speaker?, mood?, workspace?, model?, stability?, style?, speed?, similarity_boost?, use_speaker_boost?, seed?, previous_text?, next_text?, language_code?, with_timestamps?, variants?, pronunciation?, engine?, format?) |
Dialogue / character VO. Identity = a voice or a saved speaker (+ mood layered over its base delivery); shape delivery with a profile and/or precision knobs; inline v3 tags like [whispers] work; with_timestamps=True emits a per-character alignment sidecar (lip-sync/captions); variants=N (1–8) fans out N takes to audition → {job_id} (or {job_ids}) |
generate_dialogue(lines=[{voice, text}], model?, seed?, language_code?, apply_text_normalization?, engine?, format?) |
Multi-speaker scene in one call (≤10 voices, ~2000 chars) with natural turn-taking → {job_id} |
save_profile(name, voice?, model?, stability?, style?, speed?, …, tag?, seed?, description?) |
Save a reusable persona/mood preset (a preset over the speech knobs) |
save_speaker(name, voice, workspace?, model?, stability?, …, seed?, description?) |
Save a speaker (pinned voice + base delivery) under a workspace |
list_speakers(workspace?) |
Saved speakers (optionally by workspace), each with its workspace |
search_voice_library(query?, gender?, age?, accent?, use_case?, category?, descriptives?, page_size?) |
Search ElevenLabs' shared library of thousands of voices; every result carries a preview_url to audition — no generation, no slots (keep query to a word or two) |
add_library_voice(public_owner_id, voice_id, name, speaker?, workspace?, seed?, description?) |
Add a library voice to the account and save it under name (uses a voice slot); speaker= also saves it as a speaker in one step |
design_voice(description, save_as?, text?, model?, guidance_scale?, loudness?, seed?) |
Synthesize a custom voice from a text description; returns previews to audition |
save_voice(name, generated_voice_id, description?) |
Keep a designed preview as a permanent, reusable voice (uses a voice slot) |
clone_voice(name, audio_paths, description?, remove_background_noise?) |
Instant Voice Cloning from your audio file(s) → saved, reusable voice (uses a slot) |
delete_voice(voice, confirm=False) |
Delete a custom voice and free its slot (fresh name→id, blocks premade, warns on profile/speaker refs) |
account_status() |
Both providers, one call — ElevenLabs (tier, char quota, voice slots, cloning, + quality/formats the tier allows) and Mureka (credit balance, concurrency limit). Check before fan-out |
list_models() |
ElevenLabs models available on the account + capability flags |
check_jobs(job_ids) |
Batch-poll — returns status + file path per id |
list_jobs(status?, limit?) |
Recent jobs, newest first |
create_pronunciation_dictionary(name, rules, description?) |
Lock how words/lore-names are said — rules = {word: say_as} map or EL rule objects. Apply via generate_speech(pronunciation=) or save_speaker(pronunciation=) |
add_pronunciation_rules(dictionary, rules) |
Extend a saved dictionary (mints a new version) |
list_voices() |
ElevenLabs voices on the account ({account, profiles}) — resolve a voice by name or id |
get_voice(voice) |
One voice's details (category, labels, description, preview_url) |
list_presets() |
Everything saved, one call: voice aliases, music presets, profiles (built-in + custom), speakers, pronunciation dictionaries, workspaces |
Each generate_* has a soft-pinned provider (music→Mureka, SFX/speech→ElevenLabs) and an
optional engine= override. A result is {job_id, status, path, duration, format, seed, provider} once succeeded.
Voices, speakers & delivery
The voice is the speaker's identity — pick or make one, don't dial it out of parameters. Three ways to get a voice, all reusable by name afterwards:
- Use one of ElevenLabs' many —
search_voice_library(query="warm narrator", age="middle_aged")→add_library_voice(public_owner_id, voice_id, "narrator"). Thousands of ready-made voices. - Design a custom one —
design_voice("warm, measured audiobook narrator, clear articulation", save_as="narrator"). Describe it, audition the previews, keep the best. - Reuse what's on the account —
list_voices()shows the premade voices already there.
Then just generate_speech("...", voice="narrator") — the voice stays consistent.
Make it a first-class Speaker, grouped by workspace. For a whole cast across several projects,
save_speaker("narrator", voice, workspace="projectA", ...) saves the identity (pinned voice + base
delivery), and generate_speech(text, speaker="narrator", mood="calm", workspace="projectA") speaks
it — the mood layers over the speaker (a speaker is who; a profile is what mood).
search_voice_library(query) returns candidates with a preview_url each (no slots), and
add_library_voice(..., speaker="narrator", workspace="projectA") adds + saves in one step.
variants=N on generate_speech fans out N takes so a human picks the best.
Delivery (mood/tone) is a separate layer on top. Shape it with a profile and/or the
precision knobs. Built-in profiles: neutral, narrator, calm, whisper, sad, angry, excited, shout (v3, emotion via audio tags) and steady, dynamic (v2, consistency axis). Save your
own persona/mood presets with save_profile.
Two facts worth knowing (both handled for you, but they explain the design):
- Eleven v3 (default for speech) does emotion via inline audio tags (
[whispers],[angry],[snorts], …) and a 3-mode stability (creative/natural/robust) — it ignores the numericstyleslider. Tags only land on an expressive voice; a flat narration voice mutes them. - Eleven v2 uses the numeric sliders, but those control consistency (dynamic ↔ steady),
not a specific emotion. Use it via the
steady/dynamicprofiles.
Parallelism
Mureka caps concurrency at 1 request per prepaid account and it doesn't stack, so the way to run music generation in parallel is multiple accounts. This server treats keys as a pool: supply N keys and it runs N jobs in parallel, one per key, automatically routing around a key that hits its rate limit (back-off) or runs out of balance. Supplying one key is just the N=1 case. (ElevenLabs scales concurrency within a single key by tier, so a lane count > 1 per key is the norm there.)
Mount it
Claude Code
claude mcp add ofaudio \
--env ELEVENLABS_API_KEY=xi_... --env MUREKA_API_KEY=ak_... \
-- python -m ofaudio_mcp
Cursor — .cursor/mcp.json:
{
"mcpServers": {
"ofaudio": {
"command": "python",
"args": ["-m", "ofaudio_mcp"],
"env": { "ELEVENLABS_API_KEY": "xi_...", "MUREKA_API_KEY": "ak_..." }
}
}
}
Self-hosted / server — add the server to your MCP client's config and put the keys in a
.env next to it (they stay on the box):
ELEVENLABS_API_KEYS=xi_...
MUREKA_API_KEYS=acct-a:ak_...,acct-b:ak_...
OFAUDIO_OUT_DIR=/var/audio/ofaudio-out
The intended usage pattern is fan-out: fire many generate_* calls, then check_jobs.
Context cost
Most MCP clients load every tool schema into the model's context on every turn, so the size
of tools/list is a real cost. Claude Code defers schemas until a tool is used, but truncates
any tool description longer than 2048 characters. The surface is shaped around both:
- Each tool's docstring is ≤ 700 chars; every parameter is documented in its own schema
description(nothing gets cut, and schema-rendering clients see real docs, nottitles). - Tools carry MCP annotations (
readOnlyHint,destructiveHint) so clients can skip approval prompts on reads and warn ondelete_voice. - The advertised schemas are compacted at startup (pydantic's
title/anyOf null/default: nullnoise stripped; validation unchanged). OFAUDIO_TOOLS=generate,accountmounts only the groups a project needs.- The usage guide is served in-band as the MCP resource
ofaudio://guide(text/markdown) for clients that support resources; the same text ships as theskills/ofaudioskill.
| Surface | Tools | tools/list |
≈ tokens |
|---|---|---|---|
| before this shaping | 33 | 42.3 KB | 12.1k |
| all six groups | 27 | 33.7 KB | 9.6k |
OFAUDIO_TOOLS=generate,account |
9 | 13.7 KB | 3.9k |
Measure it with python scripts/tool_surface.py (honours OFAUDIO_TOOLS; exits 1 if any
description exceeds 2048 chars).
Status
Both providers work end-to-end. ElevenLabs: speech (+ timestamps, mood profiles,
variants), multi-speaker dialogue, SFX, Eleven Music, voice library / design / instant
cloning, voice lifecycle, account introspection, the speaker/workspace layer, and the transform
tools (transcribe, forced alignment, isolate, voice-convert). Mureka: instrumental + song,
prompt→song (easy-generate), user-supplied lyrics, standalone generate_lyrics, reference-track
vibe-match, and lossless flac-default output.
Design
See CLAUDE.md for the architecture, module map, tool surface, and the verified provider facts that shape the design.
License
Source-available under PolyForm Noncommercial 1.0.0, with a licensor carve-out that draws the line at the tool, not the audio:
- ✅ Run it freely for any purpose — including to generate audio you use commercially. This MCP is only a client; it claims no rights in what you generate. Your rights to the generated audio are governed by ElevenLabs' and Mureka's terms and your own accounts with them.
- ❌ Don't commercialize the tool itself — you may not sell this software, host it as a paid service, or turn it (or a derivative) into a commercial product.
In short: make whatever audio you want, sell it if your provider terms allow — just don't sell the MCP. See LICENSE for the full terms.
Installing Ofaudio
This server has no published package — it is built from source. Open the repository and follow its README.
▸ github.com/DuragonYama/ofaudio-mcpFAQ
Is Ofaudio MCP free?
Yes, Ofaudio MCP is free — one-click install via Unyly at no cost.
Does Ofaudio need an API key?
No, Ofaudio runs without API keys or environment variables.
Is Ofaudio hosted or self-hosted?
A hosted option is available: Unyly runs the server in the cloud, no local setup required.
How do I install Ofaudio in Claude Desktop, Claude Code or Cursor?
Open Ofaudio on unyly.org, pick your client tab (Claude Desktop, Claude Code, Cursor) and press Install — the config is generated automatically, no JSON editing.
Related MCPs
ARA
Generate images, video and audio from any AI agent — one connector.
by ARAOmni Video
An MCP server that transforms LLM-enabled IDEs into professional video editors by pre-processing footage into text proxies, generating motion graphics via HTML/
by buildwithtazaYouTube
Transcripts, channel stats, search
by YouTubeEverArt
AI image generation using various models.
by modelcontextprotocolgpu-bridge/mcp-server
GPU inference API for LLMs, image and video generation, TTS, Whisper, embeddings, reranking and OCR, paid per use via x402 or an API key.
by gpu-bridgemerterbak/Grok-MCP
Access xAI's Grok API with agentic tool calling, image generation, vision and file support.
by merterbakSureScaleAI/openai-gpt-image-mcp
Image generation and editing with OpenAI's GPT image models.
by SureScaleAIYangLiangwei/PersonalizationMCP
Aggregate personal data from Steam, YouTube, Bilibili, Spotify, Reddit and other gaming, music, video and social platforms, with OAuth2 and token management.
by YangLiangweiAceDataCloud/MCPFlux
Flux image generation and editing from Black Forest Labs via the Ace Data Cloud API.
by AceDataCloudAceDataCloud/MCPNanoBanana
Nano Banana image generation and editing, including virtual try-on and product placement in realistic scenes.
by AceDataCloudCompare Ofaudio with
Not sure what to pick?
Find your stack in 60 seconds
Author?
Embed badge for your README
Browse similar
All media MCPs
