Skip to main content
Glama
misbahsy

Video & Audio Editing MCP Server

by misbahsy

add_basic_transitions

Apply fade-in or fade-out transitions to videos with specified duration. Input a video file, define transition type and duration, and save the output. Enhances video editing with customizable transitions.

Instructions

Adds basic fade transitions to the beginning or end of a video.

Args: video_path: Path to the input video file. output_video_path: Path to save the video with the transition. transition_type: Type of transition. Options: 'fade_in', 'fade_out'. (Note: 'crossfade_from_black' is like 'fade_in', 'crossfade_to_black' is like 'fade_out') duration_seconds: Duration of the fade effect in seconds. Returns: A status message indicating success or failure.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
duration_secondsYes
output_video_pathYes
transition_typeYes
video_pathYes

Implementation Reference

  • The handler function implementing the 'add_basic_transitions' tool. It uses FFmpeg's 'fade' filter to apply fade-in or fade-out transitions to the video, with audio stream copying or re-encoding as fallback. Includes input validation and error handling. Automatically registered via @mcp.tool() decorator, with schema derived from type hints and docstring.
    @mcp.tool()
    def add_basic_transitions(video_path: str, output_video_path: str, transition_type: str, duration_seconds: float) -> str:
        """Adds basic fade transitions to the beginning or end of a video.
    
        Args:
            video_path: Path to the input video file.
            output_video_path: Path to save the video with the transition.
            transition_type: Type of transition. Options: 'fade_in', 'fade_out'.
                             (Note: 'crossfade_from_black' is like 'fade_in', 'crossfade_to_black' is like 'fade_out')
            duration_seconds: Duration of the fade effect in seconds.
        Returns:
            A status message indicating success or failure.
        """
        if not os.path.exists(video_path):
            return f"Error: Input video file not found at {video_path}"
        if duration_seconds <= 0:
            return "Error: Transition duration must be positive."
    
        try:
            props = _get_media_properties(video_path)
            video_total_duration = props['duration']
    
            if duration_seconds > video_total_duration:
                return f"Error: Transition duration ({duration_seconds}s) cannot exceed video duration ({video_total_duration}s)."
    
            input_stream = ffmpeg.input(video_path)
            video_stream = input_stream.video
            audio_stream = input_stream.audio
            
            processed_video = None
    
            if transition_type == 'fade_in' or transition_type == 'crossfade_from_black':
                processed_video = video_stream.filter('fade', type='in', start_time=0, duration=duration_seconds)
            elif transition_type == 'fade_out' or transition_type == 'crossfade_to_black':
                fade_start_time = video_total_duration - duration_seconds
                processed_video = video_stream.filter('fade', type='out', start_time=fade_start_time, duration=duration_seconds)
            else:
                return f"Error: Unsupported transition_type '{transition_type}'. Supported: 'fade_in', 'fade_out'."
    
            # Attempt to copy audio, fallback to re-encoding if necessary
            output_streams = []
            if props['has_video']:
                output_streams.append(processed_video)
            if props['has_audio']:
                output_streams.append(audio_stream) # Audio is passed through without fade
            else: # Video only
                pass
            
            if not output_streams:
                return "Error: No suitable video or audio streams found to apply transition."
    
            try:
                ffmpeg.output(*output_streams, output_video_path, acodec='copy').run(capture_stdout=True, capture_stderr=True)
                return f"Transition '{transition_type}' applied successfully (audio copied). Output: {output_video_path}"
            except ffmpeg.Error as e_acopy:
                # Fallback: re-encode audio (or just output video if no audio originally)
                try:
                    ffmpeg.output(*output_streams, output_video_path).run(capture_stdout=True, capture_stderr=True)
                    return f"Transition '{transition_type}' applied successfully (audio re-encoded/processed). Output: {output_video_path}"
                except ffmpeg.Error as e_recode:
                    err_acopy = e_acopy.stderr.decode('utf8') if e_acopy.stderr else str(e_acopy)
                    err_recode = e_recode.stderr.decode('utf8') if e_recode.stderr else str(e_recode)
                    return f"Error applying transition. Audio copy failed: {err_acopy}. Full re-encode failed: {err_recode}."
    
        except ffmpeg.Error as e:
            error_message = e.stderr.decode('utf8') if e.stderr else str(e)
            return f"Error applying basic transition: {error_message}"
        except ValueError as e: # For _parse_time or duration checks
            return f"Error with input values: {str(e)}"
        except RuntimeError as e: # For _get_media_properties error
            return f"Runtime error during transition processing: {str(e)}"
        except Exception as e:
            return f"An unexpected error occurred in add_basic_transitions: {str(e)}"
  • Helper function called by add_basic_transitions to retrieve media properties such as duration, used to validate that transition duration does not exceed video length.
    def _get_media_properties(media_path: str) -> dict:
        """Probes media file and returns key properties."""
        try:
            probe = ffmpeg.probe(media_path)
            video_stream_info = next((s for s in probe['streams'] if s['codec_type'] == 'video'), None)
            audio_stream_info = next((s for s in probe['streams'] if s['codec_type'] == 'audio'), None)
            
            props = {
                'duration': float(probe['format'].get('duration', 0.0)),
                'has_video': video_stream_info is not None,
                'has_audio': audio_stream_info is not None,
                'width': int(video_stream_info['width']) if video_stream_info and 'width' in video_stream_info else 0,
                'height': int(video_stream_info['height']) if video_stream_info and 'height' in video_stream_info else 0,
                'avg_fps': 0, # Default, will be calculated if possible
                'sample_rate': int(audio_stream_info['sample_rate']) if audio_stream_info and 'sample_rate' in audio_stream_info else 44100,
                'channels': int(audio_stream_info['channels']) if audio_stream_info and 'channels' in audio_stream_info else 2,
                'channel_layout': audio_stream_info.get('channel_layout', 'stereo') if audio_stream_info else 'stereo'
            }
            if video_stream_info and 'avg_frame_rate' in video_stream_info and video_stream_info['avg_frame_rate'] != '0/0':
                num, den = map(int, video_stream_info['avg_frame_rate'].split('/'))
                if den > 0:
                    props['avg_fps'] = num / den
                else:
                    props['avg_fps'] = 30 # Default if denominator is 0
            else: # Fallback if avg_frame_rate is not useful
                props['avg_fps'] = 30 # A common default
    
            return props
        except ffmpeg.Error as e:
            raise RuntimeError(f"Error probing file {media_path}: {e.stderr.decode('utf8') if e.stderr else str(e)}")
        except Exception as e:
            raise RuntimeError(f"Unexpected error probing file {media_path}: {str(e)}")
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 minimally describes behavior. It mentions what the tool does (adds fade transitions) and the return value (status message), but lacks critical details like whether it modifies the original file, requires specific video formats, has performance implications, or handles errors beyond success/failure.

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

