Skip to main content
Glama

OpenSCAD MCP Server

by quellant
API.mdโ€ข17.7 kB
# OpenSCAD MCP Server API Documentation ## Table of Contents - [Overview](#overview) - [MCP Protocol](#mcp-protocol) - [Authentication](#authentication) - [Tools](#tools) - [render_single](#render_single) - [render_perspectives](#render_perspectives) - [check_openscad](#check_openscad) - [Resources](#resources) - [server/info](#serverinfo) - [Data Types](#data-types) - [Error Handling](#error-handling) - [Examples](#examples) - [Performance Considerations](#performance-considerations) ## Overview The OpenSCAD MCP Server provides a Model Context Protocol interface for rendering OpenSCAD 3D models. It exposes tools for single and multi-view rendering, as well as system verification capabilities. ### Base Information - **Protocol Version**: MCP 1.0 - **Server Version**: 1.0.0 - **Transport**: stdio (default), HTTP/SSE (configurable) - **Framework**: FastMCP 2.11.3 ## MCP Protocol The server implements the standard MCP protocol for tool and resource discovery, invocation, and result handling. ### Connection Methods #### 1. Standard Input/Output (stdio) ```python # Direct invocation python -m openscad_mcp # Via FastMCP CLI fastmcp run openscad_mcp/server.py ``` #### 2. HTTP/SSE Transport ```python # Set transport mode export MCP_SERVER_TRANSPORT=sse export MCP_SERVER_HOST=0.0.0.0 export MCP_SERVER_PORT=3000 # Run server python -m openscad_mcp ``` ### Protocol Messages #### List Tools Request ```json { "jsonrpc": "2.0", "id": 1, "method": "tools/list" } ``` #### List Tools Response ```json { "jsonrpc": "2.0", "id": 1, "result": { "tools": [ { "name": "render_single", "description": "Render a single view of an OpenSCAD model", "inputSchema": { ... } }, { "name": "render_perspectives", "description": "Render multiple standard views", "inputSchema": { ... } }, { "name": "check_openscad", "description": "Check OpenSCAD installation", "inputSchema": { ... } } ] } } ``` ## Authentication Currently, the server does not implement authentication. For production deployments requiring authentication: 1. Use environment variables for API keys 2. Implement transport-level security (HTTPS for HTTP/SSE) 3. Add custom authentication middleware if needed ## Tools ### render_single Renders a single view of an OpenSCAD model with full camera control. #### Request Schema ```typescript interface RenderSingleRequest { // Model source (one required) scad_content?: string; // OpenSCAD code as string scad_file?: string; // Path to .scad file // Camera parameters camera_position?: [number, number, number]; // Default: [30, 30, 30] camera_target?: [number, number, number]; // Default: [0, 0, 0] camera_up?: [number, number, number]; // Default: [0, 0, 1] // Rendering options image_size?: [number, number]; // [width, height], Default: [800, 600] color_scheme?: string; // OpenSCAD color scheme name variables?: Record<string, any>; // Variables for parametric models auto_center?: boolean; // Auto-center the model } ``` #### Response Schema ```typescript interface RenderSingleResponse { success: boolean; image?: string; // Base64-encoded PNG image error?: string; // Error message if failed metadata?: { width: number; height: number; render_time: number; // Seconds color_scheme: string; }; } ``` #### Example Usage ```python # Python client example from fastmcp import Client async with Client("openscad-mcp-server") as client: result = await client.call_tool("render_single", { "scad_content": """ $fn = 100; difference() { sphere(r=20); cylinder(h=40, r=10, center=true); } """, "camera_position": [50, 50, 30], "camera_target": [0, 0, 0], "image_size": [1024, 768], "color_scheme": "BeforeDawn" }) # Save the image import base64 image_data = base64.b64decode(result.data["image"].split(",")[1]) with open("output.png", "wb") as f: f.write(image_data) ``` #### Camera Positioning Guide - **Isometric View**: `camera_position: [30, 30, 30]` - **Front View**: `camera_position: [0, -50, 0]` - **Top View**: `camera_position: [0, 0, 50]` - **Side View**: `camera_position: [50, 0, 0]` ### render_perspectives Renders multiple standard views of a model in a single operation. #### Request Schema ```typescript interface RenderPerspectivesRequest { // Model source (one required) scad_content?: string; scad_file?: string; // Rendering parameters distance?: number; // Camera distance, Default: 100 image_size?: [number, number]; // Size for each view variables?: Record<string, any>; views?: string[]; // Subset of views to render } ``` #### Available Views - `"front"` - Front orthographic view - `"back"` - Back orthographic view - `"left"` - Left orthographic view - `"right"` - Right orthographic view - `"top"` - Top orthographic view - `"bottom"` - Bottom orthographic view - `"isometric"` - Isometric 3D view - `"dimetric"` - Dimetric 3D view If `views` is not specified, all 8 views are rendered. #### Response Schema ```typescript interface RenderPerspectivesResponse { success: boolean; images?: { [viewName: string]: string; // Base64-encoded PNG for each view }; error?: string; metadata?: { total_views: number; render_time: number; image_size: [number, number]; }; } ``` #### Example Usage ```python # Render specific views result = await client.call_tool("render_perspectives", { "scad_file": "complex_model.scad", "views": ["front", "isometric", "top"], "distance": 150, "image_size": [400, 400], "variables": { "height": 50, "width": 30 } }) # Access individual images for view_name, image_data in result.data["images"].items(): save_image(f"{view_name}.png", image_data) ``` ### check_openscad Verifies OpenSCAD installation and provides system information. #### Request Schema ```typescript interface CheckOpenSCADRequest { include_paths?: boolean; // Include searched paths in response } ``` #### Response Schema ```typescript interface CheckOpenSCADResponse { success: boolean; installed: boolean; version?: string; // OpenSCAD version string path?: string; // Path to OpenSCAD executable searched_paths?: string[]; // If include_paths is true features?: { animation: boolean; customizer: boolean; manifold: boolean; }; } ``` #### Example Usage ```python # Check installation result = await client.call_tool("check_openscad", { "include_paths": true }) if result.data["installed"]: print(f"OpenSCAD {result.data['version']} found at {result.data['path']}") else: print("OpenSCAD not found. Searched paths:") for path in result.data["searched_paths"]: print(f" - {path}") ``` ## Resources ### server/info Provides server configuration and runtime information. #### URI `resource://server/info` #### Response Schema ```typescript interface ServerInfoResource { server: { name: string; version: string; transport: string; uptime: number; // Seconds }; openscad: { version: string; path: string; timeout: number; }; capabilities: { max_concurrent_renders: number; supported_formats: string[]; available_color_schemes: string[]; }; statistics: { total_renders: number; active_renders: number; failed_renders: number; average_render_time: number; }; } ``` #### Example Usage ```python # Get server information async with Client("openscad-mcp-server") as client: info = await client.read_resource("resource://server/info") print(f"Server: {info['server']['name']} v{info['server']['version']}") print(f"OpenSCAD: {info['openscad']['version']}") print(f"Active renders: {info['statistics']['active_renders']}") ``` ## Data Types ### Pydantic Models The server uses Pydantic for type validation and serialization: ```python from pydantic import BaseModel, Field from typing import List, Optional, Dict, Any class Vector3D(BaseModel): """3D vector for positions and directions""" x: float y: float z: float class ImageSize(BaseModel): """Image dimensions""" width: int = Field(gt=0, le=4096) height: int = Field(gt=0, le=4096) class RenderParams(BaseModel): """Base rendering parameters""" scad_content: Optional[str] = None scad_file: Optional[str] = None variables: Optional[Dict[str, Any]] = None model_config = { "json_schema_extra": { "examples": [ { "scad_content": "cube([10, 10, 10]);", "variables": {"size": 20} } ] } } class SingleRenderParams(RenderParams): """Parameters for single view rendering""" camera_position: Optional[List[float]] = Field( default=[30, 30, 30], min_items=3, max_items=3 ) camera_target: Optional[List[float]] = Field( default=[0, 0, 0], min_items=3, max_items=3 ) camera_up: Optional[List[float]] = Field( default=[0, 0, 1], min_items=3, max_items=3 ) image_size: Optional[List[int]] = Field( default=[800, 600], min_items=2, max_items=2 ) color_scheme: Optional[str] = None auto_center: Optional[bool] = False class PerspectiveParams(RenderParams): """Parameters for multi-view rendering""" distance: Optional[float] = Field(default=100, gt=0) image_size: Optional[List[int]] = Field( default=[400, 400], min_items=2, max_items=2 ) views: Optional[List[str]] = None ``` ## Error Handling The server implements comprehensive error handling with specific error codes and messages. ### Error Response Format ```typescript interface ErrorResponse { success: false; error: string; error_code?: string; details?: { field?: string; reason?: string; suggestion?: string; }; } ``` ### Error Codes | Code | Description | HTTP Status | |------|-------------|-------------| | `OPENSCAD_NOT_FOUND` | OpenSCAD executable not found | 503 | | `INVALID_SCAD_SOURCE` | No valid SCAD content or file provided | 400 | | `FILE_NOT_FOUND` | Specified SCAD file doesn't exist | 404 | | `RENDER_TIMEOUT` | Rendering exceeded timeout limit | 504 | | `RENDER_FAILED` | OpenSCAD rendering failed | 500 | | `INVALID_PARAMETERS` | Invalid tool parameters | 400 | | `CONCURRENT_LIMIT` | Max concurrent renders exceeded | 429 | ### Error Examples ```json // OpenSCAD not found { "success": false, "error": "OpenSCAD executable not found", "error_code": "OPENSCAD_NOT_FOUND", "details": { "suggestion": "Install OpenSCAD from https://openscad.org or set OPENSCAD_PATH environment variable" } } // Invalid parameters { "success": false, "error": "Invalid camera position", "error_code": "INVALID_PARAMETERS", "details": { "field": "camera_position", "reason": "Must be an array of 3 numbers", "suggestion": "Use format [x, y, z], e.g., [30, 30, 30]" } } // Render timeout { "success": false, "error": "Rendering exceeded 30 second timeout", "error_code": "RENDER_TIMEOUT", "details": { "suggestion": "Simplify the model or increase OPENSCAD_TIMEOUT" } } ``` ## Examples ### Basic Cube Rendering ```python # Simple cube with default settings result = await client.call_tool("render_single", { "scad_content": "cube([20, 20, 20]);" }) ``` ### Parametric Model with Variables ```python # Parametric gear model result = await client.call_tool("render_single", { "scad_file": "parametric_gear.scad", "variables": { "teeth": 24, "module": 2, "pressure_angle": 20, "thickness": 10 }, "camera_position": [100, 100, 50], "image_size": [1920, 1080] }) ``` ### Batch Rendering Multiple Views ```python # Render all views of a complex model views_needed = ["front", "back", "left", "right", "top", "bottom", "isometric"] result = await client.call_tool("render_perspectives", { "scad_file": "assembly.scad", "views": views_needed, "distance": 200, "image_size": [512, 512] }) # Process all images for view, image_data in result.data["images"].items(): process_image(view, image_data) ``` ### Animation Frame Rendering ```python # Render animation frames (sequential single renders) frames = [] for angle in range(0, 360, 10): result = await client.call_tool("render_single", { "scad_content": f""" $vpr = [60, 0, {angle}]; cube([20, 20, 20]); """, "image_size": [640, 480] }) frames.append(result.data["image"]) # Create animation from frames create_gif(frames, "rotation.gif") ``` ### Complex Model with Custom Color Scheme ```python # Advanced rendering with custom settings result = await client.call_tool("render_single", { "scad_content": """ $fn = 200; // High resolution module complex_shape() { difference() { sphere(r=30); for(i = [0:5]) { rotate([0, 0, i*60]) translate([25, 0, 0]) cylinder(h=60, r=10, center=true); } } } complex_shape(); """, "camera_position": [80, 60, 40], "camera_target": [0, 0, 0], "image_size": [2048, 1536], "color_scheme": "Tomorrow Night", "auto_center": true }) ``` ## Performance Considerations ### Optimization Tips 1. **Resolution Control** ```scad // Use appropriate $fn values $fn = 50; // Low resolution for previews $fn = 200; // High resolution for final renders ``` 2. **Image Size** - Previews: 400x400 to 800x600 - Final renders: 1920x1080 to 4096x4096 - Batch operations: Keep uniform sizes 3. **Concurrent Rendering** ```python # Configure max concurrent renders os.environ["MCP_RENDER_MAX_CONCURRENT"] = "4" ``` 4. **Timeout Configuration** ```python # Increase timeout for complex models os.environ["OPENSCAD_TIMEOUT"] = "60" # 60 seconds ``` ### Performance Metrics | Operation | Simple Model | Complex Model | Notes | |-----------|-------------|---------------|-------| | Single View | 0.5-1s | 2-5s | Depends on $fn and complexity | | 8 Perspectives | 4-8s | 16-40s | Parallel rendering helps | | Base64 Encoding | <0.05s | <0.1s | Negligible overhead | | File I/O | <0.01s | <0.05s | SSD recommended | ### Memory Usage - Base server: ~50 MB - Per render: +10-20 MB - Peak (4 concurrent): ~130 MB - Image cache: Not implemented (v1.0.0) ### Scaling Recommendations 1. **Horizontal Scaling** - Run multiple server instances - Use load balancer for distribution - Share file system for .scad files 2. **Vertical Scaling** - Increase CPU cores for parallel renders - Add RAM for larger models - Use GPU acceleration (future feature) 3. **Caching Strategy** (Future) - Cache rendered images by hash - Implement TTL for cache entries - Use Redis for distributed cache ## Rate Limiting The server implements basic rate limiting: - Max concurrent renders: 4 (configurable) - Queue size: 100 requests - Timeout per render: 30s (configurable) For production deployments, consider: - API rate limiting per client - Request throttling - Priority queues for different clients ## Logging The server provides comprehensive logging: ```python # Log levels export LOG_LEVEL=DEBUG # DEBUG, INFO, WARNING, ERROR # Log format 2025-08-25 12:00:00 INFO: Server started on stdio transport 2025-08-25 12:00:01 DEBUG: Received tool call: render_single 2025-08-25 12:00:02 INFO: Rendering completed in 1.23s ``` ## Monitoring Key metrics to monitor: - Render success/failure rate - Average render time - Queue depth - Memory usage - OpenSCAD process count ## Security Considerations 1. **Input Validation** - All parameters validated with Pydantic - File paths restricted to allowed directories - SCAD code size limited 2. **Resource Limits** - Timeout protection - Memory limits - Concurrent render limits 3. **File System Access** - Read-only access to SCAD files - Temporary files in isolated directory - Automatic cleanup of temp files ## Version Compatibility | Component | Minimum | Recommended | Notes | |-----------|---------|-------------|-------| | Python | 3.9 | 3.11+ | Async improvements | | FastMCP | 2.11.3 | 2.11.3 | Required | | Pydantic | 2.11.7 | 2.11.7 | Required | | OpenSCAD | 2019.05 | 2021.01+ | Latest features | ## Migration Guide ### From Other MCP Servers 1. Update tool names in client code 2. Adapt parameter formats 3. Update image processing for base64 format 4. Adjust error handling ### From Direct OpenSCAD CLI ```bash # Old CLI approach openscad -o output.png --camera=0,0,0,50,50,30,0 model.scad # New MCP approach result = await client.call_tool("render_single", { "scad_file": "model.scad", "camera_position": [50, 50, 30], "camera_target": [0, 0, 0] }) ``` ## Support For issues or questions: - GitHub Issues: [Report bugs](https://github.com/yourusername/openscad-mcp-server/issues) - Documentation: [README](./README.md) | [CHANGELOG](./CHANGELOG.md) - Examples: See `/examples` directory in repository --- **API Version:** 1.0.0 | **Last Updated:** 2025-08-25

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/quellant/openscad-mcp'

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