Profile-driven MCP server for Google Cloud Text-to-Speech
Project description
TTS MCP (Google Cloud Text-to-Speech)
Profile-driven MCP server and local CLI tools for Google Cloud Text-to-Speech.
This project is currently Google-specific. You can switch voices/models within Google through profiles, while keeping the same MCP tool interface.
What this project provides
- MCP server with simple speech tools:
tts_speak(text|text_file, speaking_rate, pitch)tts_doctor()tts_stop()
- Profile-fixed runtime settings (not exposed to the model):
- voice, language, model, format, output_dir, autoplay behavior
- Local CLI helpers for direct testing and voice exploration
- Non-blocking autoplay with local file persistence
Quick start
git clone git@github.com:that-lucas/tts-mcp.git
cd tts-mcp
export ABS_PATH_TO_REPO="$(pwd)"
make setup
make doctor
Requirements
- Python 3.11+
- Google Cloud project with billing enabled
- Google Cloud Text-to-Speech API enabled
- macOS playback uses
afplayby default (configurable)
Google Cloud account and authentication
1) Create and prepare your Google Cloud project
- Create or choose a Google Cloud project.
- Enable billing for that project.
- Enable Cloud Text-to-Speech API.
2) Create OAuth credentials (recommended)
- In Google Cloud Console, open
APIs & Services -> Credentials. - Create
OAuth client ID. - Choose application type
Desktop app. - Download the OAuth client JSON file.
3) Generate user credentials for this project
cd "$ABS_PATH_TO_REPO"
source .venv/bin/activate
python oauth_login.py \
--client-secret-file "<PATH_TO_OAUTH_CLIENT_JSON>" \
--out "$HOME/.config/gcp/tts-oauth-user.json" \
--quota-project "<GCP_PROJECT_ID>"
4) Set GOOGLE_APPLICATION_CREDENTIALS
You can set it in your shell profile (recommended), for example in Fish:
set --global --export GOOGLE_APPLICATION_CREDENTIALS "$HOME/.config/gcp/tts-oauth-user.json"
Or pass it explicitly in each MCP client config (recommended for portability/reliability).
Local CLI usage
make help
make setup
make speak TEXT="Hello from Google TTS" OUT=./out/hello.wav FORMAT=wav
make voices VOICES_LANGUAGE=en-US VOICE_FAMILY=Chirp3
make speak-test VOICE=en-US-Chirp3-HD-Fenrir
Profile system
Profiles are defined in:
tts_profiles.json(active)tts_profiles.example.json(reference)
Each profile fixes:
voicelanguagemodelformatspeaking_rate(default used by MCP, still overridable per call)pitch(default used by MCP, still overridable per call)output_dirusage_logautoplayplayer_command
Current example profiles include opencode, codex, and claude_code.
MCP server behavior
- Playback is launched in background mode (non-blocking).
- Output files are always saved.
- Default filename pattern:
YYYY-MM-DD-HH-MM-SS-MMM.wav(or.mp3/.ogg)
Run MCP diagnostics:
make mcp-doctor MCP_PROFILE=opencode
Run MCP server manually:
make mcp-run MCP_PROFILE=opencode
Client setup
Use an absolute repository path in all client configs.
export ABS_PATH_TO_REPO="/absolute/path/to/tts-mcp"
export ABS_PATH_TO_CREDENTIALS_JSON="/absolute/path/to/tts-oauth-user.json"
OpenCode
Edit ~/.config/opencode/opencode.jsonc:
{
"mcp": {
"speech": {
"type": "local",
"command": [
"<ABS_PATH_TO_REPO>/.venv/bin/python",
"<ABS_PATH_TO_REPO>/mcp_server.py",
"--profiles",
"<ABS_PATH_TO_REPO>/tts_profiles.json",
"--profile",
"opencode"
],
"environment": {
"GOOGLE_APPLICATION_CREDENTIALS": "<ABS_PATH_TO_CREDENTIALS_JSON>"
},
"enabled": true,
"timeout": 120000
}
}
}
Verify:
opencode mcp list
Codex CLI
Edit ~/.codex/config.toml:
[mcp_servers.speech]
command = "<ABS_PATH_TO_REPO>/.venv/bin/python"
args = [
"<ABS_PATH_TO_REPO>/mcp_server.py",
"--profiles",
"<ABS_PATH_TO_REPO>/tts_profiles.json",
"--profile",
"codex"
]
env = { GOOGLE_APPLICATION_CREDENTIALS = "<ABS_PATH_TO_CREDENTIALS_JSON>" }
startup_timeout_sec = 15
tool_timeout_sec = 120
enabled = true
Verify:
codex mcp list
codex mcp get speech
Claude Code CLI
Add server:
claude mcp add --transport stdio --scope user \
--env GOOGLE_APPLICATION_CREDENTIALS="<ABS_PATH_TO_CREDENTIALS_JSON>" \
speech -- \
"<ABS_PATH_TO_REPO>/.venv/bin/python" "<ABS_PATH_TO_REPO>/mcp_server.py" \
--profiles "<ABS_PATH_TO_REPO>/tts_profiles.json" \
--profile claude_code
Verify:
claude mcp list
Using speech from prompts
In MCP-enabled clients, ask naturally and hint tool usage, for example:
Summarize this and read it aloud. use speechStop current playback. use speech
Depending on the client, tool names may appear prefixed (for example, speech_tts_speak, speech_tts_stop).
Troubleshooting
- MCP startup handshake fails (Codex): ensure no stdout/stderr banner noise from server startup and verify command path points to project venv.
- Tool timeout while audio plays: this server uses non-blocking playback; if timeout persists, increase client
tool_timeout. - No audio output: verify player binary (
afplay) exists, or changeplayer_commandin profile. - Auth errors: confirm
GOOGLE_APPLICATION_CREDENTIALSpoints to a valid JSON credential file.
Security notes
- Do not commit credential files.
- Keep OAuth client secrets and authorized-user JSON files outside the repo.
- Review
.gitignorebefore committing local artifacts.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file tts_mcp-0.1.0.tar.gz.
File metadata
- Download URL: tts_mcp-0.1.0.tar.gz
- Upload date:
- Size: 21.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1bd1cac9709648aeaa83b8c95689634af86d295c0e1bb6b9270bb6018ee45f42
|
|
| MD5 |
e1f95a047260dccd296bc79f40377391
|
|
| BLAKE2b-256 |
4af6df36866fe329f7c825007b2a4d7b9c0982014cff16f819b405ce7472133f
|
Provenance
The following attestation bundles were made for tts_mcp-0.1.0.tar.gz:
Publisher:
release.yml on that-lucas/tts-mcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
tts_mcp-0.1.0.tar.gz -
Subject digest:
1bd1cac9709648aeaa83b8c95689634af86d295c0e1bb6b9270bb6018ee45f42 - Sigstore transparency entry: 941152306
- Sigstore integration time:
-
Permalink:
that-lucas/tts-mcp@f3a2b5381fec333fbbfe0cde1675772f5e7658af -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/that-lucas
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@f3a2b5381fec333fbbfe0cde1675772f5e7658af -
Trigger Event:
push
-
Statement type:
File details
Details for the file tts_mcp-0.1.0-py3-none-any.whl.
File metadata
- Download URL: tts_mcp-0.1.0-py3-none-any.whl
- Upload date:
- Size: 16.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
761b4dcae085884f20348c15380373616fa39c64d7105bd1dbe4a144a62faf50
|
|
| MD5 |
dae7bb05a505772126172d5f0469f2dc
|
|
| BLAKE2b-256 |
e09e06019761a531898c2fb880a1170a74f769298bb654a8bfb30e7dd9c17a17
|
Provenance
The following attestation bundles were made for tts_mcp-0.1.0-py3-none-any.whl:
Publisher:
release.yml on that-lucas/tts-mcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
tts_mcp-0.1.0-py3-none-any.whl -
Subject digest:
761b4dcae085884f20348c15380373616fa39c64d7105bd1dbe4a144a62faf50 - Sigstore transparency entry: 941152319
- Sigstore integration time:
-
Permalink:
that-lucas/tts-mcp@f3a2b5381fec333fbbfe0cde1675772f5e7658af -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/that-lucas
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@f3a2b5381fec333fbbfe0cde1675772f5e7658af -
Trigger Event:
push
-
Statement type: