Skip to main content
Glama

metadata_raster

Extract metadata from raster datasets by providing either a local file path or HTTPS URL to analyze geospatial data properties.

Instructions

Open a raster dataset in read-only mode and return metadata.

This tool supports two modes based on the provided string:

  1. A local filesystem path (e.g., "D:\Data\my_raster.tif").

  2. An HTTPS URL (e.g., "https://example.com/my_raster.tif").

The input must be a single string that is either a valid file path on the local machine or a valid HTTPS URL pointing to a raster.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
path_or_urlYes

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • Core handler function for 'metadata_raster' tool. Accepts path_or_url (local path or HTTPS URL), opens with rasterio, returns structured metadata (dimensions, CRS, bounds, nodata, transform, band dtypes). Handles remote URLs directly and validates local files.
    @gis_mcp.tool()
    def metadata_raster(path_or_url: str) -> Dict[str, Any]:
        """
        Open a raster dataset in read-only mode and return metadata.
        
        This tool supports two modes based on the provided string:
        1. A local filesystem path (e.g., "D:\\Data\\my_raster.tif").
        2. An HTTPS URL (e.g., "https://example.com/my_raster.tif").
        
        The input must be a single string that is either a valid file path
        on the local machine or a valid HTTPS URL pointing to a raster.
        """
        try:
            # Import numpy first to ensure NumPy's C-API is initialized
            import numpy as np
            import rasterio
    
            # Remove any backticks (`) if the client wrapped the path_or_url in them
            cleaned = path_or_url.replace("`", "")
    
            # Determine if the string is an HTTPS URL or a local file path
            if cleaned.lower().startswith("https://"):
                # For HTTPS URLs, let Rasterio/GDAL handle remote access directly
                dataset = rasterio.open(cleaned)
            else:
                # Treat as local filesystem path
                local_path = os.path.expanduser(cleaned)
    
                # Verify that the file exists on disk
                if not os.path.isfile(local_path):
                    raise FileNotFoundError(f"Raster file not found at '{local_path}'.")
    
                # Open the local file in read-only mode
                dataset = rasterio.open(local_path)
    
            # Build a mapping from band index to its data type (dtype)
            band_dtypes = {i: dtype for i, dtype in zip(dataset.indexes, dataset.dtypes)}
    
            # Collect core metadata fields in simple Python types
            meta: Dict[str, Any] = {
                "name": dataset.name,                                       # Full URI or filesystem path
                "mode": dataset.mode,                                       # Mode should be 'r' for read                                 
                "driver": dataset.driver,                                   # GDAL driver, e.g. "GTiff"
                "width": dataset.width,                                     # Number of columns
                "height": dataset.height,                                   # Number of rows
                "count": dataset.count,                                     # Number of bands
                "bounds": dataset.bounds,                                   # Show bounding box
                "band_dtypes": band_dtypes,                                 # { band_index: dtype_string }
                "no_data": dataset.nodatavals,                              # Number of NoData values in each band
                "crs": dataset.crs.to_string() if dataset.crs else None,    # CRS as EPSG string or None
                "transform": list(dataset.transform),                       # Affine transform coefficients (6 floats)
            }
    
            # Return a success status along with metadata
            return {
                "status": "success",
                "metadata": meta,
                "message": f"Raster dataset opened successfully from '{cleaned}'."
            }
    
        except Exception as e:
            # Log the error for debugging purposes, then raise ValueError so MCP can relay it
            logger.error(f"Error opening raster '{path_or_url}': {str(e)}")
            raise ValueError(f"Failed to open raster '{path_or_url}': {str(e)}")
  • MCP resource endpoint listing 'metadata_raster' among available rasterio operations, enabling client discovery of tools.
    @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"
            ]
        }
  • Imports rasterio_functions.py in main server entrypoint, executing @gis_mcp.tool() decorators to register 'metadata_raster' with the FastMCP server instance.
    from . import (
        geopandas_functions,
        shapely_functions,
        rasterio_functions,
        pyproj_functions,
        pysal_functions,
    )
  • src/gis_mcp/mcp.py:5-6 (registration)
    Defines the FastMCP server instance 'gis_mcp' used by decorators (@gis_mcp.tool(), @gis_mcp.resource()) to register tools and resources.
    gis_mcp = FastMCP("GIS MCP")
Behavior4/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 effectively communicates key traits: the tool operates in read-only mode (indicating no mutations), supports both local and remote inputs, and returns metadata. It does not mention potential limitations like file format support, error handling, or performance considerations, but covers essential operational context adequately.

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 appropriately sized and front-loaded, starting with the core purpose in the first sentence. Each subsequent sentence adds necessary detail about input modes and requirements without redundancy. The structure is logical and efficient, with no wasted words.

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

Completeness5/5

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

Given the tool's low complexity (single parameter, read-only operation) and the presence of an output schema (which handles return values), the description is complete enough. It covers purpose, usage context, behavioral traits, and parameter semantics thoroughly, leaving no critical gaps for an AI agent to understand and invoke the tool correctly.

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?

The schema description coverage is 0%, so the description must fully compensate. It adds significant meaning beyond the schema by explaining that the single parameter 'path_or_url' can be either a local filesystem path or an HTTPS URL, with concrete examples provided. This clarifies the parameter's purpose and valid formats, making it highly informative.

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 ('Open a raster dataset in read-only mode and return metadata'), identifies the resource ('raster dataset'), and distinguishes it from siblings by focusing solely on metadata retrieval rather than analysis or modification. It precisely communicates the tool's function without ambiguity.

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 by specifying it opens raster datasets in read-only mode for metadata extraction, and it details the two supported input modes (local path or HTTPS URL). However, it does not explicitly mention when not to use it or name alternatives among the many sibling tools, such as 'get_raster_crs' or 'raster_band_statistics', which might offer overlapping functionality.

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