Skip to main content
Glama

๐Ÿ„ MCP Surf Forecast

The AI-powered surf companion that knows every break on the planet.

An MCP server that gives LLMs real-time surf intelligence โ€” wave quality scoring, beach discovery, session planning, and forecast analysis across 12+ global data sources.

Node.js 22+ FastMCP TS License: MIT CI SonarCloud

Quick Start ยท Features ยท Tools ยท Prompts ยท Configuration ยท Contributing


๐ŸŒŠ What is this?

MCP Surf Forecast turns any AI assistant into a surf-savvy copilot. It's a Model Context Protocol server that exposes surf data, smart tools, and planning prompts โ€” so Claude, Cursor, ChatGPT, or any MCP client can help you find the perfect wave.

You: "What's the best spot near Lisbon this morning?"

AI: Using wave_quality_index and classify_best_spot_nearby...

๐Ÿ† #1 Coxos (Ericeira) โ€” WQI 8.2/10 "Very Good"
   6ft+ sets, 14s period, light NE offshore
   Best window: 07:00โ€“10:30 (dropping tide)

๐Ÿฅˆ #2 Supertubos (Peniche) โ€” WQI 7.8/10 "Very Good"
   Hollow barrels, overhead, advanced surfers only

๐Ÿฅ‰ #3 Carcavelos โ€” WQI 6.1/10 "Good"
   Fun peaks, 3-4ft, great for all levels

Related MCP server: mcp-ohmy-sql

โœจ Features

๐ŸŽฏ Wave Quality Index (0โ€“10)

A proprietary scoring algorithm that condenses swell, wind, tide, consistency, and direction into one number. No more cross-referencing 5 tabs โ€” just ask "how good is it?"

Score

Label

You should...

8โ€“10

Very Good / Epic

Drop everything and go

6โ€“7

Good

Great session guaranteed

4โ€“5

Fair

Fun if you're not picky

2โ€“3

Poor

Maybe do yoga instead

0โ€“1

Flat

Definitely do yoga

๐ŸŒ Global Coverage

Data aggregated from 12+ providers across every major surf region:

Region

Providers

๐ŸŒ Global

Surfline, Surf-Forecast, Magicseaweed

๐Ÿ‡ช๐Ÿ‡บ Europe

MeoSurf, Windguru

๐Ÿ‡ง๐Ÿ‡ท Brazil

Waves.com.br

๐Ÿ‡ฆ๐Ÿ‡บ Australia

Coastalwatch, Swellnet

๐Ÿ‡บ๐Ÿ‡ธ Hawaii

Surfnewsnetwork

๐Ÿ‡ฎ๐Ÿ‡ฉ Indonesia

Baliwaves

๐Ÿ‡ฟ๐Ÿ‡ฆ Africa

Wavescape

๐Ÿง  Smart Classification

Not just data โ€” intelligence. The server tells you where to go based on your skill level, location, and current conditions. Beginners get safe recommendations; pros get the heavy spots.


๐Ÿ›  Tools

Tool

What it does

wave_quality_index

Score any beach 0โ€“10 with full breakdown

classify_best_spot_nearby

Ranked spots by quality within your radius

classify_spot_for_skill

Go / Caution / Avoid for your level

find_beaches_in_radius

Discover spots near GPS coordinates

find_beaches_near_city

Same, but from a city name

filter_beaches

Multi-criteria search (region, wave type, skill)

best_sessions_today

Optimal windows considering tide + wind

compare_beaches

Side-by-side forecast comparison

check_swell_alert

Upcoming swell notifications

wetsuit_recommendation

Gear advice based on water temp + wind chill

surf_conditions_full

Complete conditions in one call

Tool Sequence Diagrams

wave_quality_index

