Skip to main content
Glama
nevermined-io

Weather MCP Server

client.py4.36 kB
"""Minimal HTTP client to interact with the MCP HTTP endpoint. Exposes a small programmatic client and helpers that read configuration from environment variables with sensible defaults. """ from typing import Any, Dict, Optional import requests class MCPHttpClient: """Very small JSON-RPC client targeting the /mcp endpoint.""" def __init__(self, base_url: str, token: Optional[str] = None): """Initialize the MCP HTTP client. Parameters ---------- base_url : str Base URL where the FastAPI app is listening (e.g., http://localhost:8000) token : Optional[str] Bearer token to include in Authorization header, if any """ self.base_url = base_url.rstrip("/") self.token = token self.session_id: Optional[str] = None self.protocol_version: Optional[str] = None def _headers(self) -> Dict[str, str]: """Build default headers for JSON-RPC requests.""" headers = { "Content-Type": "application/json", "Accept": "application/json, text/event-stream", } if self.token: headers["Authorization"] = f"Bearer {self.token}" if self.session_id: headers["mcp-session-id"] = self.session_id if self.protocol_version: headers["mcp-protocol-version"] = self.protocol_version return headers def initialize(self) -> Dict[str, Any]: """Call MCP initialize.""" payload = { "jsonrpc": "2.0", "id": 1, "method": "initialize", "params": { "protocolVersion": "1.0", "clientInfo": {"name": "weather-mcp-py-client", "version": "0.1.0"}, "capabilities": {}, }, } r = requests.post(f"{self.base_url}/mcp", json=payload, headers=self._headers(), timeout=20) r.raise_for_status() data = r.json() # Save session id for subsequent requests (stateful HTTP) self.session_id = r.headers.get("mcp-session-id") or self.session_id # Capture negotiated protocol version from response, if present try: self.protocol_version = ( (data.get("result") or {}).get("protocolVersion") or self.protocol_version ) except Exception: pass # Send notifications/initialized as per MCP spec try: notif_payload = { "jsonrpc": "2.0", "method": "notifications/initialized", "params": None, } requests.post(f"{self.base_url}/mcp", json=notif_payload, headers=self._headers(), timeout=10) except Exception: pass return data def _ensure_session(self) -> None: """Ensure initialize was called and session id stored.""" if not self.session_id: self.initialize() def list_tools(self) -> Dict[str, Any]: """List available tools from the MCP server.""" self._ensure_session() payload = {"jsonrpc": "2.0", "id": 2, "method": "tools/list", "params": {"cursor": None}} r = requests.post(f"{self.base_url}/mcp", json=payload, headers=self._headers(), timeout=20) r.raise_for_status() return r.json() def call_tool(self, name: str, arguments: Dict[str, Any]) -> Dict[str, Any]: """Generic tool invocation via JSON-RPC.""" self._ensure_session() payload = { "jsonrpc": "2.0", "id": 3, "method": "tools/call", "params": {"name": name, "arguments": arguments}, } r = requests.post(f"{self.base_url}/mcp", json=payload, headers=self._headers(), timeout=30) r.raise_for_status() return r.json() # Convenience methods def call_weather_today(self, city: str) -> Dict[str, Any]: """Convenience helper to call the paywalled weather tool.""" return self.call_tool("weather.today", {"city": city}) def call_weather_free(self, city: str) -> Dict[str, Any]: """Convenience helper to call the free weather tool.""" return self.call_tool("weather.free", {"city": city}) # End of minimal client. Higher-level orchestration (env, payments, CLI) lives elsewhere.

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/nevermined-io/weather-mcp-demo-py'

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