Command Palette

Search for a command to run...

UnylyUnyly
Browse all

TTS2Mic MCP Server

FreeNot checked

Go MCP server for end-to-end testing of browser voice applications by synthesizing text-to-speech audio into simulated microphone input.

GitHubEmbed

About

Go MCP server for end-to-end testing of browser voice applications by synthesizing text-to-speech audio into simulated microphone input.

README

tts2mic-mcp is a Go-based MCP server for end-to-end testing browser voice applications by injecting TTS-generated audio into a simulated microphone.

The intended flow is:

MCP client / test runner
        ↓
speak(target, text, voice)
        ↓
TTS cache lookup
        ↓
TTS provider only on cache miss
        ↓
PCM / WAV audio
        ↓
Virtual microphone backend
        ↓
Browser app using getUserMedia / WebRTC / STT

The main use case is testing browser apps where Playwright or another automation tool clicks around normally and selects a simulated microphone device, for example BlackHole 2ch on macOS.

Status

This is an early scaffold. It currently includes:

  • Go CLI entrypoint
  • MCP server over stdio using mcp-go
  • speak tool
  • pluggable TTS provider interface
  • deterministic local TTS stub
  • ElevenLabs provider
  • filesystem PCM cache
  • WAV encoding
  • macOS BlackHole backend with direct device-targeted playback
  • Linux PipeWire/PulseAudio backend
  • Chrome fake-audio-file backend
  • setup scripts
  • GitHub Actions CI

It is still intentionally small, but the core MCP transport is already in place.

Install / build

go test ./...
go build -o bin/tts2mic-mcp ./cmd/tts2mic-mcp

Run the CLI directly:

go run ./cmd/tts2mic-mcp speak \
  --target chrome-file \
  --text "hello world" \
  --out /tmp/tts2mic.wav

How to use as an MCP server

The server runs over stdio using mcp-go and currently exposes a single tool, speak.

Start the server:

go run ./cmd/tts2mic-mcp

Then send one JSON request per line on stdin:

{"name":"speak","arguments":{"target":"macos-blackhole","text":"hello world","voice":"default"}}

Example using printf:

printf '%s\n' '{"name":"speak","arguments":{"target":"macos-blackhole","text":"hello world","voice":"default"}}' \
  | go run ./cmd/tts2mic-mcp

Successful response:

{"ok":true}

Error response:

{"error":"unknown backend"}

MCP tool: speak

Input schema

{
  "type": "object",
  "required": ["target", "text"],
  "properties": {
    "target": {
      "type": "string",
      "description": "Injection backend to use: macos-blackhole, pipewire, or chrome-file"
    },
    "text": {
      "type": "string",
      "description": "Text to synthesize and inject into the simulated microphone"
    },
    "voice": {
      "type": "string",
      "description": "Provider-specific voice id. Defaults to default. Used in the cache key."
    }
  }
}

Go type

type SpeakInput struct {
    Target string `json:"target"`
    Text   string `json:"text"`
    Voice  string `json:"voice,omitempty"`
}

Example request

{
  "name": "speak",
  "arguments": {
    "target": "macos-blackhole",
    "text": "hello world",
    "voice": "en-US-JennyNeural"
  }
}

macOS: simulated microphone with BlackHole

For browser E2E testing on macOS, use BlackHole so the browser sees a real selectable microphone device. The macos-blackhole backend now opens a playback device directly through CoreAudio via malgo, so it does not need the current macOS system output to be switched just to inject speech.

Install/setup:

./scripts/setup-macos-blackhole.sh

Then:

  1. Open Audio MIDI Setup.
  2. Confirm BlackHole 2ch exists.
  3. In your browser app, select BlackHole 2ch as the microphone.
  4. Inject speech (sine test without provider):
go run ./cmd/tts2mic-mcp speak \
  --target macos-blackhole \
  --text "hello world"

By default the backend looks for the first playback device whose name contains BlackHole. You can override that lookup if needed:

export TTS2MIC_MACOS_OUTPUT_DEVICE="BlackHole 2ch"

As a use case, in Playwright, your app can select the mic the same way a user would. For apps that expose an input selector, select BlackHole 2ch. For apps using navigator.mediaDevices.enumerateDevices(), choose the audio input whose label contains BlackHole after microphone permission is granted.

