Skip to main content
Glama

Fonoster MCP Server

Official
by fonoster
MIT License
118
7,325
  • Apple
  • Linux
VoiceResponse.ts14.4 kB
/** * Copyright (C) 2025 by Fonoster Inc (https://fonoster.com) * http://github.com/fonoster/fonoster * * This file is part of Fonoster * * Licensed under the MIT License (the "License"); * you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://opensource.org/licenses/MIT * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { DialOptions, GatherOptions, GatherResponse, GatherSource, MuteDirection, MuteOptions, PlaybackControlAction, PlayOptions, PlayResponse, RecordOptions, RecordResponse, SayOptions, SayResponse, StreamEvent, StreamGatherOptions, StreamOptions, VerbResponse, VoiceRequest, VoiceSessionStreamServer } from "@fonoster/common"; import { struct } from "pb-util"; import { Answer, Dial, DialStatusStream, Gather, Hangup, Mute, Play, PlaybackControl, PlayDtmf, Record, Say, StartStream, StartStreamGather, StopStream, StopStreamGather, Stream, StreamGatherStream, Unmute } from "./verbs"; /** * @classdesc Use the VoiceResponse object, to construct advance Interactive * Voice Response (IVR) applications. * * @extends Verb * @example * * import { VoiceServer } from "@fonoster/voice"; * * async function handler (request, response) { * await response.answer(); * await response.play("https://soundsserver:9000/sounds/hello-world.wav"); * } * * new VoiceServer().listen(handler, { port: 3000 }) */ class VoiceResponse { voice: VoiceSessionStreamServer; request: VoiceRequest; /** * Constructs a new VoiceResponse object. * * @param {VoiceRequest} request - Options to indicate the objects endpoint * @param {VoiceSessionStream} voice - The voice session stream * @see module:core:APIClient */ constructor(request: VoiceRequest, voice: VoiceSessionStreamServer) { this.voice = voice; this.request = request; } /** * Answer the call. Before running any other verb you * must run the answer command. * @example * * async function handler (request, response) { * await response.answer(); * } */ async answer(): Promise<VerbResponse> { await new Answer(this.request, this.voice).run(); return { sessionRef: this.request.sessionRef }; } /** * Hangup the call. * @example * * async function handler (request, response) { * await response.hangup(); * } */ async hangup(): Promise<VerbResponse> { await new Hangup(this.request, this.voice).run(); return { sessionRef: this.request.sessionRef }; } /** * Play an audio in the call. * * @param {string} url - The URL of the media to play * @param {PlayOptions} options - Options to control the playback * @param {string} options.playbackRef - Playback identifier to use in Playback operations * @see Playback * @example * * async function handler (request, response) { * await response.answer(); * await response.play("https://soundsserver:9000/sounds/hello-world.wav"); * } */ async play(url: string, options?: PlayOptions): Promise<PlayResponse> { const response = await new Play(this.request, this.voice).run({ ...options, sessionRef: this.request.sessionRef, url }); return response.playResponse; } /** * Play a series of DTMF digits in a call. * * @param {string} digits -The DTMF digits to play (0-9, #, or *) * @example * * async function handler (request, response) { * await response.answer(); * await response.playDtmf("1234"); * } */ async playDtmf(digits: string): Promise<void> { await new PlayDtmf(this.request, this.voice).run({ sessionRef: this.request.sessionRef, digits }); } /** * Control the playback of the currently playing media. * * @param {string} playbackRef - The playback identifier * @param {PlaybackControlAction} action - The action to perform (STOP, RESTART, PAUSE, UNPAUSE, FORWARD) * @see play * @example * * async function handler (request, response) { * await response.answer(); * await response.play("https://s3.fonoster.io/uuid/hello-world.wav", { playbackRef: "playback-01" }); * * // Pause the media * await response.playbackControl("playback-01", PlaybackControlAction.PAUSE); * } */ async playbackControl( playbackRef: string, action: PlaybackControlAction ): Promise<VerbResponse> { await new PlaybackControl(this.request, this.voice).run({ sessionRef: this.request.sessionRef, playbackRef, action }); return { sessionRef: this.request.sessionRef }; } /** * Waits for data entry from the user's keypad or from a speech provider. * * @param {GatherOptions} options - Options to select the maximum number of digits, final character, and timeout * @param {number} options.maxDigits - Maximum number of digits to collect. Defaults to 1 * @param {number} options.timeout - Milliseconds to wait before timeout. Defaults to 4000. Use zero for no timeout. * @param {string} options.finishOnKey - Optional last character to wait for. Defaults to '#'. It will not be included in the returned digits * @param {GatherSource} options.source - Where to listen as input source. This option accepts `DTMF` and `SPEECH`. A speech provider must be configure * when including the `SPEECH` source. You might include both with `SPEECH_AND_DTMF`. Defaults to `SPEECH_AND_DTMF` * @note When including `SPEECH` the default timeout is 10000 (10s). * @example * * async function handler (request, response) { * await response.answer(); * const speech = await response.gather({ source: GatherSource.SPEECH, numDigits: 3 }); * console.log("speech: " + speech); * await response.hangup(); * } */ async gather( options: GatherOptions = { source: GatherSource.SPEECH_AND_DTMF } ): Promise<GatherResponse> { const response = await new Gather(this.request, this.voice).run({ sessionRef: this.request.sessionRef, ...options }); return response.gatherResponse; } /** * Send a text for a TTS engine to convert to speech. * * @param {string} text - The text to convert to speech * @param {SayOptions} options - Options to control the TTS engine * @param {string} options.playbackRef - Playback identifier to use in Playback operations * @param {TTSOptions} options.ttsOptions - Options to control the TTS engine (specific to the TTS engine) * @see Say * @example * * async function handler (request, response) { * await response.answer(); * const playbackRef = await response.say("Hello World"); * * // Like the play verb, you can control the playback * await response.playbackControl(playbackRef, PlaybackControlAction.STOP); * } */ async say(text: string, options?: SayOptions): Promise<SayResponse> { const response = await new Say(this.request, this.voice).run({ playbackRef: options?.playbackRef, options: options ? struct.encode(options) : undefined, sessionRef: this.request.sessionRef, text }); return { playbackRef: response.sayResponse.playbackRef }; } /** * Record the audio of the call. * * @param {RecordOptions} options - Options to control the record operation * @param {number} options.maxDuration - The maximum duration of the recording in seconds. Default is 60 * @param {number} options.maxSilence - The maximum duration of silence in seconds. Default is 5 * @param {boolean} options.beep - Play a beep before recording. Default is true * @param {string} options.finishOnKey - Stop recording when a DTMF digit is received. Default is '#' * @return {RecordResponse} The record response * @example * * async function handler (request, response) { * await response.answer(); * const record = await response.record(); * console.log("Recording: %s", record.name); * } */ async record(options?: RecordOptions): Promise<RecordResponse> { const response = await new Record(this.request, this.voice).run({ sessionRef: this.request.sessionRef, ...options }); return response.recordResponse; } /** * Dials a destination and returns a stream of status. * * @param {string} destination - The destination to dial * @param {DialOptions} options - Options to control the dial operation * @param {number} options.timeout - The timeout in seconds. Default is 60 * @param {RecordDirection} options.recordDirection - The direction to record the call (IN, OUT, BOTH). Default is BOTH * @return {Promise<DialStatusStream>} The dial status stream */ async dial( destination: string, options?: DialOptions ): Promise<DialStatusStream> { const stream = new DialStatusStream(); await new Dial(this.request, this.voice).run({ sessionRef: this.request.sessionRef, destination, ...options }); this.voice.on(StreamEvent.DATA, (result) => { if (result.dialResponse) { stream.emit(result.dialResponse.status); } }); return stream; } /** * Starts a bidirectional audio stream between the call and the application. * * @param {StreamOptions} options - Options to control the stream operation * @param {StreamDirection} options.direction - The direction to stream the audio (IN, OUT, BOTH). Default is BOTH * @param {StreamAudioFormat} options.format - The audio format to stream (WAV). Default is WAV * @return {Promise<Stream>} The stream object * @example * * async function handler (request, response) { * await response.answer(); * * const stream = await response.stream({ * direction: StreamDirection.BOTH * }); * * stream.onPayload((payload) => { * // Use the payload * }); * * // Or write to the stream * // stream.write({ type: StreamMessageType.AUDIO_OUT, payload: "\x00\x01\x02" }); * } */ async stream(options?: StreamOptions): Promise<Stream> { const stream = new Stream(); const startStream = new StartStream(this.request, this.voice); const stopStream = new StopStream(this.request, this.voice); const { startStreamResponse } = await startStream.run({ sessionRef: this.request.sessionRef, ...options }); this.voice.on(StreamEvent.DATA, (result) => { if (result.streamPayload) { stream.emit("payloadOut", result.streamPayload); } }); stream.onPayloadIn((payload) => { this.voice.write({ streamPayload: payload }); }); stream.cleanup(() => { stopStream.run({ sessionRef: this.request.sessionRef, streamRef: startStreamResponse?.streamRef }); }); return stream; } /** * Starts a server-side stream gather operation which sends transcription data to the voice server. * * @param {StreamGatherOptions} options - Options to control the stream gather operation * @param {StreamGatherSource} options.source - The source to gather data from (DTMF, SPEECH, SPEECH_AND_DTMF). Default is SPEECH * @return {Promise<StreamGatherStream>} The stream gather object * @see Gather * @example * * async function handler (request, response) { * await response.answer(); * const sGather = await response.sgather({ source: StreamGatherSource.SPEECH }); * sGather.onPayload((payload) => { * console.log("Payload: %s", payload); * }); * } */ async sgather(options: StreamGatherOptions): Promise<StreamGatherStream> { const stream = new StreamGatherStream(); const startStreamGather = new StartStreamGather(this.request, this.voice); const stopStreamGather = new StopStreamGather(this.request, this.voice); await startStreamGather.run({ sessionRef: this.request.sessionRef, ...options }); this.voice.on(StreamEvent.DATA, (result) => { if (result.streamGatherPayload) { stream.emit("data", result.streamGatherPayload); } }); stream.cleanup(() => { stopStreamGather.run({ sessionRef: this.request.sessionRef }); }); return stream; } /** * Mutes a call. * * @param {MuteOptions} options - Options to control the mute operation * @param {MuteDirection} options.direction - The direction to mute the channel (IN, OUT, BOTH). Default is BOTH * @see unmute * @example * * async function handler (request, response) { * await response.answer(); * await response.mute(); // Will mute both directions * } */ async mute( options: MuteOptions = { direction: MuteDirection.BOTH } ): Promise<void> { const { direction } = options; await new Mute(this.request, this.voice).run({ sessionRef: this.request.sessionRef, direction }); } /** * Unmute a call. * * @param {MuteOptions} options - Options to control the unmute operation * @param {MuteDirection} options.direction - The direction to unmute the call (IN, OUT, BOTH). Default is BOTH * @see mute * @example * * async function handler (request, response) { * await response.answer(); * await response.unmute(); // Will unmute both directions * } */ async unmute( options: MuteOptions = { direction: MuteDirection.BOTH } ): Promise<void> { const { direction } = options; await new Unmute(this.request, this.voice).run({ sessionRef: this.request.sessionRef, direction }); } /** * Register a listener for the given event. * * @param {StreamEvent} event - The event to listen for * @param {Function} listener - The callback function * @example * * async function handler (request, response) { * ... * * response.on(StreamEvent.END, () => { * console.log("Call ended"); * }); * } */ on(event: StreamEvent, listener: (...args: unknown[]) => void): void { this.voice.on(event, listener); } } export { VoiceResponse };

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/fonoster/fonoster'

If you have feedback or need assistance with the MCP directory API, please join our Discord server