MCP server
KaiCast runs a remote Model Context Protocol server:
https://kaicast.com/mcp- Transport: Streamable HTTP, stateless,
POSTonly. Supports MCP 2026-07-28 clients and 2025-era clients (2025-06-18, 2025-11-25) from the same URL. - Auth: none required. (Keys arrive with metering; the
Authorization: Bearer kc_live_…/X-KaiCast-Keyheaders are already accepted and ignored.) - Discovery: server card at
/.well-known/mcp/server-card.json; registry manifest at/server.json. - Tools: read-only, idempotent, with JSON output schemas and
structuredContent. - Spot cards: decision tools render a branded KaiCast card in hosts that support MCP Apps, and fall back to Markdown everywhere else.
It is a thin layer over the REST API: the same services, the same numbers, the same logging. Anything a tool returns, the matching endpoint returns too.
Tools #
| Tool | Layer | Does | REST twin |
|---|---|---|---|
get_conditions | Fact · free | Conditions for one spot (or nearest to lat/lon) over up to 7 days | GET /api/v1/conditions |
list_coverage | Fact · free | Covered regions, decision support, spots, activities | GET /api/v1/coverage |
recommend_spot | Decision · free in early access | Ranked picks (≤ 5) for an activity in one area on one day, with why, confidence, caveats and a spot card | GET /api/v1/recommendations |
best_day | Decision · free in early access | Best day in a window (≤ 7 days) at a spot, region or radius, versus the runner-up, with a spot card | GET /api/v1/best-day |
get_conditions #
{ "spot": "electric-beach", "from": "2026-10-06", "to": "2026-10-08" }spot or lat + lon (snapped to the nearest covered spot within 30 km). from/to are spot-local dates, at most 7 days. Returns kaicast.conditions.v1 — see REST API.
list_coverage #
{ "region": "us-hi-maui" }All arguments optional. Call this first when you don't know whether a place is covered.
recommend_spot #
{ "region": "us-hi-oahu", "activity": "snorkel", "date": "2026-10-06", "limit": 3 }| Argument | Required | Notes |
|---|---|---|
activity | yes | snorkel · dive · freedive · spearfish · surf |
region / spot / lat+lon | one of | Location is always a parameter |
radius_km | Around lat/lon, default 40, max 100 | |
date | Spot-local, up to 6 days ahead. Default today, or tomorrow once today's daylight has passed (date_rolled_forward: true) | |
limit | 1–5, default 3 |
best_day #
{ "spot": "hanauma-bay", "activity": "snorkel", "from": "2026-10-06", "to": "2026-10-12" }Same location arguments; from/to default to today … +6.
What a decision result looks like #
The text content is a ready-to-show Markdown card; structuredContent is the full kaicast.recommendation.v1 / kaicast.best_day.v1 object (schemas in /openapi.json):
**Electric Beach** · Oʻahu — Tomorrow
Great (72/100) · best 08:00–11:00
Vis 45 ft · Swell 2.1 ft @ 12s · Wind 8 kt NE · Water 81°F
Great: 45 ft visibility, 2.1 ft swell at 12s from the NW, 8 kt wind from the NE.
[Full forecast in KaiCast →](https://kaicast.com/spot/electric-beach?utm_source=agent&utm_medium=mcp&utm_campaign=spot_card_snorkel)When a place isn't covered, or the activity isn't modeled (surf), the tool returns a normal result with status: "not_covered", "conditions_only" or "activity_not_modeled" and a message to relay — not an error. Bad arguments and quota denials are tool errors (isError: true) with a stable structuredContent.error.code, and an upgrade_url when a plan limit is reached.
Connect a client #
Claude (claude.ai, Claude Desktop) #
Add KaiCast as a custom connector: open Settings → Connectors, choose to add a custom connector, name it KaiCast and paste https://kaicast.com/mcp. No sign-in is needed. Claude connects from Anthropic's cloud, so the URL must be public — it is. See Anthropic's guide: Custom connectors.
Claude renders KaiCast spot cards inline for recommend_spot and best_day.
Claude Code #
claude mcp add --transport http kaicast https://kaicast.com/mcpWith a key, or shared with your team via the project's .mcp.json:
claude mcp add --transport http kaicast https://kaicast.com/mcp --header "Authorization: Bearer kc_live_…"{
"mcpServers": {
"kaicast": { "type": "http", "url": "https://kaicast.com/mcp" }
}
}ChatGPT #
In ChatGPT on the web, enable Developer mode (Settings → Apps → Advanced), then create an app with the URL https://kaicast.com/mcp and No authentication. Available on plans that support developer mode. See OpenAI's developer mode guide.
Cursor #
~/.cursor/mcp.json (or .cursor/mcp.json in a project):
{
"mcpServers": {
"kaicast": { "url": "https://kaicast.com/mcp" }
}
}VS Code (GitHub Copilot agent mode) #
.vscode/mcp.json:
{
"servers": {
"kaicast": { "type": "http", "url": "https://kaicast.com/mcp" }
}
}Other clients #
Any client that supports remote MCP servers over Streamable HTTP works — point it at https://kaicast.com/mcp. Clients that only speak stdio can bridge with a remote-proxy such as mcp-remote:
{
"mcpServers": {
"kaicast": { "command": "npx", "args": ["-y", "mcp-remote", "https://kaicast.com/mcp"] }
}
}Use it from your own agent #
Anthropic Messages API (MCP connector) #
Claude calls KaiCast directly — no tool plumbing on your side:
curl https://api.anthropic.com/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "anthropic-beta: mcp-client-2025-11-20" \
-H "content-type: application/json" \
-d '{
"model": "claude-opus-5-5",
"max_tokens": 1500,
"mcp_servers": [{ "type": "url", "url": "https://kaicast.com/mcp", "name": "kaicast" }],
"tools": [{ "type": "mcp_toolset", "mcp_server_name": "kaicast" }],
"messages": [{ "role": "user", "content": "Best day this week to snorkel Hanauma Bay?" }]
}'OpenAI Responses API #
from openai import OpenAI
client = OpenAI()
resp = client.responses.create(
model="gpt-5",
tools=[{
"type": "mcp",
"server_label": "kaicast",
"server_url": "https://kaicast.com/mcp",
"require_approval": "never",
}],
input="Where should I dive on Maui tomorrow?",
)
print(resp.output_text)All KaiCast tools are read-only, so require_approval: "never" is safe.
MCP TypeScript SDK (any agent framework) #
import { Client, StreamableHTTPClientTransport } from '@modelcontextprotocol/client';
const client = new Client({ name: 'my-trip-planner', version: '1.0.0' });
await client.connect(new StreamableHTTPClientTransport(new URL('https://kaicast.com/mcp')));
const result = await client.callTool({
name: 'recommend_spot',
arguments: { region: 'us-hi-oahu', activity: 'snorkel' },
});
console.log(result.structuredContent.picks[0].card);Without MCP #
Every tool has a REST twin — use /openapi.json as the tool definition in any framework that imports OpenAPI (LangChain, LlamaIndex, Semantic Kernel, custom function-calling).
Raw protocol #
For debugging, a 2026-07-28 call is a single POST:
curl https://kaicast.com/mcp \
-H 'content-type: application/json' \
-H 'accept: application/json, text/event-stream' \
-H 'MCP-Protocol-Version: 2026-07-28' \
-H 'Mcp-Method: tools/call' \
-H 'Mcp-Name: list_coverage' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"list_coverage","arguments":{},
"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28",
"io.modelcontextprotocol/clientCapabilities":{},
"io.modelcontextprotocol/clientInfo":{"name":"curl","version":"1"}}}}'2025-era clients send initialize first, as usual; the server answers each request statelessly. GET /mcp returns 405 (there is no server-push stream).
Showing results #
- Relay
caveats— they carry the safety-relevant context (estimated visibility, proxy models, unchecked fishing rules). - Keep the card's Full forecast in KaiCast link, and cite KaiCast: every result's
structuredContent.sourceholdsname,urland a ready-madecitation, and the text content ends with aSource: KaiCast — https://kaicast.comline. - Show the upstream data credits. Conditions and decisions carry
data_credits(provider, required credit text, link, licence), and each spot card has a one-linecredits_text. Several sources (OpenWeather, Open-Meteo) require that credit wherever their data is shown. - Don't present a forecast as a guarantee; each response includes a
disclaimeryou can show verbatim.