sequenceDiagram
    participant Client as MCP Client
    participant Tool as wave_quality_index
    participant Repo as BeachRepository
    participant Forecast as ForecastProvider
    participant WQI as WQI Engine

    Client->>Tool: { beachId, timestamp? }
    Tool->>Repo: getById(beachId)
    Repo-->>Tool: Beach (bestSwellDir, bestWindDir, bestTide)
    Tool->>Forecast: getForecast(beachId)
    Forecast-->>Tool: ForecastEntry[]
    Tool->>WQI: calculate(forecast, beachProfile)
    Note over WQI: swellScore ร— 0.30<br/>windScore ร— 0.25<br/>consistency ร— 0.15<br/>tideAlignment ร— 0.15<br/>directionMatch ร— 0.15
    WQI-->>Tool: { wqi: 7.8, label, breakdown }
    Tool-->>Client: WQI result + summary

classify_best_spot_nearby

sequenceDiagram
    participant Client as MCP Client
    participant Tool as classify_best_spot_nearby
    participant Repo as BeachRepository
    participant WQI as WQI Engine

    Client->>Tool: { lat, lon, radiusKm, topN, skillLevel?, minWqi }
    Tool->>Repo: findInRadius({ lat, lon }, radiusKm)
    Repo-->>Tool: Beach[] with distances
    opt skillLevel provided
        Tool->>Tool: filter by skillLevel
    end
    loop For each candidate beach
        Tool->>WQI: calculate(beachId)
        WQI-->>Tool: { wqi, label, bestWindow }
    end
    Tool->>Tool: filter wqi >= minWqi
    Tool->>Tool: sort by WQI descending
    Tool->>Tool: take topN
    Tool-->>Client: Ranked list with WQI + highlights

classify_spot_for_skill

sequenceDiagram
    participant Client as MCP Client
    participant Tool as classify_spot_for_skill
    participant Repo as BeachRepository
    participant WQI as WQI Engine

    Client->>Tool: { beachId, skillLevel }
    Tool->>Repo: getById(beachId)
    Repo-->>Tool: Beach (waveType, skillLevel[])
    Tool->>WQI: calculate(beachId)
    WQI-->>Tool: { wqi, breakdown, forecast }
    Tool->>Tool: evaluate(waveSize, power, currents vs skillLevel)
    alt Safe for level
        Tool-->>Client: { recommendation: "go", reasons }
    else Marginal
        Tool->>Repo: findAlternative(nearby, beginner-friendly)
        Tool-->>Client: { recommendation: "caution", reasons, alternative }
    else Dangerous
        Tool->>Repo: findAlternative(nearby, safer)
        Tool-->>Client: { recommendation: "avoid", reasons, alternative }
    end

find_beaches_in_radius

sequenceDiagram
    participant Client as MCP Client
    participant Tool as find_beaches_in_radius
    participant Repo as BeachRepository
    participant Geo as Haversine

    Client->>Tool: { lat, lon, radiusKm, limit }
    Tool->>Repo: getAll()
    Repo-->>Tool: Beach[]
    loop For each beach
        Tool->>Geo: haversineDistance(input, beach)
        Geo-->>Tool: distanceKm
    end
    Tool->>Tool: filter distance <= radiusKm
    Tool->>Tool: sort by distance ASC
    Tool->>Tool: take limit
    Tool-->>Client: Beach[] with distanceKm

find_beaches_near_city

sequenceDiagram
    participant Client as MCP Client
    participant Tool as find_beaches_near_city
    participant Geocode as Nominatim API
    participant Radius as find_beaches_in_radius

    Client->>Tool: { city, country?, radiusKm, limit }
    Tool->>Geocode: geocodeCity(city, country)
    Geocode-->>Tool: { lat, lon }
    alt Geocoding failed
        Tool-->>Client: Error: "Could not geocode city"
    else Success
        Tool->>Radius: findInRadius(lat, lon, radiusKm, limit)
        Radius-->>Tool: Beach[] with distances
        Tool-->>Client: Beach[] with distances
    end

filter_beaches

