๐ŸŒ Planetary Explorer MCP Server - Template & Deployment Guide

June 11, 2026 ยท View on GitHub

๐Ÿ“˜ What is MCP (Model Context Protocol)?

Model Context Protocol (MCP) is a standard protocol developed by Anthropic that enables AI assistants (like Claude, GitHub Copilot, or custom agents) to interact with external services in a rich, context-aware manner.

Why MCP vs Traditional APIs?

FeatureTraditional REST APIMCP Server
ContextโŒ Stateless, no memoryโœ… Multi-turn conversations with preserved context
DiscoveryโŒ Static OpenAPI specsโœ… Dynamic capability discovery
ResourcesโŒ Manual data fetchingโœ… Direct access to datasets/catalogs
PromptsโŒ Generic responsesโœ… Domain-specific expert personas
IntegrationManual code for each AIStandard protocol works with all MCP clients

๐Ÿ—๏ธ Architecture Overview

The MCP Request/Response Flow

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ 1. CLIENT (GitHub Copilot in VS Code)                            โ”‚
โ”‚    User in Copilot Chat: "Show me the most recent satellite      โ”‚
โ”‚    data of NYC"                                                  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                 โ”‚
                 โ”‚ Sends MCP Request:
                 โ”‚ {
                 โ”‚   "method": "tools/call",
                 โ”‚   "params": {
                 โ”‚     "name": "analyze_satellite_imagery",
                 โ”‚     "arguments": {
                 โ”‚       "query": "most recent satellite data",
                 โ”‚       "location": "New York City, NY",
                 โ”‚       "timeframe": "2025-10-01/2025-10-29"
                 โ”‚     }
                 โ”‚   }
                 โ”‚ }
                 โ”‚
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ 2. HOST/TRANSPORT (VS Code MCP Extension)                        โ”‚
โ”‚    - Receives JSON-RPC message from Copilot                      โ”‚
โ”‚    - Handles authentication (if HTTP)                            โ”‚
โ”‚    - Routes to Planetary Explorer MCP server                          โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                 โ”‚
                 โ”‚
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ 3. SERVER (Planetary Explorer MCP Server)                             โ”‚
โ”‚    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”‚
โ”‚    โ”‚ server.py                                               โ”‚   โ”‚
โ”‚    โ”‚ - Parses MCP request                                    โ”‚   โ”‚
โ”‚    โ”‚ - Validates parameters (location: NYC, timeframe)       โ”‚   โ”‚
โ”‚    โ”‚ - Calls analyze_satellite_imagery handler               โ”‚   โ”‚
โ”‚    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ”‚
โ”‚                   โ”‚                                              โ”‚
โ”‚                   โ”‚ HTTP POST to Container App                   โ”‚
โ”‚                   โ”‚                                              โ”‚
โ”‚    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”‚
โ”‚    โ”‚ Planetary Explorer FastAPI Container App                     โ”‚   โ”‚
โ”‚    โ”‚ - /api/query endpoint                                   โ”‚   โ”‚
โ”‚    โ”‚ - Agent 1-5 processing pipeline                         โ”‚   โ”‚
โ”‚    โ”‚ - STAC API queries (Sentinel-2, Landsat-9)              โ”‚   โ”‚
โ”‚    โ”‚ - Returns STAC metadata (no map rendering)              โ”‚   โ”‚
โ”‚    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ”‚
โ”‚                   โ”‚                                              โ”‚
โ”‚    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”‚
โ”‚    โ”‚ MCP Server Formats Response                             โ”‚   โ”‚
โ”‚    โ”‚ โŒ NO map UI (MCP context - no web frontend)           โ”‚   โ”‚
โ”‚    โ”‚ โœ… Text summaries (dataset names, dates, metadata)     โ”‚   โ”‚
โ”‚    โ”‚ โœ… Image URLs (static map previews, thumbnails)        โ”‚   โ”‚
โ”‚    โ”‚ โœ… Clickable links (open in browser, download)         โ”‚   โ”‚
โ”‚    โ”‚ โœ… Structured data (JSON for follow-up queries)        โ”‚   โ”‚
โ”‚    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                 โ”‚
                 โ”‚ Returns MCP Response:
                 โ”‚ {
                 โ”‚   "result": {
                 โ”‚     "content": [
                 โ”‚       {
                 โ”‚         "type": "text",
                 โ”‚         "text": "Found recent satellite data for NYC:\n
                 โ”‚                  โ€ข Sentinel-2: Oct 27, 2025 (5% clouds)\n
                 โ”‚                  โ€ข Landsat-9: Oct 25, 2025 (12% clouds)\n
                 โ”‚                  ๐Ÿ“Š View static map: [Preview URL]"
                 โ”‚       },
                 โ”‚       {
                 โ”‚         "type": "image",
                 โ”‚         "data": "https://titiler.../preview.png",
                 โ”‚         "mimeType": "image/png"
                 โ”‚       },
                 โ”‚       {
                 โ”‚         "type": "resource",
                 โ”‚         "resource": {
                 โ”‚           "uri": "earth://stac/sentinel-2/...",
                 โ”‚           "mimeType": "application/json"
                 โ”‚         }
                 โ”‚       }
                 โ”‚     ]
                 โ”‚   }
                 โ”‚ }
                 โ”‚
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ 4. CLIENT (GitHub Copilot displays result in VS Code)           โ”‚
โ”‚    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”‚
โ”‚    โ”‚ ๐Ÿค– GitHub Copilot Chat Panel                           โ”‚   โ”‚
โ”‚    โ”‚                                                         โ”‚   โ”‚
โ”‚    โ”‚ I found recent satellite data for New York City:       โ”‚   โ”‚
โ”‚    โ”‚                                                         โ”‚   โ”‚
โ”‚    โ”‚ **Sentinel-2** (Oct 27, 2025)                          โ”‚   โ”‚
โ”‚    โ”‚ โ€ข Cloud cover: 5%                                       โ”‚   โ”‚
โ”‚    โ”‚ โ€ข Resolution: 10m                                       โ”‚   โ”‚
โ”‚    โ”‚ โ€ข Bands: RGB + NIR                                      โ”‚   โ”‚
โ”‚    โ”‚                                                         โ”‚   โ”‚
โ”‚    โ”‚ [Static Map Preview Image Displayed]                   โ”‚   โ”‚
โ”‚    โ”‚                                                         โ”‚   โ”‚
โ”‚    โ”‚ **Landsat-9** (Oct 25, 2025)                           โ”‚   โ”‚
โ”‚    โ”‚ โ€ข Cloud cover: 12%                                      โ”‚   โ”‚
โ”‚    โ”‚ โ€ข Resolution: 30m                                       โ”‚   โ”‚
โ”‚    โ”‚                                                         โ”‚   โ”‚
โ”‚    โ”‚ ๐Ÿ”— Open interactive map in browser                      โ”‚   โ”‚
โ”‚    โ”‚ ๐Ÿ”— Download GeoTIFF                                     โ”‚   โ”‚
โ”‚    โ”‚                                                         โ”‚   โ”‚
โ”‚    โ”‚ Would you like me to analyze these images?             โ”‚   โ”‚
โ”‚    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ”‚
โ”‚                                                                  โ”‚
โ”‚    ๐Ÿ“ Note: MCP context = chat-based interface only              โ”‚
โ”‚       โ€ข No interactive map widget in VS Code                     โ”‚
โ”‚       โ€ข Static map images embedded in chat                       โ”‚
โ”‚       โ€ข Links to open full Planetary Explorer web UI                 โ”‚
โ”‚                                                                  โ”‚
โ”‚    User can ask follow-up questions:                             โ”‚
โ”‚    "Show me the Sentinel-2 image"                                โ”‚
โ”‚    "Analyze vegetation in Central Park"                          โ”‚
โ”‚    "Compare these dates for change detection"                    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

