VoiceLab MCP Server
OfficialEnables OpenAI ChatGPT/Codex Plugins to connect to the hosted MCP endpoint using OAuth 2.1 (authorization-code + PKCE with dynamic discovery via /.well-known/oauth-protected-resource). Supports per-user billing by extracting each user's VoiceLab API key from the voicelab_api_key JWT claim, so individual ChatGPT users call VoiceLab's chat, TTS, STT, voice isolation, and realtime tools against their own account.
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
VoiceLab MCP Server
Official Model Context Protocol (MCP) server for VoiceLab — enabling AI agents (Cursor, ChatGPT, Grok, Muse, etc.) to use VoiceLab's speech AI capabilities.
Features
LLM Completions: Chat with Aisha models, manage requests
Text-to-Speech: Generate natural speech in Uzbek, Russian, and English
Speech-to-Text: Transcribe audio with timing and speaker labels
Voice Isolation: Remove background noise with optional speech restoration
Voice Management: List and discover available voices
Realtime Support: Create WebSocket tickets for streaming TTS/STT
Meeting AI: Upload recordings, poll transcripts, summaries, decisions, and action items
Related MCP server: voice-mcp-server
Installation
Prerequisites
Node.js 20.0.0 or later
VoiceLab API key (get one at voicelab.uz)
Install from npm
npm install -g @voicelab/mcpOr build from source
git clone https://github.com/voicelab/voicelab-mcp.git
cd voicelab-mcp
npm install
npm run buildConfiguration
Environment Variables
export VOICELAB_API_KEY='vlk_your_api_key_here'
export VOICELAB_BASE_URL='https://api.voicelab.uz' # Optional, uses default if not setStore your API key securely. Never commit it to version control.
Cursor Configuration
Add to your Cursor settings (~/.cursor/mcp.json or workspace .cursor/mcp.json):
{
"mcpServers": {
"voicelab": {
"command": "npx",
"args": ["@voicelab/mcp"],
"env": {
"VOICELAB_API_KEY": "${VOICELAB_API_KEY}"
}
}
}
}Or if installed globally:
{
"mcpServers": {
"voicelab": {
"command": "voicelab-mcp",
"env": {
"VOICELAB_API_KEY": "vlk_your_api_key_here"
}
}
}
}Remote Usage (ChatGPT, Grok, Muse)
Once deployed (VPS HTTP + nginx, or Cloudflare Workers), agents can connect to the hosted endpoint.
ChatGPT / OpenAI Plugins
OpenAI Plugins require OAuth 2.1 authentication with per-user billing (static API keys are not supported).
Quick Setup:
VoiceLab backend implements OAuth AS (see
BACKEND_OAUTH_SPEC.md)Configure MCP server:
export OAUTH_ISSUER='https://auth.voicelab.uz' export OAUTH_AUDIENCE='https://mcp.voicelab.uz' export VOICELAB_API_KEY='vlk_fallback_...' # For non-OAuth clientsRegister plugin in ChatGPT:
https://mcp.voicelab.uz
ChatGPT discovers OAuth via /.well-known/oauth-protected-resource and initiates authorization-code + PKCE flow with VoiceLab.
Per-User Billing: OAuth JWTs contain each user's VoiceLab API key in the voicelab_api_key claim. MCP extracts this key and uses it for all API calls, charging the correct user's account.
Full documentation: docs/OAUTH_INTEGRATION.md
Backend requirements: BACKEND_OAUTH_SPEC.md
Grok
grok mcp add --transport http voicelab https://mcp.voicelab.uz/mcpOr use custom connector in grok.com/connectors.
Muse
Submit connector at muse.ai/platform → "Existing MCP" with:
Endpoint:
https://mcp.voicelab.uz/mcpAuth: Bearer token (user provides their API key)
See packaging/ folders for detailed catalog submission guides.
Usage
Start the Server
stdio mode (for local Cursor):
npm start
# or
voicelab-mcpHTTP mode (for remote hosting):
npm run start:httpHTTP mode binds to 127.0.0.1:3100 by default (HOST / PORT). Put nginx (or another TLS terminator) in front.
HTTP environment variables
Variable | Default | Purpose |
| (optional) | Fallback API key for legacy token users; OAuth users get per-user keys from JWT |
|
| VoiceLab API origin (must be HTTPS and allowlisted) |
OAuth 2.1 (OpenAI) | ||
| (empty) | VoiceLab OAuth issuer — enables OAuth. MUST exactly match backend |
|
| MCP resource identifier (audience claim in JWTs). MUST match JWT |
Legacy Auth | ||
| (empty) | Static Bearer token for non-OpenAI clients (Cursor, Claude, Grok) |
Server Config | ||
| (empty) | Comma-separated browser origins for CORS; empty disables CORS reflection |
|
| Max request body size (10 MiB) |
|
| App-level rate limit per client IP |
|
| Listen address (keep loopback in production) |
MCP Apps / audio upload | ||
| (off) |
|
| (empty) | Optional HTTPS browser upload page (only with |
|
| ChatGPT |
| (off) | Staging only: |
Dual Authentication Mode
The server supports both OAuth 2.1 and legacy Bearer tokens simultaneously:
OAuth (VoiceLab AS): Required for OpenAI ChatGPT/Codex Plugins. Enable by setting
OAUTH_ISSUER.Per-user billing: JWTs contain user's API key in
voicelab_api_keyclaimMCP extracts this key and charges the correct user's VoiceLab account
Legacy Token: Works for Cursor, Claude Desktop, Grok, and other MCP clients. Enable by setting
MCP_AUTH_TOKEN.Coexistence: Both can be active — OpenAI clients use OAuth, others use the legacy token.
Fallback Key:
VOICELAB_API_KEYused when legacy token auth succeeds or JWT missing per-user key.
Why Per-User Keys? OpenAI ChatGPT users share one MCP endpoint. Without per-user keys, all users would charge a single shared VoiceLab account. OAuth JWTs carry each user's API key, ensuring correct billing attribution.
See docs/OAUTH_INTEGRATION.md for OAuth setup and BACKEND_OAUTH_SPEC.md for backend implementation requirements.
MCP Bearer auth (clients)
When MCP_AUTH_TOKEN is set on the server, every /mcp request must include:
Authorization: Bearer <MCP_AUTH_TOKEN>
Accept: application/json, text/event-stream
Content-Type: application/jsonExample initialize:
curl -sS https://mcp.voicelab.uz/mcp \
-H "Authorization: Bearer $MCP_AUTH_TOKEN" \
-H "Accept: application/json, text/event-stream" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"curl","version":"0"}}}'Public discovery (no auth): GET /health, GET /v1, GET /.well-known/mcp.json.
Available Tools
LLM
list_models— List available LLM models with pricingchat_completions— Create chat completion (auto-generates idempotency key)get_llm_request— Get request status and token usage
Text-to-Speech
list_tts_languages— List supported languages and modelslist_voices— List available voices (filter by language)text_to_speech— Generate speech (returns base64 WAV)list_tts_generations— List generation historyget_tts_generation— Get generation details with audio URLdelete_tts_generation— Delete a generation (destructive)
Speech-to-Text
speech_to_text— Transcribe audio from exactly one ofaudio_urloraudio_base64(≤ ~7 MB), orupload_idwhen upload sessions are enabled; returns job IDget_transcription— Get transcription status and results (poll until complete)list_transcriptions— List transcription historyupdate_transcription— Update transcription titleedit_transcription_document— Atomically replace transcript document (segments, speakers, revision-based)delete_transcription— Delete transcription (destructive)export_transcription— Export as TXT, JSON, SRT, or VTT (returns base64)
Voice Isolation
isolate_voice— Remove background noise (returns job ID for polling)isolate_voice_batch— Submit 1-4 files for atomic batch processingget_isolation— Get job status and audio URLs (poll until complete)list_isolations— List isolation historycreate_isolation_export— Request export in specific formatget_isolation_export— Get export status and download URLhide_isolation— Hide job from history (does not delete audio)
Realtime
create_realtime_ticket— Create WebSocket ticket for streaming TTS or STT
Meeting AI
list_meeting_capabilities— List supported recording languages and feature flagscreate_meeting— Submit a recording from exactly one ofaudio_urloraudio_base64(≤ ~7 MB), orupload_idwhen upload sessions are enabled; returns 202, pollget_meetinglist_meetings— List meetings or refresh selected IDsget_meeting— Poll status and read transcript, summary, decisions, and action itemsrename_meeting— Change a meeting titledelete_meeting— Delete a meeting and its results (destructive)regenerate_meeting_notes— Retry notes after a notes failure (transcribedonly)get_meeting_translations— Attempt translations (docs: not available with API keys)
Audio upload (MCP Apps) and ChatGPT files
Always on:
create_meeting_from_file— ChatGPT only (openai/fileParams): create a meeting from a file attached in ChatGPTtranscribe_file— ChatGPT only (openai/fileParams): transcribe a file attached in ChatGPT
Only with MCP_ENABLE_UPLOAD_SESSIONS=1 (backend upload sessions required):
upload_audio— Open the VoiceLab upload widget (ui://voicelab/upload) so the user can send a local file (up to 500 MB) directly to VoiceLab; processing starts automatically. Text fallback for clients without MCP Appscreate_upload_session— App-only (_meta.ui.visibility: ["app"]): fresh single-use upload session for the widgetget_upload— Upload session status (pending/ready/consumed/failed/expired)
The server always advertises capabilities.resources; with upload sessions enabled it serves ui://voicelab/upload as text/html;profile=mcp-app (MCP Apps spec 2026-01-26). Hosts without MCP Apps ignore the UI metadata. The legacy Cloudflare Worker (src/worker.ts) does not support MCP Apps.
Example Agent Prompts
Generate speech:
Use VoiceLab to generate Uzbek speech for: "Salom, dunyo!"Transcribe audio:
Transcribe this meeting recording with speaker labels.
[Attach audio file]Clean audio:
Remove background noise from this call recording using VoiceLab voice isolation.
[Attach audio file]Meeting notes:
Upload this recording to VoiceLab Meeting AI, poll until it is ready, and give me the summary, decisions, and action items.
[Attach audio file]API Reference
Full API documentation: https://docs.voicelab.uz
Idempotency
STT, TTS, Voice Isolator, and Meeting AI upload tools auto-generate UUIDs for idempotency when not provided. Retries with the same key and body return the original result without reprocessing or charging again.
Binary Audio Handling
Input (
create_meeting,speech_to_text): exactly one ofaudio_url(public HTTPS URL, ≤ 4096 chars) oraudio_base64, plusupload_id(fromupload_audio) whenMCP_ENABLE_UPLOAD_SESSIONS=1. The MCP request body is capped at 10 MiB, so base64 audio must stay under ~7 MB. Voice isolation tools acceptaudio_base64onlyOutput: Audio returned as
audio_base64(WAV/export format) or via signed URLs in job responses
Polling
STT transcriptions, Voice Isolator jobs, and Meeting AI uploads are asynchronous:
Call
speech_to_text,isolate_voice, orcreate_meetingto submitPoll
get_transcriptionorget_isolationuntilstatus: "completed"; pollget_meetinguntil status isready,transcribed, orfailed(notqueuedorrunning)Access results from the completed response
Respect Retry-After headers when present. Meeting AI has no completion webhooks.
Development
Build
npm run buildTest
npm testProject Structure
src/
├── index.ts # MCP server and tool registration
├── client.ts # HTTP client and error handling
├── llm.ts # LLM module
├── tts.ts # Text-to-Speech module
├── stt.ts # Speech-to-Text module
├── voices.ts # Voices module
├── isolator.ts # Voice Isolator module
├── realtime.ts # Realtime ticket module
└── meetings.ts # Meeting AI moduleDeployment
Cloudflare Workers
Deploy the MCP server to Cloudflare Workers for remote HTTP access at https://mcp.voicelab.uz.
Prerequisites
Cloudflare account (account ID:
ac52eda10a0df089ff1d6052087b5367)wrangler CLI:
npm install -g wranglerVoiceLab API key
Quick Deploy
# 1. Build the worker
npm run build:worker
# 2. Set your API key secret
wrangler secret put VOICELAB_API_KEY
# Paste your vlk_... key when prompted
# 3. Deploy to Workers
npm run deploy
# Your MCP endpoint will be at:
# https://voicelab-mcp.your-subdomain.workers.dev/mcpCustom Domain Setup
Deploy to Workers (initial deploy uses workers.dev subdomain)
npm run deployAdd Custom Domain in Cloudflare Dashboard:
Navigate to Workers & Pages
Select
voicelab-mcpGo to Settings → Triggers
Add Custom Domain:
mcp.voicelab.uz
Configure DNS for voicelab.uz zone:
Add
CNAMErecord:mcp→voicelab-mcp.your-subdomain.workers.devOr use Cloudflare's automatic setup
Update wrangler.toml (optional, after custom domain is configured):
routes = [{ pattern = "mcp.voicelab.uz/*", custom_domain = true }]Environment Variables
Set secrets via wrangler:
# Required
wrangler secret put VOICELAB_API_KEY
# Optional
wrangler secret put VOICELAB_BASE_URLOr configure in Cloudflare Dashboard under Settings → Variables.
Staging Environment
# Deploy to staging
npm run deploy:staging
# Set staging secrets
wrangler secret put VOICELAB_API_KEY --env stagingHealth Check
# Test deployment
curl https://mcp.voicelab.uz/
# Should return: {"name":"VoiceLab MCP Server","version":"1.0.0",...}
# Test MCP endpoint (requires MCP client)
curl -X POST https://mcp.voicelab.uz/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"tools/list","id":1}'Local Development
Test the worker locally before deploying:
# Start local worker with hot reload
npm run dev
# Server runs at http://localhost:8787
# Set VOICELAB_API_KEY in .dev.vars fileCreate .dev.vars for local development:
VOICELAB_API_KEY=vlk_your_test_key
VOICELAB_BASE_URL=https://api.voicelab.uzMonitoring
View logs:
wrangler tailDashboard: https://dash.cloudflare.com → Workers & Pages → voicelab-mcp
Metrics: requests/sec, errors, CPU time
Docker (Optional)
Create a Dockerfile:
FROM node:20-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY dist ./dist
ENV VOICELAB_API_KEY=""
CMD ["node", "dist/index.js"]Build and run:
docker build -t voicelab-mcp .
docker run -e VOICELAB_API_KEY=vlk_your_key voicelab-mcpHosting for Remote MCP
The server supports both stdio (local Cursor) and HTTP (remote agents) transports:
Stdio (default): For local Cursor usage
npm startHTTP (Cloudflare Workers): For remote access
npm run deploy
# Endpoint: https://mcp.voicelab.uz/mcpUse the Workers deployment for ChatGPT, Grok, Muse, and other agents that require remote MCP endpoints.
Security
Never expose your API key in client code, URLs, or version control
Store keys in environment variables or a secret manager
Use restricted API keys with minimum required permissions
Set
allowed_ipsandexpires_atwhen creating keysSigned audio URLs expire after ~10 minutes; refresh as needed
Realtime tickets expire after ~2 minutes; mint fresh tickets per connection
Troubleshooting
"VOICELAB_API_KEY environment variable is required"
Set the environment variable before starting:
export VOICELAB_API_KEY='vlk_...'
npm start"401 invalid_api_key"
Check that your key is correct and not expired
Verify the key is enabled in the VoiceLab dashboard
Ensure the key has required permissions (
llm:access,tts:write,stt:write, etc.)
"402 insufficient_credits"
Add credits to your VoiceLab account at voicelab.uz.
"409 idempotency_key_reused"
You're retrying with a different request body but the same idempotency key. Either:
Use a new key for the new request
Reuse the original body to retrieve the cached result
Contributing
Contributions are welcome! Please:
Fork the repository
Create a feature branch
Add tests for new functionality
Ensure
npm testandnpm run buildpassSubmit a pull request
License
MIT License - see LICENSE file for details.
Links
What's Not Included
Per the VoiceLab developer API contract, this MCP server does not expose:
Account JWT analytics and API-key management UI routes
Meeting AI dashboard-only surfaces (audio download, transcript/notes editing, speaker renaming, webhooks). Translations are documented as unavailable with API keys;
get_meeting_translationsstill attemptsGET /v1/meetings/{id}/translationsand may fail.Voice-agent dashboard data
Browser realtime streams (use
create_realtime_ticketfor WebSocket setup)
Developer Meeting AI uses /v1/meetings with an API key (meetings Access). Dashboard routes at /api/v1/meetings require a user JWT and are not used here.
AI pull request review
Changed files receive stack-specific security, readability, scalability, test and applicable UX feedback through AI&. See setup, review labels and limits.
This server cannot be deployed
Maintenance
Related MCP Connectors
Transcribe audio & video to text for AI agents: 100+ languages, speaker labels, webhooks.
Voice and chat for AI agents — Discord, Teams, Meet, Slack, Zoom, Telegram, WhatsApp, NC Talk, SIP
Audio for your agent: transcribe, speak, translate, summarise, plus sound effects and music.
Give your AI assistant a real phone line. Place and end real phone calls with AI voice agents, read call transcripts, run a live two-way interpreter between two people who share no language (31 languages, browser link or phone), create and edit voice agents, and search, buy and bind phone numbers in 21 countries. OAuth 2.1 with PKCE — the model never sees your API key; a read-only scope is available. Pay as you go from $0.10/min, $5 free credit for new accounts.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables seamless integration with ElevenLabs Conversational AI to manage agents, tools, and knowledge base sources. It supports RAG indexing, webhook integration, and document management for building advanced voice-enabled AI agents.MIT
- AlicenseNot gradedqualityCmaintenanceEnables AI agents to speak and listen in real-time with interruption handling, using local ML models and hot-swappable adapters.26 npm2MIT
- AlicenseNot gradedqualityBmaintenanceEnables voice-first interactions with AI agents and MCP tools, supporting speech input/output, STT/TTS, and a provider-independent agent core.1MIT
- AlicenseNot gradedqualityBmaintenanceEnables AI agents to initiate and control outbound telephone calls and answer inbound calls through Telnyx and LiveKit, with realtime voice conversations powered by Gemini Live or OpenAI Realtime.MIT