๐ 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?
| Feature | Traditional REST API | MCP 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 |
| Integration | Manual code for each AI | Standard 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:
- Receives the query from the user
- Identifies that it needs satellite data (recognizes Planetary Explorer MCP server capability)
- Calls the MCP server using the appropriate tool
- Receives structured data (dates, cloud cover, metadata, image URLs)
- 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)
- Preserves context so follow-up questions automatically reference the previous results
Key Difference: MCP vs Web UI
| Feature | Planetary Explorer Web UI | MCP 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
| Option | Best For | Setup Time | Guide |
|---|---|---|---|
| Local (stdio) | Development, testing, VS Code | 5 min | Quick Start |
| HTTP Server | Web apps, remote access | 10 min | Quick Start |
| Azure Container Apps | Production, scalability | 15 min | Deployment Scripts |
| Azure APIM | Enterprise, multiple consumers | 30 min | APIM 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 dataterrain_analysis- Analyze terrain features (elevation, slope, aspect)comparison_analysis- Compare imagery across time periodsmobility_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:
- AI calls
list_resources()to see what's available - AI picks a resource URI (e.g.,
earth://stac/sentinel-2) - AI calls
read_resource(uri)to get the data - 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"
})
})
Option 3: Azure Container App (Recommended for Production)
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
- Deploy the template to your Azure subscription
- Connect your AI assistant (Claude/Copilot)
- Test with example queries
- Customize tools for your use case
- Share your MCP server with others!
Questions? Check the MCP Implementation Guide or open an issue on GitHub.
License: MIT
Maintainer: Planetary Explorer Team