sequenceDiagram
    participant Client as MCP Client
    participant Tool as filter_beaches
    participant Repo as BeachRepository
    participant WQI as WQI Engine

    Client->>Tool: { region?, country?, waveType?, skillLevel?, minWqi, maxResults }
    Tool->>Repo: filter({ region, country, waveType, skillLevel })
    Repo-->>Tool: Beach[] matching criteria
    opt minWqi > 0
        loop For each beach
            Tool->>WQI: calculate(beachId)
            WQI-->>Tool: { wqi }
        end
        Tool->>Tool: filter wqi >= minWqi
    end
    Tool->>Tool: take maxResults
    Tool-->>Client: Filtered Beach[]

best_sessions_today

sequenceDiagram
    participant Client as MCP Client
    participant Tool as best_sessions_today
    participant Repo as BeachRepository
    participant Forecast as ForecastProvider
    participant WQI as WQI Engine

    Client->>Tool: { beachId }
    Tool->>Repo: getById(beachId)
    Repo-->>Tool: Beach (bestTide, bestWindDir)
    Tool->>Forecast: getForecast(beachId, days=1)
    Forecast-->>Tool: ForecastEntry[] (hourly)
    loop For each hour today (sunrise โ†’ sunset)
        Tool->>WQI: calculate(beachId, hour)
        WQI-->>Tool: { wqi, tideState, windDirection }
    end
    Tool->>Tool: find peak WQI windows
    Tool->>Tool: group consecutive good hours
    Tool-->>Client: SessionWindow[] { startTime, endTime, wqi, confidence }

compare_beaches

sequenceDiagram
    participant Client as MCP Client
    participant Tool as compare_beaches
    participant Repo as BeachRepository
    participant WQI as WQI Engine
    participant Forecast as ForecastProvider

    Client->>Tool: { beachIds[], date? }
    loop For each beachId
        Tool->>Repo: getById(beachId)
        Repo-->>Tool: Beach profile
        Tool->>WQI: calculate(beachId, date)
        WQI-->>Tool: { wqi, breakdown }
        Tool->>Forecast: getForecast(beachId)
        Forecast-->>Tool: Conditions
    end
    Tool->>Tool: build side-by-side comparison
    Tool-->>Client: Comparison[] { beach, wqi, swell, wind, tide, bestWindow }

check_swell_alert

sequenceDiagram
    participant Client as MCP Client
    participant Tool as check_swell_alert
    participant Forecast as ForecastProvider

    Client->>Tool: { beachId, minSwellHeightM, daysAhead }
    Tool->>Forecast: getForecast(beachId, daysAhead)
    Forecast-->>Tool: ForecastEntry[] (multi-day)
    Tool->>Tool: filter swellHeightM >= minSwellHeightM
    alt Swell found
        Tool-->>Client: Matching windows[] { timestamp, height, period, direction }
    else No swell
        Tool-->>Client: { alert: false, message: "No significant swell in next N days" }
    end

wetsuit_recommendation

sequenceDiagram
    participant Client as MCP Client
    participant Tool as wetsuit_recommendation
    participant Forecast as ForecastProvider
    participant Calc as Wetsuit Calculator

    Client->>Tool: { beachId, timestamp?, sessionDurationMin }
    Tool->>Forecast: getForecast(beachId)
    Forecast-->>Tool: { waterTempC, windSpeedKts, airTempC }
    Tool->>Calc: recommendWetsuit(waterTemp, windSpeed, airTemp, duration)
    Note over Calc: Wind chill adjustment<br/>Long session adjustment<br/>Thickness lookup table
    Calc-->>Tool: { type, thickness, boots, gloves, hood }
    Tool-->>Client: Full recommendation + UV advice

surf_conditions_full

