Skip to main content
Glama
lamaalrajih

KiCad MCP Server

by lamaalrajih

generate_pcb_thumbnail

Create thumbnail images from KiCad PCB project files to visualize layout designs quickly.

Instructions

Generate a thumbnail image of a KiCad PCB layout using kicad-cli.

Args: project_path: Path to the KiCad project file (.kicad_pro) ctx: Context for MCP communication

Returns: Thumbnail image of the PCB or None if generation failed

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
project_pathYes
ctxYes

Implementation Reference

  • Main handler function decorated with @mcp.tool(). Orchestrates thumbnail generation by validating input, checking cache, and invoking the CLI-based helper function.
    @mcp.tool()
    async def generate_pcb_thumbnail(project_path: str, ctx: Context | None):
        """Generate a thumbnail image of a KiCad PCB layout using kicad-cli.
    
        Args:
            project_path: Path to the KiCad project file (.kicad_pro)
            ctx: Context for MCP communication
    
        Returns:
            Thumbnail image of the PCB or None if generation failed
        """
        try:
            # Access the context (with null check)
            app_context = None
            if ctx:
                app_context = ctx.request_context.lifespan_context
            # Removed check for kicad_modules_available as we now use CLI
            
            print(f"Generating thumbnail via CLI for project: {project_path}")
    
            if not os.path.exists(project_path):
                print(f"Project not found: {project_path}")
                if ctx:
                    await ctx.info(f"Project not found: {project_path}")
                return None
    
            # Get PCB file from project
            files = get_project_files(project_path)
            if "pcb" not in files:
                print("PCB file not found in project")
                if ctx:
                    await ctx.info("PCB file not found in project")
                return None
    
            pcb_file = files["pcb"]
            print(f"Found PCB file: {pcb_file}")
    
            # Check cache
            cache_key = f"thumbnail_cli_{pcb_file}_{os.path.getmtime(pcb_file)}"
            if app_context and hasattr(app_context, 'cache') and cache_key in app_context.cache:
                print(f"Using cached CLI thumbnail for {pcb_file}")
                return app_context.cache[cache_key]
    
            if ctx:
                await ctx.report_progress(10, 100)
                await ctx.info(f"Generating thumbnail for {os.path.basename(pcb_file)} using kicad-cli")
    
            # Use command-line tools
            try:
                thumbnail = await generate_thumbnail_with_cli(pcb_file, ctx)
                if thumbnail:
                    # Cache the result if possible
                    if app_context and hasattr(app_context, 'cache'):
                        app_context.cache[cache_key] = thumbnail
                    print("Thumbnail generated successfully via CLI.")
                    return thumbnail
                else:
                     print("generate_thumbnail_with_cli returned None")
                     if ctx:
                         await ctx.info("Failed to generate thumbnail using kicad-cli.")
                     return None
            except Exception as e:
                print(f"Error calling generate_thumbnail_with_cli: {str(e)}", exc_info=True)
                if ctx:
                    await ctx.info(f"Error generating thumbnail with kicad-cli: {str(e)}")
                return None
            
        except asyncio.CancelledError:
            print("Thumbnail generation cancelled")
            raise  # Re-raise to let MCP know the task was cancelled
        except Exception as e:
            print(f"Unexpected error in thumbnail generation: {str(e)}")
            if ctx:
                await ctx.info(f"Error: {str(e)}")
            return None
  • Helper function that executes the core logic: determines kicad-cli path, builds command to export SVG thumbnail from PCB file using subprocess, and returns Image object.
    async def generate_thumbnail_with_cli(pcb_file: str, ctx: Context | None):
        """Generate PCB thumbnail using command line tools.
        This is a fallback method when the kicad Python module is not available or fails.
    
        Args:
            pcb_file: Path to the PCB file (.kicad_pcb)
            ctx: MCP context for progress reporting
    
        Returns:
            Image object containing the PCB thumbnail or None if generation failed
        """
        try:
            print("Attempting to generate thumbnail using KiCad CLI tools")
            if ctx:
                await ctx.report_progress(20, 100)
    
            # --- Determine Output Path --- 
            project_dir = os.path.dirname(pcb_file)
            project_name = os.path.splitext(os.path.basename(pcb_file))[0]
            output_file = os.path.join(project_dir, f"{project_name}_thumbnail.svg")
            # --------------------------- 
    
            # Check for required command-line tools based on OS
            kicad_cli = None
            if system == "Darwin":  # macOS
                kicad_cli_path = os.path.join(KICAD_APP_PATH, "Contents/MacOS/kicad-cli")
                if os.path.exists(kicad_cli_path):
                     kicad_cli = kicad_cli_path
                elif shutil.which("kicad-cli") is not None:
                    kicad_cli = "kicad-cli"  # Try to use from PATH
                else:
                    print(f"kicad-cli not found at {kicad_cli_path} or in PATH")
                    return None
            elif system == "Windows":
                kicad_cli_path = os.path.join(KICAD_APP_PATH, "bin", "kicad-cli.exe")
                if os.path.exists(kicad_cli_path):
                     kicad_cli = kicad_cli_path
                elif shutil.which("kicad-cli.exe") is not None:
                     kicad_cli = "kicad-cli.exe"
                elif shutil.which("kicad-cli") is not None:
                    kicad_cli = "kicad-cli"  # Try to use from PATH (without .exe)
                else:
                    print(f"kicad-cli not found at {kicad_cli_path} or in PATH")
                    return None
            elif system == "Linux":
                kicad_cli = shutil.which("kicad-cli")
                if not kicad_cli:
                    print("kicad-cli not found in PATH")
                    return None
            else:
                print(f"Unsupported operating system: {system}")
                return None
    
            if ctx:
                await ctx.report_progress(30, 100)
                await ctx.info("Using KiCad command line tools for thumbnail generation")        # Build command for generating SVG from PCB using kicad-cli (changed from PNG)
            cmd = [
                kicad_cli,
                "pcb",
                "export",
                "svg", # <-- Changed format to svg
                "--output", output_file,
                "--layers", "F.Cu,B.Cu,F.SilkS,B.SilkS,F.Mask,B.Mask,Edge.Cuts",  # Keep relevant layers
                # Consider adding options like --black-and-white if needed
                pcb_file
            ]
    
            print(f"Running command: {' '.join(cmd)}")
            if ctx:
                await ctx.report_progress(50, 100)
    
            # Run the command
            try:
                process = subprocess.run(cmd, capture_output=True, text=True, check=True, timeout=30)
                print(f"Command successful: {process.stdout}")
    
                if ctx:
                    await ctx.report_progress(70, 100)
    
                # Check if the output file was created
                if not os.path.exists(output_file):
                    print(f"Output file not created: {output_file}")
                    return None
    
                # Read the image file
                with open(output_file, 'rb') as f:
                    img_data = f.read()
    
                print(f"Successfully generated thumbnail with CLI, size: {len(img_data)} bytes")
                if ctx:
                    await ctx.report_progress(90, 100)
                    # Inform user about the saved file
                    await ctx.info(f"Thumbnail saved to: {output_file}")
                return Image(data=img_data, format="svg") # <-- Changed format to svg
    
            except subprocess.CalledProcessError as e:
                print(f"Command '{' '.join(e.cmd)}' failed with code {e.returncode}")
                print(f"Stderr: {e.stderr}")
                print(f"Stdout: {e.stdout}")
                if ctx:
                    await ctx.info(f"KiCad CLI command failed: {e.stderr or e.stdout}")
                return None
            except subprocess.TimeoutExpired:
                print(f"Command timed out after 30 seconds: {' '.join(cmd)}")
                if ctx:
                    await ctx.info("KiCad CLI command timed out")
                return None
            except Exception as e:
                print(f"Error running CLI command: {str(e)}", exc_info=True)
                if ctx:
                    await ctx.info(f"Error running KiCad CLI: {str(e)}")
                return None
                    
        except asyncio.CancelledError:
            print("CLI thumbnail generation cancelled")
            raise
        except Exception as e:
            print(f"Unexpected error in CLI thumbnail generation: {str(e)}")
            if ctx:
                await ctx.info(f"Unexpected error: {str(e)}")
            return None
  • Top-level registration call in server creation that invokes register_export_tools to add the generate_pcb_thumbnail tool to the MCP server.
    register_export_tools(mcp)
  • Import of the register_export_tools function used to register the tool.
    from kicad_mcp.tools.export_tools import register_export_tools
  • Alias tool 'generate_project_thumbnail' that redirects to the main generate_pcb_thumbnail handler.
    @mcp.tool()
    async def generate_project_thumbnail(project_path: str, ctx: Context | None):
        """Generate a thumbnail of a KiCad project's PCB layout (Alias for generate_pcb_thumbnail)."""
        # This function now just calls the main CLI-based thumbnail generator
        print(f"generate_project_thumbnail called, redirecting to generate_pcb_thumbnail for {project_path}")
        return await generate_pcb_thumbnail(project_path, ctx)