Linux: simulated microphone with PipeWire/PulseAudio (not tested yet)

Create a virtual sink and monitor source:

./scripts/setup-pipewire-virtual-mic.sh

Route playback into the virtual sink:

export PULSE_SINK=tts2mic_sink

Inject speech:

go run ./cmd/tts2mic-mcp speak \
  --target pipewire \
  --text "hello world"

Then select the monitor source as the microphone in the browser.

Chrome fake-audio-file mode

This mode does not create a normal selectable microphone. It is useful for deterministic Chromium automation but is intentionally less realistic than BlackHole/PipeWire.

Generate a WAV file:

go run ./cmd/tts2mic-mcp speak \
  --target chrome-file \
  --text "hello world" \
  --out /tmp/tts2mic.wav

Run Chromium with fake media flags:

./scripts/run-chrome-fake-audio.sh /tmp/tts2mic.wav https://example.com

TTS cache

Before calling the TTS provider, the TTS layer checks a filesystem cache.

Logical cache key:

lang:voice_id:provider:sha256(text)

Default cache directory:

.tts2mic-cache/

The cache stores raw little-endian int16 PCM files and is gitignored.

Example layout:

.tts2mic-cache/
  stub/
    und/
      default/
        und__default__stub__<sha256>.pcm

Environment variables:

export TTS_CACHE_DIR=.tts2mic-cache
export TTS_PROVIDER_NAME=stub
export TTS_LANG=en-US

Current behavior:

first speak call  → cache miss → provider called → PCM stored
next same call    → cache hit  → provider skipped

When real providers are added, the cache key should also include any options that affect output audio, such as sample rate, speaking rate, pitch, style, and output format.

TTS providers

The project currently supports two providers:

  • Default test provider: a deterministic local sine-wave stub used when TTS_PROVIDER is unset or set to anything other than elevenlabs
  • Real provider: ElevenLabs, selected with TTS_PROVIDER=elevenlabs

Default local test setup:

unset TTS_PROVIDER
export TTS_PROVIDER_NAME=stub
export TTS_LANG=en-US

ElevenLabs setup:

export TTS_PROVIDER=elevenlabs
export ELEVENLABS_API_KEY=...
export ELEVENLABS_VOICE_ID=...
export ELEVENLABS_MODEL_ID=eleven_multilingual_v2
export ELEVENLABS_OUTPUT_FORMAT=pcm_16000

Notes:

  • ELEVENLABS_OUTPUT_FORMAT defaults to pcm_16000.
  • If no voice is passed to speak, the ElevenLabs backend falls back to ELEVENLABS_VOICE_ID.
  • TTS_PROVIDER_NAME is used as part of the cache key and defaults to stub or the value of TTS_PROVIDER.

Roadmap

  • Add additional real TTS providers beyond ElevenLabs, such as Azure or OpenAI.
  • Add richer device controls for the macOS CoreAudio backend, such as explicit device listing and selection helpers.
  • Add 48 kHz resampling for browser/STT realism.
  • Add Playwright-oriented helpers for browser E2E flows, such as selecting the simulated microphone and asserting setup state.
  • Add transcript assertion helpers.
  • Add higher-level MCP/testing ergonomics on top of the existing server, such as richer tool metadata and reusable test helpers.
  • Add audio fixtures for noise, silence, barge-in, long utterances, and multi-turn flows.

from github.com/jacarte/tts2mic-mcp

Installing TTS2Mic MCP Server

This server has no published package — it is built from source. Open the repository and follow its README.

▸ github.com/jacarte/tts2mic-mcp

FAQ

Is TTS2Mic MCP Server MCP free?

Yes, TTS2Mic MCP Server MCP is free — one-click install via Unyly at no cost.

Does TTS2Mic MCP Server need an API key?

No, TTS2Mic MCP Server runs without API keys or environment variables.

Is TTS2Mic MCP Server hosted or self-hosted?

Self-hosted: the server runs locally on your machine via the install command above.

How do I install TTS2Mic MCP Server in Claude Desktop, Claude Code or Cursor?

Open TTS2Mic MCP Server 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

Compare TTS2Mic MCP Server with

Not sure what to pick?

Find your stack in 60 seconds

Author?

Embed badge for your README

Browse similar

All browse MCPs