play_sound
Play system sounds, text-to-speech audio, or custom audio files to provide audio feedback in applications.
Instructions
Play various types of sounds with customizable parameters
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| type | Yes | Type of sound to play | |
| name | No | System sound name (required when type is "system") | |
| text | No | Text to speak (required when type is "tts") | |
| voice | No | Voice name (optional, used with type "tts", uses system default if not specified) | |
| path | No | Absolute path to audio file (required when type is "file") |
Implementation Reference
- src/index.ts:306-338 (registration)Registration of the 'play_sound' tool, including name, description, and input schema definition.{ name: 'play_sound', description: 'Play various types of sounds with customizable parameters', inputSchema: { type: 'object', required: ['type'], properties: { type: { type: 'string', enum: ['system', 'tts', 'file'], description: 'Type of sound to play' }, name: { type: 'string', enum: ['Basso', 'Blow', 'Bottle', 'Frog', 'Funk', 'Glass', 'Hero', 'Morse', 'Ping', 'Pop', 'Purr', 'Sosumi', 'Submarine', 'Tink'], description: 'System sound name (required when type is "system")' }, text: { type: 'string', description: 'Text to speak (required when type is "tts")' }, voice: { type: 'string', description: 'Voice name (optional, used with type "tts", uses system default if not specified)' }, path: { type: 'string', description: 'Absolute path to audio file (required when type is "file")' } }, additionalProperties: false }, },
- src/index.ts:381-416 (handler)Handler logic for the 'play_sound' tool call: input validation and delegation to playCustomSound function.case 'play_sound': { // Validate args exists if (!args || typeof args !== 'object') { throw new Error('Invalid arguments provided'); } // Validate required parameters based on type const { type } = args as { type?: string }; if (!type || !['system', 'tts', 'file'].includes(type)) { throw new Error('Invalid or missing type. Must be "system", "tts", or "file"'); } if (type === 'system' && !(args as any).name) { throw new Error('Parameter "name" is required when type is "system"'); } if (type === 'tts' && !(args as any).text) { throw new Error('Parameter "text" is required when type is "tts"'); } if (type === 'file' && !(args as any).path) { throw new Error('Parameter "path" is required when type is "file"'); } const soundOptions = args as PlaySoundOptions; const result = await playCustomSound(soundOptions); return { content: [ { type: 'text', text: result, }, ], }; }
- src/index.ts:181-274 (helper)Core implementation of custom sound playback: handles system sounds, TTS, and file playback with validation, throttling, and timeouts.async function playCustomSound(options: PlaySoundOptions): Promise<string> { const requestId = `${options.type}-${Date.now()}`; // Throttle same type requests if (activeRequests.has(options.type)) { throw new Error(`${options.type} sound already playing`); } activeRequests.add(options.type); try { let child: ReturnType<typeof spawn>; // Validate and spawn process switch (options.type) { case 'system': { const { name: soundName } = options; if (!ALLOWED_SYSTEM_SOUNDS.has(soundName)) { throw new Error(`Unsupported system sound: ${soundName}`); } child = spawn('afplay', [`/System/Library/Sounds/${soundName}.aiff`]); break; } case 'tts': { const { text, voice } = options; // Validate text length if (text.length > MAX_TTS_TEXT_LENGTH) { throw new Error(`Text too long (max ${MAX_TTS_TEXT_LENGTH} characters)`); } // Validate voice if provided, gracefully fall back to system default let finalVoice = voice; if (voice !== undefined && !ALLOWED_TTS_VOICES.has(voice)) { // Log warning but continue with system default console.warn(`Unsupported voice: ${voice}. Using system default voice.`); finalVoice = undefined; } const args = finalVoice ? ['-v', finalVoice, text] : [text]; child = spawn('say', args); break; } case 'file': { const { path: filePath } = options; if (!isAbsolute(filePath)) { throw new Error('File path must be absolute'); } try { const stats = await getCachedFileStat(filePath); if (!stats.isFile()) { throw new Error('Path must point to a file'); } } catch (error) { throw new Error(`File not found or inaccessible: ${filePath}`); } child = spawn('afplay', [filePath]); break; } default: { // TypeScript ensures this is unreachable, but keep for runtime safety const exhaustiveCheck: never = options; throw new Error(`Unknown sound type: ${(exhaustiveCheck as any).type}`); } } // Wrap child process lifecycle in Promise with timeout return new Promise((resolve, reject) => { const timeout = setTimeout(() => { child.kill(); reject(new Error('Sound playback timed out')); }, PROCESS_TIMEOUT_MS); child.once('close', (code: number) => { clearTimeout(timeout); if (code === 0) { resolve(`${options.type} sound played successfully`); } else { reject(new Error(`Sound playback failed with code ${code}`)); } }); child.once('error', (error) => { clearTimeout(timeout); reject(error); }); }); } finally { activeRequests.delete(options.type); } }
- src/index.ts:13-17 (schema)TypeScript type definitions for PlaySoundOptions used in the tool implementation.type SystemSound = { type: 'system'; name: string }; type TTSSound = { type: 'tts'; text: string; voice?: string }; type FileSound = { type: 'file'; path: string }; type PlaySoundOptions = SystemSound | TTSSound | FileSound;