Skip to main content
Glama
primitives.py8.68 kB
import logging from typing import Any, Dict, Optional from .base import ToolProvider, ToolResult, ToolSchema logger = logging.getLogger(__name__) class PrimitiveToolProvider(ToolProvider): """Tool provider for creating primitive shapes in FreeCAD.""" def __init__(self, freecad_app=None): """ Initialize the primitive tool provider. Args: freecad_app: Optional FreeCAD application instance. If None, will try to import FreeCAD. """ self.app = freecad_app if self.app is None: try: import FreeCAD self.app = FreeCAD logger.info("Connected to FreeCAD") except ImportError: logger.warning( "Could not import FreeCAD. Make sure it's installed and in your Python path." ) self.app = None @property def tool_schema(self) -> ToolSchema: """Get the schema for primitive creation tools.""" return ToolSchema( name="primitives", description="Create primitive shapes in FreeCAD", parameters={ "type": "object", "properties": { "tool_id": { "type": "string", "enum": [ "create_box", "create_cylinder", "create_sphere", "create_cone", ], "description": "The primitive tool to execute", }, "params": { "type": "object", "description": "Parameters for the primitive creation", }, }, "required": ["tool_id"], }, returns={ "type": "object", "properties": { "status": {"type": "string"}, "result": {"type": "object"}, "error": {"type": "string"}, }, }, examples=[ { "tool_id": "create_box", "params": {"length": 10.0, "width": 5.0, "height": 3.0}, }, { "tool_id": "create_cylinder", "params": {"radius": 5.0, "height": 10.0}, }, ], ) async def execute_tool(self, tool_id: str, params: Dict[str, Any]) -> ToolResult: """ Execute a primitive creation tool. Args: tool_id: The ID of the tool to execute params: Parameters for the tool Returns: ToolResult containing the execution status and result """ if self.app is None: return self.format_result(status="error", error="FreeCAD not available") try: if tool_id == "create_box": result = await self._create_box(params) elif tool_id == "create_cylinder": result = await self._create_cylinder(params) elif tool_id == "create_sphere": result = await self._create_sphere(params) elif tool_id == "create_cone": result = await self._create_cone(params) else: return self.format_result( status="error", error=f"Unknown tool: {tool_id}" ) return self.format_result(status="success", result=result) except Exception as e: logger.error(f"Error executing primitive tool {tool_id}: {e}") return self.format_result(status="error", error=str(e)) async def _create_box(self, params: Dict[str, Any]) -> Dict[str, Any]: """Create a box primitive.""" # Get parameters with default values length = params.get("length", 10.0) width = params.get("width", 10.0) height = params.get("height", 10.0) name = params.get("name", "Box") # Validate dimensions are positive if length <= 0: raise ValueError(f"Length must be positive, got {length}") if width <= 0: raise ValueError(f"Width must be positive, got {width}") if height <= 0: raise ValueError(f"Height must be positive, got {height}") # Get or create document doc = self._get_active_document() # Create the box box = doc.addObject("Part::Box", name) box.Length = length box.Width = width box.Height = height # Recompute document doc.recompute() return { "message": f"Box created successfully with dimensions {length}x{width}x{height}", "object_name": box.Name, "object_id": box.Name, "object_type": "Part::Box", "properties": {"Length": length, "Width": width, "Height": height}, } async def _create_cylinder(self, params: Dict[str, Any]) -> Dict[str, Any]: """Create a cylinder primitive.""" # Get parameters with default values radius = params.get("radius", 5.0) height = params.get("height", 10.0) name = params.get("name", "Cylinder") # Validate dimensions are positive if radius <= 0: raise ValueError(f"Radius must be positive, got {radius}") if height <= 0: raise ValueError(f"Height must be positive, got {height}") # Get or create document doc = self._get_active_document() # Create the cylinder cylinder = doc.addObject("Part::Cylinder", name) cylinder.Radius = radius cylinder.Height = height # Recompute document doc.recompute() return { "message": f"Cylinder created successfully with radius {radius} and height {height}", "object_name": cylinder.Name, "object_id": cylinder.Name, "object_type": "Part::Cylinder", "properties": {"Radius": radius, "Height": height}, } async def _create_sphere(self, params: Dict[str, Any]) -> Dict[str, Any]: """Create a sphere primitive.""" # Get parameters with default values radius = params.get("radius", 5.0) name = params.get("name", "Sphere") # Validate dimensions are positive if radius <= 0: raise ValueError(f"Radius must be positive, got {radius}") # Get or create document doc = self._get_active_document() # Create the sphere sphere = doc.addObject("Part::Sphere", name) sphere.Radius = radius # Recompute document doc.recompute() return { "message": f"Sphere created successfully with radius {radius}", "object_name": sphere.Name, "object_id": sphere.Name, "object_type": "Part::Sphere", "properties": {"Radius": radius}, } async def _create_cone(self, params: Dict[str, Any]) -> Dict[str, Any]: """Create a cone primitive.""" # Get parameters with default values radius1 = params.get("radius1", 5.0) radius2 = params.get("radius2", 0.0) height = params.get("height", 10.0) name = params.get("name", "Cone") # Validate dimensions are positive (radius2 can be 0) if radius1 <= 0: raise ValueError(f"Radius1 must be positive, got {radius1}") if radius2 < 0: raise ValueError(f"Radius2 must be non-negative, got {radius2}") if height <= 0: raise ValueError(f"Height must be positive, got {height}") # Get or create document doc = self._get_active_document() # Create the cone cone = doc.addObject("Part::Cone", name) cone.Radius1 = radius1 cone.Radius2 = radius2 cone.Height = height # Recompute document doc.recompute() return { "message": f"Cone created successfully with radius1 {radius1}, radius2 {radius2}, and height {height}", "object_name": cone.Name, "object_id": cone.Name, "object_type": "Part::Cone", "properties": {"Radius1": radius1, "Radius2": radius2, "Height": height}, } def _get_active_document(self): """Get the active document or create a new one if none exists.""" if self.app.ActiveDocument: return self.app.ActiveDocument else: return self.app.newDocument("Unnamed")

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/jango-blockchained/mcp-freecad'

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