How the User Sees the Response:

The user types their question in the VS Code Copilot Chat panel (accessed via Ctrl+I or the chat icon). GitHub Copilot:

  1. Receives the query from the user
  2. Identifies that it needs satellite data (recognizes Planetary Explorer MCP server capability)
  3. Calls the MCP server using the appropriate tool
  4. Receives structured data (dates, cloud cover, metadata, image URLs)
  5. Formats a chat response in the VS Code chat window with:
    • โœ… Text summaries (natural language descriptions)
    • โœ… Static map images (embedded PNG/JPEG previews)
    • โœ… Clickable links (to open full Planetary Explorer web UI, download data)
    • โœ… Structured metadata (for follow-up queries)
    • โŒ NO interactive map UI (VS Code Copilot Chat is text-based)
  6. Preserves context so follow-up questions automatically reference the previous results

Key Difference: MCP vs Web UI

FeaturePlanetary Explorer Web UIMCP in VS Code Copilot
Interactive Mapโœ… Leaflet/Azure MapsโŒ Not available
Map Renderingโœ… Dynamic tile layersโŒ Static images only
Chat Interfaceโœ… Custom chat panelโœ… VS Code chat panel
Static Previewsโœ… Thumbnailsโœ… Embedded images
Data Accessโœ… Full STAC resultsโœ… Full STAC results
Follow-up Contextโœ… Preservedโœ… Preserved
External Linksโœ… Open datasetsโœ… Open in browser