Behavior2/5

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

With no annotations provided, the description carries full burden for behavioral disclosure. It mentions that the tool 'returns thumbnail image of the PCB or None if generation failed,' which gives basic output behavior. However, it doesn't disclose important traits: whether this is a read-only operation, what permissions are needed, potential side effects (e.g., temporary file creation), performance characteristics, or error conditions beyond failure. For a tool that presumably reads and processes project files, this is insufficient.

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 uses minimal sentences. Each section adds value: the opening sentence states the core function, Args explains parameters, Returns clarifies output behavior. There's no redundant information, though the ctx explanation could be more concise given its detailed schema definition. Overall, it's appropriately sized and front-loaded with the main purpose.

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?

Given the complexity (generating images from PCB layouts), lack of annotations, and no output schema, the description is moderately complete. It covers the basic purpose, parameters, and return behavior. However, it misses important context: what the thumbnail looks like (e.g., image format, dimensions), how failures manifest, dependencies on kicad-cli availability, or interaction with sibling tools. For a tool with 2 parameters and no annotation coverage, this is adequate but leaves gaps an agent would need to infer.

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 provides parameter documentation in an 'Args' section, explaining that 'project_path' is the 'Path to the KiCad project file (.kicad_pro)' and 'ctx' is 'Context for MCP communication.' With 0% schema description coverage, this adds meaningful context beyond the bare schema. However, it doesn't elaborate on format requirements for project_path (e.g., absolute vs. relative paths, file existence) or practical usage of ctx beyond its definition. The baseline is 3 since the description compensates somewhat for the schema gap.

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 tool's purpose: 'Generate a thumbnail image of a KiCad PCB layout using kicad-cli.' It specifies the verb ('generate'), resource ('thumbnail image'), and technology ('KiCad PCB layout using kicad-cli'). However, it doesn't explicitly differentiate from sibling tools like 'generate_project_thumbnail' which might serve a similar purpose for different project aspects.

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. It doesn't mention prerequisites (e.g., needing a valid KiCad project), compare it to 'generate_project_thumbnail', or indicate scenarios where thumbnail generation is appropriate versus other analysis tools. The only contextual hint is the technology stack (kicad-cli), but no usage boundaries are defined.

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/lamaalrajih/kicad-mcp'

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