speak
Read text aloud on macOS using built-in text-to-speech. Supports voice selection and adjustable speech rate.
Instructions
Speak text using macOS text-to-speech
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| text | Yes | Text to speak | |
| voice | No | Voice to use (defaults to system voice) | |
| rate | No | Speech rate (-50 to 50, defaults to 0) |
Implementation Reference
- src/features/speech.ts:60-88 (handler)Main handler function 'speak' that validates params, builds the macOS 'say' command, executes it, and handles errors (command failed, permission denied, etc.).
export async function speak(params: SpeechParams): Promise<void> { try { validateSpeechParams(params); const command = buildSpeechCommand(params); await execAsync(command); } catch (error) { if (error instanceof NotificationError) { throw error; } const err = error as Error; if (err.message.includes('execution error')) { throw new NotificationError( NotificationErrorType.COMMAND_FAILED, 'Failed to execute speech command' ); } else if (err.message.includes('permission')) { throw new NotificationError( NotificationErrorType.PERMISSION_DENIED, 'Permission denied when trying to speak' ); } else { throw new NotificationError( NotificationErrorType.UNKNOWN, `Unexpected error: ${err.message}` ); } } } - src/types.ts:50-60 (schema)Input schema interface 'SpeechParams' with fields: text (required), voice (optional string), rate (optional number -50 to 50).
/** * Parameters for text-to-speech */ export interface SpeechParams { /** Text to speak */ text: string; /** Voice to use (defaults to system voice) */ voice?: string; /** Speech rate (-50 to 50, defaults to 0) */ rate?: number; } - src/index.ts:118-142 (registration)Tool registration in the MCP server: defines the 'speak' tool with description and JSON schema (inputSchema) matching SpeechParams.
{ name: 'speak', description: 'Speak text using macOS text-to-speech', inputSchema: { type: 'object', properties: { text: { type: 'string', description: 'Text to speak', }, voice: { type: 'string', description: 'Voice to use (defaults to system voice)', }, rate: { type: 'number', description: 'Speech rate (-50 to 50, defaults to 0)', minimum: -50, maximum: 50 } }, required: ['text'], additionalProperties: false, }, }, - src/index.ts:269-287 (handler)The switch case in the CallToolRequestSchema handler that extracts params (text, voice, rate) from the request, constructs SpeechParams, and calls the speak function.
case 'speak': { const { text, voice, rate } = request.params.arguments as Record<string, unknown>; const params: SpeechParams = { text: text as string, voice: typeof voice === 'string' ? voice : undefined, rate: typeof rate === 'number' ? rate : undefined }; await speak(params); return { content: [ { type: 'text', text: 'Speech completed successfully', }, ], }; } - src/features/speech.ts:41-55 (helper)Helper function 'buildSpeechCommand' that constructs the macOS 'say' command with optional voice (-v) and rate (-r) flags.
function buildSpeechCommand(params: SpeechParams): string { let command = 'say'; if (params.voice) { command += ` -v "${escapeString(params.voice)}"`; } if (params.rate !== undefined) { command += ` -r ${params.rate}`; } command += ` "${escapeString(params.text)}"`; return command; }