Example MCP Response Content:

  • Text: "Found Sentinel-2 imagery for Seattle (Oct 27, 2025, 5% cloud cover)"
  • Image: Static map preview PNG (via TiTiler or similar)
  • Links: "Open interactive map in Planetary Explorer web UI", "Download GeoTIFF"
  • Metadata: JSON with STAC item details for programmatic access

The response appears in the Copilot Chat panel as formatted markdown with embedded actions, making it easy for the user to explore the data without leaving VS Code.


---

### ๐Ÿ”— MCP Tool-to-API Mapping

Each MCP tool corresponds to a specific backend API endpoint in the Planetary Explorer Container App. All backend APIs are hosted in **Azure Container Apps** for scalability and reliability.

| MCP Tool | Backend API Endpoint | Status | Description |
|----------|---------------------|--------|-------------|
| `analyze_satellite_imagery` | `/api/query` | โœ… **Working** | General search box queries - routes through agent pipeline |
| `terrain_analysis` | `/api/geoint/terrain` | โœ… **Working** | Pin drop module #1 - terrain elevation, slope, aspect analysis |
| `comparison_analysis` | `/api/geoint/comparison` | โœ… **Working** | Pin drop module #4 - temporal change detection |
| `mobility_analysis` | `/api/geoint/mobility` | ๐Ÿšง **Coming Up** | Pin drop module #2 - trafficability and mobility assessment |
| `building_damage_analysis` | `/api/geoint/building-damage` | ๐Ÿšง **Coming Up** | Pin drop module #3 - structural damage detection |
| `animation_generation` | `/api/geoint/animation` | ๐Ÿšง **Coming Up** | Pin drop module #5 - time-lapse satellite animation |

