Skip to main content
Glama
server.py3.48 kB
import asyncio from typing import Literal, Optional from mcp import Server from mcp.server import NotificationOptions, ServerOptions from mcp.server.models import Tool from mcp.server.stdio import stdio_server from pydantic import BaseModel, Field from .config import AudioPlaybackConfig, ConfigError from .manager import AudioPlaybackManager server = Server("audio-playback-server") def _build_tool_schema() -> Tool: class AudioPlaybackArgs(BaseModel): action: Literal["play", "stop", "status"] = Field( description="Playback action to perform." ) filename: Optional[str] = Field( default=None, description=( "Relative path of the audio file (under AUDIO_ROOT_DIR). Required for 'play'." ), ) loop: bool = Field( default=False, description="If true, loop the file until 'stop' is called.", ) start_offset_ms: int = Field( default=0, description=( "Start playback at this offset in milliseconds (0 = start of file). Optional." ), ge=0, ) @server.tool( "audio_playback", description=( "Control playback of local audio files for automated testing. Audio is " "played via a virtual audio output device that is routed into the Android " "emulator’s microphone. Use this to simulate a human speaking into the mic " "by playing prerecorded files." ), args_schema=AudioPlaybackArgs, ) async def audio_playback( # type: ignore[unused-ignore] action: Literal["play", "stop", "status"], filename: Optional[str] = None, loop: bool = False, start_offset_ms: int = 0, ) -> dict: if action == "play" and (filename is None or not filename.strip()): return { "success": False, "message": "filename is required for 'play' action.", "state": manager.state, } if start_offset_ms < 0: return { "success": False, "message": "start_offset_ms must be non-negative.", "state": manager.state, } try: if action == "play": success, message, state = await manager.play( filename=filename or "", loop=loop, start_offset_ms=start_offset_ms, ) elif action == "stop": success, message, state = await manager.stop() else: success, message, state = await manager.status() except ValueError as exc: success, message, state = False, str(exc), manager.state return {"success": success, "message": message, "state": state} return audio_playback # type: ignore[return-value] def _load_manager() -> AudioPlaybackManager: config = AudioPlaybackConfig.load() return AudioPlaybackManager(config) manager = _load_manager() _build_tool_schema() async def main() -> None: await server.connect( stdio_server(), options=ServerOptions(notification_options=NotificationOptions()), ) def run() -> None: try: asyncio.run(main()) except ConfigError as exc: raise SystemExit(f"Configuration error: {exc}") if __name__ == "__main__": run()

Latest Blog Posts

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/dcarter610/MCP-Virtual-Audio-Player'

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