weather-mcp

weather-mcp

MCP server that provides weather forecast tools including current conditions, daily forecasts, and day-specific recommendations like whether to carry an umbrella or wear a jacket, powered by Open-Meteo.

Category
访问服务器

README

Weather MCP Server and Agent Bricks Agent

An MCP server exposing weather forecast tools, deployed as a Databricks App, registered through the Databricks AI Gateway as an external MCP service, and consumed by an Agent Bricks Supervisor Agent that answers natural language weather questions.

Built as Day 3 homework, following the structure of the Alpaca paper-trading MCP server reference repo (mcp_server/alpaca_mcp_server.py plus alpaca_broker.py).

Architecture

User question
     |
     v
Agent Bricks Supervisor Agent          (system prompt, tool routing)
     |
     v
Databricks AI Gateway                  (workspace.vsf.weather-mcp, OAuth M2M)
     |
     v
Databricks App: weather-mcp            (FastMCP, streamable HTTP at /mcp)
     |
     +-- weather_mcp_server.py         (thin @mcp.tool functions, threshold logic)
     |
     +-- weather_client.py             (all HTTP calls, parsing, retries)
              |
              v
        Open-Meteo API                 (geocoding + forecast, no API key)

Deployment

  • Databricks App: https://weather-mcp-7474654713254531.aws.databricksapps.com (the bare URL returns "Not Found" by design, because the MCP protocol is served only at /mcp)
  • MCP endpoint: the same URL with /mcp appended
  • AI Gateway MCP service: workspace.vsf.weather-mcp
  • Agent Bricks agent: weather-agent (Supervisor Agent)
  • Workspace: https://dbc-6ef118f0-f5e7.cloud.databricks.com
  • Source repo: https://github.com/Sheethal-crypto/weather-mcp

Weather API and authentication

Open-Meteo, chosen because it requires no signup and no API key. Two endpoints are used: the geocoding API to turn a place name into coordinates, and the forecast API for current conditions and daily forecasts. The forecast endpoint only accepts coordinates, so geocoding is a required first hop rather than a convenience.

On the secrets requirement: the assignment requires that any API key be stored as a Databricks secret and never committed. Open-Meteo has no credential of any kind, so there is nothing to store. The requirement is satisfied by the choice of provider rather than by secret handling code. There are no keys, tokens, or credentials anywhere in this repo. The one credential in the system, the OAuth client secret for the AI Gateway connection, is held by Databricks in the Unity Catalog connection object and never appears in source.

Tools

All three are defined in weather_mcp_server.py with @mcp.tool decorators. Each returns a dict carrying a status field of ok or error, so a failure is a value the agent can reason about rather than an exception.

get_current_weather(location, units="imperial")

Current observed conditions. Returns temperature, feels-like, humidity, wind speed, precipitation, a plain-English conditions string, and the observation timestamp in the location's own timezone.

get_forecast(location, days=3, units="imperial")

Daily forecast, day one being today in the location's timezone. Each day carries high, low, precipitation chance, expected accumulation, max wind, and conditions. Days are clamped to the 1 to 16 range Open-Meteo supports.

get_day_recommendation(location, date=None, units="imperial")

The derived judgment tool. It does not pass the forecast through. It applies thresholds and returns both the recommendation and the rule that produced it.

Umbrella rule. The obvious implementation is a single probability threshold, and it is misleading: a 45 percent chance of 0.01 inches is a passing sprinkle, while a 35 percent chance of half an inch soaks you. So the rule uses two factors.

  • Yes, when precipitation chance is at or above 50 percent
  • Yes, when chance is at or above 30 percent AND expected accumulation is at least 0.10 inches
  • Maybe, when chance is at or above 30 percent with less accumulation than that
  • No, otherwise

Wind override. If max wind exceeds 25 mph, an umbrella inverts and becomes useless, so the recommendation switches to a rain jacket instead. This is a judgment the raw API cannot provide and is the clearest evidence the tool is not a passthrough.

Jacket rule. Yes when the daytime high is below 62F, or when the overnight low is below 50F. The second clause exists because the overnight low is what catches people out on evening plans.

Advisories. Raised for max wind above 30 mph, a daytime high above 95F, and any thunderstorm in the day's conditions.

Every threshold is a named module constant, so the values are visible in one place rather than scattered through the branching.

Repository layout

weather_client.py        Open-Meteo adapter. All HTTP and parsing. No MCP imports.
weather_mcp_server.py    FastMCP server. Three thin tools plus threshold logic.
test_tools.py            Async MCP client test against a local server, 5 checks.
test_deployed.py         Same, against the deployed app over OAuth.
app.yaml                 Databricks Apps start command.
requirements.txt         Runtime dependencies for the deployed app.
.gitignore               Excludes .venv, __pycache__, .pyc and .env from the repo.
images/                  Demo screenshots.

