WindWise MCP
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@WindWise MCP Is there a good wind window for wing foiling in Tarifa tomorrow?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
WindWise MCP
A portfolio project, not production weather advice. Forecasts are model output; see Limitations.
An MCP server that lets AI agents answer "should I go out on the water?" It combines Open-Meteo's weather and marine forecasts and adds wind-sport logic on top. It finds rideable wind windows, rates sea state, compares spots and gives a go / marginal / no-go call with reasons.
It is not just a thin API wrapper. The API returns raw hourly columns. WindWise turns them into the answers a wing-foiler, kiter or dinghy sailor actually needs, and is honest about forecast uncertainty.
A real conversation in Claude, using the dinghy_sailing preset:
Tools
Tool | What it answers | Business logic beyond the API |
| "What's the weather in Sayulita?" | Weather codes → words, degrees → compass points, trims to the next N hours |
| "When is the wind strongest between 10 and 5?" | Per-day rollup: average/peak/peak time, strongest gust, circular-mean prevailing direction, Beaufort |
| "Are the waves OK for a beginner?" | Hour-by-hour sea-state rating; short-period chop rates one level rougher than swell; detects inland points |
| "When is it 12–22 kn with gusts under 25?" | Finds continuous windows across days, filters by direction and thunderstorms, explains why when nothing matches |
| "Bucerías or La Cruz tomorrow?" | Ranks 2–5 spots, tolerates partial failures, flags spots in the same model grid cell |
| "Should I go out tomorrow?" | Combines weather and marine into a go / marginal / no-go verdict with human-readable reasons |
All tools are read-only (readOnlyHint) and validate their input with Zod. Each one publishes an
outputSchema, returns both text and structuredContent, and includes Open-Meteo attribution
and a forecast caveat. Forecasts always start from the current local hour, so a tool never
offers a wind window that has already passed.
Activity presets
find_wind_windows, compare_locations and get_weather_summary accept an activity
instead of raw knots. Any explicit min_wind_knots, max_wind_knots or max_gust_knots
overrides the preset.
| Wind range |
| 12 kn and up |
| 10–18 kn |
With no activity and no min_wind_knots, the minimum defaults to 12 kn. All three tools
share min_window_hours (default 2), so they agree on what counts as a usable session.
To add a preset, add one line to ACTIVITY_PRESETS in src/domain/activities.ts. The tool
schemas and descriptions pick it up automatically.
A preset's maximum is not silently dropped: activity: "dinghy_sailing" with
min_wind_knots: 20 fails with a message saying the 18 kn cap comes from the preset, and
asks you to pass max_wind_knots as well.
Example: find_wind_windows
// Input
{
"location": "Bucerias, Mexico",
"min_wind_knots": 12,
"max_wind_knots": 22,
"max_gust_knots": 25,
"start_hour": 9,
"end_hour": 18,
"directions": ["W", "WSW", "WNW", "SW"] // onshore/cross-shore for this beach
}
// Output (example values, abridged)
{
"found": true,
"bestWindow": {
"date": "2026-11-09", "start": "2026-11-09T13:00", "end": "2026-11-09T17:00",
"durationHours": 4, "avgWindKn": 14.6, "maxWindKn": 16.8, "maxGustKn": 21.3,
"direction": "WSW", "gusty": false
},
"windows": [ ... ],
"attribution": "Weather data by Open-Meteo.com (CC BY 4.0) - https://open-meteo.com/"
}When nothing matches, the tool still gives the agent something useful to say (example values):
{
"found": false,
"whyNoWindows": { "too_light": 27 },
"strongestHourInRange": { "time": "2026-11-06T15:00", "windKn": 7.8, "gustKn": 21, "direction": "NNW" }
}Related MCP server: Weather MCP Server
How it's built
AI agent ──MCP over stdio──▶ tools/ 6 tools · Zod input/output schemas · error mapping
├──▶ domain/ pure functions: wind windows, sea state, verdicts, ranking
└──▶ openmeteo/ HTTP with timeouts and retry · response validation · geocoding cacheThe highlights:
Tools depend on an interface, not on HTTP. The integration tests run a real MCP client against the real server with a fake
WeatherService, so there's no network and nofetchmocks.Business logic is pure. Everything in
domain/takes arrays and returns data, and that is where most of the tests are.Errors are for the model, bugs are for the developer. Known failures return actionable
isErrorresults. Anything unexpected is logged and hidden from the model. Open-Meteo responses are validated with Zod, so an API change becomes one clear error rather than silent nulls.When Open-Meteo could not be reached, the tool returned an
isErrorresult the model can read, not a crash or a stack trace. Claude read it and called the tools again on its own.Forecasts start now, in the spot's local time. Hours that have already passed are never offered,
daysmeans 24-hour periods from now, and times never pass through the server's time zone.Honest about uncertainty. Every answer carries a caveat, and
compare_locationssays when two towns share a forecast grid cell instead of pretending one is better.
See docs/ARCHITECTURE.md for the layer diagram, the source tree, every design decision and how to add a tool.
Getting started
Requires Node.js 22 or newer. No API key is needed.
git clone https://github.com/kacaben/windwise-mcp.git
cd windwise-mcp
npm install
npm run buildUse it from Claude Code
claude mcp add windwise -- node /absolute/path/to/windwise-mcp/dist/index.jsUse it from Claude Desktop (or any stdio MCP client)
Add this to claude_desktop_config.json:
{
"mcpServers": {
"windwise": {
"command": "node",
"args": ["/absolute/path/to/windwise-mcp/dist/index.js"]
}
}
}Then try asking:
"Will there be enough wind for wing foiling in Bucerías tomorrow?"
"Show me the wind forecast for the next three days between 10 AM and 5 PM."
"Find 2-hour windows of 15–25 knots from the west in Cabarete this week."
"When could I go dinghy sailing in Bucerías this week?"
"Compare Bucerías, La Cruz de Huanacaxtle and Sayulita for tomorrow afternoon."
"Are the waves likely to be manageable for a beginner in Sayulita?"
You can also explore the tools interactively with the MCP Inspector:
npx @modelcontextprotocol/inspector node dist/index.jsDevelopment
Command | What it does |
| Run the server from source with |
| Biome lint and format check, failing on warnings ( |
| Strict TypeScript check of |
| Tests with a V8 coverage report (about 97% of statements) |
| Unit and integration tests (Vitest, no network) |
| Compile to |
| Live end-to-end test: spawns |
Tests
Domain unit tests: wind windows (gaps, limits, direction filters, thunderstorms, midnight crossings, missing data), sea-state ratings including chop and worst-hour rating, verdict reasons, ranking, activity presets, units, local time and session-hour selection.
Integration-layer tests: query building, Open-Meteo error payloads, retry/backoff, timeouts, response validation (missing variables, mismatched lengths, changed time format), cancellation, geocoding disambiguation (the "Sydney, US" regression and aliases such as "UK" and "USA"), "did you mean" suggestions, LRU eviction and inland detection. These use a fake
fetch.MCP server tests: a real
Clientconnected throughInMemoryTransportchecks every tool's output, input and output schemas, validation errors, past-hour filtering, grid-cell choice, partial failures incompare_locations, time-zone date mismatches and hidden internal errors, with a fakeWeatherService.
There is one test file per module. npm run coverage prints a per-file report.
CI runs lint, typecheck, tests and build on Node 22 and 24 for every push and pull request. A separate weekly workflow runs the live smoke test to catch upstream API changes.
Adding a tool
See Adding a tool in the architecture notes.
Limitations and roadmap
These are model forecasts. Sea breezes and thermal winds, which matter a lot in Banderas Bay, are often under-forecast by global models.
Marine data has ~5 km resolution and is less reliable inside bays and near the shore.
Wave ratings are deliberately simple and conservative: height bands, with short-period chop rated one level rougher than swell of the same height. They are a hint, not safety advice, and they don't account for wave direction or the shape of the beach.
The go / marginal / no-go verdict looks at wind, gusts, thunderstorms and waves. It ignores rain, temperature and the rider's skill level.
Any thunderstorm hour in the session makes the whole day
no_go, even when a clean window comes before it. That is deliberately conservative; the windows are still listed.The wind tools use the sea grid cell, so the temperature and rain in
get_weather_summarydescribe the water cell, not the town.get_weatheruses the land cell.compare_locationstakes place names only, not coordinates, and waves are just a tie-breaker in its ranking.Forecasts are not cached (only place lookups are), and a rate-limited request is retried once after a short delay, ignoring
Retry-After.Prevailing direction is an unweighted vector mean, so a few calm hours from another direction can pull it around.
Ideas for later:
Short-TTL forecast cache and
Retry-AfterhandlingCoordinates and a direction filter for
compare_locations; weigh waves in the rankingSkill-level input for the sea-state rating and verdict
Compare several weather models (ECMWF, GFS, ICON) side by side to show forecast spread
Verify past forecasts against Open-Meteo's historical data to measure local bias
Tide data, and "offshore wind" warnings computed from each spot's beach orientation
Streamable HTTP transport for remote deployment
Attribution and license
Weather data by Open-Meteo.com, licensed under CC BY 4.0. The free Open-Meteo API is for non-commercial use.
Code licensed under the MIT License.
Available Tools
6 toolscompare_locationsCompare spotsARead-onlyIdempotent
Compare wind (and optionally waves) across 2-5 places for one day and rank them for a session. Ranking: most hours in usable windows, then longest continuous window, then steadier wind, then smaller waves. Set activity (e.g. dinghy_sailing) to rank for that wind range. Use for 'Bucerias or La Cruz tomorrow?' questions.
Inputs: locations (required), day, activity, end_hour, +6 more. Returns: date, hours, notes, ranking, +4 more
find_wind_windowsFind rideable wind windowsARead-onlyIdempotent
Find continuous time windows from now on when the wind matches the criteria: an activity preset (e.g. dinghy_sailing) or explicit min/max knots and max gusts, plus allowed directions and time of day. Returns each window with its average/peak wind and direction, the best window, and, when nothing matches, why each hour was rejected. Use for questions like 'will there be enough wind for wing foiling tomorrow?' or 'when can I go dinghy sailing this week?'.
Inputs: days, activity, end_hour, latitude, +9 more. Returns: found, notes, windows, criteria, +7 more
get_marine_conditionsWaves, swell and sea temperatureARead-onlyIdempotent
Marine forecast for a coastal location: wave height and period, swell height/direction/period, sea surface temperature and ocean current. Each day includes a sea-state rating and whether it is beginner-friendly. Only works for coastal or offshore points; inland places return an error.
Inputs: days, end_hour, latitude, location, +2 more. Returns: daily, hours, units, caveat, +3 more
get_weatherCurrent weather and hourly forecastARead-onlyIdempotent
Current conditions plus an hourly forecast (temperature, rain, cloud, wind) for a place. Use for general 'what's the weather' questions. Wind is in knots, times are local to the location. For wind-sport planning prefer get_wind_forecast or find_wind_windows.
Inputs: hours, latitude, location, longitude. Returns: units, caveat, hourly, current, +2 more
get_weather_summarySession summary for a dayARead-onlyIdempotent
One-call briefing for a water-sports day at a place: weather, temperature range, rain and thunderstorm risk, wind summary and best wind window, waves and sea state, and a go / marginal / no_go verdict with reasons. Combines the weather and marine forecasts. For today, only the remaining hours count. Set activity (e.g. dinghy_sailing) to judge the day for that wind range. Start here for 'should I go out tomorrow?' questions.
Inputs: day, activity, end_hour, latitude, +8 more. Returns: date, wind, hours, notes, +10 more
get_wind_forecastDetailed wind forecastARead-onlyIdempotent
Hourly wind speed, gusts and direction in knots for up to 7 days, plus a per-day summary (average, peak and peak time, strongest gust, prevailing direction). Only hours from now on are included. Restrict to daylight with start_hour/end_hour (local time). Use this to answer 'when is the wind strongest' questions.
Inputs: days, end_hour, latitude, location, +2 more. Returns: daily, hours, units, caveat, +3 more
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 6 tools
The tools are mostly distinct, but get_weather, get_wind_forecast, and get_weather_summary all overlap in weather/wind reporting. The descriptions clarify when to use each, though get_weather_summary as a 'start here' briefing could still be confused with the narrower forecast tools.
All names use consistent snake_case and follow a predictable verb_noun pattern: get_weather, get_wind_forecast, get_marine_conditions, get_weather_summary, find_wind_windows, compare_locations. The mix of get/find/compare reflects real action differences without becoming inconsistent.
Six tools is well-scoped for a wind and weather planning server. Each tool has a distinct role: general weather, detailed wind forecast, marine conditions, window search, location comparison, and a combined briefing.
The surface covers the core wind-sports workflow well: forecast data, marine conditions, window finding, location comparison, and a go/no-go summary. Minor gaps remain around tides, weather alerts, or location search, but agents can work around these for most stated use cases.
Maintenance
Related MCP Connectors
Wind, swell and tide conditions per foil spot; sessions and coaching for signed-in users.
Global weather via Open-Meteo: forecast, historical, marine, air quality, geocoding, elevation.
Marine MCP — wraps marine-api.open-meteo.com (free, no auth)
Flight and sky conditions for agents, from METAR/TAF and airports to aurora and satellite passes.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceProvides surf forecast data including swell height, period, direction, and wind conditions for any location worldwide using the Open-Meteo Marine API. It also includes tools to find the best day to surf and integrates with MCP clients via a Python server.21-
- FlicenseBqualityDmaintenanceProvides current weather conditions and forecasts for any location using the Open-Meteo API.2-
- FlicenseNot gradedqualityDmaintenanceEnables checking live tide, swell, and wind data for La Jolla surf spots, with an AI agent that makes judgment calls like a local surfer.-
- FlicenseNot gradedqualityDmaintenanceProvides current weather, forecasts, trend predictions, and personalized recommendations for any location using the Open-Meteo API.-