Skip to main content
Glama
ext-sakamoro

Aseprite MCP Tools

by ext-sakamoro

batch_resize

Resize multiple Aseprite files at once by specifying target dimensions, scale factors, or maintaining aspect ratios for pixel art projects.

Instructions

Batch resize multiple Aseprite files.

Args: input_dir: Directory containing input files output_dir: Directory for resized files width: Target width (optional) height: Target height (optional) scale: Scale factor (optional, alternative to width/height) maintain_aspect_ratio: Maintain aspect ratio when resizing file_pattern: File pattern to match (default: "*.aseprite")

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
input_dirYes
output_dirYes
widthNo
heightNo
scaleNo
maintain_aspect_ratioNo
file_patternNo*.aseprite

Implementation Reference

  • The batch_resize tool handles resizing multiple Aseprite files by building a Lua script and executing it via a command handler.
    @mcp.tool()
    async def batch_resize(
        input_dir: str,
        output_dir: str,
        width: Optional[int] = None,
        height: Optional[int] = None,
        scale: Optional[float] = None,
        maintain_aspect_ratio: bool = True,
        file_pattern: str = "*.aseprite"
    ) -> str:
        """Batch resize multiple Aseprite files.
    
        Args:
            input_dir: Directory containing input files
            output_dir: Directory for resized files
            width: Target width (optional)
            height: Target height (optional)
            scale: Scale factor (optional, alternative to width/height)
            maintain_aspect_ratio: Maintain aspect ratio when resizing
            file_pattern: File pattern to match (default: "*.aseprite")
        """
        try:
            # Validate inputs
            input_path = validate_file_path(input_dir, must_exist=True)
            output_path = validate_file_path(output_dir, must_exist=True)
            
            if not input_path.is_dir():
                raise ValidationError("input_dir", str(input_path), "Must be a directory")
            if not output_path.is_dir():
                raise ValidationError("output_dir", str(output_path), "Must be a directory")
            
            # Must provide either scale or dimensions
            if scale is None and width is None and height is None:
                raise ValidationError("parameters", None, "Must provide either scale or width/height")
            
            # Find all matching files
            files = list(input_path.glob(file_pattern))
            if not files:
                return f"No files matching '{file_pattern}' found in {input_path}"
            
            # Build resize script
            builder = LuaBuilder()
            
            # Batch process each file
            results = []
            errors = []
            
            for file in files:
                try:
                    builder = LuaBuilder()
                    builder.open_sprite(str(file))
                    builder.add_line('local spr = app.activeSprite')
                    builder.if_condition('not spr')
                    builder.add_line('error("Failed to open sprite")')
                    builder.end_if()
                    
                    # Calculate new dimensions
                    if scale is not None:
                        builder.add_line(f'local newWidth = math.floor(spr.width * {scale})')
                        builder.add_line(f'local newHeight = math.floor(spr.height * {scale})')
                    else:
                        if width and height:
                            if maintain_aspect_ratio:
                                builder.add_line(f'local aspectRatio = spr.width / spr.height')
                                builder.add_line(f'local targetRatio = {width} / {height}')
                                builder.if_condition('aspectRatio > targetRatio')
                                builder.add_line(f'local newWidth = {width}')
                                builder.add_line(f'local newHeight = math.floor({width} / aspectRatio)')
                                builder.else_block()
                                builder.add_line(f'local newHeight = {height}')
                                builder.add_line(f'local newWidth = math.floor({height} * aspectRatio)')
                                builder.end_if()
                            else:
                                builder.add_line(f'local newWidth = {width}')
                                builder.add_line(f'local newHeight = {height}')
                        elif width:
                            builder.add_line(f'local newWidth = {width}')
                            builder.add_line(f'local newHeight = math.floor(spr.height * ({width} / spr.width))')
                        else:  # height only
                            builder.add_line(f'local newHeight = {height}')
                            builder.add_line(f'local newWidth = math.floor(spr.width * ({height} / spr.height))')
                    
                    # Resize sprite
                    builder.add_line('app.command.SpriteSize{width=newWidth, height=newHeight}')
                    
                    # Save to output directory
                    output_file = output_path / file.name
                    builder.save_sprite(str(output_file))
                    
                    # Execute
                    cmd = get_command()
                    success, output = cmd.execute_lua_script(builder.build())
                    
                    results.append(f"Resized: {file.name}")
                    
                except Exception as e:
                    errors.append(f"Failed {file.name}: {e}")
                    if not get_config().batch.continue_on_error:
                        break
            
            # Summary
            summary = f"Batch resize completed:\n"
            summary += f"- Processed: {len(results)} files\n"
            summary += f"- Failed: {len(errors)} files\n"
            
            if results:
                summary += "\nSuccessful:\n" + "\n".join(results[:10])
                if len(results) > 10:
                    summary += f"\n... and {len(results) - 10} more"
            
            if errors:
                summary += "\n\nErrors:\n" + "\n".join(errors[:5])
                if len(errors) > 5:
                    summary += f"\n... and {len(errors) - 5} more"
            
            return summary
            
        except (ValidationError, AsepriteError) as e:
            return f"Failed to batch resize: {e}"
        except Exception as e:
            return f"Unexpected error: {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 lacks critical behavioral details: it doesn't specify if files are overwritten, if the operation is destructive, what happens on errors, or performance characteristics. It mentions 'batch' but not concurrency or progress reporting.

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 efficiently structured with a clear purpose statement followed by parameter explanations. Every sentence adds value, though the parameter list format is slightly verbose. It's appropriately sized for a 7-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 batch processing tool with 7 parameters and no annotations or output schema, the description covers the core operation and parameters adequately but lacks behavioral context (error handling, side effects) and output expectations. It's minimally viable but has clear gaps.

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%, so the description compensates by explaining all 7 parameters clearly, including optionality, defaults, and relationships (e.g., scale as alternative to width/height). It adds meaningful context beyond schema titles, though some nuances like unit constraints remain implicit.

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 ('batch resize') and resource ('multiple Aseprite files'), distinguishing it from sibling tools like 'batch_export' or 'batch_apply_palette' which perform different operations. It precisely communicates the tool's function without redundancy.

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 no guidance on when to use this tool versus alternatives like 'batch_export' or 'batch_process_custom', nor does it mention prerequisites, constraints, or typical scenarios for batch resizing. Usage context is implied but not explicitly stated.

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/ext-sakamoro/AsepriteMCP'

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