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.
- coops_mcp-0.1.0/.gitignore +42 -0
- coops_mcp-0.1.0/LICENSE +21 -0
- coops_mcp-0.1.0/PKG-INFO +140 -0
- coops_mcp-0.1.0/README.md +110 -0
- coops_mcp-0.1.0/eval/evaluation.xml +67 -0
- coops_mcp-0.1.0/pyproject.toml +68 -0
- coops_mcp-0.1.0/server.json +22 -0
- coops_mcp-0.1.0/smithery.yaml +9 -0
- coops_mcp-0.1.0/src/coops_mcp/__init__.py +1 -0
- coops_mcp-0.1.0/src/coops_mcp/__main__.py +5 -0
- coops_mcp-0.1.0/src/coops_mcp/client.py +63 -0
- coops_mcp-0.1.0/src/coops_mcp/models.py +65 -0
- coops_mcp-0.1.0/src/coops_mcp/server.py +32 -0
- coops_mcp-0.1.0/src/coops_mcp/tools/__init__.py +0 -0
- coops_mcp-0.1.0/src/coops_mcp/tools/currents.py +111 -0
- coops_mcp-0.1.0/src/coops_mcp/tools/derived.py +354 -0
- coops_mcp-0.1.0/src/coops_mcp/tools/meteorological.py +108 -0
- coops_mcp-0.1.0/src/coops_mcp/tools/stations.py +222 -0
- coops_mcp-0.1.0/src/coops_mcp/tools/water_levels.py +216 -0
- coops_mcp-0.1.0/src/coops_mcp/utils.py +170 -0
- coops_mcp-0.1.0/tests/__init__.py +0 -0
- coops_mcp-0.1.0/tests/test_client.py +99 -0
- coops_mcp-0.1.0/tests/test_live.py +117 -0
- coops_mcp-0.1.0/tests/test_models.py +58 -0
- coops_mcp-0.1.0/tests/test_utils.py +122 -0
|
@@ -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
|
coops_mcp-0.1.0/LICENSE
ADDED
|
@@ -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.
|
coops_mcp-0.1.0/PKG-INFO
ADDED
|
@@ -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 @@
|
|
|
1
|
+
"""CO-OPS MCP Server — NOAA Tides & Currents for AI Assistants."""
|
|
@@ -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
|