Open Meteo Mcp — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited Open Meteo Mcp (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
mcp-name: io.github.fcto-demos/open_meteo_mcp
A Model Context Protocol (MCP) server that provides weather information using the Open-Meteo API. This server supports multiple transport modes: standard stdio, HTTP Server-Sent Events (SSE), and the new Streamable HTTP protocol for web-based integration.
By default, the MCP server runs without authentication - all endpoints are publicly accessible. This is suitable for:
#### Running in un-secured mode
# stdio mode (default - no authentication available)
python -m open_meteo_mcp
# SSE mode (no authentication)
python -m open_meteo_mcp --mode sse
# Streamable HTTP mode (no authentication)
python -m open_meteo_mcp --mode streamable-httpNo additional configuration is required. The server will log: "Authentication disabled - server is open"
#### Manual Configuration for MCP Clients (for example, Claude Desktop)
This server is designed to be installed manually by adding its configuration to the claude_desktop_config.json file.
[!TIP]
>
We recommend to install and use uv (Python package manager)
mcpServers object in the config file - Make sure to use the full path to the uvx binary (use which uvxon Linux/Mac if you don't know where it was installed.){
"mcpServers": {
"secure-free-meteo": {
"command": "<fullpath_to_uvx>",
"args": [
"secure-free-meteo"
]
},
...
}
}claude_desktop_config.json file.[!NOTE]
>
You will be asked to authorize the usage of the tools you just installed.
For production deployments or when you need to secure your MCP server endpoints, you can enable JWT token authentication using WSO2 Identity Server.
[!IMPORTANT]
>
Authentication is only available in streamable-http mode.#### Requirements
pip install secure-free-meteo[auth]
# or manually:
pip install pyjwt cryptographyInstructions are available in the Asgardeo Setup guide in this repository.
#### Server Configuration
Enable authentication by setting the following environment variables:
Required:
AUTH_ENABLED=true - Enables authenticationWSO2_IS_URL - Your WSO2 IS base URL (e.g., https://your-wso2-is.com or https://api.asgardeo.io/t/{orgName}Optional
WSO2_IS_AUDIENCE - Expected audience claim / client_id for token validation - This is the clientID of the MCP Client application created in IS. This is highly recommended from a security standpoint.WSO2_VERIFY_SSL - Set to false to disable SSL verification (local dev only, default: true)#### Running in Secured Mode
Using environment variables:
# Set environment variables
export AUTH_ENABLED=true
export WSO2_IS_URL="https://your-wso2-is.com"
export WSO2_IS_AUDIENCE="your-client-id"
# Start the server in streamable-http mode
python -m open_meteo_mcp --mode streamable-http --host 0.0.0.0 --port 8080For local development with self-signed certificates:
export AUTH_ENABLED=true
export WSO2_IS_URL="https://localhost:9443"
export WSO2_VERIFY_SSL=false
export WSO2_IS_AUDIENCE="your-client-id"
python -m open_meteo_mcp --mode streamable-http --host 0.0.0.0 --port 8080#### Making Authenticated Requests
When authentication is enabled, all requests to the /mcp endpoint must include a valid JWT Bearer token:
// Get access token from your OAuth2 provider (e.g., client credentials flow)
const accessToken = "your-jwt-access-token";
// Make authenticated request
const response = await fetch('http://localhost:8080/mcp', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${accessToken}`
},
body: JSON.stringify({
jsonrpc: '2.0',
method: 'tools/call',
params: {
name: 'get_current_weather',
arguments: { city: 'Tokyo' }
},
id: 1
})
});Using curl:
# Get access token (example using client credentials)
TOKEN=$(curl -X POST "https://your-wso2-is.com/oauth2/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET" \
| jq -r '.access_token')
# Make authenticated request
curl -X POST "http://localhost:8080/mcp" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "get_current_weather",
"arguments": {"city": "Tokyo"}
},
"id": 1
}'#### Authentication Response Codes
{
"error": "unauthorized",
"message": "Missing Authorization header"
}#### Excluded Endpoints
The following endpoints are excluded from authentication (when configured):
/health - Health check endpoint (if implemented)OPTIONS requests (CORS preflight)| Mode | Authentication Support | Use Case |
|---|---|---|
stdio | Not available | Desktop MCP clients (always un-secured) |
sse | Not available | Web applications (always un-secured) |
streamable-http | Optional (WSO2 IS) | Production web/API deployments |
This server does not require an API key for the weather data. It uses the Open-Meteo API, which is free and open-source.
This server provides several tools for weather and time-related operations:
#### Weather Tools
#### Air Quality Tools
#### Time & Timezone Tools
#### get_current_weather
Retrieves comprehensive current weather information for a given city with enhanced metrics.
Parameters:
city (string, required): The name of the city (English names only)Returns: Detailed weather data including:
Example Response:
The weather in Tokyo is Mainly clear with a temperature of 22.5°C (feels like 21.0°C),
relative humidity at 65%, and dew point at 15.5°C. Wind is blowing from the NE at 12.5 km/h
with gusts up to 18.5 km/h. Atmospheric pressure is 1013.2 hPa with 25% cloud cover.
UV index is 5.5 (Moderate). Visibility is 10.0 km.#### get_weather_by_datetime_range
Retrieves hourly weather information with comprehensive metrics for a specified city between start and end dates.
Parameters:
city (string, required): The name of the city (English names only)start_date (string, required): Start date in format YYYY-MM-DD (ISO 8601)end_date (string, required): End date in format YYYY-MM-DD (ISO 8601)Returns: Comprehensive weather analysis including:
Example Response:
[Analysis of weather trends over 2024-01-01 to 2024-01-07]
- Temperature ranges from 5°C to 15°C
- Precipitation expected on Jan 3rd and 5th (60% probability)
- Wind speeds averaging 15 km/h from SW direction
- UV index moderate (3-5) throughout the period
- Recommendation: Umbrella needed for midweek#### get_weather_details
Get detailed weather information for a specified city as structured JSON data for programmatic use.
Parameters:
city (string, required): The name of the city (English names only)Returns: Raw JSON data with all weather metrics suitable for processing and analysis
#### get_air_quality
Get current air quality information for a specified city with pollutant levels and health advisories.
Parameters:
city (string, required): The name of the city (English names only)variables (array, optional): Specific pollutants to retrieve. Options:pm10 - Particulate matter ≤10μmpm2_5 - Particulate matter ≤2.5μmcarbon_monoxide - CO levelsnitrogen_dioxide - NO2 levelsozone - O3 levelssulphur_dioxide - SO2 levelsammonia - NH3 levelsdust - Dust particle levelsaerosol_optical_depth - Atmospheric turbidityReturns: Comprehensive air quality report including:
Example Response:
Air quality in Beijing (lat: 39.90, lon: 116.41):
PM2.5: 45.3 μg/m³ (Unhealthy for Sensitive Groups)
PM10: 89.2 μg/m³ (Moderate)
Ozone (O3): 52.1 μg/m³
Nitrogen Dioxide (NO2): 38.5 μg/m³
Carbon Monoxide (CO): 420.0 μg/m³
Health Advice: Sensitive groups (children, elderly, people with respiratory conditions)
should limit outdoor activities.#### get_air_quality_details
Get detailed air quality information as structured JSON data for programmatic analysis.
Parameters:
city (string, required): The name of the city (English names only)variables (array, optional): Specific pollutants to retrieve (same options as get_air_quality)Returns: Raw JSON data with complete air quality metrics and hourly data
#### get_current_datetime
Retrieves the current time in a specified timezone.
Parameters:
timezone_name (string, required): IANA timezone name (e.g., 'America/New_York', 'Europe/London'). Use UTC if no timezone provided.Returns: Current date and time in the specified timezone
Example:
{
"timezone": "America/New_York",
"current_time": "2024-01-15T14:30:00-05:00",
"utc_time": "2024-01-15T19:30:00Z"
}#### get_timezone_info
Get information about a specific timezone.
Parameters:
timezone_name (string, required): IANA timezone nameReturns: Timezone details including offset and DST information
#### convert_time
Convert time from one timezone to another.
Parameters:
time_str (string, required): Time to convert (ISO format)from_timezone (string, required): Source timezoneto_timezone (string, required): Target timezoneReturns: Converted time in target timezone
The project includes a React-based MCP Client application that demonstrates how to integrate with the Open Meteo MCP Server using the MCP Streamable HTTP protocol. The client provides a user-friendly web interface for accessing weather and air quality data.
The client application consists of:
Navigate to the weather-client directory and install dependencies:
cd weather-client
npm installCreate a .env file in the weather-client directory with the following variables:
# MCP Server Configuration
VITE_MCP_SERVER_URL=http://localhost:8080
# OAuth2/OIDC Configuration (WSO2 IS or Asgardeo)
VITE_WSO2_IS_URL=https://your-wso2-is.com/oauth2
VITE_WSO2_CLIENT_ID=weather-client
# For Asgardeo (SaaS):
# VITE_WSO2_IS_URL=https://api.asgardeo.io/t/{your-org}/oauth2Configuration Options:
| Variable | Description | Default |
|---|---|---|
VITE_MCP_SERVER_URL | MCP server base URL | http://localhost:8080 |
VITE_WSO2_IS_URL | OAuth2 authority URL | https://localhost:9443/oauth2 |
VITE_WSO2_CLIENT_ID | OAuth2 client ID | weather-client |
#### Development Mode
The client uses Vite for development with hot module replacement:
# Start the development server (default: http://localhost:5173)
npm run devImportant: The Vite dev server proxies /mcp requests to the MCP server, so make sure your MCP server is running:
# In a separate terminal, start the MCP server
python -m open_meteo_mcp --mode streamable-http --host 0.0.0.0 --port 8080#### Production Build
# Build for production
npm run build
# Preview the production build
npm run previewThe client supports OAuth2/OIDC authentication via WSO2 Identity Server or Asgardeo.
#### WSO2 Identity Server Setup
http://localhost:5173/callback (dev), https://your-domain.com/callback (prod)http://localhost:5173 (dev), https://your-domain.com (prod)openid (required)read_airquality or other custom scopes as needed VITE_WSO2_IS_URL=https://your-wso2-is.com/oauth2
VITE_WSO2_CLIENT_ID=your-client-id#### Asgardeo Setup (Cloud)
Asgardeo is WSO2's cloud identity platform:
http://localhost:5173/callbackhttp://localhost:5173 VITE_WSO2_IS_URL=https://api.asgardeo.io/t/{your-org}/oauth2
VITE_WSO2_CLIENT_ID=your-client-idThe client library (mcpClient.ts) provides functions for calling MCP tools.
#### Basic Usage
import {
initializeSession,
getCurrentWeather,
getAirQuality,
callMcpTool
} from './services/mcpClient';
// Initialize the MCP session (required before making tool calls)
await initializeSession(accessToken);
// Get current weather
const weather = await getCurrentWeather('Tokyo', accessToken);
console.log(weather);
// Get air quality with specific variables
const airQuality = await getAirQuality(
'Beijing',
['pm2_5', 'pm10', 'ozone'],
accessToken
);
console.log(airQuality);#### Using React Hooks
The client includes custom React hooks for easy integration:
import { useCurrentWeather } from './hooks/useWeather';
import { useAirQuality } from './hooks/useAirQuality';
function WeatherComponent() {
const { data: weather, isLoading, error } = useCurrentWeather('Tokyo');
const { data: airQuality } = useAirQuality('Tokyo');
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<div>
<h2>Weather in Tokyo</h2>
<p>Temperature: {weather.current_weather.temperature}°C</p>
<p>Humidity: {weather.current_weather.humidity}%</p>
</div>
);
}#### Session Management
`initializeSession(accessToken?: string): Promise<void>`
Initializes the MCP session with the server. Must be called before making tool calls.
accessToken - Optional OAuth2 access token for authentication#### Weather Functions
`getCurrentWeather(city: string, accessToken?: string): Promise<string>`
Get current weather for a city.
`getWeatherDetails(city: string, includeForecast: boolean, accessToken?: string): Promise<string>`
Get detailed weather data as JSON.
`getWeatherByDateRange(city: string, startDate: string, endDate: string, accessToken?: string): Promise<string>`
Get weather for a date range.
#### Air Quality Functions
`getAirQuality(city: string, variables?: string[], accessToken?: string): Promise<string>`
Get air quality information for a city.
variables - Optional array of pollutants: ['pm2_5', 'pm10', 'ozone', 'nitrogen_dioxide', 'carbon_monoxide']`getAirQualityDetails(city: string, variables?: string[], accessToken?: string): Promise<string>`
Get detailed air quality data as JSON.
#### Time Functions
`getCurrentDateTime(timezone: string, accessToken?: string): Promise<string>`
Get current time in a specific timezone.
`getTimezoneInfo(timezone: string, accessToken?: string): Promise<string>`
Get timezone information.
`convertTime(datetime: string, fromTimezone: string, toTimezone: string, accessToken?: string): Promise<string>`
Convert time between timezones.
#### Generic Tool Call
`callMcpTool(toolName: string, args: Record<string, unknown>, accessToken?: string): Promise<string>`
Call any MCP tool by name with custom arguments.
// Example: Call a custom tool
const result = await callMcpTool(
'get_current_weather',
{ city: 'Paris' },
accessToken
);weather-client/
├── src/
│ ├── components/ # React UI components
│ │ ├── WeatherDashboard.tsx
│ │ ├── WeatherCard.tsx
│ │ ├── AirQualityCard.tsx
│ │ ├── WeatherSearch.tsx
│ │ ├── LoginButton.tsx
│ │ └── ProtectedRoute.tsx
│ ├── hooks/ # React hooks
│ │ ├── useWeather.ts # Weather data hooks
│ │ └── useAirQuality.ts # Air quality hooks
│ ├── services/ # Core services
│ │ └── mcpClient.ts # MCP client implementation
│ ├── config/ # Configuration
│ │ └── auth.ts # OAuth2/OIDC config
│ ├── types/ # TypeScript types
│ │ └── weather.ts # Type definitions
│ ├── App.tsx # Main app component
│ └── main.tsx # Entry point
├── public/ # Static assets
├── .env # Environment configuration
├── vite.config.ts # Vite configuration
├── tailwind.config.js # Tailwind CSS config
└── package.json # Dependencies#### Adding New MCP Tools
To add support for new MCP tools in the client:
export async function getNewTool(
arg1: string,
accessToken?: string
): Promise<string> {
return callMcpTool('tool_name', { arg1 }, accessToken);
}hooks/:import { useQuery } from '@tanstack/react-query';
import { useAuth } from 'react-oidc-context';
import { getNewTool, initializeSession } from '../services/mcpClient';
export function useNewTool(arg1: string | null) {
const auth = useAuth();
const accessToken = auth.user?.access_token;
return useQuery({
queryKey: ['newTool', arg1],
queryFn: async () => {
if (!arg1) throw new Error('Argument required');
await initializeSession(accessToken);
return await getNewTool(arg1, accessToken);
},
enabled: !!arg1 && auth.isAuthenticated,
});
}const { data, isLoading, error } = useNewTool('value');#### Vite Proxy Configuration
The client uses Vite's proxy feature to forward /mcp requests to the MCP server during development. This is configured in vite.config.ts:
export default defineConfig({
server: {
proxy: {
'/mcp': {
target: 'http://localhost:8080',
changeOrigin: true,
},
},
},
});sessionStorage (cleared on tab close)automaticSilentRenew)CORS Errors
Authentication Fails
MCP Connection Errors
VITE_MCP_SERVER_URL points to the correct serverstreamable-http modeSession Issues
If you want to build the Docker image yourself:
#### Standard Build
# Build
docker build -t mcp-weather-server:sse .
# Run (port will be read from PORT env var, defaults to 8081)
docker run -p 8081:8081 mcp-weather-server:sse
# Run with custom port
docker run -p 8080:8080 mcp-weather-server:local --mode sse#### Streamable HTTP Build
# Build using streamable-http Dockerfile
docker build -f Dockerfile.streamable-http -t mcp-weather-server:streamable-http .
# Run in stateful mode
docker run -p 8080:8080 mcp-weather-server:streamable-http
# Run in stateless mode
docker run -p 8080:8080 -e STATELESS=true mcp-weather-server:streamable-httpopen_meteo_mcp/
├── src/
│ └── open_meteo_mcp/
│ ├── __init__.py
│ ├── __main__.py # Main MCP server entry point
│ ├── server.py # Unified server (stdio, SSE, streamable-http)
│ ├── utils.py # Utility functions
│ └── tools/ # Tool implementations
│ ├── __init__.py
│ ├── toolhandler.py # Base tool handler
│ ├── tools_weather.py # Weather-related tools
│ ├── tools_time.py # Time-related tools
│ ├── tools_air_quality.py # Air quality tools
│ ├── weather_service.py # Weather API service
│ └── air_quality_service.py # Air quality API service
├── tests/
├── Dockerfile # Docker configuration for SSE mode
├── Dockerfile.streamable-http # Docker configuration for streamable-http mode
├── pyproject.toml
├── requirements.txt
└── README.md#### Standard MCP Mode (stdio)
# From project root
python -m open_meteo_mcp
# Or with PYTHONPATH
export PYTHONPATH="/path/to/mcp_weather_server/src"
python -m open_meteo_mcp#### SSE Server Mode
# From project root
python -m open_meteo_mcp --mode sse --host 0.0.0.0 --port 8080
# With custom host/port
python -m open_meteo_mcp --mode sse --host localhost --port 3000#### Streamable HTTP Mode
# Stateful mode (default)
python -m open_meteo_mcp --mode streamable-http --host 0.0.0.0 --port 8080
# With debug logging
python -m open_meteo_mcp --mode streamable-http --debugTo add new weather or time-related tools:
tools/ToolHandler base classget_name, get_description, call)server.pymcp>=1.0.0 - Model Context Protocol implementationhttpx>=0.28.1 - HTTP client for API requestspython-dateutil>=2.8.2 - Date/time parsing utilitiesstarlette - ASGI web frameworkuvicorn - ASGI serverpytest - Testing frameworkThis server uses free and open-source APIs:
1. City not found
2. HTTP Server not accessible (SSE or Streamable HTTP)
python -m open_meteo_mcp --mode ssepython -m open_meteo_mcp --mode streamable-httppip install starlette uvicornhttp://localhost:8080/sse and http://localhost:8080/messages/http://localhost:8080/mcp3. MCP Client connection issues
secure-free-meteo package is installed (imports as open_meteo_mcp)4. Date format errors
5. Authentication errors (Secured Mode)
Authorization: Bearer <token> header in your requestsiss claim)WSO2_IS_AUDIENCE configurationpip install secure-free-meteo[auth]pip install pyjwt cryptographyWSO2_IS_URL when AUTH_ENABLED=trueexport WSO2_IS_URL="https://your-wso2-is.com"WSO2_VERIFY_SSL=falseThe server returns structured error messages:
Weather/API errors:
{
"error": "Could not retrieve coordinates for InvalidCity."
}Authentication errors (Secured Mode):
{
"error": "unauthorized",
"message": "Missing Authorization header"
}~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.