Skip to main content
Glama

stop_video

Ends active video recording on an Android device to complete screen capture sessions and save recorded content.

Instructions

Stop the active video recording for the specified device.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
device_idNo

Implementation Reference

  • Handler function for the stop_video tool. Stops the scrcpy recording process by sending SIGTERM (graceful) or SIGKILL (force) to the process group, calculates duration, checks file existence/size, and cleans up the global active_recordings tracker. Registered via @mcp.tool() decorator.
    @mcp.tool()
    async def stop_video(device_id: str = None) -> dict:
        """Stop the active video recording for the specified device."""
        try:
            recording_key = device_id or "default"
    
            if recording_key not in active_recordings:
                return {
                    "success": False,
                    "error": f"No active recording found for device {recording_key}",
                    "device_id": device_id or "default"
                }
    
            recording_info = active_recordings[recording_key]
            process = recording_info["process"]
            filepath = recording_info["filepath"]
            filename = recording_info["filename"]
            start_time = recording_info["start_time"]
    
            # Check if process is still running
            if process.poll() is not None:
                # Process already terminated
                del active_recordings[recording_key]
                return {
                    "success": False,
                    "error": "Recording process has already terminated",
                    "filepath": filepath,
                    "filename": filename
                }
    
            # Gracefully terminate the scrcpy process
            try:
                # Send SIGTERM to the process group
                os.killpg(os.getpgid(process.pid), signal.SIGTERM)
    
                # Wait for the process to terminate (with timeout)
                process.wait(timeout=10)
    
            except subprocess.TimeoutExpired:
                # If it doesn't terminate gracefully, force kill
                os.killpg(os.getpgid(process.pid), signal.SIGKILL)
                process.wait()
            except ProcessLookupError:
                # Process already terminated
                pass
    
            # Remove from active recordings
            del active_recordings[recording_key]
    
            # Calculate recording duration
            end_time = datetime.now()
            duration = end_time - start_time
            duration_seconds = duration.total_seconds()
    
            # Check if file exists and get size
            file_size = None
            file_exists = os.path.exists(filepath)
            if file_exists:
                file_size = os.path.getsize(filepath)
    
            return {
                "success": True,
                "message": f"Video recording stopped successfully",
                "filepath": filepath if file_exists else None,
                "filename": filename,
                "device_id": device_id or "default",
                "duration_seconds": duration_seconds,
                "file_size_bytes": file_size,
                "file_exists": file_exists
            }
    
        except Exception as e:
            # Clean up the recording entry even if there was an error
            recording_key = device_id or "default"
            if recording_key in active_recordings:
                del active_recordings[recording_key]
    
            return {
                "success": False,
                "error": f"Error stopping recording: {e}",
                "device_id": device_id or "default"
            }
  • Global dictionary used by both record_video and stop_video tools to track active scrcpy recording processes, filepaths, and metadata for proper termination.
    # Global dictionary to track active video recordings
    active_recordings = {}
  • Related handler for record_video tool, which initializes the recording process tracked by stop_video.
    async def record_video(device_id: str = None, filename: str = None, resolution: str = None, bitrate: str = "8M") -> dict:
        """Start recording a video using scrcpy. The video will be saved to the videos directory."""
        try:
            # Use android-puppeteer/videos directory for video recordings
            current_dir = os.path.dirname(os.path.abspath(__file__))
            videos_dir = os.path.join(current_dir, "videos")
            os.makedirs(videos_dir, exist_ok=True)
    
            # Generate filename if not provided
            if filename:
                # Ensure it has .mp4 extension
                if not filename.endswith('.mp4'):
                    filename = f"{filename}.mp4"
            else:
                # Use timestamp if no filename provided
                timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
                filename = f"recording_{timestamp}.mp4"
    
            filepath = os.path.join(videos_dir, filename)
    
            # Create recording key for tracking
            recording_key = device_id or "default"
    
            # Check if already recording for this device
            if recording_key in active_recordings:
                return {
                    "success": False,
                    "error": f"Already recording for device {recording_key}. Stop the current recording first.",
                    "device_id": device_id or "default"
                }
    
            # Build scrcpy command for recording
            cmd = ['scrcpy']
    
            # Add device selection if specified
            if device_id:
                cmd.extend(['-s', device_id])
    
            # Add recording parameters
            cmd.extend(['--record', filepath])
    
            # Add video quality parameters
            cmd.extend(['--video-bit-rate', bitrate])
    
            if resolution:
                cmd.extend(['--max-size', resolution])
    
            # Add minimal parameters for recording
            cmd.extend([
                '--no-playback'  # Don't show the device screen (updated flag for scrcpy v3.2+)
            ])
    
            # Start the recording process
            process = subprocess.Popen(
                cmd,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                preexec_fn=os.setsid  # Create new process group for proper termination
            )
    
            # Give the process a moment to start and check if it's still running
            import time
            time.sleep(1)
    
            # Check if process started successfully
            if process.poll() is not None:
                # Process terminated immediately, capture error output
                stderr_output = process.stderr.read().decode() if process.stderr else ""
                stdout_output = process.stdout.read().decode() if process.stdout else ""
                return {
                    "success": False,
                    "error": f"scrcpy process terminated immediately. stderr: {stderr_output}, stdout: {stdout_output}",
                    "filepath": None,
                    "command": ' '.join(cmd)
                }
    
            # Store the process for later termination
            active_recordings[recording_key] = {
                "process": process,
                "filepath": filepath,
                "filename": filename,
                "start_time": datetime.now(),
                "device_id": device_id or "default"
            }
    
            return {
                "success": True,
                "message": f"Video recording started successfully",
                "filepath": filepath,
                "filename": filename,
                "device_id": device_id or "default",
                "recording_key": recording_key,
                "bitrate": bitrate,
                "resolution": resolution,
                "process_id": process.pid
            }
    
        except FileNotFoundError:
            return {
                "success": False,
                "error": "scrcpy not found. Please ensure scrcpy is installed and in PATH.",
                "filepath": None
            }
        except PermissionError:
            return {
                "success": False,
                "error": f"Permission denied: Cannot create directory or write to {videos_dir}",
                "filepath": None
            }
        except Exception as e:
            return {
                "success": False,
                "error": f"Unexpected error starting recording: {e}",
                "filepath": None
            }
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries full burden but only states the basic action. It doesn't disclose behavioral traits such as whether this requires specific permissions, what happens if no recording is active (error vs. no-op), or any side effects like file saving. This leaves significant gaps for a mutation tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, direct sentence with no wasted words, clearly front-loading the core action. It efficiently communicates the essential information without unnecessary elaboration, making it easy to parse quickly.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (a mutation with no annotations, no output schema, and low parameter coverage), the description is incomplete. It lacks details on behavior, error conditions, or output, which are critical for safe and effective use. This is inadequate for a tool that modifies system state.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The description adds minimal meaning beyond the schema: it clarifies that 'device_id' specifies which device's recording to stop. However, with 0% schema description coverage and only 1 parameter, the baseline is 4, but the description doesn't fully compensate by explaining format or constraints (e.g., valid device IDs), so it scores slightly lower.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action ('Stop') and the resource ('active video recording for the specified device'), making the purpose immediately understandable. However, it doesn't explicitly differentiate from sibling tools like 'record_video' beyond the obvious inverse relationship, which prevents a perfect score.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides minimal guidance by implying usage when there's an active video recording to stop, but it doesn't specify when to use this versus alternatives (e.g., stopping via other methods) or mention prerequisites like needing a recording in progress. No explicit when-not or alternative guidance is included.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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/pedro-rivas/android-puppeteer-mcp'

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