**๐Ÿ“– Full Tool Definitions**: See the [MCP Capabilities](#-mcp-capabilities-explained) section below for complete parameter schemas and usage examples.

**What are MCP tools?** MCP tools are callable functions exposed by the MCP server that AI assistants can invoke. In Planetary Explorer's implementation, each tool acts as a wrapper that calls a specific backend API endpoint in the Planetary Explorer Container App. This 1:1 mapping keeps the architecture simple and maintainable.

For example: 

โœ… analyze_satellite_imagery** 
Maps to:** `/api/query` (Main search box queries)

```json
{
  "name": "analyze_satellite_imagery",
  "description": "Analyze satellite imagery for specific locations and timeframes using STAC collections",
  "parameters": {
    "query": {
      "type": "string",
      "description": "Natural language query describing the analysis needed",
      "required": true
    },
    "location": {
      "type": "string",
      "description": "Geographic location (place name, coordinates, or bounding box)",
      "required": true
    },
    "timeframe": {
      "type": "string",
      "description": "Time period for analysis (e.g., '2023-01-01/2023-12-31')"
    },
    "collections": {
      "type": "array",
      "items": ["landsat-8", "sentinel-2", "modis"],
      "description": "STAC collections to use"
    },
    "analysis_type": {
      "type": "string",
      "enum": ["change_detection", "environmental_monitoring", "disaster_assessment", "vegetation_analysis"],
      "description": "Type of analysis to perform"
    }
  }
}

Implementation: โœ… Fully working - calls /api/query endpoint which routes through the agent pipeline (semantic translator, collection mapper, datetime translator, etc.)


๐Ÿš€ Getting Started

Quick Setup (5 minutes)

Want to get the MCP server running immediately? See the Quick Start Guide for:

  • Installation steps
  • Basic configuration
  • Running the server locally or in Azure
  • Testing your deployment

Deploy to Azure (15 minutes)

Ready to deploy to production? See the Deployment & Testing Guide for:

  • Docker containerization
  • Azure Container Apps deployment
  • Comprehensive testing suite
  • Monitoring and troubleshooting

Quick deploy:

cd planetary-explorer/mcp-server
.\quick-deploy.ps1 -ResourceGroup "planetary-explorer-rg" -PlanetaryExplorerBackendUrl "https://your-backend.azurecontainerapps.io"

Connect AI Clients

Once your server is running, connect your AI assistant. See the Client Connection Guide for detailed instructions on:

  • Claude Desktop - Chat with your satellite data
  • GitHub Copilot - Geospatial intelligence in VS Code
  • Custom Python/TypeScript clients - Build your own integrations
  • REST API - HTTP-based access for any application

Deployment Options Summary

OptionBest ForSetup TimeGuide
Local (stdio)Development, testing, VS Code5 minQuick Start
HTTP ServerWeb apps, remote access10 minQuick Start
Azure Container AppsProduction, scalability15 minDeployment Scripts
Azure APIMEnterprise, multiple consumers30 minAPIM Guide

๐Ÿ—‚๏ธ MCP Capabilities Explained

The Planetary Explorer MCP Server exposes three types of capabilities to AI assistants:

1. Tools (Callable Actions)

See the Tool-to-API Mapping table above for all 6 tools. Tools are functions the AI can call to perform analysis:

  • analyze_satellite_imagery - Search and analyze satellite data
  • terrain_analysis - Analyze terrain features (elevation, slope, aspect)
  • comparison_analysis - Compare imagery across time periods
  • mobility_analysis, building_damage_analysis, animation_generation - Coming up!

2. Resources (Direct Data Access)

Resources let AI assistants read data directly without calling a function. When an AI connects to this MCP server, it can:

  • Browse available resources - List all 6 resources exposed by the server
  • Read STAC collection metadata - Get details about Landsat-8, Sentinel-2, MODIS datasets
  • Access elevation data info - Learn about Copernicus DEM specifications
  • Discover analysis capabilities - See what tools and parameters are available
  • Retrieve conversation context - Access previous queries for multi-turn conversations

Available Resources:

// STAC satellite collections
earth://stac/sentinel-2      // ESA Sentinel-2 multi-spectral imagery (10m resolution)
earth://stac/landsat-8       // NASA/USGS Landsat-8 global coverage
earth://stac/modis           // NASA MODIS environmental monitoring

// Elevation data
earth://elevation/copernicus-dem  // Global Digital Elevation Model

// Server metadata
earth://analysis/capabilities     // List of available analysis tools
earth://context/{conversation_id} // Preserved context for multi-turn chat

Example Usage:

User: "What Sentinel-2 data is available?"

AI: *Reads resource earth://stac/sentinel-2*

AI: "Sentinel-2 provides 13 spectral bands at 10-60m resolution, 
     covering global land and coastal areas since 2015. The collection
     includes multispectral imagery optimized for land monitoring,
     with revisit time of 5 days at the equator..."

How Resources Work:

  1. AI calls list_resources() to see what's available
  2. AI picks a resource URI (e.g., earth://stac/sentinel-2)
  3. AI calls read_resource(uri) to get the data
  4. MCP server returns metadata as text/JSON without calling backend APIs

This is faster than tools because resources are read-only metadata that the MCP server can return immediately without backend processing.


๐Ÿš€ Deployment Options (Step 1: Run the MCP Server)

These options determine WHERE and HOW the MCP server itself runs. Choose based on your environment and scale needs. The server must be running before AI clients can connect to it.

Option 1: Local Development (stdio transport)

Best for: Testing, development, VS Code integration

# 1. Install dependencies
cd planetary-explorer/mcp-server
pip install -r requirements.txt

# 2. Configure environment
cp .env.example .env
# Edit .env with your Planetary Explorer backend URL

# 3. Run MCP server
python server.py

# 4. Connect from VS Code
# Add to VS Code settings.json:
{
  "mcp.servers": {
    "planetary-explorer": {
      "command": "python",
      "args": ["server.py"],
      "cwd": "/path/to/planetary-explorer/mcp-server"
    }
  }
}

Option 2: HTTP Server (FastAPI bridge)

Best for: Web apps, REST API consumers, remote access

# 1. Run HTTP bridge
uvicorn mcp_bridge:app --host 0.0.0.0 --port 8080

# 2. Test with curl
curl -X POST http://localhost:8080/tools/list

# 3. Integrate with any HTTP client
fetch("http://localhost:8080/analysis/satellite", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    query: "Show me wildfires in California",
    location: "California",
    timeframe: "2024-08-01/2024-08-31"
  })
})

Best for: Enterprise deployment, scalability, security

# 1. Deploy to Azure Container Apps
az containerapp create `
  --name planetary-explorer-mcp `
  --resource-group planetary-explorer-rg `
  --environment your-container-env `
  --image mcr.microsoft.com/azuredocs/containerapps-helloworld:latest `
  --target-port 8080 `
  --ingress external `
  --query properties.configuration.ingress.fqdn

# 2. Configure your backend URLs (Container App environment variables)
az containerapp update `
  --name planetary-explorer-mcp `
  --resource-group planetary-explorer-rg `
  --set-env-vars `
    PLANETARY_EXPLORER_BASE_URL=https://your-backend-container.azurecontainerapps.io `
    GEOINT_SERVICE_URL=https://your-geoint-container.azurecontainerapps.io

# 3. Get your endpoint
# Output: https://planetary-explorer-mcp.azurecontainerapps.io

Option 4: Azure API Management (Enterprise)

Best for: Multiple consumers, rate limiting, monetization

Adds:

  • OAuth 2.0 authentication
  • Rate limiting per subscriber
  • Response caching
  • Analytics dashboard
  • Developer portal
# Deploy APIM pointing to your Container App
cd apim
.\deploy-apim.ps1 `
  -ResourceGroupName "planetary-explorer-rg" `
  -ApimServiceName "planetary-explorer-api" `
  -PublisherEmail "admin@yourcompany.com" `
  -PublisherName "Your Company" `
  -McpServerUrl "https://planetary-explorer-mcp.azurecontainerapps.io"

# Result:
# MCP Server: https://planetary-explorer-mcp.azurecontainerapps.io
# APIM Gateway: https://planetary-explorer-api.azure-api.net/planetary-explorer/mcp
# Developer Portal: https://planetary-explorer-api.developer.azure-api.net

๐Ÿ”Œ Integration Examples (Step 2: Connect AI Clients)

Once your MCP server is running (from Step 1), connect AI assistants to it. These examples show how different AI clients discover and use your MCP server's capabilities.

For GitHub Copilot

What this does: Enables GitHub Copilot in VS Code to call your MCP server for satellite data analysis.

Create .github/copilot/mcp-servers.json:

{
  "planetary-explorer": {
    "type": "http",
    "url": "https://my-planetary-explorer-mcp.azurewebsites.net",
    "headers": {
      "Ocp-Apim-Subscription-Key": "${APIM_KEY}"
    }
  }
}

Then in VS Code:

# User comment: "Get Sentinel-2 imagery of Seattle with low clouds"

# Copilot: *Calls MCP server via HTTP*
response = await planetary_explorer_client.call_tool(
    "analyze_satellite_imagery",
    {
        "query": "Sentinel-2 imagery of Seattle",
        "location": "Seattle, WA",
        "timeframe": "2024-10-01/2024-10-31",
        "collections": ["sentinel-2"],
        "cloud_cover_max": 10
    }
)

For Claude Desktop

What this does: Configures Claude Desktop app to use your MCP server for geospatial queries.

Create claude_desktop_config.json:

{
  "mcpServers": {
    "planetary-explorer": {
      "command": "python",
      "args": ["/path/to/planetary-explorer/mcp-server/server.py"],
      "env": {
        "PLANETARY_EXPLORER_BASE_URL": "https://your-backend.azurewebsites.net"
      }
    }
  }
}

Then in Claude Desktop:

You: Show me recent wildfire activity in California

Claude: *Uses analyze_satellite_imagery tool*
I found 22 active fire detections in California from MODIS data...
[Shows map visualization]

You: What's the terrain like in those areas?

Claude: *Uses terrain_analysis tool with context from previous query*
The affected areas have steep terrain with slopes averaging 25-35 degrees...

For Custom Agent Framework

What this does: Shows how to build your own Python application that connects to the MCP server.

from mcp_client import MCPClient

# Initialize MCP client
client = MCPClient("https://my-planetary-explorer-mcp.azurewebsites.net")

# List available tools
tools = await client.list_tools()
print(f"Available tools: {[t.name for t in tools]}")

# Execute terrain analysis
result = await client.call_tool(
    "terrain_analysis",
    {
        "location": "Grand Canyon, Arizona",
        "analysis_types": ["slope", "aspect", "hillshade"],
        "resolution": 30
    }
)

# Access STAC resources
sentinel2_info = await client.read_resource("earth://stac/sentinel-2")
print(f"Sentinel-2 info: {sentinel2_info}")

# Use specialized prompt
expert_context = await client.get_prompt(
    "geospatial_expert",
    {"specialization": "environmental"}
)
# AI now has environmental geospatial expert persona

๐Ÿ“ Template Structure

planetary-explorer/mcp-server/
โ”œโ”€โ”€ server.py                 # Core MCP server implementation
โ”œโ”€โ”€ mcp_bridge.py            # HTTP/REST adapter
โ”œโ”€โ”€ requirements.txt          # Python dependencies
โ”œโ”€โ”€ package.json             # MCP metadata and capabilities
โ”œโ”€โ”€ .env.example             # Environment template
โ”œโ”€โ”€ deploy-mcp-server.ps1    # Azure deployment script
โ”œโ”€โ”€ MCP_IMPLEMENTATION_GUIDE.md  # Detailed docs
โ”œโ”€โ”€ README.md                # This file
โ”œโ”€โ”€ __init__.py              # Python module init
โ””โ”€โ”€ apim/
    โ”œโ”€โ”€ deploy-apim.ps1      # APIM deployment
    โ””โ”€โ”€ apim-template.json   # APIM ARM template

โš™๏ธ Configuration Guide

Environment Variables

Create .env file:

# Planetary Explorer Backend
PLANETARY_EXPLORER_BASE_URL=https://your-planetary-explorer-backend.azurewebsites.net
GEOINT_SERVICE_URL=https://your-geoint-app.azurewebsites.net

# Azure Integration (for production)
APPLICATIONINSIGHTS_CONNECTION_STRING=InstrumentationKey=xxx
AZURE_CLIENT_ID=your-app-registration-id
AZURE_CLIENT_SECRET=your-secret
AZURE_TENANT_ID=your-tenant-id

# Server Configuration
MCP_SERVER_MODE=production  # or development
HOST=0.0.0.0
PORT=8080

# Optional: APIM
APIM_SUBSCRIPTION_KEY=your-subscription-key

๐Ÿงช Testing Your MCP Server

1. Test Tools Endpoint

# List available tools
curl -X POST http://localhost:8080/tools/list

# Expected output:
{
  "tools": [
    {
      "name": "analyze_satellite_imagery",
      "description": "Analyze satellite imagery...",
      "inputSchema": {...}
    },
    ...
  ]
}

2. Test Tool Execution

# Execute satellite analysis
curl -X POST http://localhost:8080/tools/call \
  -H "Content-Type: application/json" \
  -d '{
    "name": "analyze_satellite_imagery",
    "arguments": {
      "query": "Show me wildfires in California",
      "location": "California",
      "timeframe": "2024-08-01/2024-08-31"
    }
  }'

# Expected output:
{
  "result": {
    "content": [
      {
        "type": "text",
        "text": "Found 22 MODIS fire features in California..."
      },
      {
        "type": "image",
        "data": "https://titiler.../map.png"
      }
    ]
  }
}

3. Test Resources

# Read STAC collection info
curl -X POST http://localhost:8080/resources/read \
  -H "Content-Type: application/json" \
  -d '{
    "uri": "earth://stac/sentinel-2"
  }'

# Expected output:
{
  "contents": [
    {
      "type": "text",
      "text": "Sentinel-2 Level-2A Collection\nResolution: 10-60m\nCoverage: Global..."
    }
  ]
}

๐ŸŽ“ Tutorial: Create Your Own MCP Server Template

Step 1: Clone This Template

# Clone Planetary Explorer repo
git clone https://github.com/microsoft/Planetary-Explorer
cd Planetary-Explorer/planetary-explorer/mcp-server

# Create your own MCP server folder
mkdir ../my-geospatial-mcp
cp -r * ../my-geospatial-mcp/
cd ../my-geospatial-mcp

Step 2: Customize Your Tools

Edit server.py:

# Add your custom tool
Tool(
    name="my_custom_analysis",
    description="My custom geospatial analysis",
    inputSchema={
        "type": "object",
        "properties": {
            "location": {"type": "string"},
            "custom_param": {"type": "string"}
        },
        "required": ["location"]
    }
)

# Add your custom tool handler
@self.server.call_tool()
async def handle_call_tool(name: str, arguments: dict):
    if name == "my_custom_analysis":
        return await self._my_custom_analysis(arguments)

Step 3: Add Your Resources

# Add custom resource
Resource(
    uri="myapp://data/custom-collection",
    name="My Custom Data",
    description="Description of my custom dataset",
    mimeType="application/json"
)

# Add custom resource handler
@self.server.read_resource()
async def handle_read_resource(uri: str):
    if uri.startswith("myapp://data/"):
        return await self._read_custom_data(uri)

Step 4: Deploy Your MCP Server

# Deploy to Azure Container Apps
az containerapp create `
  --name my-geospatial-mcp `
  --resource-group my-geospatial-rg `
  --environment my-container-env `
  --image your-registry.azurecr.io/my-geospatial-mcp:latest `
  --target-port 8080 `
  --ingress external

Step 5: Share Your Template

# Create template package
cp server.py my-template/
cp mcp_bridge.py my-template/
cp requirements.txt my-template/
cp README.md my-template/

# Publish to GitHub
cd my-template
git init
git add .
git commit -m "Initial MCP server template"
git push origin main

๐Ÿ” Security Best Practices

1. Authentication

For HTTP deployments, always use authentication:

# In mcp_bridge.py
from fastapi import Depends, HTTPException, Header

async def verify_api_key(x_api_key: str = Header()):
    if x_api_key != os.getenv("API_KEY"):
        raise HTTPException(status_code=401, detail="Invalid API key")
    return x_api_key

# Protect endpoints
@app.post("/tools/call", dependencies=[Depends(verify_api_key)])
async def call_tool(request: ToolCallRequest):
    ...

2. Rate Limiting

Use APIM or implement custom rate limiting:

from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address

limiter = Limiter(key_func=get_remote_address)
app.state.limiter = limiter

@app.post("/tools/call")
@limiter.limit("100/minute")
async def call_tool(request: Request, tool_request: ToolCallRequest):
    ...

3. Input Validation

Always validate user inputs:

from pydantic import BaseModel, Field, validator

class AnalysisRequest(BaseModel):
    query: str = Field(..., max_length=500)
    location: str = Field(..., max_length=200)
    
    @validator('query')
    def validate_query(cls, v):
        # Prevent injection attacks
        if any(char in v for char in ['<', '>', ';', '&']):
            raise ValueError("Invalid characters in query")
        return v

๐Ÿ“Š Monitoring & Analytics

Application Insights Integration

# In server.py
from opencensus.ext.azure.log_exporter import AzureLogHandler
import logging

# Configure logging
logger = logging.getLogger(__name__)
logger.addHandler(AzureLogHandler(
    connection_string=os.getenv('APPLICATIONINSIGHTS_CONNECTION_STRING')
))

# Log tool calls
logger.info(f"Tool called: {tool_name}", extra={
    'custom_dimensions': {
        'tool': tool_name,
        'arguments': arguments,
        'user_id': user_id
    }
})

Key Metrics to Track

// Tool usage analysis
requests
| where url contains "/tools/call"
| extend toolName = tostring(customDimensions.tool)
| summarize count() by toolName, bin(timestamp, 1h)
| render timechart

// Performance monitoring
requests
| summarize 
    avg(duration), 
    percentile(duration, 95),
    count() 
    by operation_Name

๐Ÿ†˜ Troubleshooting

Common Issues

Issue: MCP server not responding

# Check if server is running
curl http://localhost:8080/health

# Check logs
tail -f logs/mcp-server.log

Issue: Tool execution fails

# Add detailed error logging
try:
    result = await execute_tool(name, arguments)
except Exception as e:
    logger.error(f"Tool execution failed: {str(e)}", exc_info=True)
    raise

Issue: Resource not found

# Verify resource URI format
logger.info(f"Attempting to read resource: {uri}")
parsed = urlparse(uri)
logger.info(f"Parsed URI - scheme: {parsed.scheme}, path: {parsed.path}")

๐Ÿ“š Additional Resources

  • MCP Specification: https://modelcontextprotocol.io/
  • Planetary Explorer Docs: ../documentation/
  • STAC Collections: ../documentation/data_collections/STAC_COLLECTIONS.md
  • Agent System: ../documentation/app_workflow/AGENT_SYSTEM_OVERVIEW.md

๐Ÿ’ก Use Cases

1. Claude Desktop Integration

Users chat with Claude to analyze satellite imagery without leaving the desktop app.

2. VS Code Extension

Developers get geospatial code suggestions powered by real satellite data.

3. Custom Agent Orchestration

Multi-agent systems route geospatial queries to Planetary Explorer MCP server.

4. Automated Workflows

CI/CD pipelines use MCP server for environmental compliance checks.

5. Research & Education

Students access Earth observation data through conversational interfaces.


๐Ÿš€ Next Steps

  1. Deploy the template to your Azure subscription
  2. Connect your AI assistant (Claude/Copilot)
  3. Test with example queries
  4. Customize tools for your use case
  5. Share your MCP server with others!

Questions? Check the MCP Implementation Guide or open an issue on GitHub.

License: MIT
Maintainer: Planetary Explorer Team