coops-mcp 0.1.0__tar.gz

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.
@@ -0,0 +1,42 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.egg-info/
6
+ *.egg
7
+ dist/
8
+ build/
9
+ *.whl
10
+
11
+ # Virtual environments
12
+ .venv/
13
+ venv/
14
+ env/
15
+
16
+ # Testing
17
+ .pytest_cache/
18
+ .coverage
19
+ htmlcov/
20
+ .tox/
21
+
22
+ # IDE
23
+ .idea/
24
+ .vscode/
25
+ *.swp
26
+ *.swo
27
+ *~
28
+
29
+ # OS
30
+ .DS_Store
31
+ Thumbs.db
32
+
33
+ # Linting
34
+ .ruff_cache/
35
+ .mypy_cache/
36
+
37
+ # Lock files (each server manages its own)
38
+ uv.lock
39
+
40
+ # Environment
41
+ .env
42
+ .env.local
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Mansur Ali Jisan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,140 @@
1
+ Metadata-Version: 2.4
2
+ Name: coops-mcp
3
+ Version: 0.1.0
4
+ Summary: MCP server providing access to NOAA CO-OPS tides, water levels, currents, and meteorological data
5
+ Project-URL: Homepage, https://github.com/mansurjisan/ocean-mcp
6
+ Project-URL: Repository, https://github.com/mansurjisan/ocean-mcp
7
+ Project-URL: Bug Tracker, https://github.com/mansurjisan/ocean-mcp/issues
8
+ Project-URL: Documentation, https://github.com/mansurjisan/ocean-mcp/tree/main/servers/coops-mcp
9
+ Project-URL: Changelog, https://github.com/mansurjisan/ocean-mcp/releases
10
+ Author-email: Mansur Ali Jisan <mansur.jisan@noaa.gov>
11
+ License-Expression: MIT
12
+ License-File: LICENSE
13
+ Keywords: coastal,coops,currents,mcp,model-context-protocol,noaa,oceanography,tides,water-levels
14
+ Classifier: Development Status :: 4 - Beta
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Intended Audience :: Science/Research
17
+ Classifier: License :: OSI Approved :: MIT License
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Scientific/Engineering :: Atmospheric Science
23
+ Classifier: Topic :: Scientific/Engineering :: GIS
24
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
25
+ Requires-Python: >=3.11
26
+ Requires-Dist: httpx>=0.27.0
27
+ Requires-Dist: mcp[cli]>=1.0.0
28
+ Requires-Dist: pydantic>=2.0.0
29
+ Description-Content-Type: text/markdown
30
+
31
+ # CO-OPS MCP Server
32
+
33
+ <!-- mcp-name: io.github.mansurjisan/coops-mcp -->
34
+
35
+ MCP server providing AI assistants with access to NOAA CO-OPS water levels, tides, currents, and coastal oceanographic data.
36
+
37
+ **No API key required** — all CO-OPS APIs are free and public.
38
+
39
+ ## Features
40
+
41
+ - **Station Discovery** — List, search, and find nearest CO-OPS stations by type, state, or coordinates
42
+ - **Water Levels** — Real-time and historical observed water levels with multiple datum references
43
+ - **Tide Predictions** — Harmonic tide predictions (6-min, hourly, or high/low)
44
+ - **Meteorological Data** — Wind, air/water temperature, pressure, humidity, visibility, and more
45
+ - **Currents** — Current observations and predictions from PORTS stations
46
+ - **Derived Products** — Extreme water levels, flood statistics, sea level trends, storm events, tidal datums
47
+
48
+ ## Quick Start
49
+
50
+ ### Install with uv
51
+
52
+ ```bash
53
+ git clone https://github.com/mansurjisan/ocean-mcp.git
54
+ cd ocean-mcp/servers/coops-mcp
55
+ uv sync
56
+ ```
57
+
58
+ ### Configure your MCP client
59
+
60
+ Add to your MCP settings:
61
+
62
+ ```json
63
+ {
64
+ "mcpServers": {
65
+ "coops": {
66
+ "command": "uv",
67
+ "args": ["run", "--directory", "/path/to/ocean-mcp/servers/coops-mcp", "python", "-m", "coops_mcp"]
68
+ }
69
+ }
70
+ }
71
+ ```
72
+
73
+ Or if installed as a package:
74
+
75
+ ```json
76
+ {
77
+ "mcpServers": {
78
+ "coops": {
79
+ "command": "uvx",
80
+ "args": ["coops-mcp"]
81
+ }
82
+ }
83
+ }
84
+ ```
85
+
86
+ ## Available Tools
87
+
88
+ | Tool | Description | Key Parameters |
89
+ |------|-------------|----------------|
90
+ | `coops_list_stations` | List CO-OPS stations by type/state | `station_type`, `state`, `limit` |
91
+ | `coops_get_station` | Get detailed station metadata | `station_id`, `expand` (sensors, datums, etc.) |
92
+ | `coops_find_nearest_stations` | Find stations near coordinates | `latitude`, `longitude`, `radius_km` |
93
+ | `coops_get_water_levels` | Observed water level data | `station_id`, `begin_date`, `end_date`, `datum` |
94
+ | `coops_get_tide_predictions` | Tide predictions | `station_id`, `begin_date`, `end_date`, `interval` |
95
+ | `coops_get_meteorological` | Met observations (wind, temp, etc.) | `station_id`, `product`, `date` |
96
+ | `coops_get_currents` | Current observations/predictions | `station_id`, `product`, `bin_num` |
97
+ | `coops_get_extreme_water_levels` | Record water levels | `station_id`, `datum` |
98
+ | `coops_get_flood_stats` | Flood day counts & HTF outlook | `station_id`, `year` |
99
+ | `coops_get_sea_level_trends` | Sea level trend data | `station_id` |
100
+ | `coops_get_peak_storm_events` | Peak storm surge events | `station_id`, `year` |
101
+ | `coops_get_datums` | Tidal datum values | `station_id`, `units` |
102
+
103
+ ## Usage Examples
104
+
105
+ Ask naturally — the right tool will be selected automatically:
106
+
107
+ - **"Get current water levels at The Battery, NY"** → `coops_get_water_levels(station_id="8518750", date="latest")`
108
+ - **"Find tide stations near Miami Beach"** → `coops_find_nearest_stations(latitude=25.77, longitude=-80.13, station_type="waterlevels")`
109
+ - **"What were the highest water levels ever recorded at San Francisco?"** → `coops_get_extreme_water_levels(station_id="9414290")`
110
+ - **"Show me wind data for Key West today"** → `coops_get_meteorological(station_id="8724580", product="wind", date="today")`
111
+ - **"What are the flood statistics for The Battery?"** → `coops_get_flood_stats(station_id="8518750")`
112
+ - **"Get tide predictions for Charleston, SC for next week"** → `coops_get_tide_predictions(station_id="8665530", begin_date="...", end_date="...")`
113
+
114
+ ## API Reference
115
+
116
+ This server wraps three NOAA CO-OPS APIs:
117
+
118
+ - [Data API](https://tidesandcurrents.noaa.gov/api/) — Observations and predictions
119
+ - [Metadata API](https://tidesandcurrents.noaa.gov/mdapi/latest/) — Station information
120
+ - [Derived Product API](https://api.tidesandcurrents.noaa.gov/dpapi/prod/) — Historical/statistical products
121
+
122
+ ## Development
123
+
124
+ ```bash
125
+ # Install dev dependencies
126
+ uv sync
127
+
128
+ # Run unit tests
129
+ uv run pytest tests/test_models.py tests/test_utils.py tests/test_client.py -v
130
+
131
+ # Run live integration tests (makes real API calls)
132
+ uv run pytest tests/test_live.py -v -s
133
+
134
+ # Start the server
135
+ uv run python -m coops_mcp
136
+ ```
137
+
138
+ ## License
139
+
140
+ MIT
@@ -0,0 +1,110 @@
1
+ # CO-OPS MCP Server
2
+
3
+ <!-- mcp-name: io.github.mansurjisan/coops-mcp -->
4
+
5
+ MCP server providing AI assistants with access to NOAA CO-OPS water levels, tides, currents, and coastal oceanographic data.
6
+
7
+ **No API key required** — all CO-OPS APIs are free and public.
8
+
9
+ ## Features
10
+
11
+ - **Station Discovery** — List, search, and find nearest CO-OPS stations by type, state, or coordinates
12
+ - **Water Levels** — Real-time and historical observed water levels with multiple datum references
13
+ - **Tide Predictions** — Harmonic tide predictions (6-min, hourly, or high/low)
14
+ - **Meteorological Data** — Wind, air/water temperature, pressure, humidity, visibility, and more
15
+ - **Currents** — Current observations and predictions from PORTS stations
16
+ - **Derived Products** — Extreme water levels, flood statistics, sea level trends, storm events, tidal datums
17
+
18
+ ## Quick Start
19
+
20
+ ### Install with uv
21
+
22
+ ```bash
23
+ git clone https://github.com/mansurjisan/ocean-mcp.git
24
+ cd ocean-mcp/servers/coops-mcp
25
+ uv sync
26
+ ```
27
+
28
+ ### Configure your MCP client
29
+
30
+ Add to your MCP settings:
31
+
32
+ ```json
33
+ {
34
+ "mcpServers": {
35
+ "coops": {
36
+ "command": "uv",
37
+ "args": ["run", "--directory", "/path/to/ocean-mcp/servers/coops-mcp", "python", "-m", "coops_mcp"]
38
+ }
39
+ }
40
+ }
41
+ ```
42
+
43
+ Or if installed as a package:
44
+
45
+ ```json
46
+ {
47
+ "mcpServers": {
48
+ "coops": {
49
+ "command": "uvx",
50
+ "args": ["coops-mcp"]
51
+ }
52
+ }
53
+ }
54
+ ```
55
+
56
+ ## Available Tools
57
+
58
+ | Tool | Description | Key Parameters |
59
+ |------|-------------|----------------|
60
+ | `coops_list_stations` | List CO-OPS stations by type/state | `station_type`, `state`, `limit` |
61
+ | `coops_get_station` | Get detailed station metadata | `station_id`, `expand` (sensors, datums, etc.) |
62
+ | `coops_find_nearest_stations` | Find stations near coordinates | `latitude`, `longitude`, `radius_km` |
63
+ | `coops_get_water_levels` | Observed water level data | `station_id`, `begin_date`, `end_date`, `datum` |
64
+ | `coops_get_tide_predictions` | Tide predictions | `station_id`, `begin_date`, `end_date`, `interval` |
65
+ | `coops_get_meteorological` | Met observations (wind, temp, etc.) | `station_id`, `product`, `date` |
66
+ | `coops_get_currents` | Current observations/predictions | `station_id`, `product`, `bin_num` |
67
+ | `coops_get_extreme_water_levels` | Record water levels | `station_id`, `datum` |
68
+ | `coops_get_flood_stats` | Flood day counts & HTF outlook | `station_id`, `year` |
69
+ | `coops_get_sea_level_trends` | Sea level trend data | `station_id` |
70
+ | `coops_get_peak_storm_events` | Peak storm surge events | `station_id`, `year` |
71
+ | `coops_get_datums` | Tidal datum values | `station_id`, `units` |
72
+
73
+ ## Usage Examples
74
+
75
+ Ask naturally — the right tool will be selected automatically:
76
+
77
+ - **"Get current water levels at The Battery, NY"** → `coops_get_water_levels(station_id="8518750", date="latest")`
78
+ - **"Find tide stations near Miami Beach"** → `coops_find_nearest_stations(latitude=25.77, longitude=-80.13, station_type="waterlevels")`
79
+ - **"What were the highest water levels ever recorded at San Francisco?"** → `coops_get_extreme_water_levels(station_id="9414290")`
80
+ - **"Show me wind data for Key West today"** → `coops_get_meteorological(station_id="8724580", product="wind", date="today")`
81
+ - **"What are the flood statistics for The Battery?"** → `coops_get_flood_stats(station_id="8518750")`
82
+ - **"Get tide predictions for Charleston, SC for next week"** → `coops_get_tide_predictions(station_id="8665530", begin_date="...", end_date="...")`
83
+
84
+ ## API Reference
85
+
86
+ This server wraps three NOAA CO-OPS APIs:
87
+
88
+ - [Data API](https://tidesandcurrents.noaa.gov/api/) — Observations and predictions
89
+ - [Metadata API](https://tidesandcurrents.noaa.gov/mdapi/latest/) — Station information
90
+ - [Derived Product API](https://api.tidesandcurrents.noaa.gov/dpapi/prod/) — Historical/statistical products
91
+
92
+ ## Development
93
+
94
+ ```bash
95
+ # Install dev dependencies
96
+ uv sync
97
+
98
+ # Run unit tests
99
+ uv run pytest tests/test_models.py tests/test_utils.py tests/test_client.py -v
100
+
101
+ # Run live integration tests (makes real API calls)
102
+ uv run pytest tests/test_live.py -v -s
103
+
104
+ # Start the server
105
+ uv run python -m coops_mcp
106
+ ```
107
+
108
+ ## License
109
+
110
+ MIT
@@ -0,0 +1,67 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <evaluation>
3
+ <description>
4
+ Evaluation questions for the CO-OPS MCP Server.
5
+ Each question tests tool usage against real NOAA CO-OPS data.
6
+ </description>
7
+
8
+ <question id="1">
9
+ <text>What is the tidal range (MHHW minus MLLW) at station 9414290 (San Francisco) in meters?</text>
10
+ <tools_required>coops_get_datums</tools_required>
11
+ <hint>Retrieve datums for station 9414290 in metric units and compute MHHW - MLLW.</hint>
12
+ </question>
13
+
14
+ <question id="2">
15
+ <text>Which CO-OPS water level station in Florida has the highest recorded extreme water level?</text>
16
+ <tools_required>coops_list_stations, coops_get_extreme_water_levels</tools_required>
17
+ <hint>List water level stations filtered by state FL, then query extreme water levels for each.</hint>
18
+ </question>
19
+
20
+ <question id="3">
21
+ <text>How many active water level stations are there in the state of New York?</text>
22
+ <tools_required>coops_list_stations</tools_required>
23
+ <hint>List stations with type=waterlevels and state=NY, using a high limit to get all results.</hint>
24
+ </question>
25
+
26
+ <question id="4">
27
+ <text>What is the sea level trend at The Battery, NY (8518750)?</text>
28
+ <tools_required>coops_get_sea_level_trends</tools_required>
29
+ <hint>Query sea level trends for station 8518750.</hint>
30
+ </question>
31
+
32
+ <question id="5">
33
+ <text>What are the names of the 3 closest CO-OPS water level stations to latitude 25.77, longitude -80.13 (Miami Beach)?</text>
34
+ <tools_required>coops_find_nearest_stations</tools_required>
35
+ <hint>Search for nearest waterlevels stations to (25.77, -80.13) with limit=3.</hint>
36
+ </question>
37
+
38
+ <question id="6">
39
+ <text>What is the mean tidal range at Honolulu (1612340) in feet?</text>
40
+ <tools_required>coops_get_datums</tools_required>
41
+ <hint>Retrieve datums for station 1612340 in english units, compute MHW - MLW.</hint>
42
+ </question>
43
+
44
+ <question id="7">
45
+ <text>What is the station name and state for CO-OPS station 8443970?</text>
46
+ <tools_required>coops_get_station</tools_required>
47
+ <hint>Get station details for 8443970.</hint>
48
+ </question>
49
+
50
+ <question id="8">
51
+ <text>How many annual minor flood days were recorded at 8518750 (The Battery) in 2023?</text>
52
+ <tools_required>coops_get_flood_stats</tools_required>
53
+ <hint>Query flood stats for station 8518750 with year=2023.</hint>
54
+ </question>
55
+
56
+ <question id="9">
57
+ <text>What datums are available at station 9414290 (San Francisco)?</text>
58
+ <tools_required>coops_get_datums</tools_required>
59
+ <hint>Get datums for station 9414290 and list all datum names.</hint>
60
+ </question>
61
+
62
+ <question id="10">
63
+ <text>What sensors are installed at station 8724580 (Key West)?</text>
64
+ <tools_required>coops_get_station</tools_required>
65
+ <hint>Get station 8724580 with expand=sensors.</hint>
66
+ </question>
67
+ </evaluation>
@@ -0,0 +1,68 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "coops-mcp"
7
+ version = "0.1.0"
8
+ description = "MCP server providing access to NOAA CO-OPS tides, water levels, currents, and meteorological data"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ license-files = ["LICENSE"]
12
+ requires-python = ">=3.11"
13
+ authors = [
14
+ {name = "Mansur Ali Jisan", email = "mansur.jisan@noaa.gov"},
15
+ ]
16
+ keywords = [
17
+ "mcp",
18
+ "model-context-protocol",
19
+ "noaa",
20
+ "tides",
21
+ "water-levels",
22
+ "currents",
23
+ "coastal",
24
+ "oceanography",
25
+ "coops",
26
+ ]
27
+ classifiers = [
28
+ "Development Status :: 4 - Beta",
29
+ "Intended Audience :: Science/Research",
30
+ "Intended Audience :: Developers",
31
+ "License :: OSI Approved :: MIT License",
32
+ "Programming Language :: Python :: 3",
33
+ "Programming Language :: Python :: 3.11",
34
+ "Programming Language :: Python :: 3.12",
35
+ "Programming Language :: Python :: 3.13",
36
+ "Topic :: Scientific/Engineering :: Atmospheric Science",
37
+ "Topic :: Scientific/Engineering :: GIS",
38
+ "Topic :: Software Development :: Libraries :: Python Modules",
39
+ ]
40
+ dependencies = [
41
+ "mcp[cli]>=1.0.0",
42
+ "httpx>=0.27.0",
43
+ "pydantic>=2.0.0",
44
+ ]
45
+
46
+ [project.urls]
47
+ Homepage = "https://github.com/mansurjisan/ocean-mcp"
48
+ Repository = "https://github.com/mansurjisan/ocean-mcp"
49
+ "Bug Tracker" = "https://github.com/mansurjisan/ocean-mcp/issues"
50
+ Documentation = "https://github.com/mansurjisan/ocean-mcp/tree/main/servers/coops-mcp"
51
+ Changelog = "https://github.com/mansurjisan/ocean-mcp/releases"
52
+
53
+ [project.scripts]
54
+ coops-mcp = "coops_mcp.server:main"
55
+
56
+ [tool.hatch.build.targets.wheel]
57
+ packages = ["src/coops_mcp"]
58
+
59
+ [tool.pytest.ini_options]
60
+ testpaths = ["tests"]
61
+ asyncio_mode = "auto"
62
+
63
+ [dependency-groups]
64
+ dev = [
65
+ "pytest>=8.0.0",
66
+ "pytest-asyncio>=0.24.0",
67
+ "respx>=0.22.0",
68
+ ]
@@ -0,0 +1,22 @@
1
+ {
2
+ "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
3
+ "name": "io.github.mansurjisan/coops-mcp",
4
+ "title": "NOAA CO-OPS MCP Server",
5
+ "description": "MCP server for NOAA CO-OPS tides, water levels, currents, and meteorological data. No API key required.",
6
+ "version": "0.1.0",
7
+ "repository": {
8
+ "url": "https://github.com/mansurjisan/ocean-mcp",
9
+ "source": "github"
10
+ },
11
+ "packages": [
12
+ {
13
+ "registryType": "pypi",
14
+ "identifier": "coops-mcp",
15
+ "version": "0.1.0",
16
+ "runtimeHint": "uvx",
17
+ "transport": {
18
+ "type": "stdio"
19
+ }
20
+ }
21
+ ]
22
+ }
@@ -0,0 +1,9 @@
1
+ # Smithery configuration — https://smithery.ai/docs/config
2
+ startCommand:
3
+ type: stdio
4
+ configSchema:
5
+ type: object
6
+ required: []
7
+ properties: {}
8
+ commandFunction: |-
9
+ (config) => ({ command: 'uvx', args: ['coops-mcp'] })
@@ -0,0 +1 @@
1
+ """CO-OPS MCP Server — NOAA Tides & Currents for AI Assistants."""
@@ -0,0 +1,5 @@
1
+ """Allow running the package with python -m coops_mcp."""
2
+
3
+ from .server import main
4
+
5
+ main()
@@ -0,0 +1,63 @@
1
+ """Shared async HTTP client for CO-OPS APIs."""
2
+
3
+ import httpx
4
+ from typing import Any
5
+
6
+ DATA_API_BASE = "https://api.tidesandcurrents.noaa.gov/api/prod/datagetter"
7
+ METADATA_API_BASE = "https://api.tidesandcurrents.noaa.gov/mdapi/prod/webapi"
8
+ DERIVED_API_BASE = "https://api.tidesandcurrents.noaa.gov/dpapi/prod/webapi"
9
+
10
+ APPLICATION_NAME = "coops_mcp"
11
+
12
+
13
+ class COOPSAPIError(Exception):
14
+ """Custom exception for CO-OPS API errors."""
15
+ pass
16
+
17
+
18
+ class COOPSClient:
19
+ """Async client for CO-OPS APIs."""
20
+
21
+ def __init__(self) -> None:
22
+ self._client: httpx.AsyncClient | None = None
23
+
24
+ async def _get_client(self) -> httpx.AsyncClient:
25
+ if self._client is None or self._client.is_closed:
26
+ self._client = httpx.AsyncClient(timeout=30.0)
27
+ return self._client
28
+
29
+ async def fetch_data(self, params: dict[str, Any]) -> dict:
30
+ """Fetch from the Data API (datagetter).
31
+
32
+ Automatically sets format=json and application=coops_mcp.
33
+ Raises COOPSAPIError if the API returns an error in the JSON body.
34
+ """
35
+ params["format"] = "json"
36
+ params["application"] = APPLICATION_NAME
37
+ client = await self._get_client()
38
+ response = await client.get(DATA_API_BASE, params=params)
39
+ response.raise_for_status()
40
+ data = response.json()
41
+ if "error" in data:
42
+ raise COOPSAPIError(data["error"].get("message", "Unknown API error"))
43
+ return data
44
+
45
+ async def fetch_metadata(self, path: str, params: dict[str, Any] | None = None) -> dict:
46
+ """Fetch from the Metadata API."""
47
+ url = f"{METADATA_API_BASE}/{path}"
48
+ client = await self._get_client()
49
+ response = await client.get(url, params=params or {})
50
+ response.raise_for_status()
51
+ return response.json()
52
+
53
+ async def fetch_derived(self, path: str, params: dict[str, Any] | None = None) -> dict:
54
+ """Fetch from the Derived Product API."""
55
+ url = f"{DERIVED_API_BASE}/{path}"
56
+ client = await self._get_client()
57
+ response = await client.get(url, params=params or {})
58
+ response.raise_for_status()
59
+ return response.json()
60
+
61
+ async def close(self) -> None:
62
+ if self._client and not self._client.is_closed:
63
+ await self._client.aclose()
@@ -0,0 +1,65 @@
1
+ """Pydantic models for CO-OPS MCP server validation and response formatting."""
2
+
3
+ from enum import Enum
4
+
5
+
6
+ class Datum(str, Enum):
7
+ MLLW = "MLLW"
8
+ MHHW = "MHHW"
9
+ MSL = "MSL"
10
+ NAVD = "NAVD"
11
+ STND = "STND"
12
+ MHW = "MHW"
13
+ MLW = "MLW"
14
+ MTL = "MTL"
15
+ IGLD = "IGLD"
16
+ LWD = "LWD"
17
+
18
+
19
+ class Units(str, Enum):
20
+ METRIC = "metric"
21
+ ENGLISH = "english"
22
+
23
+
24
+ class TimeZone(str, Enum):
25
+ GMT = "gmt"
26
+ LST = "lst"
27
+ LST_LDT = "lst_ldt"
28
+
29
+
30
+ class Interval(str, Enum):
31
+ SIX_MIN = "6"
32
+ HOURLY = "h"
33
+ HILO = "hilo"
34
+
35
+
36
+ class DateShorthand(str, Enum):
37
+ TODAY = "today"
38
+ LATEST = "latest"
39
+ RECENT = "recent"
40
+
41
+
42
+ class StationType(str, Enum):
43
+ WATERLEVELS = "waterlevels"
44
+ CURRENTPREDICTIONS = "currentpredictions"
45
+ WATERLEVELSANDMET = "waterlevelsandmet"
46
+ TCOON = "tcoon"
47
+ NWLON = "nwlon"
48
+ PORTS = "ports"
49
+
50
+
51
+ class MetProduct(str, Enum):
52
+ WIND = "wind"
53
+ AIR_TEMPERATURE = "air_temperature"
54
+ WATER_TEMPERATURE = "water_temperature"
55
+ AIR_PRESSURE = "air_pressure"
56
+ HUMIDITY = "humidity"
57
+ CONDUCTIVITY = "conductivity"
58
+ SALINITY = "salinity"
59
+ VISIBILITY = "visibility"
60
+ AIR_GAP = "air_gap"
61
+
62
+
63
+ class CurrentsProduct(str, Enum):
64
+ CURRENTS = "currents"
65
+ CURRENTS_PREDICTIONS = "currents_predictions"
@@ -0,0 +1,32 @@
1
+ """FastMCP server entry point for CO-OPS MCP."""
2
+
3
+ from collections.abc import AsyncIterator
4
+ from contextlib import asynccontextmanager
5
+
6
+ from mcp.server.fastmcp import FastMCP
7
+
8
+ from .client import COOPSClient
9
+
10
+
11
+ @asynccontextmanager
12
+ async def app_lifespan(server: FastMCP) -> AsyncIterator[dict]:
13
+ """Manage the shared CO-OPS API client lifecycle."""
14
+ client = COOPSClient()
15
+ try:
16
+ yield {"coops_client": client}
17
+ finally:
18
+ await client.close()
19
+
20
+
21
+ mcp = FastMCP("coops_mcp", lifespan=app_lifespan)
22
+
23
+ # Import tool modules to register them with the server
24
+ from .tools import currents, derived, meteorological, stations, water_levels # noqa: E402, F401
25
+
26
+
27
+ def main() -> None:
28
+ mcp.run()
29
+
30
+
31
+ if __name__ == "__main__":
32
+ main()
File without changes