Skip to main content
Glama
shapely_functions.pyโ€ข20.2 kB
"""Shapely-related MCP tool functions and resource listings.""" import os import logging from typing import Any, Dict, List, Optional from .mcp import gis_mcp # Configure logging logger = logging.getLogger(__name__) # Resource handlers for Shapely operations @gis_mcp.resource("gis://operations/basic") def get_basic_operations() -> Dict[str, List[str]]: """List available basic geometric operations.""" return { "operations": [ "buffer", "intersection", "union", "difference", "symmetric_difference" ] } @gis_mcp.resource("gis://operations/geometric") def get_geometric_properties() -> Dict[str, List[str]]: """List available geometric property operations.""" return { "operations": [ "convex_hull", "envelope", "minimum_rotated_rectangle", "get_centroid", "get_bounds", "get_coordinates", "get_geometry_type" ] } @gis_mcp.resource("gis://operations/transformations") def get_transformations() -> Dict[str, List[str]]: """List available geometric transformations.""" return { "operations": [ "rotate_geometry", "scale_geometry", "translate_geometry" ] } @gis_mcp.resource("gis://operations/advanced") def get_advanced_operations() -> Dict[str, List[str]]: """List available advanced operations.""" return { "operations": [ "triangulate_geometry", "voronoi", "unary_union_geometries" ] } @gis_mcp.resource("gis://operations/measurements") def get_measurements() -> Dict[str, List[str]]: """List available measurement operations.""" return { "operations": [ "get_length", "get_area" ] } @gis_mcp.resource("gis://operations/validation") def get_validation_operations() -> Dict[str, List[str]]: """List available validation operations.""" return { "operations": [ "is_valid", "make_valid", "simplify" ] } @gis_mcp.resource("gis://operations/shapely_util") def get_shapely_util_operations() -> Dict[str, List[str]]: """List available Shapely utility/advanced operations.""" return { "operations": [ "snap_geometry", "nearest_point_on_geometry", "normalize_geometry", "geometry_to_geojson", "geojson_to_geometry" ] } # Basic geometric operations @gis_mcp.tool() def buffer(geometry: str, distance: float, resolution: int = 16, join_style: int = 1, mitre_limit: float = 5.0, single_sided: bool = False) -> Dict[str, Any]: """Create a buffer around a geometry.""" try: from shapely import wkt geom = wkt.loads(geometry) buffered = geom.buffer( distance=distance, resolution=resolution, join_style=join_style, mitre_limit=mitre_limit, single_sided=single_sided ) return { "status": "success", "geometry": buffered.wkt, "message": "Buffer created successfully" } except Exception as e: logger.error(f"Error creating buffer: {str(e)}") raise ValueError(f"Failed to create buffer: {str(e)}") @gis_mcp.tool() def intersection(geometry1: str, geometry2: str) -> Dict[str, Any]: """Find intersection of two geometries.""" try: from shapely import wkt geom1 = wkt.loads(geometry1) geom2 = wkt.loads(geometry2) result = geom1.intersection(geom2) return { "status": "success", "geometry": result.wkt, "message": "Intersection created successfully" } except Exception as e: logger.error(f"Error creating intersection: {str(e)}") raise ValueError(f"Failed to create intersection: {str(e)}") @gis_mcp.tool() def union(geometry1: str, geometry2: str) -> Dict[str, Any]: """Combine two geometries.""" try: from shapely import wkt geom1 = wkt.loads(geometry1) geom2 = wkt.loads(geometry2) result = geom1.union(geom2) return { "status": "success", "geometry": result.wkt, "message": "Union created successfully" } except Exception as e: logger.error(f"Error creating union: {str(e)}") raise ValueError(f"Failed to create union: {str(e)}") @gis_mcp.tool() def difference(geometry1: str, geometry2: str) -> Dict[str, Any]: """Find difference between geometries.""" try: from shapely import wkt geom1 = wkt.loads(geometry1) geom2 = wkt.loads(geometry2) result = geom1.difference(geom2) return { "status": "success", "geometry": result.wkt, "message": "Difference created successfully" } except Exception as e: logger.error(f"Error creating difference: {str(e)}") raise ValueError(f"Failed to create difference: {str(e)}") @gis_mcp.tool() def symmetric_difference(geometry1: str, geometry2: str) -> Dict[str, Any]: """Find symmetric difference between geometries.""" try: from shapely import wkt geom1 = wkt.loads(geometry1) geom2 = wkt.loads(geometry2) result = geom1.symmetric_difference(geom2) return { "status": "success", "geometry": result.wkt, "message": "Symmetric difference created successfully" } except Exception as e: logger.error(f"Error creating symmetric difference: {str(e)}") raise ValueError(f"Failed to create symmetric difference: {str(e)}") # Geometric properties @gis_mcp.tool() def convex_hull(geometry: str) -> Dict[str, Any]: """Calculate convex hull of a geometry.""" try: from shapely import wkt geom = wkt.loads(geometry) result = geom.convex_hull return { "status": "success", "geometry": result.wkt, "message": "Convex hull created successfully" } except Exception as e: logger.error(f"Error creating convex hull: {str(e)}") raise ValueError(f"Failed to create convex hull: {str(e)}") @gis_mcp.tool() def envelope(geometry: str) -> Dict[str, Any]: """Get bounding box of a geometry.""" try: from shapely import wkt geom = wkt.loads(geometry) result = geom.envelope return { "status": "success", "geometry": result.wkt, "message": "Envelope created successfully" } except Exception as e: logger.error(f"Error creating envelope: {str(e)}") raise ValueError(f"Failed to create envelope: {str(e)}") @gis_mcp.tool() def minimum_rotated_rectangle(geometry: str) -> Dict[str, Any]: """Get minimum rotated rectangle of a geometry.""" try: from shapely import wkt geom = wkt.loads(geometry) result = geom.minimum_rotated_rectangle return { "status": "success", "geometry": result.wkt, "message": "Minimum rotated rectangle created successfully" } except Exception as e: logger.error(f"Error creating minimum rotated rectangle: {str(e)}") raise ValueError(f"Failed to create minimum rotated rectangle: {str(e)}") @gis_mcp.tool() def get_centroid(geometry: str) -> Dict[str, Any]: """Get the centroid of a geometry.""" try: from shapely import wkt geom = wkt.loads(geometry) result = geom.centroid return { "status": "success", "geometry": result.wkt, "message": "Centroid calculated successfully" } except Exception as e: logger.error(f"Error calculating centroid: {str(e)}") raise ValueError(f"Failed to calculate centroid: {str(e)}") @gis_mcp.tool() def get_bounds(geometry: str) -> Dict[str, Any]: """Get the bounds of a geometry.""" try: from shapely import wkt geom = wkt.loads(geometry) return { "status": "success", "bounds": list(geom.bounds), "message": "Bounds calculated successfully" } except Exception as e: logger.error(f"Error calculating bounds: {str(e)}") raise ValueError(f"Failed to calculate bounds: {str(e)}") @gis_mcp.tool() def get_coordinates(geometry: str) -> Dict[str, Any]: """Get the coordinates of a geometry.""" try: from shapely import wkt geom = wkt.loads(geometry) return { "status": "success", "coordinates": [list(coord) for coord in geom.coords], "message": "Coordinates retrieved successfully" } except Exception as e: logger.error(f"Error getting coordinates: {str(e)}") raise ValueError(f"Failed to get coordinates: {str(e)}") @gis_mcp.tool() def get_geometry_type(geometry: str) -> Dict[str, Any]: """Get the type of a geometry.""" try: from shapely import wkt geom = wkt.loads(geometry) return { "status": "success", "type": geom.geom_type, "message": "Geometry type retrieved successfully" } except Exception as e: logger.error(f"Error getting geometry type: {str(e)}") raise ValueError(f"Failed to get geometry type: {str(e)}") # Transformations @gis_mcp.tool() def rotate_geometry(geometry: str, angle: float, origin: str = "center", use_radians: bool = False) -> Dict[str, Any]: """Rotate a geometry.""" try: from shapely import wkt from shapely.affinity import rotate geom = wkt.loads(geometry) result = rotate(geom, angle=angle, origin=origin, use_radians=use_radians) return { "status": "success", "geometry": result.wkt, "message": "Geometry rotated successfully" } except Exception as e: logger.error(f"Error rotating geometry: {str(e)}") raise ValueError(f"Failed to rotate geometry: {str(e)}") @gis_mcp.tool() def scale_geometry(geometry: str, xfact: float, yfact: float, origin: str = "center") -> Dict[str, Any]: """Scale a geometry.""" try: from shapely import wkt from shapely.affinity import scale geom = wkt.loads(geometry) result = scale(geom, xfact=xfact, yfact=yfact, origin=origin) return { "status": "success", "geometry": result.wkt, "message": "Geometry scaled successfully" } except Exception as e: logger.error(f"Error scaling geometry: {str(e)}") raise ValueError(f"Failed to scale geometry: {str(e)}") @gis_mcp.tool() def translate_geometry(geometry: str, xoff: float, yoff: float, zoff: float = 0.0) -> Dict[str, Any]: """Translate a geometry.""" try: from shapely import wkt from shapely.affinity import translate geom = wkt.loads(geometry) result = translate(geom, xoff=xoff, yoff=yoff, zoff=zoff) return { "status": "success", "geometry": result.wkt, "message": "Geometry translated successfully" } except Exception as e: logger.error(f"Error translating geometry: {str(e)}") raise ValueError(f"Failed to translate geometry: {str(e)}") # Advanced operations @gis_mcp.tool() def triangulate_geometry(geometry: str) -> Dict[str, Any]: """Create a triangulation of a geometry.""" try: from shapely import wkt from shapely.ops import triangulate geom = wkt.loads(geometry) triangles = triangulate(geom) return { "status": "success", "geometries": [tri.wkt for tri in triangles], "message": "Triangulation created successfully" } except Exception as e: logger.error(f"Error creating triangulation: {str(e)}") raise ValueError(f"Failed to create triangulation: {str(e)}") @gis_mcp.tool() def voronoi(geometry: str) -> Dict[str, Any]: """Create a Voronoi diagram from points.""" try: from shapely import wkt from shapely.ops import voronoi_diagram geom = wkt.loads(geometry) result = voronoi_diagram(geom) return { "status": "success", "geometry": result.wkt, "message": "Voronoi diagram created successfully" } except Exception as e: logger.error(f"Error creating Voronoi diagram: {str(e)}") raise ValueError(f"Failed to create Voronoi diagram: {str(e)}") @gis_mcp.tool() def unary_union_geometries(geometries: List[str]) -> Dict[str, Any]: """Create a union of multiple geometries.""" try: from shapely import wkt from shapely.ops import unary_union geoms = [wkt.loads(g) for g in geometries] result = unary_union(geoms) return { "status": "success", "geometry": result.wkt, "message": "Union created successfully" } except Exception as e: logger.error(f"Error creating union: {str(e)}") raise ValueError(f"Failed to create union: {str(e)}") # Measurements @gis_mcp.tool() def get_length(geometry: str) -> Dict[str, Any]: """Get the length of a geometry.""" try: from shapely import wkt geom = wkt.loads(geometry) return { "status": "success", "length": float(geom.length), "message": "Length calculated successfully" } except Exception as e: logger.error(f"Error calculating length: {str(e)}") raise ValueError(f"Failed to calculate length: {str(e)}") @gis_mcp.tool() def get_area(geometry: str) -> Dict[str, Any]: """Get the area of a geometry.""" try: from shapely import wkt geom = wkt.loads(geometry) return { "status": "success", "area": float(geom.area), "message": "Area calculated successfully" } except Exception as e: logger.error(f"Error calculating area: {str(e)}") raise ValueError(f"Failed to calculate area: {str(e)}") # Validation operations @gis_mcp.tool() def is_valid(geometry: str) -> Dict[str, Any]: """Check if a geometry is valid.""" try: from shapely import wkt geom = wkt.loads(geometry) return { "status": "success", "is_valid": bool(geom.is_valid), "message": "Geometry validation completed successfully" } except Exception as e: logger.error(f"Error validating geometry: {str(e)}") raise ValueError(f"Failed to validate geometry: {str(e)}") @gis_mcp.tool() def make_valid(geometry: str) -> Dict[str, Any]: """Make a geometry valid.""" try: from shapely import wkt geom = wkt.loads(geometry) result = geom.make_valid() return { "status": "success", "geometry": result.wkt, "message": "Geometry made valid successfully" } except Exception as e: logger.error(f"Error making geometry valid: {str(e)}") raise ValueError(f"Failed to make geometry valid: {str(e)}") @gis_mcp.tool() def simplify(geometry: str, tolerance: float, preserve_topology: bool = True) -> Dict[str, Any]: """Simplify a geometry.""" try: from shapely import wkt geom = wkt.loads(geometry) result = geom.simplify(tolerance=tolerance, preserve_topology=preserve_topology) return { "status": "success", "geometry": result.wkt, "message": "Geometry simplified successfully" } except Exception as e: logger.error(f"Error simplifying geometry: {str(e)}") raise ValueError(f"Failed to simplify geometry: {str(e)}") # Utility operations (already existed) @gis_mcp.tool() def snap_geometry(geometry1: str, geometry2: str, tolerance: float) -> Dict[str, Any]: """ Snap one geometry to another using shapely.ops.snap. Args: geometry1: WKT string of the geometry to be snapped. geometry2: WKT string of the reference geometry. tolerance: Distance tolerance for snapping. Returns: Dictionary with status, message, and snapped geometry as WKT. """ try: from shapely import wkt from shapely.ops import snap geom1 = wkt.loads(geometry1) geom2 = wkt.loads(geometry2) snapped = snap(geom1, geom2, tolerance) return { "status": "success", "geometry": snapped.wkt, "message": "Geometry snapped successfully" } except Exception as e: logger.error(f"Error in snap_geometry: {str(e)}") return {"status": "error", "message": str(e)} @gis_mcp.tool() def nearest_point_on_geometry(geometry1: str, geometry2: str) -> Dict[str, Any]: """ Find the nearest point on geometry2 to geometry1 using shapely.ops.nearest_points. Args: geometry1: WKT string of the first geometry (e.g., a point). geometry2: WKT string of the second geometry. Returns: Dictionary with status, message, and the nearest point as WKT. """ try: from shapely import wkt from shapely.ops import nearest_points geom1 = wkt.loads(geometry1) geom2 = wkt.loads(geometry2) p1, p2 = nearest_points(geom1, geom2) return { "status": "success", "nearest_point": p2.wkt, "message": "Nearest point found successfully" } except Exception as e: logger.error(f"Error in nearest_point_on_geometry: {str(e)}") return {"status": "error", "message": str(e)} @gis_mcp.tool() def normalize_geometry(geometry: str) -> Dict[str, Any]: """ Normalize the orientation/order of a geometry using shapely.normalize. Args: geometry: WKT string of the geometry. Returns: Dictionary with status, message, and normalized geometry as WKT. """ try: from shapely import wkt, normalize geom = wkt.loads(geometry) normalized = normalize(geom) return { "status": "success", "geometry": normalized.wkt, "message": "Geometry normalized successfully" } except Exception as e: logger.error(f"Error in normalize_geometry: {str(e)}") return {"status": "error", "message": str(e)} @gis_mcp.tool() def geometry_to_geojson(geometry: str) -> Dict[str, Any]: """ Convert a Shapely geometry (WKT) to GeoJSON using shapely.geometry.mapping. Args: geometry: WKT string of the geometry. Returns: Dictionary with status, message, and GeoJSON representation. """ try: from shapely import wkt from shapely.geometry import mapping geom = wkt.loads(geometry) geojson = mapping(geom) return { "status": "success", "geojson": geojson, "message": "Geometry converted to GeoJSON successfully" } except Exception as e: logger.error(f"Error in geometry_to_geojson: {str(e)}") return {"status": "error", "message": str(e)} @gis_mcp.tool() def geojson_to_geometry(geojson: Dict[str, Any]) -> Dict[str, Any]: """ Convert GeoJSON to a Shapely geometry using shapely.shape. Args: geojson: GeoJSON dictionary. Returns: Dictionary with status, message, and geometry as WKT. """ try: from shapely import shape geom = shape(geojson) return { "status": "success", "geometry": geom.wkt, "message": "GeoJSON converted to geometry successfully" } except Exception as e: logger.error(f"Error in geojson_to_geometry: {str(e)}") return {"status": "error", "message": str(e)}

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/mahdin75/gis-mcp'

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