@theproductivepixel/aittsm
v1.2.1
Published
MCP stdio server for AI TTS Microservice — connects AI agents, IDEs, and MCP-compatible clients to the unified TTS API via tool calls
Maintainers
Readme
@theproductivepixel/aittsm
MCP (Model Context Protocol) stdio server for AI TTS Microservice. Connects AI agents, IDEs, and any MCP-compatible client to the unified TTS API via tool calls.
Install
npm install -g @theproductivepixel/aittsmSetup
export AITTSM_API_KEY=tts_your_api_key_hereGet your API key from aitts.theproductivepixel.com/dashboard/api.
Usage
Claude Desktop
{
"mcpServers": {
"aitts": {
"command": "npx",
"args": ["@theproductivepixel/aittsm"],
"env": { "AITTSM_API_KEY": "tts_your_api_key_here" }
}
}
}Cursor / Windsurf
{
"aitts": {
"command": "npx",
"args": ["@theproductivepixel/aittsm"],
"env": { "AITTSM_API_KEY": "tts_your_api_key_here" }
}
}Direct CLI
aittsmTools (34)
Voice & Generation
| Tool | Permission | Bucket | Description |
|------|-----------|--------|-------------|
| search_voices | voices:list | read | Search available TTS voices |
| generate_speech | tts:generate | generate | Generate TTS audio |
| get_job_status | tts:status | read | Check job status and metadata |
| get_audio_link | tts:status | read | Get signed download URL |
Jobs
| Tool | Permission | Bucket | Description |
|------|-----------|--------|-------------|
| list_jobs | jobs:read | read | List jobs with pagination |
| get_job_text | jobs:read | read | Get input text of a job |
| update_job_metadata | jobs:write | generate | Update tags/collection |
| delete_job_audio | jobs:write | generate | Delete stored audio |
Shares
| Tool | Permission | Bucket | Description |
|------|-----------|--------|-------------|
| create_share | shares:write | generate | Create share link |
| list_shares | shares:read | read | List active shares |
| get_share | shares:read | read | Get full share details |
| update_share | shares:write | generate | Update share settings |
| revoke_share | shares:write | generate | Revoke a share |
| bulk_revoke_shares | shares:write | generate | Revoke multiple shares |
| toggle_share_permanent | shares:write | generate | Toggle permanent status |
| update_track_order | shares:write | generate | Reorder tracks |
Access Codes & QR
| Tool | Permission | Bucket | Description |
|------|-----------|--------|-------------|
| create_access_codes | shares:write | generate | Create access codes |
| list_access_codes | shares:read | read | List codes (no raw values) |
| update_access_code | shares:write | generate | Update a code |
| delete_access_code | shares:write | generate | Delete a code |
| export_access_codes | shares:read | read | Export as CSV format |
| get_qr_code | shares:write | generate | Generate QR image |
Library & Storage
| Tool | Permission | Bucket | Description |
|------|-----------|--------|-------------|
| list_collections | library:read | read | List audio collections |
| manage_collection | library:write | generate | Create/rename/delete collection |
| list_tags | library:read | read | List tags with counts |
| create_bookmark | library:write | generate | Bookmark a share |
| list_bookmarks | library:read | read | List bookmarks |
| delete_bookmark | library:write | generate | Delete a bookmark |
| manage_bookmark_collection | library:write | generate | Manage bookmark collections |
| get_storage | storage:read | read | Storage usage summary |
| list_storage_items | storage:read | read | List stored items |
| bulk_delete_storage | storage:write | generate | Bulk delete storage |
| estimate_cost | pricing:estimate | read | Estimate credit cost |
| get_usage | usage:read | read | Get balance and account type |
Examples
Async Generation Workflow
// 1. Generate audio
{
"name": "generate_speech",
"arguments": {
"text": "Welcome to our podcast.",
"voice_id": "google:en-US-Chirp3HD-Charon",
"tags": ["podcast", "intro"]
}
}
// Response:
// {
// "job_id": "abc123",
// "status": "pending",
// ...
// }
// 2. Poll until completed
{
"name": "get_job_status",
"arguments": {
"job_id": "abc123"
}
}
// Response:
// {
// "status": "completed",
// "audio_bytes": 48000,
// ...
// }
// 3. Get download URL
{
"name": "get_audio_link",
"arguments": {
"job_id": "abc123"
}
}
// Response:
// {
// "audio_endpoint": "/api/v1/tts/abc123/audio",
// "signed_url": "https://...",
// ...
// }Streaming Generation
{
"name": "generate_speech",
"arguments": {
"text": "Stream this audio.",
"voice_id": "google:en-US-Chirp3HD-Charon",
"delivery_mode": "stream",
"output_format": "ogg_opus",
"idempotency_key": "unique-key-abc"
}
}Stream supports all 7 formats. Async supports wav, mp3, ogg_opus only.
Voice Search
{
"name": "search_voices",
"arguments": {
"language": "en-US",
"provider": "google",
"model_type": "ultra"
}
}Share Workflow
// 1. Create a password-protected share from completed jobs
{
"name": "create_share",
"arguments": {
"job_ids": ["job1", "job2"],
"title": "Client Review",
"auth_mode": "password",
"password": "secret123",
"allow_download": true
}
}
// Response:
// {
// "code": "xyz789",
// "url": "https://aitts.theproductivepixel.com/share/audio/xyz789",
// "item_count": 2
// }
// 2. Generate a QR code for the share
{
"name": "get_qr_code",
"arguments": {
"code": "xyz789",
"format": "png",
"preset": "branded"
}
}
// 3. Later, revoke access
{
"name": "revoke_share",
"arguments": {
"code": "xyz789"
}
}Collection Management
// 1. Create a collection
{
"name": "manage_collection",
"arguments": {
"action": "create",
"name": "Podcast Episodes"
}
}
// Response:
// {
// "id": "col-abc",
// "name": "Podcast Episodes"
// }
// 2. Assign jobs to it
{
"name": "update_job_metadata",
"arguments": {
"job_id": "job1",
"collection_id": "col-abc",
"tags": ["episode-1"]
}
}
// 3. Create a live share from the collection
{
"name": "create_share",
"arguments": {
"source_type": "collection",
"source_id": "col-abc",
"share_mode": "live",
"title": "All Episodes"
}
}Tool Reference
Complete per-tool parameter tables, response shapes, and error codes for all 34 tools.
search_voices
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| language | string | — | Filter by language code (e.g. en-US) |
| provider | string | — | Filter by provider (google, polly, kokoro) |
| model_type | premium | ultra | — | Filter by model type |
Response:
{
"voices": [
{
"voice_id": "google:en-US-Chirp3HD-Charon",
"name": "Charon",
"language": "en-US",
"provider": "google",
"model_type": "ultra",
"gender": "male"
}
]
}generate_speech
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| text | string (1–500000) | ✓ | Text to synthesize |
| voice_id | string | — | Voice ID (provider:lang-Family-Name) |
| delivery_mode | async | stream | — | Default: async |
| model_type | premium | ultra | — | Model type |
| model | string | — | Specific model ID |
| speed | number (0.25–4) | — | Speaking rate multiplier |
| format | text | ssml | markup | — | Input format |
| speaker_type | single | multi | — | Speaker type |
| voice_id_speaker_1 | string | — | Speaker 1 voice ID (required for multi) |
| voice_id_speaker_2 | string | — | Speaker 2 voice ID (required for multi) |
| output_format | wav | mp3 | ogg_opus | pcm | mulaw | alaw | ogg_vorbis | — | Audio format |
| prompt | string | — | Ultra model guidance prompt |
| webhook_url | string (URL) | — | Completion webhook (enterprise) |
| metadata | object | — | Custom metadata |
| sample_rate_hertz | integer | — | Output sample rate in Hz |
| output_bitrate_kbps | integer | — | Bitrate (async only) |
| language | string | — | Language code override |
| tags | string[] | — | Library tags |
| collection_id | string | — | Collection ID |
| idempotency_key | string (max 256) | — | Safe retry key |
Response (async):
{
"job_id": "uuid",
"status": "pending",
"poll_url": "/api/v1/tts/{job_id}",
"audio_endpoint": "/api/v1/tts/{job_id}/audio",
"chars_charged": 16
}Response (stream):
{
"job_id": "uuid",
"status": "pending",
"stream_url": "https://...",
"stream_url_expires_at": "...",
"transport_format": "ogg_opus",
"transport_mime_type": "audio/ogg; codecs=opus",
"transport_sample_rate_hertz": 48000,
"chars_charged": 30
}get_job_status
| Param | Type | Required | Description | |-------|------|----------|-------------| | job_id | string | ✓ | Job ID to check |
Response:
{
"job_id": "uuid",
"status": "completed",
"voice_id": "...",
"model_type": "ultra",
"provider": "google",
"created_at": "...",
"completed_at": "...",
"audio_bytes": 48000,
"output_format": "ogg_opus",
"chars_charged": 16,
"tags": [],
"collection_id": null,
"source": "api",
"is_expired": false
}get_audio_link
| Param | Type | Required | Description | |-------|------|----------|-------------| | job_id | string | ✓ | Job ID |
Response:
{
"audio_endpoint": "/api/v1/tts/{job_id}/audio",
"signed_url": "https://...",
"expires_at": "2026-05-08T12:00:00Z",
"job_id": "uuid"
}get_job_text
| Param | Type | Required | Description | |-------|------|----------|-------------| | job_id | string | ✓ | Job ID |
Response:
{
"text": "Hello world"
}list_jobs
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| page_size | integer (1–100) | — | Items per page (default 20) |
| page_token | string | — | Pagination cursor |
| source | api | ui | — | Filter by source |
| status | completed | failed | pending | processing | — | Filter by status |
Response:
{
"jobs": [
{
"job_id": "...",
"status": "completed",
"...": "..."
}
],
"next_page_token": "eyJ..."
}delete_job_audio
| Param | Type | Required | Description | |-------|------|----------|-------------| | job_id | string | ✓ | Job ID |
Response:
{
"shares_revoked": 0,
"storage": null
}update_job_metadata
| Param | Type | Required | Description | |-------|------|----------|-------------| | job_id | string | ✓ | Job ID | | tags | string[] | — | Replace tags array | | collection_id | string | null | — | Set or clear collection |
Response:
{
"job_id": "uuid",
"tags": ["podcast", "episode-1"],
"collection_id": "col-abc"
}create_share
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| job_ids | string[] | — | Job IDs for snapshot share |
| source_type | collection | tag | — | Source type |
| source_id | string | — | Source ID |
| share_mode | snapshot | live | — | Share mode |
| auth_mode | none | password | access_code | — | Auth mode |
| password | string | — | Password (if auth_mode=password) |
| title | string | — | Share title |
| allow_download | boolean | — | Allow download |
| include_text | boolean | — | Include text excerpts |
| show_voice | boolean | — | Show voice metadata |
| show_model | boolean | — | Show model metadata |
| show_provider | boolean | — | Show provider metadata |
| show_language | boolean | — | Show language metadata |
| show_expiry | boolean | — | Show expiry metadata |
| show_track_meta | boolean | — | Show track metadata |
| track_titles | object | — | Custom track titles |
| track_order | string[] | — | Custom track order |
Response:
{
"code": "abc123",
"url": "https://aitts.theproductivepixel.com/share/audio/abc123",
"item_count": 3
}list_shares
| Param | Type | Required | Description | |-------|------|----------|-------------| | page_size | integer (1–100) | — | Items per page | | page_token | string | — | Pagination cursor |
Response:
{
"shares": [
{
"code": "...",
"title": "...",
"item_count": 3,
"auth_mode": "none",
"share_mode": "snapshot",
"is_permanent": false,
"created_at": "..."
}
],
"next_page_token": null
}get_share
| Param | Type | Required | Description | |-------|------|----------|-------------| | code | string | ✓ | Share code |
Response:
{
"code": "abc123",
"title": "Demo",
"auth_mode": "none",
"share_mode": "snapshot",
"is_permanent": false,
"allow_download": true,
"item_count": 2,
"created_at": "...",
"jobs": ["..."]
}update_share
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| code | string | ✓ | Share code |
| title | string | — | New title |
| auth_mode | none | password | access_code | — | Auth mode |
| password | string | — | Password |
| allow_download | boolean | — | Allow download |
| share_mode | snapshot | live | — | Share mode |
| include_text | boolean | — | Include text |
| show_voice | boolean | — | Show voice |
| show_model | boolean | — | Show model |
| show_provider | boolean | — | Show provider |
| show_language | boolean | — | Show language |
| show_expiry | boolean | — | Show expiry |
| show_track_meta | boolean | — | Show track meta |
| track_titles | object | — | Track titles |
| track_order | string[] | null | — | Track order or null |
| source_type | collection | tag | — | Source type |
| source_id | string | — | Source ID |
Response:
{
"code": "abc123",
"title": "Updated",
"auth_mode": "password",
"updated_at": "..."
}revoke_share
| Param | Type | Required | Description | |-------|------|----------|-------------| | code | string | ✓ | Share code |
Response:
{
"revoked": true
}bulk_revoke_shares
| Param | Type | Required | Description | |-------|------|----------|-------------| | codes | string[] (1–100) | ✓ | Share codes to revoke |
Response:
{
"revoked_count": 3,
"skipped": ["code-not-found"]
}toggle_share_permanent
| Param | Type | Required | Description | |-------|------|----------|-------------| | code | string | ✓ | Share code |
Response:
{
"code": "abc123",
"permanent": true,
"expires_at": null
}update_track_order
| Param | Type | Required | Description | |-------|------|----------|-------------| | code | string | ✓ | Share code | | track_order | string[] | null | ✓ | Ordered job IDs or null to reset |
Response:
{
"code": "abc123",
"track_order": ["job-2", "job-1", "job-3"]
}create_access_codes
| Param | Type | Required | Description | |-------|------|----------|-------------| | code | string | ✓ | Share code | | count | integer (1–100) | — | Number of codes (default 1) | | label | string | — | Label or label prefix | | expires_at | string (ISO date) | — | Expiration date | | max_uses | integer (≥1) | — | Max uses per code |
Response (count=1):
{
"id": "doc-id",
"code": "ABCD1234EFGH",
"code_prefix": "ABCD",
"label": "VIP",
"active": true,
"created_at": "...",
"expires_at": null,
"max_uses": 10
}Response (count>1):
[
{
"id": "doc-1",
"code": "ABCD1111AAAA"
},
{
"id": "doc-2",
"code": "ABCD2222BBBB"
}
]list_access_codes
| Param | Type | Required | Description | |-------|------|----------|-------------| | code | string | ✓ | Share code |
Response:
[
{
"id": "...",
"code_prefix": "ABCD",
"label": "VIP",
"active": true,
"uses": 3,
"max_uses": 10,
"created_at": "...",
"expires_at": null,
"last_used_at": null
}
]update_access_code
| Param | Type | Required | Description | |-------|------|----------|-------------| | code | string | ✓ | Share code | | access_code_id | string | ✓ | Access code document ID | | label | string | — | New label | | active | boolean | — | Active status | | expires_at | string | null | — | New expiry or null | | max_uses | integer | null | — | New max uses or null |
Response:
{
"id": "doc-id",
"code_prefix": "ABCD",
"label": "Updated",
"active": true,
"uses": 3,
"max_uses": 20,
"created_at": "2026-05-01T00:00:00Z",
"expires_at": null,
"last_used_at": null
}delete_access_code
| Param | Type | Required | Description | |-------|------|----------|-------------| | code | string | ✓ | Share code | | access_code_id | string | ✓ | Access code document ID |
Response:
{
"deleted": true
}export_access_codes
| Param | Type | Required | Description | |-------|------|----------|-------------| | code | string | ✓ | Share code |
Response:
[
{
"id": "ac-1",
"code_prefix": "AB12",
"label": "Reviewer",
"active": true,
"created_at": "...",
"expires_at": null,
"max_uses": 10,
"uses": 3
}
]get_qr_code
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| code | string | ✓ | Share code |
| format | svg | png | ✓ | Image format |
| preset | clean | branded | — | Visual preset |
| include_access_code | boolean | — | Embed access code in URL |
| access_code | string | — | Access code to embed |
Response:
{
"data_uri": "data:image/png;base64,...",
"format": "png"
}list_collections
No parameters.
Response:
{
"collections": [
{
"id": "col-abc",
"name": "Podcast Episodes",
"created_at": "...",
"updated_at": "..."
}
]
}manage_collection
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| action | create | rename | delete | ✓ | Operation |
| name | string | — | Name (required for create/rename) |
| collection_id | string | — | ID (required for rename/delete) |
Response (create/rename):
{
"id": "col-id",
"name": "New Name"
}Response (delete):
{
"deleted": true
}list_tags
No parameters.
Response:
{
"tags": [
{
"tag": "podcast",
"count": 12
},
{
"tag": "demo",
"count": 3
}
]
}create_bookmark
| Param | Type | Required | Description | |-------|------|----------|-------------| | share_code | string | ✓ | Share code to bookmark |
Response:
{
"created": true
}list_bookmarks
| Param | Type | Required | Description | |-------|------|----------|-------------| | page_size | integer (1–100) | — | Items per page | | page_token | string | — | Pagination cursor |
Response:
{
"bookmarks": [
{
"id": "bm-1",
"share_code": "xyz789",
"title": "Shared Audio",
"personal_title": null,
"collection_id": null,
"created_at": "...",
"last_opened_at": null,
"effective_status": "active"
}
],
"next_page_token": null
}delete_bookmark
| Param | Type | Required | Description | |-------|------|----------|-------------| | bookmark_id | string | ✓ | Bookmark ID (share code) |
Response:
{
"deleted": true
}manage_bookmark_collection
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| action | create | rename | delete | ✓ | Operation |
| name | string | — | Name (required for create/rename) |
| collection_id | string | — | ID (required for rename/delete) |
Response (create/rename):
{
"id": "col-id",
"name": "Favorites"
}Response (delete):
{
"deleted": true
}get_storage
No parameters.
Response:
{
"used_bytes": 15728640,
"cap_bytes": 104857600,
"remaining_bytes": 89128960,
"pending_reclaim_bytes": 0,
"sync_status": "healthy"
}list_storage_items
| Param | Type | Required | Description | |-------|------|----------|-------------| | page_size | integer (1–100) | — | Items per page | | page_token | string | — | Pagination cursor |
Response:
{
"items": [
{
"job_id": "uuid",
"status": "completed",
"audio_bytes": 48000,
"output_format": "ogg_opus",
"created_at": "...",
"storage_tier": "permanent"
}
],
"next_page_token": null
}bulk_delete_storage
| Param | Type | Required | Description | |-------|------|----------|-------------| | job_ids | string[] (1–100) | ✓ | Job IDs to delete |
Response:
{
"deleted_count": 3,
"skipped_count": 1,
"skipped": [
{
"job_id": "uuid",
"reason": "job_in_progress"
}
]
}estimate_cost
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| text | string (1–500000) | ✓ | Text to estimate |
| model_type | premium | ultra | — | Model type |
| voice_id | string | — | Voice ID |
| output_format | wav | mp3 | ogg_opus | — | Output format |
Response:
{
"estimated_cost": 2.5,
"chars_charged": 500,
"model_type": "ultra",
"provider": "google",
"output_format": "ogg_opus"
}get_usage
No parameters.
Response:
{
"account_type": "standard",
"credits_balance": 4250
}Pagination
Paginated tools accept page_size (1–100, default 20) and page_token (opaque cursor). Results include next_page_token (null when exhausted).
Idempotency
Pass idempotency_key to generate_speech for safe retries:
- Same key + same body → cached result (no duplicate generation)
- Same key + different body →
IDEMPOTENCY_KEY_REUSE(409) - Key still processing →
REQUEST_IN_PROGRESS(409)
Rate Limiting
Two buckets: read (higher limits — queries, lists) and generate (lower limits — mutations, generation). Per-account enforcement. Exceeding returns an error message at tool level; HTTP 429 at transport level.
Permissions
| Permission | Tools | |-----------|-------| | voices:list | search_voices | | tts:generate | generate_speech | | tts:status | get_job_status, get_audio_link | | jobs:read | list_jobs, get_job_text | | jobs:write | delete_job_audio, update_job_metadata | | shares:read | list_shares, get_share, list_access_codes, export_access_codes | | shares:write | create_share, update_share, revoke_share, bulk_revoke_shares, toggle_share_permanent, update_track_order, create_access_codes, update_access_code, delete_access_code, get_qr_code | | library:read | list_collections, list_tags, list_bookmarks | | library:write | manage_collection, create_bookmark, delete_bookmark, manage_bookmark_collection | | storage:read | get_storage, list_storage_items | | storage:write | bulk_delete_storage | | pricing:estimate | estimate_cost | | usage:read | get_usage |
Error Reference
| Code | Status | Description | |------|--------|-------------| | VALIDATION_ERROR | 400 | Invalid input parameters | | INVALID_VOICE | 400 | Voice ID not found or invalid | | PROVIDER_DISABLED | 400 | Provider unknown or disabled | | INSUFFICIENT_CREDITS | 402 | Not enough credits | | STORAGE_CAP_EXCEEDED | 403 | Storage quota full | | FORBIDDEN | 403 | Enterprise-only or ownership failed | | INVALID_WEBHOOK_URL | 400 | Webhook URL validation failed | | ENTERPRISE_TIER_REQUIRED | 400 | Enterprise pricing without tier | | STREAM_NOT_SUPPORTED | 400 | Voice/provider doesn't support streaming | | SPEED_OUT_OF_RANGE | 400 | Speaking rate exceeds stream limit | | STREAM_BITRATE_NOT_SUPPORTED | 400 | Bitrate in stream mode | | STREAM_FORMAT_MISMATCH | 400 | Format not supported for stream | | MAINTENANCE | 503 | API in maintenance mode | | IDEMPOTENCY_KEY_REUSE | 409 | Key reused with different body | | REQUEST_IN_PROGRESS | 409 | Key still processing | | JOB_NOT_FOUND | 404 | Job doesn't exist or not owned | | JOB_IN_PROGRESS | 409 | Cannot delete pending/processing job | | TEXT_UNAVAILABLE | 410 | Job expired or text not stored | | SHARE_NOT_FOUND | 404 | Share doesn't exist or not owned | | AMBIGUOUS_SHARE_INPUT | 400 | Both job_ids and source provided | | INVALID_SHARE_SOURCE | 400 | Invalid source configuration | | PASSWORD_REQUIRED | 400 | auth_mode=password without password | | INVALID_AUTH_MODE_PASSWORD_COMBO | 400 | auth_mode and password combination invalid | | SOURCE_IMMUTABLE | 400 | Cannot change source on source-backed share | | ACCESS_CODE_NOT_FOUND | 404 | Access code doesn't exist | | COLLECTION_NOT_FOUND | 404 | Collection doesn't exist or not owned | | BOOKMARK_NOT_FOUND | 404 | Bookmark or collection doesn't exist | | ALREADY_EXISTS | 409 | Bookmark already exists |
Error envelope: { error: "message", code?: "ERROR_CODE", status?: 404 }
Configuration
| Variable | Required | Description |
|----------|----------|-------------|
| AITTSM_API_KEY | Yes | API key (starts with tts_) |
| AITTSM_BASE_URL | No | Custom API base URL |
Requirements
- Node.js 18+
- An API key (get one here)
Links
License
MIT