sequenceDiagram
    participant Client as MCP Client
    participant Tool as surf_conditions_full
    participant Repo as BeachRepository
    participant Forecast as ForecastProvider
    participant WQI as WQI Engine
    participant Wetsuit as Wetsuit Calculator

    Client->>Tool: { beachId, timestamp? }
    Tool->>Repo: getById(beachId)
    Repo-->>Tool: Beach profile
    Tool->>Forecast: getForecast(beachId)
    Forecast-->>Tool: Full forecast (marine + weather + ocean)
    Tool->>WQI: calculate(beachId, timestamp)
    WQI-->>Tool: { wqi, label, breakdown }
    Tool->>Wetsuit: recommendWetsuit(waterTemp, wind, airTemp)
    Wetsuit-->>Tool: Gear recommendation
    Tool->>Tool: assess safety (lightning, fog, currents)
    Tool-->>Client: Complete response { marine, wind, weather, sun, ocean, gear, safety, wqi }

๐Ÿ’ฌ Prompts

Pre-built conversation starters that turn your AI into a surf expert:

Prompt

Use case

plan_surf_trip

Multi-day itinerary with forecasts

daily_surf_report

Morning conditions check

analyze_spot

Deep dive on a specific break

beginner_spot_finder

Safe spots for learners


๐Ÿš€ Quick Start

Prerequisites

Install

git clone https://github.com/YOUR_ORG/mcp-surf-forecast.git
cd mcp-surf-forecast
npm install

Run the server

# stdio transport (for Claude Desktop, Cursor, etc.)
npm start

# HTTP transport (for network clients, debugging)
npm run start:http
# โ†’ Server running at http://localhost:3000

# Interactive Inspector UI (development)
npm run dev

Connect your AI client

Claude Desktop โ€” add to your mcp.json:

{
  "mcpServers": {
    "surf-forecast": {
      "command": "npx",
      "args": ["fastmcp", "run", "/path/to/mcp-surf-forecast/src/server.ts"]
    }
  }
}

Cursor / HTTP clients:

{
  "mcpServers": {
    "surf-forecast": {
      "url": "http://localhost:3000"
    }
  }
}

๐Ÿงช Testing

Run tests locally

# Run all tests
npm test

# Run tests in watch mode (re-runs on file change)
npm run test:watch

# Run tests with coverage report
npm run test:coverage

# Type check (no emit)
npm run typecheck

Test structure

tests/
โ”œโ”€โ”€ unit/          # Pure logic: WQI engine, geo math, schemas
โ”œโ”€โ”€ integration/   # Tools + resources with mock data
โ””โ”€โ”€ e2e/           # Full MCP server via client connection

Verify MCP compliance

# List all registered resources, tools, and prompts
npm run inspect

# Call a specific tool from terminal
npx fastmcp call wave_quality_index --file src/server.ts beachId=supertubos-peniche

# Open the visual Inspector UI
npm run dev

๐Ÿ” MCP Inspector

The FastMCP Inspector is a visual development tool that lets you browse, test, and debug all your MCP components interactively โ€” without needing an AI client connected.

Launch the Inspector

npm run dev

This opens a browser-based UI with hot reload. Every time you save a file, the Inspector reloads your server automatically.

What you can do in the Inspector

Feature

How

๐Ÿ“‹ Browse all tools, resources & prompts

Listed in the sidebar with schemas

๐Ÿงช Call any tool with custom params

Fill in the form, hit "Run", see the response

๐Ÿ“– Read any resource by URI

Type surf://beaches/supertubos-peniche and see the data

๐Ÿ’ฌ Render prompts with arguments

Preview exactly what the LLM receives

โŒ Test error handling

Pass invalid params and verify error messages

โฑ๏ธ Check response times

Each call shows execution duration

Inspector from the terminal (headless)

If you prefer CLI over UI:

# List everything the server exposes
npx fastmcp inspect --file src/server.ts

