Skip to main content
Glama
vlad-ds

Street View MCP

by vlad-ds

get_street_view

Fetch and save Google Street View images using location, coordinates, or panorama ID to create virtual tours and visualize streets and landmarks.

Instructions

Fetch a Street View image based on location, coordinates, or panorama ID and save to file.

Args: filename: Required filename to save the image (must not already exist in output directory) location: The address to get Street View image for (e.g., "Empire State Building, NY") lat_lng: Comma-separated latitude and longitude (e.g., "40.748817,-73.985428") pano_id: Specific panorama ID to fetch size: Image dimensions as "widthxheight" (e.g., "600x400") heading: Camera heading in degrees (0-360) pitch: Camera pitch in degrees (-90 to 90) fov: Field of view in degrees (zoom level, 10-120) radius: Search radius in meters when using location or coordinates source: Limit Street View searches to selected sources ("default" or "outdoor")

Returns: Image: The Street View image

Raises: ValueError: If filename already exists in output directory

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
filenameYes
locationNo
lat_lngNo
pano_idNo
sizeNo600x400
headingNo
pitchNo
fovNo
radiusNo
sourceNodefault

Implementation Reference

  • The main handler function for the 'get_street_view' MCP tool. It parses inputs, calls the helper function to fetch the image from Google Street View API, converts it to bytes, and returns it as a FastMCP Image object.
    @mcp.tool()
    def get_street_view(
        filename: str,
        location: Optional[str] = None,
        lat_lng: Optional[str] = None,
        pano_id: Optional[str] = None,
        size: str = "600x400",
        heading: int = 0,
        pitch: int = 0,
        fov: int = 90,
        radius: int = 50,
        source: str = "default",
    ) -> Image:
        """
        Fetch a Street View image based on location, coordinates, or panorama ID and save to file.
        
        Args:
            filename: Required filename to save the image (must not already exist in output directory)
            location: The address to get Street View image for (e.g., "Empire State Building, NY")
            lat_lng: Comma-separated latitude and longitude (e.g., "40.748817,-73.985428")
            pano_id: Specific panorama ID to fetch
            size: Image dimensions as "widthxheight" (e.g., "600x400")
            heading: Camera heading in degrees (0-360)
            pitch: Camera pitch in degrees (-90 to 90)
            fov: Field of view in degrees (zoom level, 10-120)
            radius: Search radius in meters when using location or coordinates
            source: Limit Street View searches to selected sources ("default" or "outdoor")
            
        Returns:
            Image: The Street View image
            
        Raises:
            ValueError: If filename already exists in output directory
        """
        # Parse lat_lng string to tuple if provided
        lat_lng_tuple = None
        if lat_lng:
            try:
                lat, lng = map(float, lat_lng.split(','))
                lat_lng_tuple = (lat, lng)
            except (ValueError, TypeError):
                raise ValueError("Invalid lat_lng format. Use format: '40.714728,-73.998672'")
                
        # Fetch the image and save it
        pil_image = get_street_view_image(
            location=location,
            lat_lng=lat_lng_tuple,
            pano_id=pano_id,
            size=size,
            heading=heading,
            pitch=pitch,
            fov=fov,
            radius=radius,
            source=source,
            return_error_code=True,
            filename=filename,
        )
        
        # Convert PIL Image to bytes
        buffer = io.BytesIO()
        pil_image.save(buffer, format="JPEG")
        img_bytes = buffer.getvalue()
        
        # Return using FastMCP's Image helper
        return Image(data=img_bytes, format="jpeg")
  • Helper function that performs the actual API call to Google Maps Street View Static API, handles parameters, saves the image if filename provided, and returns the PIL Image.
    def get_street_view_image(
        location: Optional[str] = None,
        lat_lng: Optional[Tuple[float, float]] = None,
        pano_id: Optional[str] = None,
        size: str = "600x400",
        heading: int = 0,
        pitch: int = 0,
        fov: int = 90,
        radius: int = 50,
        source: str = "default",
        return_error_code: bool = True,
        filename: Optional[str] = None,
    ):
        """
        Fetch a Street View image using various location specifiers.
        
        Args:
            location (str, optional): The address to get Street View image for
            lat_lng (tuple, optional): Latitude and longitude coordinates as (lat, lng)
            pano_id (str, optional): Specific panorama ID to fetch
            size (str): The size of the image in pixels as 'widthxheight'
            heading (int): Camera heading in degrees relative to true north
            pitch (int): Camera pitch in degrees, relative to the street view vehicle
            fov (int): Field of view in degrees (zoom level)
            radius (int): Search radius in meters (when using location or lat_lng)
            source (str): Limits Street View searches to selected sources (default, outdoor)
            return_error_code (bool): Whether to return error codes instead of generic images
            filename (str, optional): If provided, save the image to this filename in the output directory
            
        Returns:
            PIL.Image: The Street View image
            
        Raises:
            ValueError: If no location method is provided or multiple are provided, or if filename already exists
            Exception: If the API request fails
        """
        # If filename is provided, check if it exists in output directory
        if filename:
            output_path = OUTPUT_DIR / filename
            if output_path.exists():
                raise ValueError(f"File {output_path} already exists")
        
        # Validate input: exactly one location method must be provided
        location_methods = sum(1 for m in [location, lat_lng, pano_id] if m is not None)
        if location_methods == 0:
            raise ValueError("Must provide one of: location, lat_lng, or pano_id")
        if location_methods > 1:
            raise ValueError("Provide only one of: location, lat_lng, or pano_id")
        
        base_url = "https://maps.googleapis.com/maps/api/streetview"
        
        params = {
            "size": size,
            "heading": heading,
            "pitch": pitch,
            "fov": fov,
            "radius": radius,
            "source": source,
            "return_error_code": str(return_error_code).lower(),
            "key": API_KEY,
        }
        
        # Set the location parameter based on what was provided
        if location:
            params["location"] = location
        elif lat_lng:
            params["location"] = f"{lat_lng[0]},{lat_lng[1]}"
        elif pano_id:
            params["pano"] = pano_id
            # Remove radius when using pano_id as it's not applicable
            if "radius" in params:
                del params["radius"]
        
        response = requests.get(base_url, params=params)
        
        if response.status_code == 200:
            if response.headers.get('content-type', '').startswith('image/'):
                image = Image.open(BytesIO(response.content))
                
                # Save to file if filename is provided
                if filename:
                    # Ensure output directory exists
                    output_path.parent.mkdir(parents=True, exist_ok=True)
                    image.save(output_path)
                    
                return image
            else:
                raise Exception("Received non-image response from API")
        else:
            raise Exception(f"Error fetching Street View image: {response.status_code}")
  • The @mcp.tool() decorator registers the get_street_view function as an MCP tool.
    @mcp.tool()
  • Function signature defines the input schema (parameters with types and defaults) and output type for the tool.
    def get_street_view(
        filename: str,
        location: Optional[str] = None,
        lat_lng: Optional[str] = None,
        pano_id: Optional[str] = None,
        size: str = "600x400",
        heading: int = 0,
        pitch: int = 0,
        fov: int = 90,
        radius: int = 50,
        source: str = "default",
    ) -> Image:
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 and does well by disclosing key behaviors: it saves to a file, requires a unique filename, and raises a ValueError for duplicates. It also hints at search functionality with 'radius' and 'source' parameters, though it doesn't cover rate limits or authentication needs.

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

Conciseness4/5

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

The description is well-structured with a clear opening sentence, organized parameter list, and return/error sections. It's appropriately sized for a 10-parameter tool, though some redundancy exists (e.g., repeating 'degrees' for heading/pitch).

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 complex tool with 10 parameters, no annotations, and no output schema, the description is largely complete, covering purpose, parameters, returns, and errors. However, it lacks details on output format beyond 'Image' and doesn't address potential network or API limitations.

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?

Given 0% schema description coverage, the description fully compensates by providing detailed semantics for all 10 parameters, including examples, constraints (e.g., '0-360' for heading), and defaults where applicable, adding significant value beyond the bare schema.

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 tool's purpose with specific verbs ('fetch', 'save to file') and resources ('Street View image'), and distinguishes it from sibling tools like 'get_metadata' or 'open_image_locally' by emphasizing image retrieval and file saving.

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

Usage Guidelines3/5

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

The description implies usage through parameter explanations (e.g., location vs. lat_lng vs. pano_id) but lacks explicit guidance on when to use this tool versus alternatives like 'get_metadata' or 'open_image_locally'. No exclusions or prerequisites are mentioned.

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/vlad-ds/street-view-mcp'

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