Skip to main content
Glama
dh1011

Auto Favicon MCP Server

by dh1011

generate_favicon_from_url

Download an image from a URL and generate a complete favicon set, including multiple sizes, ICO files, Apple touch icons, and a manifest.json for web applications.

Instructions

Download an image from a URL and generate a complete favicon set.

Args:
    image_url: URL of the image to download.
    output_path: Directory where favicon files will be generated.
Returns:
    A message describing the generated files and output directory.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
image_urlYes
output_pathYes

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • The main handler function implementing the 'generate_favicon_from_url' MCP tool. It validates the output path, downloads the image using aiohttp, calls create_favicon_set to generate favicons, and returns a success message with generated files list.
    @mcp.tool()
    async def generate_favicon_from_url(image_url: str, output_path: str) -> str:
        """
        Download an image from a URL and generate a complete favicon set.
    
        Args:
            image_url: URL of the image to download.
            output_path: Absolute path to the directory where favicon files will be generated.
        Returns:
            A message describing the generated files and output directory.
        """
        try:
            # Validate absolute path for output directory
            output_path_obj = validate_absolute_path(output_path, "output_path")
            
            # Check if output directory can be created
            try:
                output_path_obj.mkdir(parents=True, exist_ok=True)
            except Exception as e:
                return f"Error: Cannot create output directory {output_path}: {str(e)}"
            
            async with aiohttp.ClientSession() as session:
                async with session.get(image_url) as response:
                    response.raise_for_status()
                    image_data = await response.read()
            result = create_favicon_set(image_data, str(output_path_obj))
            return (
                f"Successfully downloaded image from {image_url} and generated favicon set!\n\n"
                f"Output directory: {result['output_directory']}\n"
                f"Generated files:\n" + "\n".join(f"- {f}" for f in result['generated_files'])
            )
        except ValueError as e:
            return f"Error: {str(e)}"
        except Exception as e:
            return f"Error generating favicon from URL: {str(e)}"
  • Supporting helper function that generates the complete favicon set (PNG sizes, ICO, Apple touch icons, manifest.json) from raw image bytes using Pillow.
    def create_favicon_set(image_data: bytes, output_dir: str) -> Dict[str, Any]:
        """Create a complete favicon set from image data."""
        # Write image data to a temp file
        with tempfile.NamedTemporaryFile(delete=False, suffix='.png') as temp_file:
            temp_file.write(image_data)
            temp_file.flush()
            temp_path = temp_file.name
    
        try:
            with Image.open(temp_path) as img:
                # Convert to RGBA if needed
                if img.mode != 'RGBA':
                    img = img.convert('RGBA')
    
                output_path = Path(output_dir)
                output_path.mkdir(parents=True, exist_ok=True)
                generated_files = []
    
                # Generate PNG favicons
                for size in FAVICON_SIZES:
                    resized = img.resize((size, size), Image.Resampling.LANCZOS)
                    filename = f"favicon-{size}x{size}.png"
                    filepath = output_path / filename
                    resized.save(filepath, "PNG")
                    generated_files.append(str(filepath))
    
                # Generate ICO file
                ico_images = [img.resize((size, size), Image.Resampling.LANCZOS) for size in ICO_SIZES]
                ico_path = output_path / "favicon.ico"
                ico_images[0].save(ico_path, format='ICO', sizes=[(size, size) for size in ICO_SIZES])
                generated_files.append(str(ico_path))
    
                # Generate Apple touch icons
                for size in APPLE_SIZES:
                    resized = img.resize((size, size), Image.Resampling.LANCZOS)
                    filename = f"apple-touch-icon-{size}x{size}.png"
                    filepath = output_path / filename
                    resized.save(filepath, "PNG")
                    generated_files.append(str(filepath))
    
                # Generate manifest.json
                manifest = {
                    "name": "Favicon App",
                    "short_name": "Favicon",
                    "description": "Generated favicon application",
                    "start_url": "/",
                    "display": "standalone",
                    "background_color": "#ffffff",
                    "theme_color": "#000000",
                    "icons": [
                        {
                            "src": f"favicon-{size}x{size}.png",
                            "sizes": f"{size}x{size}",
                            "type": "image/png"
                        } for size in FAVICON_SIZES
                    ]
                }
                manifest_path = output_path / "manifest.json"
                with open(manifest_path, 'w') as f:
                    json.dump(manifest, f, indent=2)
                generated_files.append(str(manifest_path))
    
                return {
                    "generated_files": generated_files,
                    "manifest": manifest,
                    "output_directory": str(output_path)
                }
        finally:
            os.unlink(temp_path)
  • Utility helper to validate that the output_path is an absolute path.
    def validate_absolute_path(path: str, path_type: str) -> Path:
        """Validate that a path is absolute and exists (for files) or can be created (for directories)."""
        path_obj = Path(path)
        
        if not path_obj.is_absolute():
            raise ValueError(f"{path_type} must be an absolute path: {path}")
        
        return path_obj
  • The @mcp.tool() decorator registers the generate_favicon_from_url function as an MCP tool.
    @mcp.tool()
Behavior2/5

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

No annotations are provided, so the description carries the full burden. It mentions downloading an image and generating files, but lacks details on permissions, rate limits, error handling, or what happens if the URL is invalid. This is a significant gap for a tool that performs network operations and file generation.

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 appropriately sized and front-loaded, with a clear purpose statement followed by concise parameter and return value explanations. Every sentence adds value without waste.

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

Completeness4/5

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

Given the tool's complexity (network download and file generation) and no annotations, the description covers the basic operation and parameters. With an output schema present, it need not explain return values in detail, but it could benefit from more behavioral context like error cases or dependencies.

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?

The description adds meaning beyond the input schema by explaining that 'image_url' is for downloading an image and 'output_path' is where favicon files will be generated. With 0% schema description coverage, this compensates well, though it could include format details like supported image types or path requirements.

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 tool's purpose with a specific verb ('generate') and resource ('complete favicon set'), and distinguishes it from its sibling tool 'generate_favicon_from_png' by specifying it downloads from a URL rather than using a PNG file.

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

Usage Guidelines4/5

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

The description implies usage context by specifying 'from a URL,' which differentiates it from the sibling tool that likely uses a PNG file. However, it does not explicitly state when to use this tool versus alternatives or any exclusions.

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/dh1011/auto-favicon-mcp'

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