Conciseness4/5

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

The description is well-structured with clear sections (purpose, Args, Returns) and front-loaded core functionality. Each sentence adds value, though the transition type note could be slightly more concise. Overall efficient for a 4-parameter tool.

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

Completeness3/5

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

For a video processing tool with 4 parameters, no annotations, and no output schema, the description provides adequate basics but lacks completeness. It covers what the tool does and parameter meanings, but misses behavioral details (e.g., file handling, format requirements, error conditions) that would help an agent use it correctly in complex scenarios.

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

Parameters4/5

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

Schema description coverage is 0%, but the description provides meaningful context for all 4 parameters: it explains what 'transition_type' options mean with helpful notes about equivalents, clarifies that 'duration_seconds' controls fade length, and identifies input/output paths. This compensates well for the schema gap, though some parameter details (like path formats) remain unspecified.

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

Purpose5/5

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

The description clearly states the specific action ('Adds basic fade transitions') and target resource ('to the beginning or end of a video'), distinguishing it from sibling tools like 'add_text_overlay' or 'change_aspect_ratio' which perform different video modifications.

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?

No explicit guidance on when to use this tool versus alternatives is provided. While the description mentions 'beginning or end of a video', it doesn't specify scenarios where this is preferred over other transition methods or when not to use it, leaving the agent without usage context.

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

Related 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/misbahsy/video-audio-mcp'

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