# Output:
# Tools (9):
#   - wave_quality_index
#   - classify_best_spot_nearby
#   - classify_spot_for_skill
#   - find_beaches_in_radius
#   - find_beaches_near_city
#   - filter_beaches
#   - best_sessions_today
#   - compare_beaches
#   - check_swell_alert
#
# Resources (6):
#   - surf://providers
#   - surf://providers/{providerId}
#   - surf://beaches
#   - surf://beaches/{beachId}
#   - surf://forecast/{beachId}
#   - surf://cams/{beachId}
#
# Prompts (4):
#   - plan_surf_trip
#   - daily_surf_report
#   - analyze_spot
#   - beginner_spot_finder

Call tools directly from terminal

# Score a beach
npx fastmcp call wave_quality_index --file src/server.ts beachId=supertubos-peniche

# Find beaches near coordinates
npx fastmcp call find_beaches_in_radius --file src/server.ts lat=38.7 lon=-9.14 radiusKm=50

# Classify for a beginner
npx fastmcp call classify_spot_for_skill --file src/server.ts beachId=carcavelos skillLevel=beginner

# Check upcoming swell
npx fastmcp call check_swell_alert --file src/server.ts beachId=pipeline-oahu minSwellHeightM=3 daysAhead=5

Run server locally for HTTP clients

# Start on port 3000 (default)
npm run start:http

# Or specify a custom port
PORT=8080 npx fastmcp run src/server.ts --transport http --port 8080

Then test with curl:

# Health check (server is up)
curl http://localhost:3000

# Or connect a FastMCP client
npx fastmcp call wave_quality_index --url http://localhost:3000 beachId=coxos-ericeira

โš™๏ธ Configuration

Environment Variables

Variable

Required

Default

Description

PORT

No

3000

HTTP transport port

TRANSPORT

No

stdio

Transport type: stdio or http

LOG_LEVEL

No

info

Logging level: debug, info, warn, error

NOMINATIM_USER_AGENT

No

mcp-surf-forecast

User-Agent for geocoding requests

SONAR_TOKEN

CI only

โ€”

SonarCloud authentication token

SEMGREP_APP_TOKEN

CI only

โ€”

Semgrep security scanning token

sonar-project.properties