The adapter split is deliberate and matches the reference repo: weather_client.py contains every requests call in the project, and the @mcp.tool functions do nothing but resolve arguments, call the adapter, catch WeatherAPIError, and return a dict.

Error handling

Failures surface as clean messages rather than stack traces at three levels.

weather_client.py retries connection errors, timeouts, 429 and 5xx with bounded backoff across three attempts. It does not retry other 4xx, because a 400 from Open-Meteo means the request itself is malformed and a second identical attempt fails identically. Exhausted retries and unresolvable locations raise WeatherAPIError.

weather_mcp_server.py catches WeatherAPIError at the tool boundary and returns {"status": "error", "error": "..."}.

The agent's system prompt instructs it to report the error and not substitute an estimate. Demo 5 below shows this working end to end.

Setup

Local

python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install fastmcp requests
python weather_mcp_server.py

test_deployed.py additionally needs pip install databricks-sdk. That is a local development dependency, deliberately kept out of requirements.txt because that file covers only what the deployed app installs.

Serves at http://localhost:8000/mcp. Run python test_tools.py in a second shell for the five-check smoke test.

Deploy as a Databricks App

  1. Clone this repo into the workspace as a Git folder.
  2. Compute, Apps, Create app, source set to that Git folder, deploy.
  3. Databricks reads app.yaml for the start command and installs requirements.txt.

The deployed MCP endpoint is the app URL with /mcp appended.

Register as an external MCP service

Agents, MCPs, Connect an existing MCP server. Server URL is the app URL plus /mcp.

Authentication is the non-obvious part. Databricks Apps sit behind OAuth, and custom MCP servers on Apps reject personal access tokens. Dynamic Client Registration also fails, because the Databricks OIDC metadata contains no registration_endpoint. What works is OAuth M2M:

  • Create a service principal and generate an OAuth secret on it
  • Grant that service principal CAN USE on the app, otherwise the token authenticates but the app still refuses
  • Token endpoint: https://<workspace-host>/oidc/v1/token
  • Scope: all-apis

The registered service is workspace.vsf.weather-mcp and loads all three tools.

Agent configuration

Agent Bricks Supervisor Agent, with workspace.vsf.weather-mcp attached as its tool source.

System prompt

You are a weather assistant. You answer questions about current
conditions, forecasts, and what to wear or carry.

You have three tools:
- get_current_weather(location, units): conditions right now
- get_forecast(location, days): daily forecast, day one is today
- get_day_recommendation(location, date, units): applies threshold
  logic to decide about umbrellas, jackets, and advisories

Which tool to call:
- Questions about right now: get_current_weather
- Questions asking for forecast numbers across days, with no carry
  or wear judgment attached: get_forecast
- Questions about whether to bring or wear something, or whether a
  day is suitable for an activity: get_day_recommendation

Using get_day_recommendation:
- It is authoritative for carry and wear questions. Do not answer
  those from get_forecast.
- It covers one day per call. For a multi-day question, call it once
  per day rather than switching to get_forecast.
- Quote its "rule" field verbatim so the user sees which threshold
  fired. State the verdict and the rule, not just the verdict.
- Take any numbers you cite from its "forecast" and "summary"
  fields. Do not call another tool to obtain numbers it already
  returned.
- Report anything in its "advisories" list.

Rules:
- Never state a temperature, precipitation chance, wind speed, or
  condition that did not come from a tool call in this conversation.
  You have no weather knowledge of your own.
- Every tool returns a "status" field. If status is "error", tell
  the user the lookup failed and repeat the error message. Do not
  substitute your own estimate and do not retry with a different
  location unless the user asks.
- If the location is ambiguous, ask which one rather than guessing.
- Forecast dates are in the location's timezone, not the user's.

The line carrying the most weight is "You have no weather knowledge of your own." Without it, a model will answer a weather question from priors when a tool call fails, which is precisely the hallucination the assignment warns against.

Demonstrated conversations

1. Threshold logic, umbrella

Question: Do I need an umbrella in Seattle tomorrow?

Tool called: get_day_recommendation with {"location": "Seattle", "date": "tomorrow"}

Tool output:

