Skip to main content
Glama

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)

Related MCP server: wetter-mcp-server

Deployment

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.

F
license - not found
-
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

View all related MCP servers

Related MCP Connectors

  • This MCP server provides seamless access to Malaysia's government open data, including datasets, w…

  • MCP server for AI dialogue using various LLM models via AceDataCloud

  • Pocket Agent (aipocketagent.com) MCP server — read tools for personas, apps, and product info.

View all MCP Connectors

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/Sheethal-crypto/weather-mcp'

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