sonar.projectKey=mcp-surf-forecast
sonar.organization=<your-github-org>
sonar.sources=src
sonar.tests=tests
sonar.javascript.lcov.reportPaths=coverage/lcov.info
sonar.exclusions=src/data/**,dist/**

Data Configuration

The beach database and provider registry live in src/data/:

  • beaches.json โ€” Static database of ~50-100 surf spots worldwide

  • providers.json โ€” Metadata for all data source providers

To add a new beach, just append to beaches.json:

{
  "id": "your-spot-name",
  "name": "Your Spot",
  "region": "Europe",
  "country": "Portugal",
  "lat": 39.36,
  "lon": -9.37,
  "waveType": ["beach-break"],
  "skillLevel": ["intermediate"],
  "bestTide": "mid",
  "bestSwellDir": "NW",
  "bestWindDir": "E",
  "providers": ["surfline", "windguru"],
  "camUrl": null
}

No code changes required โ€” the server picks it up automatically.

WQI Weights

The Wave Quality Index scoring weights are defined in src/tools/wqi.ts:

const WQI_WEIGHTS = {
  swellScore:     0.30,   // Wave height + period
  windScore:      0.25,   // Offshore vs onshore
  consistency:    0.15,   // Set frequency
  tideAlignment:  0.15,   // Current vs ideal tide
  directionMatch: 0.15,   // Swell direction vs spot's sweet spot
}

๐Ÿ“ Project Structure

src/
โ”œโ”€โ”€ server.ts          # Composition root โ€” wires everything together
โ”œโ”€โ”€ resources/         # MCP resources (read-only data endpoints)
โ”œโ”€โ”€ tools/             # MCP tools (computation & actions)
โ”œโ”€โ”€ prompts/           # MCP prompts (LLM interaction templates)
โ”œโ”€โ”€ models/            # Domain entities & Zod schemas
โ”œโ”€โ”€ providers/         # Data access layer (static JSON for MVP)
โ”œโ”€โ”€ data/              # Beach & provider JSON databases
โ””โ”€โ”€ utils/             # Geo math, geocoding, helpers

Full architecture details in docs/01-architecture.md


๐Ÿ— Built With

Technology

Why

๐Ÿ”Œ

FastMCP TypeScript

The standard MCP framework

๐Ÿ›ก๏ธ

Zod

Runtime schema validation

๐ŸŒ

Haversine

Geographic distance calculations

๐Ÿงช

Vitest

Lightning-fast testing

๐Ÿ“Š

SonarCloud

Code quality & security


๐Ÿค Contributing

We welcome contributions! Whether it's adding new beaches, improving the WQI algorithm, or integrating real-time data sources.

How to contribute

  1. Fork the repo

  2. Create a feature branch (git checkout -b feature/add-bali-spots)

  3. Make your changes

  4. Run tests (npm test) and type check (npm run typecheck)

  5. Open a PR

Easy first contributions

  • ๐Ÿ–๏ธ Add beaches โ€” Drop entries into src/data/beaches.json (no code needed!)

  • ๐ŸŒŠ Tune WQI โ€” Improve scoring accuracy for specific wave types

  • ๐ŸŒ Add providers โ€” Implement a new ForecastProvider for a data source

  • ๐Ÿ“ Improve prompts โ€” Better LLM guidance for surf planning

Development workflow

npm run dev          # Inspector UI with hot reload
npm test             # Run test suite
npm run test:watch   # Tests re-run on save
npm run inspect      # Validate all MCP components

๐Ÿ“‹ Roadmap

  • Static beach database (50+ spots worldwide)

  • Wave Quality Index (0โ€“10 scoring)

  • Geo-based search & classification

  • Parameterized prompts for trip planning

  • Real-time Surfline API integration

  • Live cam snapshot analysis

  • Historical data & trend analysis

  • User favorites & personalized alerts

  • Multi-language support

  • Mobile companion app


๐Ÿ“„ Documentation

Full technical documentation lives in docs/:

Document

Topic

Architecture

System design & SOLID principles

Data Models

Beach, Forecast, WQI schemas

Resources

MCP data endpoints

Tools

Computation & classification

WQI Spec

Scoring algorithm deep-dive

Prompts

LLM interaction templates

Testing

CI, SonarCloud, test strategy

Project Setup

Dev environment & config


๐Ÿ“œ License

MIT โ€” see LICENSE for details.


Built for surfers, by surfers. ๐Ÿค™

Stop checking 5 different apps. Let AI find your next session.

โญ Star this repo ยท ๐Ÿ› Report Bug ยท ๐Ÿ’ก Request Feature

F
license - not found
-
quality - not tested
C
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

  • F
    license
    B
    quality
    D
    maintenance
    A minimal Python MCP server that provides surf forecasts for a single Surfline spot. It fetches both conditions and rating data through the get_surf_forecast tool.
    Last updated
    1
  • -
    license
    -
    quality
    C
    maintenance
    An MCP server that bridges AI assistants with SQL databases, enabling natural language querying across multiple database types with built-in optimization and security.
    Last updated
    3
  • F
    license
    -
    quality
    C
    maintenance
    Provides 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.
    Last updated
    19
  • A
    license
    A
    quality
    C
    maintenance
    An MCP server that enables AI assistants to fetch web content in multiple formats (HTML, JSON, text, Markdown) with intelligent content extraction, chunk management, and browser automation support.
    Last updated
    5
    72
    15
    MIT

View all related MCP servers

Related MCP Connectors

  • Driflyte MCP server which lets AI assistants query topic-specific knowledge from web and GitHub.

  • MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.

  • MCP server connecting AI agents to non-custodial staking data across 130+ networks.

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/luisaugustomachadomoretto/mcp-surf-forecast'

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