{"status":"ok","location":"Seattle, Washington, United States","date":"2026-08-10",
"units":{"temperature":"F","wind_speed":"mph","precipitation":"inch"},
"forecast":{"date":"2026-08-10","high":74.6,"low":55.3,"precip_chance_pct":2,
"precip_amount":0.0,"wind_max":8.5,"conditions":"overcast"},
"umbrella":{"recommendation":"no","rule":"precipitation chance 2% is below 30%"},
"jacket":{"recommendation":"no","rule":"high 74.6 and low 55.3 both stay above the jacket thresholds"},
"advisories":[],"summary":"2026-08-10 in Seattle, Washington, United States: overcast,
high 74.6, low 55.3."}

Answer: No, you don't need an umbrella in Seattle tomorrow. The forecast shows only a 2% chance of precipitation with no expected rain - "precipitation chance 2% is below 30%." Tomorrow (Aug 10) will be overcast with a high of 75F and a low of 55F, but it should stay dry.

The agent quotes the rule field verbatim rather than only giving the verdict, which is what the system prompt asks for and the point of the tool.

Umbrella recommendation for Seattle Umbrella recommendation continued

2. Current conditions

Question: What is it like in Denver right now?

Tool called: get_current_weather with {"location": "Denver"}

Tool output:

{"location":"Denver, Colorado, United States","latitude":39.73915,"longitude":-104.9847,
"observed_at":"2026-08-09T17:15","timezone":"America/Denver","temperature":96.0,
"feels_like":91.2,"humidity_pct":11,"wind_speed":2.7,"precipitation":0.0,
"conditions":"mainly clear","units":{"temperature":"F","wind_speed":"mph",
"precipitation":"inch"},"status":"ok"}

Answer: Right now in Denver, Colorado, it's 96F and mainly clear. It feels like 91F with very low humidity at 11%. Winds are light at 3 mph, and there's no precipitation. It's a hot, dry afternoon in Denver.

Current conditions in Denver Current conditions continued

3. Two-factor umbrella threshold firing

Question: Will it rain in Chicago tomorrow?

Tool called: get_day_recommendation with {"location": "Chicago", "date": "tomorrow"}

Tool output:

{"status":"ok","location":"Chicago, Illinois, United States","date":"2026-08-10",
"units":{"temperature":"F","wind_speed":"mph","precipitation":"inch"},
"forecast":{"date":"2026-08-10","high":80.0,"low":71.2,"precip_chance_pct":48,
"precip_amount":0.126,"wind_max":17.8,"conditions":"moderate rain"},
"umbrella":{"recommendation":"yes","rule":"precipitation chance 48% is at or above 30%
and expected accumulation 0.126 is at or above 0.1"},
"jacket":{"recommendation":"no","rule":"high 80.0 and low 71.2 both stay above the jacket thresholds"},
"advisories":[],"summary":"2026-08-10 in Chicago, Illinois, United States: moderate rain,
high 80.0, low 71.2. Bring an umbrella."}

Answer: Yes, it will rain in Chicago tomorrow. The forecast calls for moderate rain with a 48% chance of precipitation and 0.13 inches expected. You should bring an umbrella

  • "precipitation chance 48% is at or above 30% and expected accumulation 0.126 is at or above 0.1". The high will be 80F and the low 71F.

This is the second branch of the umbrella rule firing. A 48% chance alone would not clear the 50% bar, but combined with 0.126 inches of expected accumulation it does. A single-threshold rule would have answered no.

Forecast for Chicago Forecast for Chicago continued

4. Multi-day judgment with cited thresholds

Question: Should I bring a jacket to Austin this weekend?

Tools called: get_day_recommendation three times, once per day, plus one exploratory get_forecast

Tool output (first call, {"location": "Austin, Texas", "date": "2026-08-09"}):

{"status":"ok","location":"Austin, Texas, United States","date":"2026-08-09",
"units":{"temperature":"F","wind_speed":"mph","precipitation":"inch"},
"forecast":{"date":"2026-08-09","high":99.0,"low":78.2,"precip_chance_pct":12,
"precip_amount":0.0,"wind_max":12.9,"conditions":"overcast"},
"umbrella":{"recommendation":"no","rule":"precipitation chance 12% is below 30%"},
"jacket":{"recommendation":"no","rule":"high 99.0 and low 78.2 both stay above the jacket thresholds"},
"advisories":["Heat: high of 99.0 expected."],"summary":"2026-08-09 in Austin, Texas,
United States: overcast, high 99.0, low 78.2. Heat: high of 99.0 expected."}

Answer: No, you won't need a jacket in Austin this weekend. It's going to be very hot:

  • Saturday (Aug 9), high 99F, low 78F, "high 99.0 and low 78.2 both stay above the jacket thresholds", heat advisory in effect.
  • Sunday (Aug 10), high 98F, low 79F, "high 97.9 and low 79.1 both stay above the jacket thresholds", heat advisory in effect.

Both days will have temperatures well above jacket weather. Instead, prepare for extreme heat with sun protection and plenty of water.

The agent quotes the rule field verbatim for each day and surfaces the advisories, taking every number from get_day_recommendation rather than from the forecast. It also made one exploratory get_forecast call to establish which days the weekend spans, and none of that data reached the answer.

Jacket recommendation for Austin Jacket recommendation continued

5. Error handling

Question: What is the weather in Zzzzqqq Nowhereville?

Tool called: get_current_weather with {"location": "Zzzzqqq Nowhereville"}

Tool output:

{"status":"error","error":"Could not resolve the location 'Zzzzqqq Nowhereville'.
Try a city name, 'city, state', or 'lat,lon'."}

Answer: The weather lookup failed. The location 'Zzzzqqq Nowhereville' could not be found. Please provide a valid city name, 'city, state' format, or latitude/longitude coordinates, and I'll be happy to check the weather for you.

No weather was invented for a location that does not exist, and the agent asked for a usable format instead of retrying blindly.

Error handling for an unresolvable location Error handling continued

6. Multi-day forecast, no judgment attached

Question: What is the forecast for Denver for the next 3 days?

Tool called: get_forecast with {"location": "Denver", "days": 3}

Tool output:

{"location":"Denver, Colorado, United States","latitude":39.73915,"longitude":-104.9847,
"timezone":"America/Denver","units":{"temperature":"F","wind_speed":"mph",
"precipitation":"inch"},"days":[{"date":"2026-08-09","high":97.9,"low":67.4,
"precip_chance_pct":12,"precip_amount":0.0,"wind_max":14.2,"conditions":"overcast"},
{"date":"2026-08-10","high":94.8,"low":68.7,"precip_chance_pct":7,"precip_amount":0.0,
"wind_max":14.2,"conditions":"overcast"},{"date":"2026-08-11","high":99.0,"low":66.6,
"precip_chance_pct":10,"precip_amount":0.0,"wind_max":12.7,"conditions":"overcast"}],
"status":"ok"}

Answer: Here's the 3-day forecast for Denver, Colorado.

  • Today (Aug 9): high 98F, low 67F, overcast with a 12% chance of precipitation, max winds 14 mph.
  • Tomorrow (Aug 10): high 95F, low 69F, overcast with a 7% chance of precipitation, max winds 14 mph.
  • Tuesday (Aug 11): high 99F, low 67F, overcast with a 10% chance of precipitation, max winds 13 mph.

Hot and dry conditions are expected throughout the next three days, with temperatures in the mid-to-upper 90s and very low chances of rain.

This question asks for forecast numbers with no carry or wear judgment attached, so it routes to get_forecast rather than get_day_recommendation. Together with the demos above it exercises all three exposed tools.

Three day forecast for Denver Three day forecast continued Three day forecast continued

Testing

test_tools.py runs five checks against a local server: tool discovery, all three tools, and a deliberate failure case asserting that an unresolvable location returns status: error rather than raising.

test_deployed.py runs the same MCP client against the deployed app, minting an OAuth token through the Databricks CLI profile. It expects a profile named weather, created with databricks auth login --host <workspace-host> --profile weather. This verifies the deployment independently of the gateway and the agent.

Both connect over MCP and discover tools at runtime rather than importing the server module, so they exercise the same protocol surface the agent uses.

Known limitations

  • No caching. Every tool call hits Open-Meteo. Well within the 10,000 calls per day non-commercial limit for this use, but it would matter at volume.
  • Geocoding takes the first match. "Springfield" resolves to one of many without asking. The system prompt instructs the agent to ask about ambiguous locations, but the tool itself does not surface the alternatives.
  • Thresholds are calibrated in Fahrenheit and mph. Passing units="metric" returns metric values but compares them against imperial thresholds, so imperial is the supported path for get_day_recommendation.
  • Databricks Apps on Free Edition stop when idle. If the app is asleep, the gateway receives an HTML page instead of MCP protocol and tool registration fails until the app is restarted.

Assignment requirements

Requirement Where it is met
FastMCP server with @mcp.tool, streamable HTTP weather_mcp_server.py, three tools served over HTTP transport. See Tools.
Separate adapter module, no raw requests calls in tool functions weather_client.py holds every requests call in the project. See Repository layout.
API key stored as a Databricks secret (if the API needs one) Open-Meteo needs no credential, so there is nothing to store. See Weather API and authentication.
requirements.txt and app.yaml, deployed as its own Databricks App Both at the repo root, deployed from a Git folder. See Deploy as a Databricks App.
Agent Bricks agent registered against the MCP server weather-agent uses workspace.vsf.weather-mcp as its tool source. See Agent configuration.
System prompt with tool routing and guardrails Routing rules plus the no-invented-weather guardrail. See System prompt.
README with tools, setup, API and auth method This file, covering Tools, Setup and Weather API and authentication.
Three or more demonstrated natural language questions Six demonstrated, covering all three tools plus an error case. See Demonstrated conversations.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选