Skip to main content
Glama

transform_frames

Convert coordinates between reference frames (ECEF, ECI, ITRF, GCRS, GEODETIC) for aerospace applications. Specify source and target frames with optional epoch for time-dependent transformations.

Instructions

Transform coordinates between reference frames (ECEF, ECI, ITRF, GCRS, GEODETIC).

Args: coordinates: Dict with coordinate data (format depends on frame) from_frame: Source reference frame to_frame: Target reference frame epoch_utc: Optional epoch for time-dependent transformations (ISO format)

Returns: JSON string with transformed coordinates

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
coordinatesYes
from_frameYes
to_frameYes
epoch_utcNo

Implementation Reference

  • The MCP tool handler for 'transform_frames'. Accepts coordinates as dict, frame names, optional epoch, calls the underlying integration function, and returns formatted JSON output or error messages.
    def transform_frames(
        coordinates: dict,
        from_frame: Literal["ECEF", "ECI", "ITRF", "GCRS", "GEODETIC"],
        to_frame: Literal["ECEF", "ECI", "ITRF", "GCRS", "GEODETIC"],
        epoch_utc: str | None = None,
    ) -> str:
        """Transform coordinates between reference frames (ECEF, ECI, ITRF, GCRS, GEODETIC).
    
        Args:
            coordinates: Dict with coordinate data (format depends on frame)
            from_frame: Source reference frame
            to_frame: Target reference frame
            epoch_utc: Optional epoch for time-dependent transformations (ISO format)
    
        Returns:
            JSON string with transformed coordinates
        """
        try:
            from ..integrations.frames import transform_frames as _transform
    
            result = _transform(coordinates, from_frame, to_frame, epoch_utc)
            return json.dumps(result, indent=2)
    
        except ImportError as e:
            return f"Frame transformation not available - missing dependency: {str(e)}"
        except Exception as e:
            logger.error(f"Frame transformation error: {str(e)}", exc_info=True)
            return f"Frame transformation error: {str(e)}"
  • Registers the transform_frames function as an MCP tool in the FastMCP server.
    mcp.tool(transform_frames)
  • Core implementation of frame transformations using astropy if available, or manual methods for ECEF/GEODETIC and approximations for others.
    def transform_frames(
        xyz: list[float],
        from_frame: str,
        to_frame: str,
        epoch_iso: str = "2000-01-01T12:00:00",
    ) -> CoordinatePoint:
        """
        Transform coordinates between reference frames.
    
        Args:
            xyz: [x, y, z] coordinates in meters
            from_frame: Source frame ("ECEF", "ECI", "ITRF", "GCRS")
            to_frame: Target frame ("ECEF", "ECI", "ITRF", "GCRS")
            epoch_iso: Reference epoch in ISO format
    
        Returns:
            CoordinatePoint with transformed coordinates
        """
        if len(xyz) != 3:
            raise ValueError("xyz must be a list of 3 coordinates")
    
        x, y, z = xyz
    
        # Validate frame names
        valid_frames = {"ECEF", "ECI", "ITRF", "GCRS", "GEODETIC"}
        if from_frame not in valid_frames or to_frame not in valid_frames:
            raise ValueError(f"Frame must be one of {valid_frames}")
    
        # Same frame - no transformation needed
        if from_frame == to_frame:
            return CoordinatePoint(x=x, y=y, z=z, frame=to_frame, epoch=epoch_iso)
    
        # Use high-precision libraries if available
        if ASTROPY_AVAILABLE:
            try:
                # Parse epoch
                time = Time(epoch_iso, format="isot")
    
                # Map frame names to astropy
                frame_map = {
                    "ECI": GCRS,
                    "GCRS": GCRS,
                    "ECEF": ITRS,
                    "ITRF": ITRS,
                }
    
                if from_frame in frame_map and to_frame in frame_map:
                    # Create coordinate object
                    coords_from = frame_map[from_frame](
                        CartesianRepresentation(x=x * u.m, y=y * u.m, z=z * u.m),
                        obstime=time,
                    )
    
                    # Transform
                    coords_to = coords_from.transform_to(frame_map[to_frame](obstime=time))
    
                    return CoordinatePoint(
                        x=float(coords_to.cartesian.x.to(u.m).value),
                        y=float(coords_to.cartesian.y.to(u.m).value),
                        z=float(coords_to.cartesian.z.to(u.m).value),
                        frame=to_frame,
                        epoch=epoch_iso,
                    )
            except Exception:
                # Fall back to manual methods
                pass
    
        # Manual transformations for basic cases
        if from_frame == "ECEF" and to_frame == "GEODETIC":
            lat, lon, alt = _manual_ecef_to_geodetic(x, y, z)
            return CoordinatePoint(x=lat, y=lon, z=alt, frame="GEODETIC", epoch=epoch_iso)
        elif from_frame == "GEODETIC" and to_frame == "ECEF":
            x_new, y_new, z_new = _manual_geodetic_to_ecef(x, y, z)
            return CoordinatePoint(x=x_new, y=y_new, z=z_new, frame="ECEF", epoch=epoch_iso)
        elif (from_frame in ["ECI", "GCRS"] and to_frame in ["ECEF", "ITRF"]) or (
            from_frame in ["ECEF", "ITRF"] and to_frame in ["ECI", "GCRS"]
        ):
            # Simple approximation: ECI ≈ ECEF (ignoring Earth rotation)
            # In real implementation, would apply rotation matrix based on GMST
            return CoordinatePoint(x=x, y=y, z=z, frame=to_frame, epoch=epoch_iso)
    
        raise NotImplementedError(
            f"Transformation from {from_frame} to {to_frame} not implemented. "
            f"Install astropy or skyfield for full functionality."
        )
  • Pydantic models defining input/output schemas for coordinate transformations.
    class CoordinatePoint(BaseModel):
        """A point in 3D space with metadata."""
    
        x: float = Field(..., description="X coordinate (m)")
        y: float = Field(..., description="Y coordinate (m)")
        z: float = Field(..., description="Z coordinate (m)")
        frame: str = Field(..., description="Coordinate frame")
        epoch: str | None = Field(None, description="Epoch (ISO format)")
    
    
    class GeodeticPoint(BaseModel):
        """Geodetic coordinates."""
    
        latitude_deg: float = Field(..., description="Latitude in degrees")
        longitude_deg: float = Field(..., description="Longitude in degrees")
        altitude_m: float = Field(..., description="Height above ellipsoid (m)")

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/cheesejaguar/aerospace-mcp'

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