thirdtrail
MCP serverEverything elseElevation-corrected sun, moon, twilight, solar and tide data for any point on Earth
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use thirdtrail
Install thirdtrail
The server’s own address, for the clients that take one directly. Or connect ahel onceand every client you use reads it from one address, with the account kept on ahel rather than in each client’s config.
Claude Code
claude mcp add --transport http thirdtrail 'https://thirdtrail.life/mcp'Run it once in your project, then open /mcp to approve any sign-in the server asks for.
Claude Desktop
https://thirdtrail.life/mcpAdd a custom connector in Settings, paste this address, and approve the sign-in.
Cursor
cursor://anysphere.cursor-deeplink/mcp/install?name=thirdtrail&config=eyJ1cmwiOiJodHRwczovL3RoaXJkdHJhaWwubGlmZS9tY3AifQ==Open the link and Cursor adds the server at that address.
ChatGPT
https://thirdtrail.life/mcpIn Settings, enable Developer mode, create an MCP app, and paste this address. Your plan and workspace must allow custom apps.
Codex
codex mcp add thirdtrail --url 'https://thirdtrail.life/mcp'Run it once, then sign in with codex mcp login thirdtrail if the server asks for an account.
From the project's README
As published by thirdtrail/thirdtrail-python in README.md.
Python client for the thirdtrail APIs — sun, moon, twilight, solar irradiance and tides for any point on Earth, with elevation as a first-class input.
pip install thirdtrail
from thirdtrail import Client
tt = Client(api_key="tt_live_…")
for day in tt.ephemerides(lat=53.3498, lon=-6.2603, elevation=20):
print(day.date, day.sun.rise, day.sun.set)
Why elevation
Most sunrise APIs answer for an observer standing at sea level. The higher you are, the further you see, and the earlier the sun clears the horizon.
At the Cliffs of Moher (214 m) the difference is about three minutes — on sunrise, sunset, and every golden- and blue-hour boundary with them:
| sea level | at 214 m | |
|---|---|---|
| sunrise | 07:23:33 | 07:20:25 |
| golden hour, morning start | 06:56:51 | 06:53:42 |
| moonrise | 18:03:48 | 17:59:40 |
Golden hour lasts 20–40 minutes, so three minutes is a real slice of it. Pass
elevation whenever you know it.
What you get
day.sun.rise # datetime, with its timezone offset intact
day.sun.golden_hour.morning.start
day.moon.phase.name # "Waxing Gibbous"
day.moon.phase.illumination # 0.7376
Timestamps arrive as aware datetime objects, not strings. Anything the
client does not model is still there on day.raw and day.response, so a new
server-side field never has to wait for a client release.
Endpoints
tt.ephemerides(lat=…, lon=…, elevation=…, days=7) # sun + moon + twilight
tt.prayer_times(lat=…, lon=…, school="mwl") # five daily prayers
tt.solar(lat=…, lon=…, timestamp=…) # position + irradiance
tt.solar_path(lat=…, lon=…, interval="5m") # the sun's arc, sampled
tt.solar_dli(lat=…, lon=…, from_date=…, to_date=…) # Daily Light Integral
tt.tide_heights(lat=…, lon=…, step="10m") # water height series
tt.tide_extremes(lat=…, lon=…) # high and low waters
tt.tide_window(lat=…, lon=…, elevation=…) # tides + sun + moon
tt.tide_constituents(lat=…, lon=…) # harmonic constants
Tides take no elevation — except one
tide_heights and tide_extremes have no elevation parameter, and that is
deliberate: how high you stand does not change the ocean surface. Passing it
raises TypeError rather than being silently ignored.
tide_window is the exception, because half of what it returns is sun and
moon data:
for day in tt.tide_window(lat=52.9715, lon=-9.4309, elevation=214, days=3):
print(day.date, day.sun.golden_hour.morning.start)
for t in day.low_waters:
print(" low water", t.time, t.height_m)
Tide heights are metres relative to mean sea level, not chart datum, and exclude weather-driven surge. Not for navigation.
Errors
Catch a type, not a sentence:
from thirdtrail import PlanLimitExceeded
try:
tt.tide_extremes(lat=51.5, lon=-2.7, days=90)
except PlanLimitExceeded as e:
tt.tide_extremes(lat=51.5, lon=-2.7, days=e.limit) # e.limit == 31
AuthenticationError (401), PermissionDenied (403, a tier you are not on),
PlanLimitExceeded and InvalidRequest (400), RateLimited (429),
DataUnavailable (503), ServerError (5xx). All subclass ThirdtrailError.
Transient failures and 429s are retried with backoff. A plan ceiling is not — it will fail identically every time.
Keys
Mint one at thirdtrail.life/apis/keys/.
A key belongs to one subscription, so it works with one API; a Tides key
calling a solar endpoint gets PermissionDenied.
There is a free tier on every API.
Not covered yet
Bulk (POST) endpoints, iCalendar feeds and webhook management. Use the REST
API directly for those — the full contract is published as
OpenAPI 3.1.
Using an AI agent? There is an MCP server that exposes the same data as tools.
Licence
MIT
Advanced
- Delivery
- thirdtrail MCP server → your ahel gateway (mcp.ahel.ai) → every connected AI client.
- Catalog kind
- mcp-server
- Gateway key
io-github-thirdtrail-thirdtrail- Source
- github.com/thirdtrail/thirdtrail-python
- Hosted endpoint
https://thirdtrail.life/mcp