Skip to main content
Glama

clip_raster_with_shapefile

Extract raster data within polygon boundaries from a shapefile. Converts coordinate systems automatically and saves the clipped raster to a specified location.

Instructions

Clip a raster dataset using polygons from a shapefile and write the result. Converts the shapefile's CRS to match the raster's CRS if they are different.

Parameters:

  • raster_path_or_url: local path or HTTPS URL of the source raster.

  • shapefile_path: local filesystem path to a .shp file containing polygons.

  • destination: local path where the masked raster will be written.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
raster_path_or_urlYes
shapefile_pathYes
destinationYes

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • The core handler function decorated with @gis_mcp.tool(). It opens the raster (local or URL), reads shapefile geometries with fiona, reprojects geometries to raster CRS if needed, applies rasterio.mask to clip, and writes the output GeoTIFF.
    @gis_mcp.tool()
    def clip_raster_with_shapefile(
        raster_path_or_url: str,
        shapefile_path: str,
        destination: str
    ) -> Dict[str, Any]:
        """
        Clip a raster dataset using polygons from a shapefile and write the result.
        Converts the shapefile's CRS to match the raster's CRS if they are different.
        
        Parameters:
        - raster_path_or_url: local path or HTTPS URL of the source raster.
        - shapefile_path:     local filesystem path to a .shp file containing polygons.
        - destination:        local path where the masked raster will be written.
        """
        try:
            import numpy as np
            import rasterio
            import rasterio.mask
            from rasterio.warp import transform_geom
            import pyproj
            import fiona
    
            # Clean paths
            raster_clean = raster_path_or_url.replace("`", "")
            shp_clean = shapefile_path.replace("`", "")
            dst_clean = destination.replace("`", "")
    
            # Verify shapefile exists
            shp_path = os.path.expanduser(shp_clean)
            if not os.path.isfile(shp_path):
                raise FileNotFoundError(f"Shapefile not found at '{shp_path}'.")
    
            # Open the raster
            if raster_clean.lower().startswith("https://"):
                src = rasterio.open(raster_clean)
            else:
                src_path = os.path.expanduser(raster_clean)
                if not os.path.isfile(src_path):
                    raise FileNotFoundError(f"Raster not found at '{src_path}'.")
                src = rasterio.open(src_path)
    
            raster_crs = src.crs  # Get raster CRS
    
            # Read geometries from shapefile and check CRS
            with fiona.open(shp_path, "r") as shp:
                shapefile_crs = pyproj.CRS(shp.crs)  # Get shapefile CRS
                shapes: List[Dict[str, Any]] = [feat["geometry"] for feat in shp]
    
                # Convert geometries to raster CRS if necessary
                if shapefile_crs != raster_crs:
                    shapes = [transform_geom(str(shapefile_crs), str(raster_crs), shape) for shape in shapes]
    
            # Apply mask: crop to shapes and set outside pixels to zero
            out_image, out_transform = rasterio.mask.mask(src, shapes, crop=True)
            out_meta = src.meta.copy()
            src.close()
    
            # Update metadata for the masked output
            out_meta.update({
                "driver": "GTiff",
                "height": out_image.shape[1],
                "width": out_image.shape[2],
                "transform": out_transform
            })
    
            # Resolve destination path relative to storage
            dst_path = resolve_path(dst_clean, relative_to_storage=True)
            dst_path.parent.mkdir(parents=True, exist_ok=True)
    
            # Write the masked raster
            with rasterio.open(str(dst_path), "w", **out_meta) as dst:
                dst.write(out_image)
    
            return {
                "status": "success",
                "destination": str(dst_path),
                "message": f"Raster masked and saved to '{dst_path}'."
            }
    
        except Exception as e:
            print(f"Error: {e}")
            raise ValueError(f"Failed to mask raster: {e}")
  • Imports rasterio_functions.py (and others), executing the module code and triggering @gis_mcp.tool() decorators to register the clip_raster_with_shapefile tool with the FastMCP server.
    from . import (
        geopandas_functions,
        shapely_functions,
        rasterio_functions,
        pyproj_functions,
        pysal_functions,
    )
  • GIS resource endpoint that lists all available rasterio tools, including "clip_raster_with_shapefile", allowing clients to discover the tool.
    @gis_mcp.resource("gis://operation/rasterio")
    def get_rasterio_operations() -> Dict[str, List[str]]:
        """List available rasterio operations."""
        return {
            "operations": [
                "metadata_raster",
                "get_raster_crs",
                "clip_raster_with_shapefile",
                "resample_raster",
                "reproject_raster",
                "weighted_band_sum",
                "concat_bands",
                "raster_algebra",
                "compute_ndvi",
                "raster_histogram",
                "tile_raster",
                "raster_band_statistics",
                "extract_band",
                "zonal_statistics",
                "reclassify_raster",
                "focal_statistics",
                "hillshade",
                "write_raster"
            ]
        }
  • src/gis_mcp/mcp.py:5-6 (registration)
    Defines the FastMCP server instance 'gis_mcp' to which all tools are registered via decorators.
    gis_mcp = FastMCP("GIS MCP")
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It usefully describes the CRS conversion behavior ('Converts the shapefile's CRS to match the raster's CRS if they are different') and implies a write operation. However, it doesn't mention permission requirements, whether the operation is destructive to source files, error handling, or performance characteristics, leaving some behavioral gaps.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is perfectly structured with a clear purpose statement, important behavioral note about CRS conversion, and a concise parameter section. Every sentence adds value with zero wasted words, and the most critical information (what the tool does) comes first.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 3-parameter tool with no annotations but with an output schema (which handles return values), the description provides excellent coverage of the operation's purpose, parameters, and key behavioral aspect (CRS conversion). The main gap is lack of information about permissions, error conditions, or performance limits, but given the output schema exists, this is reasonably complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema description coverage (no parameter descriptions in the schema), the description fully compensates by providing clear semantic explanations for all three parameters: source raster location, shapefile path, and output destination. Each parameter's purpose is explicitly documented beyond just the schema's type information.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the specific action ('Clip a raster dataset using polygons from a shapefile and write the result') and distinguishes it from siblings like 'clip_vector' (which clips vector data) and 'write_raster' (which writes without clipping). The verb+resource+scope is precise and unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context for when to use this tool (clipping rasters with shapefiles) and implicitly distinguishes it from alternatives like 'clip_vector' (for vector clipping) and 'reproject_raster' (for coordinate transformations). However, it doesn't explicitly state when NOT to use it or name specific alternatives, keeping it at a 4.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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

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