Skip to main content
Glama
cad_context.py6.4 kB
import logging import platform from typing import Any, Dict, List, Optional logger = logging.getLogger(__name__) class CADContextExtractor: """Extracts context information from FreeCAD.""" def __init__(self, freecad_app=None): """ Initialize the CAD context extractor. 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 def extract_full_context(self) -> Dict[str, Any]: """Extract comprehensive context from the current FreeCAD state""" if self.app is None: return {"error": "FreeCAD not available"} context = { "application": self._extract_application_context(), "documents": self._extract_documents_context(), "active_document": self._extract_active_document_context(), "selection": self._extract_selection_context(), } return context def _extract_application_context(self) -> Dict[str, Any]: """Extract information about the FreeCAD application""" if self.app is None: return {"error": "FreeCAD not available"} return { "version": self.app.Version, "build_type": getattr(self.app, "BuildVersionMajor", "Unknown"), "operating_system": platform.system(), "available_workbenches": ( list(self.app.getWorkbenches().keys()) if hasattr(self.app, "getWorkbenches") else [] ), } def _extract_documents_context(self) -> List[Dict[str, Any]]: """Extract information about all open documents""" if self.app is None: return [{"error": "FreeCAD not available"}] docs = [] for doc_name in self.app.listDocuments(): doc = self.app.getDocument(doc_name) docs.append( { "name": doc.Name, "label": doc.Label, "file": doc.FileName if hasattr(doc, "FileName") else None, "objects_count": len(doc.Objects), "modified": doc.Modified, } ) return docs def _extract_active_document_context(self) -> Optional[Dict[str, Any]]: """Extract detailed information about the active document""" if self.app is None or self.app.ActiveDocument is None: return None doc = self.app.ActiveDocument return { "name": doc.Name, "label": doc.Label, "file": doc.FileName if hasattr(doc, "FileName") else None, "objects": self._extract_objects_context(doc), "object_hierarchy": self._extract_object_hierarchy(doc), } def _extract_objects_context(self, doc) -> List[Dict[str, Any]]: """Extract information about all objects in a document""" objects = [] for obj in doc.Objects: objects.append( { "id": obj.Name, "label": obj.Label, "type": obj.TypeId, "visibility": obj.Visibility, "properties": self._extract_object_properties(obj), } ) return objects def _extract_object_properties(self, obj) -> Dict[str, Any]: """Extract properties of an object""" properties = {} for prop in obj.PropertiesList: try: prop_type = obj.getTypeIdOfProperty(prop) prop_value = getattr(obj, prop) # Convert complex types to serializable format if hasattr(prop_value, "__dict__"): prop_value = str(prop_value) properties[prop] = {"type": prop_type, "value": prop_value} except Exception as e: # Skip properties that can't be serialized logger.debug(f"Could not extract property {prop} from {obj.Name}: {e}") return properties def _extract_object_hierarchy(self, doc) -> Dict[str, Any]: """Extract the hierarchical structure of objects in a document""" hierarchy = {} # Create a dictionary of all objects all_objects = { obj.Name: {"label": obj.Label, "type": obj.TypeId, "children": []} for obj in doc.Objects } # Identify parent-child relationships for obj in doc.Objects: # Check for Group property (used by many container objects) if hasattr(obj, "Group") and obj.Group: for child in obj.Group: if child.Name in all_objects: all_objects[obj.Name]["children"].append(child.Name) # Build the root level (objects with no parents) root_objects = [] for obj_name, obj_data in all_objects.items(): is_child = False for other_obj in all_objects.values(): if obj_name in other_obj["children"]: is_child = True break if not is_child: root_objects.append(obj_name) # Build the final hierarchy hierarchy = {"root": root_objects, "objects": all_objects} return hierarchy def _extract_selection_context(self) -> List[Dict[str, Any]]: """Extract information about the current selection""" if ( self.app is None or not hasattr(self.app, "Gui") or not hasattr(self.app.Gui, "Selection") ): return [] selection = [] for obj in self.app.Gui.Selection.getSelection(): selection.append( { "id": obj.Name, "label": obj.Label, "type": obj.TypeId, "document": obj.Document.Name, } ) return selection

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