tides-mcp 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,43 @@
1
+ # tides-mcp
2
+
3
+ A small MCP server for coastal planning with NOAA CO-OPS tide data. It is useful for fishing, kayaking, tidepool trips, photography, flood awareness, and checking whether a tide window is worth investigating.
4
+
5
+ ## Tools
6
+
7
+ - `get_tide_predictions`: high and low predictions or hourly predictions for a station and date range.
8
+ - `get_water_levels`: observed water levels for a station and date range.
9
+
10
+ The server uses the public NOAA CO-OPS API and needs no key. Dates use `YYYY-MM-DD`; station ids are NOAA station identifiers such as `9414290`. Requests time out after 20 seconds.
11
+
12
+ ## Run
13
+
14
+ ```bash
15
+ npm install
16
+ npm run build
17
+ node dist/index.js
18
+ ```
19
+
20
+ The server uses stdio MCP transport and does not write files or contact any service other than NOAA.
21
+
22
+ ## Quick start
23
+
24
+ ```bash
25
+ npm install
26
+ npm run build
27
+ node dist/index.js
28
+ ```
29
+
30
+ The server uses stdio, so it can be connected to Claude Desktop, Cursor, VS Code, MCP Inspector, or another compatible MCP client.
31
+
32
+ ## Tools at a glance
33
+
34
+ - `get_tide_predictions`: Get NOAA high low or hourly tide predictions for a station and date range.
35
+ - `get_water_levels`: Get observed NOAA water levels for a station and short date range.
36
+
37
+ ## Limits and privacy
38
+
39
+ This project is intentionally narrow. It should be treated as a practical helper, not a complete certification or security audit. Check the implementation and the returned data before using it with sensitive material. No credentials are required unless the project explicitly says otherwise.
40
+
41
+ ## Try it
42
+
43
+ After building, connect the server through your MCP client. The repository root also contains `smoke-test.mjs` for projects covered by the shared harness. A typical tool call starts with `get_tide_predictions`.
package/dist/api.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ export declare class TidesError extends Error {
2
+ }
3
+ export declare function predictions(station: string, begin: string, end: string, interval?: "hilo" | "h", units?: string): Promise<any>;
4
+ export declare function waterLevels(station: string, begin: string, end: string, interval?: string, units?: string): Promise<any>;
5
+ export declare function format(data: any): string;
package/dist/api.js ADDED
@@ -0,0 +1,10 @@
1
+ const BASE = "https://api.tidesandcurrents.noaa.gov/api/prod/datagetter";
2
+ const HEADERS = { "User-Agent": "mrfentmen-tides-mcp/1.0" };
3
+ export class TidesError extends Error {
4
+ }
5
+ async function get(params) { const url = new URL(BASE); Object.entries({ ...params, format: "json", units: params.units ?? "english", time_zone: params.time_zone ?? "gmt" }).forEach(([k, v]) => url.searchParams.set(k, v)); const res = await fetch(url, { headers: HEADERS, signal: AbortSignal.timeout(20000) }); if (!res.ok)
6
+ throw new TidesError(`NOAA tides error ${res.status}`); const data = await res.json(); if (data.error)
7
+ throw new TidesError(data.error.message ?? "NOAA returned an error"); return data; }
8
+ export function predictions(station, begin, end, interval = "hilo", units = "english") { return get({ station, product: "predictions", datum: "MLLW", begin_date: begin.replaceAll("-", ""), end_date: end.replaceAll("-", ""), interval, units }); }
9
+ export function waterLevels(station, begin, end, interval = "6", units = "english") { return get({ station, product: "water_level", datum: "MLLW", begin_date: begin.replaceAll("-", ""), end_date: end.replaceAll("-", ""), interval, units }); }
10
+ export function format(data) { return JSON.stringify(data, null, 2).slice(0, 12000); }
@@ -0,0 +1 @@
1
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,12 @@
1
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
2
+ import { createServer } from "./server.js";
3
+ async function main() {
4
+ const server = createServer();
5
+ const transport = new StdioServerTransport();
6
+ await server.connect(transport);
7
+ console.error("MCP server running on stdio");
8
+ }
9
+ main().catch((err) => {
10
+ console.error("Fatal error:", err);
11
+ process.exit(1);
12
+ });
@@ -0,0 +1,4 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { TidesError } from "./api.js";
3
+ export declare function createServer(): McpServer;
4
+ export { TidesError };
package/dist/server.js ADDED
@@ -0,0 +1,33 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { z } from "zod";
3
+ import { format, predictions, TidesError, waterLevels } from "./api.js";
4
+ const text = (s) => ({ content: [{ type: "text", text: s }] });
5
+ const textError = (t) => ({ content: [{ type: "text", text: t }], isError: true });
6
+ const READ_ONLY = { readOnlyHint: true, openWorldHint: true };
7
+ export function createServer() {
8
+ const server = new McpServer({ name: "tides-mcp", version: "1.0.0" });
9
+ server.registerTool("get_tide_predictions", {
10
+ title: "Get tide predictions",
11
+ description: "Get NOAA high low or hourly tide predictions for a station and date range.",
12
+ inputSchema: z.object({ station: z.string().min(3), begin: z.string().describe("YYYY-MM-DD"), end: z.string().describe("YYYY-MM-DD"), interval: z.enum(["hilo", "h"]).default("hilo"), units: z.enum(["english", "metric"]).default("english") }),
13
+ annotations: READ_ONLY,
14
+ }, async ({ station, begin, end, interval, units }) => { try {
15
+ return text(format(await predictions(station, begin, end, interval, units)));
16
+ }
17
+ catch (e) {
18
+ return textError(`Error: ${e instanceof Error ? e.message : String(e)}`);
19
+ } });
20
+ server.registerTool("get_water_levels", {
21
+ title: "Get water levels",
22
+ description: "Get observed NOAA water levels for a station and short date range.",
23
+ inputSchema: z.object({ station: z.string().min(3), begin: z.string(), end: z.string(), interval: z.enum(["6", "h"]).default("6"), units: z.enum(["english", "metric"]).default("english") }),
24
+ annotations: READ_ONLY,
25
+ }, async ({ station, begin, end, interval, units }) => { try {
26
+ return text(format(await waterLevels(station, begin, end, interval, units)));
27
+ }
28
+ catch (e) {
29
+ return textError(`Error: ${e instanceof Error ? e.message : String(e)}`);
30
+ } });
31
+ return server;
32
+ }
33
+ export { TidesError };
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "tides-mcp",
3
+ "version": "1.0.0",
4
+ "description": "Use this MCP server to NOAA tides and currents predictions and water levels. Tools include get tide predictions, get water levels",
5
+ "type": "module",
6
+ "mcpName": "io.github.mrfentmen/tides-mcp",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/mrfentmen/tides-mcp.git"
10
+ },
11
+ "bin": {
12
+ "tides-mcp": "./dist/index.js"
13
+ },
14
+ "main": "./dist/index.js",
15
+ "files": [
16
+ "dist",
17
+ "server.json",
18
+ "README.md"
19
+ ],
20
+ "scripts": {
21
+ "build": "tsc -p tsconfig.json",
22
+ "start": "node dist/index.js",
23
+ "dev": "npm run build && node dist/index.js"
24
+ },
25
+ "keywords": [
26
+ "mcp",
27
+ "public-data",
28
+ "tides"
29
+ ],
30
+ "license": "MIT",
31
+ "dependencies": {
32
+ "@modelcontextprotocol/sdk": "^1.0.4",
33
+ "zod": "^3.23.8"
34
+ },
35
+ "devDependencies": {
36
+ "@types/node": "^22.0.0",
37
+ "typescript": "^5.6.0"
38
+ },
39
+ "engines": {
40
+ "node": ">=20"
41
+ }
42
+ }
package/server.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
3
+ "name": "io.github.mrfentmen/tides-mcp",
4
+ "description": "Use this MCP server to NOAA tides and currents predictions and water levels. Tools include get...",
5
+ "repository": {
6
+ "url": "https://github.com/mrfentmen/tides-mcp",
7
+ "source": "github"
8
+ },
9
+ "version": "1.0.0",
10
+ "packages": [
11
+ {
12
+ "registryType": "npm",
13
+ "identifier": "tides-mcp",
14
+ "version": "1.0.0",
15
+ "transport": {
16
+ "type": "stdio"
17
+ }
18
+ }
19
+ ]
20
+ }