MCP Hub
Back to servers

Weather MCP Server

Enables secure retrieval of real-time weather data for any location via Open-Meteo using AWS Cognito OAuth 2.1 Bearer token authentication. Implements full MCP Authorization Specification with dynamic client registration and protected resource metadata discovery.

glama
Updated
Apr 4, 2026

Weather MCP Server

A Model Context Protocol server that provides real-time weather data, secured with AWS Cognito OAuth 2.1 Bearer token authentication.

Implements the full MCP Authorization Specification (2025-11-25):

  • RFC 9728 — Protected Resource Metadata (PRM) discovery
  • RFC 6750 — Bearer token usage
  • RFC 7591 — Dynamic Client Registration (DCR) bridged to Cognito

Architecture

Client / AI Agent
  │
  ├─ GET  /.well-known/oauth-protected-resource   → discover auth server
  ├─ POST /register                               → dynamic client registration (optional)
  ├─ POST Cognito /oauth2/token                   → exchange credentials for JWT
  └─ POST /mcp   Authorization: Bearer <token>    → call MCP tools

Weather data is sourced from Open-Meteo — free, no API key required.


Project Structure

weather-mcp/
├── weather_mcp/
│   ├── __init__.py
│   ├── config.py       # All env var loading (COGNITO_*, SERVER_URL)
│   ├── auth.py         # JWT validation, middleware, PRM + DCR handlers
│   ├── tools.py        # MCP instance + weather tools
│   └── main.py         # Starlette app factory + uvicorn entrypoint
├── infra/
│   └── cognito.yaml    # CloudFormation — Cognito User Pool, App Client
├── pyproject.toml
├── Dockerfile
├── .env.example
└── README.md

Prerequisites

  • Python 3.13+ and uv
  • AWS account with CLI configured (aws configure)
  • Docker (optional, for containerised deployment)

Quick Start

1 — Deploy AWS Cognito

aws cloudformation deploy \
  --template-file infra/cognito.yaml \
  --stack-name weather-mcp \
  --region us-east-1 \
  --capabilities CAPABILITY_NAMED_IAM

Get the output values:

aws cloudformation describe-stacks \
  --stack-name weather-mcp \
  --query "Stacks[0].Outputs" \
  --output table

2 — Configure environment

cp .env.example .env
# Fill in the values from the CloudFormation Outputs

3 — Run

Locally:

uv sync
uv run python -m weather_mcp.main

Docker:

docker build -t weather-mcp:local .
docker run --env-file .env -p 8000:8000 weather-mcp:local

Server starts at http://localhost:8000.


API Endpoints

EndpointAuthDescription
GET /healthNoneHealth check
GET /.well-known/oauth-protected-resourceNoneRFC 9728 discovery document
POST /registerNoneRFC 7591 Dynamic Client Registration
POST /mcpBearer tokenMCP tools (streamable HTTP)

MCP Tools

ToolDescription
get_current_weatherCurrent weather for any location by latitude/longitude

Usage

Option A — Static credentials (pre-registered client)

# 1. Get a token
TOKEN=$(curl -s -X POST \
  https://weather-mcp-auth.auth.us-east-1.amazoncognito.com/oauth2/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials&client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET&scope=weather-mcp/read" \
  | python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])")

# 2. List tools
curl -s -X POST http://localhost:8000/mcp \
  -H "Authorization: Bearer $TOKEN" \
  -H "Accept: application/json, text/event-stream" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"tools/list","id":1}'

# 3. Call the weather tool
curl -s -X POST http://localhost:8000/mcp \
  -H "Authorization: Bearer $TOKEN" \
  -H "Accept: application/json, text/event-stream" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"tools/call","id":2,"params":{"name":"get_current_weather","arguments":{"latitude":37.77,"longitude":-122.42}}}'

Option B — Dynamic Client Registration (zero pre-configuration)

# 1. Register a new client
CREDS=$(curl -s -X POST http://localhost:8000/register \
  -H "Content-Type: application/json" \
  -d '{"client_name":"my-agent","grant_types":["client_credentials"],"scope":"weather-mcp/read"}')

CLIENT_ID=$(echo $CREDS | python3 -c "import sys,json; print(json.load(sys.stdin)['client_id'])")
CLIENT_SECRET=$(echo $CREDS | python3 -c "import sys,json; print(json.load(sys.stdin)['client_secret'])")

# 2. Get a token with the new client
TOKEN=$(curl -s -X POST \
  https://weather-mcp-auth.auth.us-east-1.amazoncognito.com/oauth2/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials&client_id=$CLIENT_ID&client_secret=$CLIENT_SECRET&scope=weather-mcp/read" \
  | python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])")

# 3. Call MCP
curl -s -X POST http://localhost:8000/mcp \
  -H "Authorization: Bearer $TOKEN" \
  -H "Accept: application/json, text/event-stream" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"tools/list","id":1}'

Environment Variables

VariableDescription
COGNITO_REGIONAWS region (e.g. us-east-1)
COGNITO_USER_POOL_IDCognito User Pool ID
COGNITO_APP_CLIENT_IDApp Client ID for token audience validation
COGNITO_DOMAIN_PREFIXHosted-UI domain prefix
SERVER_URLPublic URL of this server (default: http://localhost:8000)

How Authentication Works

  1. A request arrives at /mcp without a token → server responds with 401 and a WWW-Authenticate header pointing to /.well-known/oauth-protected-resource
  2. The client fetches the discovery document to find the Cognito authorization server
  3. The client obtains a JWT access token from Cognito (via client_credentials or Dynamic Client Registration)
  4. The client includes Authorization: Bearer <token> on subsequent requests
  5. The middleware validates the JWT signature against Cognito's JWKS endpoint (RS256, cached 1 hour)

Reviews

No reviews yet

Sign in to write a review