vesselapi-mcp 1.3.0 → 2.0.1
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/CHANGELOG.md +84 -0
- package/README.md +26 -26
- package/dist/index.js +114 -189
- package/dist/index.js.map +1 -1
- package/package.json +6 -5
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this server are documented here.
|
|
4
|
+
This project follows [Semantic Versioning](https://semver.org/).
|
|
5
|
+
|
|
6
|
+
## [2.0.1] - 2026-10-08
|
|
7
|
+
|
|
8
|
+
Documentation only. No tool, parameter or response changed.
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- Tool descriptions now say what each endpoint actually returns and where its
|
|
13
|
+
limits are: `get_vessel_position` is the latest stored position, which may be
|
|
14
|
+
hours or days old; `get_vessel_eta` is the ETA the vessel last reported, not a
|
|
15
|
+
prediction; `get_vessel_emissions` and `list_emissions` are EU MRV reports;
|
|
16
|
+
the port event tools state the 2-hour default window and cover "all covered
|
|
17
|
+
ports" rather than "global"; `get_vessels_in_area` and `get_vessels_in_radius`
|
|
18
|
+
describe the time window (default 2 hours, at most 4) and the 4-degree
|
|
19
|
+
bounding box span; `get_port_inbound` describes its ETA window.
|
|
20
|
+
|
|
21
|
+
### Removed
|
|
22
|
+
|
|
23
|
+
- The README section on a third-party hosted deployment.
|
|
24
|
+
|
|
25
|
+
## [2.0.0] - 2026-08-13
|
|
26
|
+
|
|
27
|
+
Vessel ownership, classification and inspection data, and NAVTEX messages were
|
|
28
|
+
retired from the VesselAPI service on **10 August 2026**. There is no
|
|
29
|
+
replacement for them.
|
|
30
|
+
|
|
31
|
+
### Removed (breaking)
|
|
32
|
+
|
|
33
|
+
- `get_vessel_classification`
|
|
34
|
+
- `get_vessel_ownership`
|
|
35
|
+
- `get_vessel_inspections`
|
|
36
|
+
- `get_vessel_inspection_detail`
|
|
37
|
+
- `get_navtex_messages`
|
|
38
|
+
|
|
39
|
+
`search_vessels` no longer accepts `classSociety` or `owner`. The API rejects
|
|
40
|
+
both with HTTP 400.
|
|
41
|
+
|
|
42
|
+
**19 tools remain**, down from 24.
|
|
43
|
+
|
|
44
|
+
### Added
|
|
45
|
+
|
|
46
|
+
- **`q` on `search_vessels`.** Free-text search across name, IMO, MMSI, ENI and
|
|
47
|
+
callsign. The response reports which fields matched.
|
|
48
|
+
- **`eni` on `search_vessels`**, for inland waterway vessels.
|
|
49
|
+
- **`sat` on `get_vessel_position`.** Falls back to a satellite position when no
|
|
50
|
+
recent terrestrial one exists. Charged per call against a prepaid balance.
|
|
51
|
+
- **`timeFrom` and `timeTo` on `get_port_events`, `search_port_events_by_port`
|
|
52
|
+
and `search_port_events_by_vessel`.** Without them the service returns only
|
|
53
|
+
the last 2 hours.
|
|
54
|
+
|
|
55
|
+
### Fixed
|
|
56
|
+
|
|
57
|
+
- **`get_vessels_in_radius` asked for the radius in nautical miles.** The API
|
|
58
|
+
takes metres, so a request for 20 nautical miles searched 20 metres and
|
|
59
|
+
returned nothing.
|
|
60
|
+
- **`get_port_inbound` required an ETA window.** It is now optional, and the
|
|
61
|
+
service defaults to the next 72 hours.
|
|
62
|
+
- **`idType` offered `vesselId`, which the API rejects with HTTP 400.** It now
|
|
63
|
+
accepts `imo` and `mmsi` only.
|
|
64
|
+
- **402 and 403 reported as generic API errors.** Out of satellite credits, a
|
|
65
|
+
suspended key and a feature outside the plan are now distinct conditions,
|
|
66
|
+
none worth retrying unchanged.
|
|
67
|
+
- **A missing `VESSELAPI_API_KEY` killed the process with a stack trace during
|
|
68
|
+
startup.** It now prints one line naming the variable.
|
|
69
|
+
- **Two version mismatches.** `server.json` declared 1.0.1 while the package was
|
|
70
|
+
1.3.0, and the server reported 1.0.0 in the MCP handshake whatever the
|
|
71
|
+
installed version.
|
|
72
|
+
- **Tool schemas now match what the API accepts.** `idType`, `eventType` and
|
|
73
|
+
`sortOrder` are enumerations, `limit` is bounded to 1 to 50, and the area
|
|
74
|
+
tools state the 4 hour maximum window.
|
|
75
|
+
|
|
76
|
+
### Requires
|
|
77
|
+
|
|
78
|
+
`vesselapi` 2.0.0 or later.
|
|
79
|
+
|
|
80
|
+
### Attribution
|
|
81
|
+
|
|
82
|
+
Emissions and casualty data: © European Union. Source: European Maritime Safety
|
|
83
|
+
Agency (EMSA), THETIS-MRV (EU MRV, Regulation (EU) 2015/757) and the European
|
|
84
|
+
Marine Casualty Information Platform (EMCIP). See the README.
|
package/README.md
CHANGED
|
@@ -21,16 +21,15 @@ An [MCP (Model Context Protocol)](https://modelcontextprotocol.io/) server that
|
|
|
21
21
|
|
|
22
22
|
## Features
|
|
23
23
|
|
|
24
|
-
- **
|
|
25
|
-
- Vessel search, positions (single and batch), ETA,
|
|
26
|
-
- Port search, details, port events (arrivals/departures), and
|
|
24
|
+
- **19 tools** covering vessels, ports, location search, and emissions
|
|
25
|
+
- Vessel search, positions (single and batch), ETA, emissions, and casualties
|
|
26
|
+
- Port search, details, port events (arrivals/departures), and port event search across all covered ports
|
|
27
27
|
- Geographic vessel search (bounding box and radius)
|
|
28
|
-
- NAVTEX maritime safety messages
|
|
29
28
|
- Manual pagination to control API quota usage
|
|
30
29
|
|
|
31
30
|
## Quick Start
|
|
32
31
|
|
|
33
|
-
No installation required
|
|
32
|
+
No installation required. Configure your AI client with `npx`:
|
|
34
33
|
|
|
35
34
|
```json
|
|
36
35
|
{
|
|
@@ -54,7 +53,7 @@ Add the JSON above to the config file for your client:
|
|
|
54
53
|
|---|---|
|
|
55
54
|
| Claude Desktop | `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows) |
|
|
56
55
|
| Cursor | `.cursor/mcp.json` or `~/.cursor/mcp.json` |
|
|
57
|
-
| Claude Code | `.
|
|
56
|
+
| Claude Code | `claude mcp add`, which writes `.mcp.json` in the project or `~/.claude.json` for user scope |
|
|
58
57
|
| Windsurf | `~/.codeium/windsurf/mcp_config.json` |
|
|
59
58
|
|
|
60
59
|
## Tools
|
|
@@ -63,16 +62,12 @@ Add the JSON above to the config file for your client:
|
|
|
63
62
|
|
|
64
63
|
| Tool | Description |
|
|
65
64
|
|---|---|
|
|
66
|
-
| `search_vessels` | Search vessels by name, IMO, MMSI, flag, type, callsign, year built
|
|
65
|
+
| `search_vessels` | Search vessels by name, IMO, MMSI, flag, type, callsign, or year built |
|
|
67
66
|
| `get_vessel` | Get detailed vessel information |
|
|
68
|
-
| `get_vessel_position` | Get
|
|
69
|
-
| `get_vessel_eta` | Get vessel
|
|
70
|
-
| `
|
|
71
|
-
| `get_vessel_ownership` | Get ownership details (owner, manager, operator) |
|
|
72
|
-
| `get_vessel_emissions` | Get emissions data (CO2, fuel consumption) |
|
|
73
|
-
| `get_vessel_inspections` | Get port state control inspections |
|
|
67
|
+
| `get_vessel_position` | Get the latest stored vessel position (lat/lon, speed, heading, timestamp); it may be hours or days old |
|
|
68
|
+
| `get_vessel_eta` | Get the ETA the vessel last reported (declared, not predicted) |
|
|
69
|
+
| `get_vessel_emissions` | Get EU MRV emissions reports (CO2, fuel consumption) |
|
|
74
70
|
| `get_vessel_casualties` | Get marine casualty records |
|
|
75
|
-
| `get_vessel_inspection_detail` | Get detailed information about a specific inspection |
|
|
76
71
|
| `get_vessel_positions_batch` | Get positions for multiple vessels at once (with optional time range) |
|
|
77
72
|
|
|
78
73
|
### Port Tools
|
|
@@ -81,9 +76,10 @@ Add the JSON above to the config file for your client:
|
|
|
81
76
|
|---|---|
|
|
82
77
|
| `search_ports` | Search ports by name, country, type, size, region, harbor size, or harbor use |
|
|
83
78
|
| `get_port` | Get port details by UN/LOCODE |
|
|
84
|
-
| `
|
|
85
|
-
| `
|
|
86
|
-
| `
|
|
79
|
+
| `get_port_inbound` | Get vessels reporting a port as their destination, within an ETA window |
|
|
80
|
+
| `get_port_events` | Get arrivals/departures for a port (last 2 hours unless `timeFrom` is given) |
|
|
81
|
+
| `get_port_events_by_vessel` | Get port events for a vessel (last 2 hours unless `timeFrom` is given) |
|
|
82
|
+
| `list_port_events` | List port events across all covered ports, with filters for time, country, port, vessel, or event type |
|
|
87
83
|
| `search_port_events_by_port` | Search port events by port name |
|
|
88
84
|
| `search_port_events_by_vessel` | Search port events by vessel name |
|
|
89
85
|
| `get_vessel_last_port_event` | Get the most recent port event for a vessel |
|
|
@@ -92,24 +88,19 @@ Add the JSON above to the config file for your client:
|
|
|
92
88
|
|
|
93
89
|
| Tool | Description |
|
|
94
90
|
|---|---|
|
|
95
|
-
| `list_emissions` | List
|
|
91
|
+
| `list_emissions` | List EU MRV emissions reports, with an optional reporting-year filter |
|
|
96
92
|
|
|
97
93
|
### Location Tools
|
|
98
94
|
|
|
99
95
|
| Tool | Description |
|
|
100
96
|
|---|---|
|
|
101
|
-
| `get_vessels_in_area` | Find vessels in a bounding box (
|
|
102
|
-
| `get_vessels_in_radius` | Find vessels within a radius of a point (
|
|
97
|
+
| `get_vessels_in_area` | Find vessels with an AIS position in a bounding box (default last 2 hours, at most 4 hours) |
|
|
98
|
+
| `get_vessels_in_radius` | Find vessels with an AIS position within a radius of a point (default last 2 hours, at most 4 hours) |
|
|
103
99
|
|
|
104
|
-
### Safety Tools
|
|
105
|
-
|
|
106
|
-
| Tool | Description |
|
|
107
|
-
|---|---|
|
|
108
|
-
| `get_navtex_messages` | Get NAVTEX maritime safety messages |
|
|
109
100
|
|
|
110
101
|
## Pagination
|
|
111
102
|
|
|
112
|
-
All list endpoints support `limit` and `nextToken` parameters for manual pagination. When more results exist, the response includes a `nextToken
|
|
103
|
+
All list endpoints support `limit` and `nextToken` parameters for manual pagination. When more results exist, the response includes a `nextToken`. Pass it in the next call to get the next page.
|
|
113
104
|
|
|
114
105
|
## Development
|
|
115
106
|
|
|
@@ -132,6 +123,15 @@ npm run clean # Remove build artifacts
|
|
|
132
123
|
VESSELAPI_API_KEY=your-key npx @modelcontextprotocol/inspector node dist/index.js
|
|
133
124
|
```
|
|
134
125
|
|
|
126
|
+
## Data Sources & Attribution
|
|
127
|
+
|
|
128
|
+
Emissions and casualty data: © European Union. Source: European Maritime Safety Agency
|
|
129
|
+
(EMSA): THETIS-MRV (EU MRV, Regulation (EU) 2015/757) and the European Marine Casualty
|
|
130
|
+
Information Platform (EMCIP). Reused under the European Commission reuse notice
|
|
131
|
+
(Commission Decision 2011/833/EU), which authorises reuse for commercial and
|
|
132
|
+
non-commercial purposes with acknowledgement of the source. Data may be transformed and
|
|
133
|
+
combined; EMSA does not endorse this service.
|
|
134
|
+
|
|
135
135
|
## License
|
|
136
136
|
|
|
137
137
|
MIT
|
package/dist/index.js
CHANGED
|
@@ -5,6 +5,9 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
5
5
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
6
|
import { VesselClient } from "vesselapi";
|
|
7
7
|
|
|
8
|
+
// src/version.ts
|
|
9
|
+
var VERSION = "2.0.1";
|
|
10
|
+
|
|
8
11
|
// src/tools/location.ts
|
|
9
12
|
import { z } from "zod";
|
|
10
13
|
|
|
@@ -12,7 +15,9 @@ import { z } from "zod";
|
|
|
12
15
|
import {
|
|
13
16
|
VesselAPIError,
|
|
14
17
|
VesselAuthError,
|
|
18
|
+
VesselForbiddenError,
|
|
15
19
|
VesselNotFoundError,
|
|
20
|
+
VesselPaymentRequiredError,
|
|
16
21
|
VesselRateLimitError,
|
|
17
22
|
VesselServerError
|
|
18
23
|
} from "vesselapi";
|
|
@@ -24,15 +29,21 @@ function formatResult(data) {
|
|
|
24
29
|
function handleToolError(error) {
|
|
25
30
|
let message;
|
|
26
31
|
if (error instanceof VesselAuthError) {
|
|
27
|
-
message = "Authentication failed. Check your VESSELAPI_API_KEY.";
|
|
32
|
+
message = "Authentication failed. Check your VESSELAPI_API_KEY. Do not retry.";
|
|
33
|
+
} else if (error instanceof VesselPaymentRequiredError) {
|
|
34
|
+
message = "Out of satellite credits, and no stored position was available to fall back on. Retry without the satellite option to use stored data, or top up the balance at https://dashboard.vesselapi.com. Retrying the same request will not help.";
|
|
35
|
+
} else if (error instanceof VesselForbiddenError) {
|
|
36
|
+
message = error.code === "feature_not_available" ? "This endpoint is not included in the current plan. Do not retry; a different plan is required." : "The API key is suspended, usually for sustained quota abuse. Do not retry; check the account at https://dashboard.vesselapi.com.";
|
|
28
37
|
} else if (error instanceof VesselNotFoundError) {
|
|
29
|
-
message =
|
|
38
|
+
message = `Resource not found. Verify the ID or parameters. ${error.message}`;
|
|
30
39
|
} else if (error instanceof VesselRateLimitError) {
|
|
31
|
-
message = "Rate limit exceeded.
|
|
40
|
+
message = "Rate limit exceeded. Retrying later may succeed; reduce request frequency.";
|
|
32
41
|
} else if (error instanceof VesselServerError) {
|
|
33
|
-
message = `Server error: ${error.message}`;
|
|
42
|
+
message = `Server error, retrying later may succeed: ${error.message}`;
|
|
34
43
|
} else if (error instanceof VesselAPIError) {
|
|
35
|
-
|
|
44
|
+
const code = error.code ? ` (code: ${error.code})` : "";
|
|
45
|
+
const retry = error.statusCode >= 400 && error.statusCode < 500 ? " Do not retry without changing the request." : "";
|
|
46
|
+
message = `Request rejected${code}: ${error.message}.${retry}`;
|
|
36
47
|
} else if (error instanceof Error) {
|
|
37
48
|
message = error.message;
|
|
38
49
|
} else {
|
|
@@ -48,15 +59,15 @@ function handleToolError(error) {
|
|
|
48
59
|
function registerLocationTools(server2, client2) {
|
|
49
60
|
server2.tool(
|
|
50
61
|
"get_vessels_in_area",
|
|
51
|
-
"Find
|
|
62
|
+
"Find vessels with an AIS position inside a rectangular bounding box during the time window (default the last 2 hours, at most 4 hours). The latitude span plus the longitude span may not exceed 4 degrees.",
|
|
52
63
|
{
|
|
53
64
|
latMin: z.number().describe("Southern boundary latitude"),
|
|
54
65
|
latMax: z.number().describe("Northern boundary latitude"),
|
|
55
66
|
lonMin: z.number().describe("Western boundary longitude"),
|
|
56
67
|
lonMax: z.number().describe("Eastern boundary longitude"),
|
|
57
|
-
timeFrom: z.string().optional().describe("Start time
|
|
58
|
-
timeTo: z.string().optional().describe("End time
|
|
59
|
-
limit: z.number().optional().describe("
|
|
68
|
+
timeFrom: z.string().optional().describe("Start of the time window, RFC3339. Defaults to 2 hours ago. The window may not exceed 4 hours."),
|
|
69
|
+
timeTo: z.string().optional().describe("End of the time window, RFC3339. Defaults to now. The window may not exceed 4 hours."),
|
|
70
|
+
limit: z.number().int().min(1).max(50).optional().describe("Results per page, 1 to 50. Defaults to 20."),
|
|
60
71
|
nextToken: z.string().optional().describe("Pagination token from previous response")
|
|
61
72
|
},
|
|
62
73
|
async (params) => {
|
|
@@ -79,14 +90,14 @@ function registerLocationTools(server2, client2) {
|
|
|
79
90
|
);
|
|
80
91
|
server2.tool(
|
|
81
92
|
"get_vessels_in_radius",
|
|
82
|
-
"Find
|
|
93
|
+
"Find vessels with an AIS position within a radius of a point during the time window (default the last 2 hours, at most 4 hours). The radius is in METRES, not nautical miles or kilometres.",
|
|
83
94
|
{
|
|
84
95
|
latitude: z.number().describe("Center latitude"),
|
|
85
96
|
longitude: z.number().describe("Center longitude"),
|
|
86
|
-
radius: z.number().describe("
|
|
87
|
-
timeFrom: z.string().optional().describe("Start time
|
|
88
|
-
timeTo: z.string().optional().describe("End time
|
|
89
|
-
limit: z.number().optional().describe("
|
|
97
|
+
radius: z.number().describe("Search radius in METRES, maximum 100000 (100 km). One nautical mile is 1852 metres."),
|
|
98
|
+
timeFrom: z.string().optional().describe("Start of the time window, RFC3339. Defaults to 2 hours ago. The window may not exceed 4 hours."),
|
|
99
|
+
timeTo: z.string().optional().describe("End of the time window, RFC3339. Defaults to now. The window may not exceed 4 hours."),
|
|
100
|
+
limit: z.number().int().min(1).max(50).optional().describe("Results per page, 1 to 50. Defaults to 20."),
|
|
90
101
|
nextToken: z.string().optional().describe("Pagination token from previous response")
|
|
91
102
|
},
|
|
92
103
|
async (params) => {
|
|
@@ -122,7 +133,7 @@ function registerPortTools(server2, client2) {
|
|
|
122
133
|
region: z2.string().optional().describe("Geographic region (partial match)"),
|
|
123
134
|
harborSize: z2.string().optional().describe("Harbor size classification"),
|
|
124
135
|
harborUse: z2.string().optional().describe("Primary harbor use"),
|
|
125
|
-
limit: z2.number().optional().describe("
|
|
136
|
+
limit: z2.number().int().min(1).max(50).optional().describe("Results per page, 1 to 50. Defaults to 20."),
|
|
126
137
|
nextToken: z2.string().optional().describe("Pagination token from previous response")
|
|
127
138
|
},
|
|
128
139
|
async (params) => {
|
|
@@ -161,14 +172,14 @@ function registerPortTools(server2, client2) {
|
|
|
161
172
|
);
|
|
162
173
|
server2.tool(
|
|
163
174
|
"get_port_inbound",
|
|
164
|
-
"Get vessels
|
|
175
|
+
"Get vessels whose own reported destination is this port, with a declared ETA inside the arrival window. ETAs are reported by the vessels, not predicted.",
|
|
165
176
|
{
|
|
166
177
|
unlocode: z2.string().describe("UN/LOCODE of the destination port (e.g. NLRTM for Rotterdam)"),
|
|
167
|
-
etaFrom: z2.string().describe("Start of ETA arrival window (RFC3339
|
|
168
|
-
etaTo: z2.string().describe("End of ETA arrival window (RFC3339
|
|
169
|
-
timeFrom: z2.string().optional().describe("
|
|
170
|
-
timeTo: z2.string().optional().describe("
|
|
171
|
-
limit: z2.number().optional().describe("
|
|
178
|
+
etaFrom: z2.string().optional().describe("Start of ETA arrival window (RFC3339). Omit to default to now."),
|
|
179
|
+
etaTo: z2.string().optional().describe("End of ETA arrival window (RFC3339). Omit to default to 72 hours ahead."),
|
|
180
|
+
timeFrom: z2.string().optional().describe("Only use reports received after this time, RFC3339. Defaults to 24 hours ago."),
|
|
181
|
+
timeTo: z2.string().optional().describe("Only use reports received before this time, RFC3339. Defaults to now."),
|
|
182
|
+
limit: z2.number().int().min(1).max(50).optional().describe("Results per page, 1 to 50. Defaults to 20."),
|
|
172
183
|
nextToken: z2.string().optional().describe("Pagination token from previous response")
|
|
173
184
|
},
|
|
174
185
|
async (params) => {
|
|
@@ -189,15 +200,19 @@ function registerPortTools(server2, client2) {
|
|
|
189
200
|
);
|
|
190
201
|
server2.tool(
|
|
191
202
|
"get_port_events",
|
|
192
|
-
"Get port events (arrivals/departures) for a specific port",
|
|
203
|
+
"Get port events (arrivals/departures) for a specific port. Covers only the last 2 hours unless timeFrom is given.",
|
|
193
204
|
{
|
|
194
205
|
unlocode: z2.string().describe("UN/LOCODE of the port"),
|
|
195
|
-
|
|
206
|
+
timeFrom: z2.string().optional().describe("Start of the time window, RFC3339. Without it the service returns only the last 2 hours."),
|
|
207
|
+
timeTo: z2.string().optional().describe("End of the time window, RFC3339. Defaults to now."),
|
|
208
|
+
limit: z2.number().int().min(1).max(50).optional().describe("Results per page, 1 to 50. Defaults to 20."),
|
|
196
209
|
nextToken: z2.string().optional().describe("Pagination token from previous response")
|
|
197
210
|
},
|
|
198
211
|
async (params) => {
|
|
199
212
|
try {
|
|
200
213
|
const data = await client2.portEvents.byPort(params.unlocode, {
|
|
214
|
+
timeFrom: params.timeFrom,
|
|
215
|
+
timeTo: params.timeTo,
|
|
201
216
|
paginationLimit: params.limit,
|
|
202
217
|
paginationNextToken: params.nextToken
|
|
203
218
|
});
|
|
@@ -209,15 +224,15 @@ function registerPortTools(server2, client2) {
|
|
|
209
224
|
);
|
|
210
225
|
server2.tool(
|
|
211
226
|
"get_port_events_by_vessel",
|
|
212
|
-
"Get port events (arrivals/departures) for a specific vessel",
|
|
227
|
+
"Get port events (arrivals/departures) for a specific vessel. Covers only the last 2 hours unless timeFrom is given. Events are kept for 31 days.",
|
|
213
228
|
{
|
|
214
229
|
vesselId: z2.string().describe("Vessel identifier (IMO number by default)"),
|
|
215
|
-
idType: z2.
|
|
216
|
-
eventType: z2.
|
|
217
|
-
sortOrder: z2.
|
|
218
|
-
timeFrom: z2.string().optional().describe("Start time
|
|
219
|
-
timeTo: z2.string().optional().describe("End time
|
|
220
|
-
limit: z2.number().optional().describe("
|
|
230
|
+
idType: z2.enum(["imo", "mmsi"]).optional().describe("Identifier type: imo (default) or mmsi"),
|
|
231
|
+
eventType: z2.enum(["arrival", "departure", "all"]).optional().describe("Filter by event type. Omit for both arrivals and departures"),
|
|
232
|
+
sortOrder: z2.enum(["asc", "desc"]).optional().describe("Sort order by timestamp"),
|
|
233
|
+
timeFrom: z2.string().optional().describe("Start of the time window, RFC3339. Without it the service returns only the last 2 hours."),
|
|
234
|
+
timeTo: z2.string().optional().describe("End of the time window, RFC3339. Defaults to now."),
|
|
235
|
+
limit: z2.number().int().min(1).max(50).optional().describe("Results per page, 1 to 50. Defaults to 20."),
|
|
221
236
|
nextToken: z2.string().optional().describe("Pagination token from previous response")
|
|
222
237
|
},
|
|
223
238
|
async (params) => {
|
|
@@ -239,16 +254,16 @@ function registerPortTools(server2, client2) {
|
|
|
239
254
|
);
|
|
240
255
|
server2.tool(
|
|
241
256
|
"list_port_events",
|
|
242
|
-
"List port events (arrivals/departures)
|
|
257
|
+
"List port events (arrivals/departures) across all covered ports, with optional filters for time, country, port, vessel, or event type. Covers only the last 2 hours unless timeFrom is given. Events are kept for 31 days.",
|
|
243
258
|
{
|
|
244
|
-
timeFrom: z2.string().optional().describe("Start time
|
|
245
|
-
timeTo: z2.string().optional().describe("End time
|
|
259
|
+
timeFrom: z2.string().optional().describe("Start of the time window, RFC3339. Without it the service returns only the last 2 hours."),
|
|
260
|
+
timeTo: z2.string().optional().describe("End of the time window, RFC3339. Defaults to now."),
|
|
246
261
|
country: z2.string().optional().describe("Filter by port country (case-insensitive)"),
|
|
247
262
|
unlocode: z2.string().optional().describe("Filter by port UN/LOCODE"),
|
|
248
|
-
eventType: z2.
|
|
263
|
+
eventType: z2.enum(["arrival", "departure", "all"]).optional().describe("Filter by event type. Omit for both arrivals and departures"),
|
|
249
264
|
vesselName: z2.string().optional().describe("Filter by vessel name (full-text search)"),
|
|
250
265
|
portName: z2.string().optional().describe("Filter by port name (full-text search)"),
|
|
251
|
-
limit: z2.number().optional().describe("
|
|
266
|
+
limit: z2.number().int().min(1).max(50).optional().describe("Results per page, 1 to 50. Defaults to 20."),
|
|
252
267
|
nextToken: z2.string().optional().describe("Pagination token from previous response")
|
|
253
268
|
},
|
|
254
269
|
async (params) => {
|
|
@@ -272,16 +287,20 @@ function registerPortTools(server2, client2) {
|
|
|
272
287
|
);
|
|
273
288
|
server2.tool(
|
|
274
289
|
"search_port_events_by_port",
|
|
275
|
-
"Search port events by port name",
|
|
290
|
+
"Search port events by port name. Covers only the last 2 hours unless timeFrom is given.",
|
|
276
291
|
{
|
|
277
292
|
portName: z2.string().describe("Port name to search for"),
|
|
278
|
-
|
|
293
|
+
timeFrom: z2.string().optional().describe("Start of the time window, RFC3339. Without it the service returns only the last 2 hours."),
|
|
294
|
+
timeTo: z2.string().optional().describe("End of the time window, RFC3339. Defaults to now."),
|
|
295
|
+
limit: z2.number().int().min(1).max(50).optional().describe("Results per page, 1 to 50. Defaults to 20."),
|
|
279
296
|
nextToken: z2.string().optional().describe("Pagination token from previous response")
|
|
280
297
|
},
|
|
281
298
|
async (params) => {
|
|
282
299
|
try {
|
|
283
300
|
const data = await client2.portEvents.byPorts({
|
|
284
301
|
filterPortName: params.portName,
|
|
302
|
+
timeFrom: params.timeFrom,
|
|
303
|
+
timeTo: params.timeTo,
|
|
285
304
|
paginationLimit: params.limit,
|
|
286
305
|
paginationNextToken: params.nextToken
|
|
287
306
|
});
|
|
@@ -293,16 +312,20 @@ function registerPortTools(server2, client2) {
|
|
|
293
312
|
);
|
|
294
313
|
server2.tool(
|
|
295
314
|
"search_port_events_by_vessel",
|
|
296
|
-
"Search port events by vessel name",
|
|
315
|
+
"Search port events by vessel name. Covers only the last 2 hours unless timeFrom is given.",
|
|
297
316
|
{
|
|
298
317
|
vesselName: z2.string().describe("Vessel name to search for"),
|
|
299
|
-
|
|
318
|
+
timeFrom: z2.string().optional().describe("Start of the time window, RFC3339. Without it the service returns only the last 2 hours."),
|
|
319
|
+
timeTo: z2.string().optional().describe("End of the time window, RFC3339. Defaults to now."),
|
|
320
|
+
limit: z2.number().int().min(1).max(50).optional().describe("Results per page, 1 to 50. Defaults to 20."),
|
|
300
321
|
nextToken: z2.string().optional().describe("Pagination token from previous response")
|
|
301
322
|
},
|
|
302
323
|
async (params) => {
|
|
303
324
|
try {
|
|
304
325
|
const data = await client2.portEvents.byVessels({
|
|
305
326
|
filterVesselName: params.vesselName,
|
|
327
|
+
timeFrom: params.timeFrom,
|
|
328
|
+
timeTo: params.timeTo,
|
|
306
329
|
paginationLimit: params.limit,
|
|
307
330
|
paginationNextToken: params.nextToken
|
|
308
331
|
});
|
|
@@ -317,7 +340,7 @@ function registerPortTools(server2, client2) {
|
|
|
317
340
|
"Get the most recent port event (arrival or departure) for a vessel",
|
|
318
341
|
{
|
|
319
342
|
vesselId: z2.string().describe("Vessel identifier (IMO number by default)"),
|
|
320
|
-
idType: z2.
|
|
343
|
+
idType: z2.enum(["imo", "mmsi"]).optional().describe("Identifier type: imo (default) or mmsi")
|
|
321
344
|
},
|
|
322
345
|
async (params) => {
|
|
323
346
|
try {
|
|
@@ -332,10 +355,10 @@ function registerPortTools(server2, client2) {
|
|
|
332
355
|
);
|
|
333
356
|
server2.tool(
|
|
334
357
|
"list_emissions",
|
|
335
|
-
"List
|
|
358
|
+
"List EU MRV annual emissions reports (ships calling at EU and EEA ports), with an optional reporting-year filter",
|
|
336
359
|
{
|
|
337
360
|
period: z2.number().optional().describe("Reporting year filter (e.g. 2024)"),
|
|
338
|
-
limit: z2.number().optional().describe("
|
|
361
|
+
limit: z2.number().int().min(1).max(50).optional().describe("Results per page, 1 to 50. Defaults to 20."),
|
|
339
362
|
nextToken: z2.string().optional().describe("Pagination token from previous response")
|
|
340
363
|
},
|
|
341
364
|
async (params) => {
|
|
@@ -353,57 +376,31 @@ function registerPortTools(server2, client2) {
|
|
|
353
376
|
);
|
|
354
377
|
}
|
|
355
378
|
|
|
356
|
-
// src/tools/safety.ts
|
|
357
|
-
import { z as z3 } from "zod";
|
|
358
|
-
function registerSafetyTools(server2, client2) {
|
|
359
|
-
server2.tool(
|
|
360
|
-
"get_navtex_messages",
|
|
361
|
-
"Get NAVTEX maritime safety messages (navigational warnings, weather forecasts)",
|
|
362
|
-
{
|
|
363
|
-
timeFrom: z3.string().optional().describe("Start time (ISO 8601 format)"),
|
|
364
|
-
timeTo: z3.string().optional().describe("End time (ISO 8601 format)"),
|
|
365
|
-
limit: z3.number().optional().describe("Max results per page"),
|
|
366
|
-
nextToken: z3.string().optional().describe("Pagination token from previous response")
|
|
367
|
-
},
|
|
368
|
-
async (params) => {
|
|
369
|
-
try {
|
|
370
|
-
const data = await client2.navtex.list({
|
|
371
|
-
timeFrom: params.timeFrom,
|
|
372
|
-
timeTo: params.timeTo,
|
|
373
|
-
paginationLimit: params.limit,
|
|
374
|
-
paginationNextToken: params.nextToken
|
|
375
|
-
});
|
|
376
|
-
return formatResult(data);
|
|
377
|
-
} catch (error) {
|
|
378
|
-
return handleToolError(error);
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
);
|
|
382
|
-
}
|
|
383
|
-
|
|
384
379
|
// src/tools/vessels.ts
|
|
385
|
-
import { z as
|
|
380
|
+
import { z as z3 } from "zod";
|
|
386
381
|
function registerVesselTools(server2, client2) {
|
|
387
382
|
server2.tool(
|
|
388
383
|
"search_vessels",
|
|
389
|
-
"Search for vessels
|
|
384
|
+
"Search for vessels. Use q when you have an identifier but do not know which kind it is; use the specific filters to narrow a fleet.",
|
|
390
385
|
{
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
limit:
|
|
402
|
-
nextToken:
|
|
386
|
+
q: z3.string().optional().describe("Free-text search across name, IMO, MMSI, ENI and callsign. Use this when the type of identifier is unknown."),
|
|
387
|
+
name: z3.string().optional().describe("Vessel name (partial match)"),
|
|
388
|
+
imo: z3.string().optional().describe("IMO number"),
|
|
389
|
+
mmsi: z3.string().optional().describe("MMSI number"),
|
|
390
|
+
eni: z3.string().optional().describe("ENI number, used for inland waterway vessels"),
|
|
391
|
+
flag: z3.string().optional().describe("Flag state (ISO country code)"),
|
|
392
|
+
vesselType: z3.string().optional().describe("Vessel type"),
|
|
393
|
+
callsign: z3.string().optional().describe("Radio callsign"),
|
|
394
|
+
yearBuiltMin: z3.number().optional().describe("Minimum year built"),
|
|
395
|
+
yearBuiltMax: z3.number().optional().describe("Maximum year built"),
|
|
396
|
+
limit: z3.number().int().min(1).max(50).optional().describe("Results per page, 1 to 50. Defaults to 20."),
|
|
397
|
+
nextToken: z3.string().optional().describe("Pagination token from previous response")
|
|
403
398
|
},
|
|
404
399
|
async (params) => {
|
|
405
400
|
try {
|
|
406
401
|
const data = await client2.search.vessels({
|
|
402
|
+
q: params.q,
|
|
403
|
+
filterEni: params.eni,
|
|
407
404
|
filterName: params.name,
|
|
408
405
|
filterImo: params.imo,
|
|
409
406
|
filterMmsi: params.mmsi,
|
|
@@ -412,8 +409,6 @@ function registerVesselTools(server2, client2) {
|
|
|
412
409
|
filterCallsign: params.callsign,
|
|
413
410
|
filterYearBuiltMin: params.yearBuiltMin,
|
|
414
411
|
filterYearBuiltMax: params.yearBuiltMax,
|
|
415
|
-
filterClassSociety: params.classSociety,
|
|
416
|
-
filterOwner: params.owner,
|
|
417
412
|
paginationLimit: params.limit,
|
|
418
413
|
paginationNextToken: params.nextToken
|
|
419
414
|
});
|
|
@@ -427,8 +422,8 @@ function registerVesselTools(server2, client2) {
|
|
|
427
422
|
"get_vessel",
|
|
428
423
|
"Get detailed information about a specific vessel",
|
|
429
424
|
{
|
|
430
|
-
vesselId:
|
|
431
|
-
idType:
|
|
425
|
+
vesselId: z3.string().describe("Vessel identifier (IMO number by default)"),
|
|
426
|
+
idType: z3.enum(["imo", "mmsi"]).optional().describe("Identifier type: imo (default) or mmsi")
|
|
432
427
|
},
|
|
433
428
|
async (params) => {
|
|
434
429
|
try {
|
|
@@ -443,14 +438,16 @@ function registerVesselTools(server2, client2) {
|
|
|
443
438
|
);
|
|
444
439
|
server2.tool(
|
|
445
440
|
"get_vessel_position",
|
|
446
|
-
"Get the
|
|
441
|
+
"Get the latest stored position of a vessel (latitude, longitude, speed, heading, timestamp). Check the timestamp: the fix may be hours or days old, especially for a vessel away from the coast.",
|
|
447
442
|
{
|
|
448
|
-
vesselId:
|
|
449
|
-
idType:
|
|
443
|
+
vesselId: z3.string().describe("Vessel identifier (IMO number by default)"),
|
|
444
|
+
idType: z3.enum(["imo", "mmsi"]).optional().describe("Identifier type: imo (default) or mmsi"),
|
|
445
|
+
sat: z3.boolean().optional().describe("Fall back to a satellite position when no recent terrestrial one exists. Charged per call against a prepaid balance, so use it only when a stored position is genuinely insufficient.")
|
|
450
446
|
},
|
|
451
447
|
async (params) => {
|
|
452
448
|
try {
|
|
453
449
|
const data = await client2.vessels.position(params.vesselId, {
|
|
450
|
+
filterSat: params.sat,
|
|
454
451
|
filterIdType: params.idType
|
|
455
452
|
});
|
|
456
453
|
return formatResult(data);
|
|
@@ -461,10 +458,10 @@ function registerVesselTools(server2, client2) {
|
|
|
461
458
|
);
|
|
462
459
|
server2.tool(
|
|
463
460
|
"get_vessel_eta",
|
|
464
|
-
"Get the
|
|
461
|
+
"Get the most recent ETA the vessel itself reported in its AIS voyage data. This is the declared ETA, not a prediction.",
|
|
465
462
|
{
|
|
466
|
-
vesselId:
|
|
467
|
-
idType:
|
|
463
|
+
vesselId: z3.string().describe("Vessel identifier (IMO number by default)"),
|
|
464
|
+
idType: z3.enum(["imo", "mmsi"]).optional().describe("Identifier type: imo (default) or mmsi")
|
|
468
465
|
},
|
|
469
466
|
async (params) => {
|
|
470
467
|
try {
|
|
@@ -477,50 +474,14 @@ function registerVesselTools(server2, client2) {
|
|
|
477
474
|
}
|
|
478
475
|
}
|
|
479
476
|
);
|
|
480
|
-
server2.tool(
|
|
481
|
-
"get_vessel_classification",
|
|
482
|
-
"Get the classification details for a vessel (class society, surveys, hull info)",
|
|
483
|
-
{
|
|
484
|
-
vesselId: z4.string().describe("Vessel identifier (IMO number by default)"),
|
|
485
|
-
idType: z4.string().optional().describe("Identifier type: imo (default), mmsi, or vesselId")
|
|
486
|
-
},
|
|
487
|
-
async (params) => {
|
|
488
|
-
try {
|
|
489
|
-
const data = await client2.vessels.classification(params.vesselId, {
|
|
490
|
-
filterIdType: params.idType
|
|
491
|
-
});
|
|
492
|
-
return formatResult(data);
|
|
493
|
-
} catch (error) {
|
|
494
|
-
return handleToolError(error);
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
);
|
|
498
|
-
server2.tool(
|
|
499
|
-
"get_vessel_ownership",
|
|
500
|
-
"Get the ownership details for a vessel (owner, manager, operator)",
|
|
501
|
-
{
|
|
502
|
-
vesselId: z4.string().describe("Vessel identifier (IMO number by default)"),
|
|
503
|
-
idType: z4.string().optional().describe("Identifier type: imo (default), mmsi, or vesselId")
|
|
504
|
-
},
|
|
505
|
-
async (params) => {
|
|
506
|
-
try {
|
|
507
|
-
const data = await client2.vessels.ownership(params.vesselId, {
|
|
508
|
-
filterIdType: params.idType
|
|
509
|
-
});
|
|
510
|
-
return formatResult(data);
|
|
511
|
-
} catch (error) {
|
|
512
|
-
return handleToolError(error);
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
);
|
|
516
477
|
server2.tool(
|
|
517
478
|
"get_vessel_emissions",
|
|
518
|
-
"Get emissions
|
|
479
|
+
"Get EU MRV annual emissions reports for a vessel (CO2, fuel consumption). Only ships that report under EU MRV have data.",
|
|
519
480
|
{
|
|
520
|
-
vesselId:
|
|
521
|
-
idType:
|
|
522
|
-
limit:
|
|
523
|
-
nextToken:
|
|
481
|
+
vesselId: z3.string().describe("Vessel identifier (IMO number by default)"),
|
|
482
|
+
idType: z3.enum(["imo", "mmsi"]).optional().describe("Identifier type: imo (default) or mmsi"),
|
|
483
|
+
limit: z3.number().int().min(1).max(50).optional().describe("Results per page, 1 to 50. Defaults to 20."),
|
|
484
|
+
nextToken: z3.string().optional().describe("Pagination token from previous response")
|
|
524
485
|
},
|
|
525
486
|
async (params) => {
|
|
526
487
|
try {
|
|
@@ -535,36 +496,14 @@ function registerVesselTools(server2, client2) {
|
|
|
535
496
|
}
|
|
536
497
|
}
|
|
537
498
|
);
|
|
538
|
-
server2.tool(
|
|
539
|
-
"get_vessel_inspections",
|
|
540
|
-
"Get port state control inspections for a vessel",
|
|
541
|
-
{
|
|
542
|
-
vesselId: z4.string().describe("Vessel identifier (IMO number by default)"),
|
|
543
|
-
idType: z4.string().optional().describe("Identifier type: imo (default), mmsi, or vesselId"),
|
|
544
|
-
limit: z4.number().optional().describe("Max results per page"),
|
|
545
|
-
nextToken: z4.string().optional().describe("Pagination token from previous response")
|
|
546
|
-
},
|
|
547
|
-
async (params) => {
|
|
548
|
-
try {
|
|
549
|
-
const data = await client2.vessels.inspections(params.vesselId, {
|
|
550
|
-
filterIdType: params.idType,
|
|
551
|
-
paginationLimit: params.limit,
|
|
552
|
-
paginationNextToken: params.nextToken
|
|
553
|
-
});
|
|
554
|
-
return formatResult(data);
|
|
555
|
-
} catch (error) {
|
|
556
|
-
return handleToolError(error);
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
);
|
|
560
499
|
server2.tool(
|
|
561
500
|
"get_vessel_casualties",
|
|
562
501
|
"Get marine casualty records for a vessel",
|
|
563
502
|
{
|
|
564
|
-
vesselId:
|
|
565
|
-
idType:
|
|
566
|
-
limit:
|
|
567
|
-
nextToken:
|
|
503
|
+
vesselId: z3.string().describe("Vessel identifier (IMO number by default)"),
|
|
504
|
+
idType: z3.enum(["imo", "mmsi"]).optional().describe("Identifier type: imo (default) or mmsi"),
|
|
505
|
+
limit: z3.number().int().min(1).max(50).optional().describe("Results per page, 1 to 50. Defaults to 20."),
|
|
506
|
+
nextToken: z3.string().optional().describe("Pagination token from previous response")
|
|
568
507
|
},
|
|
569
508
|
async (params) => {
|
|
570
509
|
try {
|
|
@@ -579,35 +518,16 @@ function registerVesselTools(server2, client2) {
|
|
|
579
518
|
}
|
|
580
519
|
}
|
|
581
520
|
);
|
|
582
|
-
server2.tool(
|
|
583
|
-
"get_vessel_inspection_detail",
|
|
584
|
-
"Get detailed information about a specific vessel inspection",
|
|
585
|
-
{
|
|
586
|
-
vesselId: z4.string().describe("Vessel identifier (IMO number by default)"),
|
|
587
|
-
detailId: z4.string().describe("Inspection detail ID"),
|
|
588
|
-
idType: z4.string().optional().describe("Identifier type: imo (default), mmsi, or vesselId")
|
|
589
|
-
},
|
|
590
|
-
async (params) => {
|
|
591
|
-
try {
|
|
592
|
-
const data = await client2.vessels.inspectionDetail(params.vesselId, params.detailId, {
|
|
593
|
-
filterIdType: params.idType
|
|
594
|
-
});
|
|
595
|
-
return formatResult(data);
|
|
596
|
-
} catch (error) {
|
|
597
|
-
return handleToolError(error);
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
|
-
);
|
|
601
521
|
server2.tool(
|
|
602
522
|
"get_vessel_positions_batch",
|
|
603
523
|
"Get positions for multiple vessels at once by MMSI or IMO numbers",
|
|
604
524
|
{
|
|
605
|
-
ids:
|
|
606
|
-
idType:
|
|
607
|
-
timeFrom:
|
|
608
|
-
timeTo:
|
|
609
|
-
limit:
|
|
610
|
-
nextToken:
|
|
525
|
+
ids: z3.string().describe("Comma-separated list of MMSI or IMO numbers"),
|
|
526
|
+
idType: z3.enum(["imo", "mmsi"]).optional().describe("Identifier type: imo (default) or mmsi"),
|
|
527
|
+
timeFrom: z3.string().optional().describe("Start time filter in RFC3339 format (defaults to 2 hours ago)"),
|
|
528
|
+
timeTo: z3.string().optional().describe("End time filter in RFC3339 format (defaults to current time)"),
|
|
529
|
+
limit: z3.number().int().min(1).max(50).optional().describe("Results per page, 1 to 50. Defaults to 20."),
|
|
530
|
+
nextToken: z3.string().optional().describe("Pagination token from previous response")
|
|
611
531
|
},
|
|
612
532
|
async (params) => {
|
|
613
533
|
try {
|
|
@@ -628,15 +548,20 @@ function registerVesselTools(server2, client2) {
|
|
|
628
548
|
}
|
|
629
549
|
|
|
630
550
|
// src/index.ts
|
|
631
|
-
|
|
551
|
+
if (!process.env.VESSELAPI_API_KEY) {
|
|
552
|
+
process.stderr.write(
|
|
553
|
+
"vesselapi-mcp: VESSELAPI_API_KEY is not set. Add it to the env block of your MCP client configuration. Keys are issued at https://dashboard.vesselapi.com\n"
|
|
554
|
+
);
|
|
555
|
+
process.exit(1);
|
|
556
|
+
}
|
|
557
|
+
var client = new VesselClient(void 0, { userAgent: `vesselapi-mcp/${VERSION}` });
|
|
632
558
|
var server = new McpServer({
|
|
633
559
|
name: "vesselapi",
|
|
634
|
-
version:
|
|
560
|
+
version: VERSION
|
|
635
561
|
});
|
|
636
562
|
registerVesselTools(server, client);
|
|
637
563
|
registerPortTools(server, client);
|
|
638
564
|
registerLocationTools(server, client);
|
|
639
|
-
registerSafetyTools(server, client);
|
|
640
565
|
var transport = new StdioServerTransport();
|
|
641
566
|
await server.connect(transport);
|
|
642
567
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/tools/location.ts","../src/errors.ts","../src/tools/ports.ts","../src/tools/safety.ts","../src/tools/vessels.ts"],"sourcesContent":["import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { VesselClient } from \"vesselapi\";\nimport { registerLocationTools } from \"./tools/location.js\";\nimport { registerPortTools } from \"./tools/ports.js\";\nimport { registerSafetyTools } from \"./tools/safety.js\";\nimport { registerVesselTools } from \"./tools/vessels.js\";\n\nconst client = new VesselClient();\n\nconst server = new McpServer({\n name: \"vesselapi\",\n version: \"1.0.0\",\n});\n\nregisterVesselTools(server, client);\nregisterPortTools(server, client);\nregisterLocationTools(server, client);\nregisterSafetyTools(server, client);\n\nconst transport = new StdioServerTransport();\nawait server.connect(transport);\n","import type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { VesselClient } from \"vesselapi\";\nimport { z } from \"zod\";\nimport { formatResult, handleToolError } from \"../errors.js\";\n\nexport function registerLocationTools(server: McpServer, client: VesselClient): void {\n server.tool(\n \"get_vessels_in_area\",\n \"Find all vessels within a rectangular bounding box (latitude/longitude)\",\n {\n latMin: z.number().describe(\"Southern boundary latitude\"),\n latMax: z.number().describe(\"Northern boundary latitude\"),\n lonMin: z.number().describe(\"Western boundary longitude\"),\n lonMax: z.number().describe(\"Eastern boundary longitude\"),\n timeFrom: z.string().optional().describe(\"Start time filter in RFC3339 format (defaults to 2 hours ago)\"),\n timeTo: z.string().optional().describe(\"End time filter in RFC3339 format (defaults to current time)\"),\n limit: z.number().optional().describe(\"Max results per page\"),\n nextToken: z.string().optional().describe(\"Pagination token from previous response\"),\n },\n async (params) => {\n try {\n const data = await client.location.vesselsBoundingBox({\n latMin: params.latMin,\n latMax: params.latMax,\n lonMin: params.lonMin,\n lonMax: params.lonMax,\n timeFrom: params.timeFrom,\n timeTo: params.timeTo,\n paginationLimit: params.limit,\n paginationNextToken: params.nextToken,\n });\n return formatResult(data);\n } catch (error) {\n return handleToolError(error);\n }\n },\n );\n\n server.tool(\n \"get_vessels_in_radius\",\n \"Find all vessels within a radius (in nautical miles) of a point\",\n {\n latitude: z.number().describe(\"Center latitude\"),\n longitude: z.number().describe(\"Center longitude\"),\n radius: z.number().describe(\"Radius in nautical miles\"),\n timeFrom: z.string().optional().describe(\"Start time filter in RFC3339 format (defaults to 2 hours ago)\"),\n timeTo: z.string().optional().describe(\"End time filter in RFC3339 format (defaults to current time)\"),\n limit: z.number().optional().describe(\"Max results per page\"),\n nextToken: z.string().optional().describe(\"Pagination token from previous response\"),\n },\n async (params) => {\n try {\n const data = await client.location.vesselsRadius({\n latitude: params.latitude,\n longitude: params.longitude,\n radius: params.radius,\n timeFrom: params.timeFrom,\n timeTo: params.timeTo,\n paginationLimit: params.limit,\n paginationNextToken: params.nextToken,\n });\n return formatResult(data);\n } catch (error) {\n return handleToolError(error);\n }\n },\n );\n}\n","import {\n VesselAPIError,\n VesselAuthError,\n VesselNotFoundError,\n VesselRateLimitError,\n VesselServerError,\n} from \"vesselapi\";\n\nexport function formatResult(data: unknown): { content: { type: \"text\"; text: string }[] } {\n return {\n content: [{ type: \"text\", text: JSON.stringify(data, null, 2) }],\n };\n}\n\nexport function handleToolError(error: unknown): { isError: true; content: { type: \"text\"; text: string }[] } {\n let message: string;\n\n if (error instanceof VesselAuthError) {\n message = \"Authentication failed. Check your VESSELAPI_API_KEY.\";\n } else if (error instanceof VesselNotFoundError) {\n message = \"Resource not found. Verify the ID or parameters.\";\n } else if (error instanceof VesselRateLimitError) {\n message = \"Rate limit exceeded. Try again later or reduce request frequency.\";\n } else if (error instanceof VesselServerError) {\n message = `Server error: ${error.message}`;\n } else if (error instanceof VesselAPIError) {\n message = `API error: ${error.message}`;\n } else if (error instanceof Error) {\n message = error.message;\n } else {\n message = String(error);\n }\n\n return {\n isError: true,\n content: [{ type: \"text\", text: message }],\n };\n}\n","import type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { VesselClient } from \"vesselapi\";\nimport { z } from \"zod\";\nimport { formatResult, handleToolError } from \"../errors.js\";\n\nexport function registerPortTools(server: McpServer, client: VesselClient): void {\n server.tool(\n \"search_ports\",\n \"Search for ports by name, country, type, size, region, harbor size, or harbor use\",\n {\n name: z.string().optional().describe(\"Port name (partial match)\"),\n country: z.string().optional().describe(\"Country (ISO code)\"),\n portType: z.string().optional().describe(\"Port type classification\"),\n size: z.string().optional().describe(\"Port size classification\"),\n region: z.string().optional().describe(\"Geographic region (partial match)\"),\n harborSize: z.string().optional().describe(\"Harbor size classification\"),\n harborUse: z.string().optional().describe(\"Primary harbor use\"),\n limit: z.number().optional().describe(\"Max results per page\"),\n nextToken: z.string().optional().describe(\"Pagination token from previous response\"),\n },\n async (params) => {\n try {\n const data = await client.search.ports({\n filterName: params.name,\n filterCountry: params.country,\n filterPortType: params.portType,\n filterSize: params.size,\n filterRegion: params.region,\n filterHarborSize: params.harborSize,\n filterHarborUse: params.harborUse,\n paginationLimit: params.limit,\n paginationNextToken: params.nextToken,\n });\n return formatResult(data);\n } catch (error) {\n return handleToolError(error);\n }\n },\n );\n\n server.tool(\n \"get_port\",\n \"Get detailed information about a specific port by UN/LOCODE\",\n {\n unlocode: z.string().describe(\"UN/LOCODE of the port (e.g. NLRTM for Rotterdam)\"),\n },\n async (params) => {\n try {\n const data = await client.ports.get(params.unlocode);\n return formatResult(data);\n } catch (error) {\n return handleToolError(error);\n }\n },\n );\n\n server.tool(\n \"get_port_inbound\",\n \"Get vessels heading to a specific port within an ETA arrival window\",\n {\n unlocode: z.string().describe(\"UN/LOCODE of the destination port (e.g. NLRTM for Rotterdam)\"),\n etaFrom: z.string().describe(\"Start of ETA arrival window (RFC3339 format, e.g. 2026-03-07T00:00:00Z)\"),\n etaTo: z.string().describe(\"End of ETA arrival window (RFC3339 format, e.g. 2026-03-14T00:00:00Z)\"),\n timeFrom: z.string().optional().describe(\"AIS position time range start (RFC3339 format)\"),\n timeTo: z.string().optional().describe(\"AIS position time range end (RFC3339 format)\"),\n limit: z.number().optional().describe(\"Max results per page\"),\n nextToken: z.string().optional().describe(\"Pagination token from previous response\"),\n },\n async (params) => {\n try {\n const data = await client.ports.inbound(params.unlocode, {\n filterEtaFrom: params.etaFrom,\n filterEtaTo: params.etaTo,\n timeFrom: params.timeFrom,\n timeTo: params.timeTo,\n paginationLimit: params.limit,\n paginationNextToken: params.nextToken,\n });\n return formatResult(data);\n } catch (error) {\n return handleToolError(error);\n }\n },\n );\n\n server.tool(\n \"get_port_events\",\n \"Get port events (arrivals/departures) for a specific port\",\n {\n unlocode: z.string().describe(\"UN/LOCODE of the port\"),\n limit: z.number().optional().describe(\"Max results per page\"),\n nextToken: z.string().optional().describe(\"Pagination token from previous response\"),\n },\n async (params) => {\n try {\n const data = await client.portEvents.byPort(params.unlocode, {\n paginationLimit: params.limit,\n paginationNextToken: params.nextToken,\n });\n return formatResult(data);\n } catch (error) {\n return handleToolError(error);\n }\n },\n );\n\n server.tool(\n \"get_port_events_by_vessel\",\n \"Get port events (arrivals/departures) for a specific vessel\",\n {\n vesselId: z.string().describe(\"Vessel identifier (IMO number by default)\"),\n idType: z.string().optional().describe(\"Identifier type: imo (default), mmsi, or vesselId\"),\n eventType: z.string().optional().describe(\"Filter by event type (arrival, departure)\"),\n sortOrder: z.string().optional().describe(\"Sort order by timestamp (asc or desc)\"),\n timeFrom: z.string().optional().describe(\"Start time (ISO 8601 format)\"),\n timeTo: z.string().optional().describe(\"End time (ISO 8601 format)\"),\n limit: z.number().optional().describe(\"Max results per page\"),\n nextToken: z.string().optional().describe(\"Pagination token from previous response\"),\n },\n async (params) => {\n try {\n const data = await client.portEvents.byVessel(params.vesselId, {\n filterIdType: params.idType,\n filterEventType: params.eventType,\n filterSortOrder: params.sortOrder,\n timeFrom: params.timeFrom,\n timeTo: params.timeTo,\n paginationLimit: params.limit,\n paginationNextToken: params.nextToken,\n });\n return formatResult(data);\n } catch (error) {\n return handleToolError(error);\n }\n },\n );\n\n server.tool(\n \"list_port_events\",\n \"List port events (arrivals/departures) globally with optional filters for time, country, port, vessel, or event type\",\n {\n timeFrom: z.string().optional().describe(\"Start time (RFC3339 format)\"),\n timeTo: z.string().optional().describe(\"End time (RFC3339 format)\"),\n country: z.string().optional().describe(\"Filter by port country (case-insensitive)\"),\n unlocode: z.string().optional().describe(\"Filter by port UN/LOCODE\"),\n eventType: z.string().optional().describe(\"Filter by event type (arrival, departure)\"),\n vesselName: z.string().optional().describe(\"Filter by vessel name (full-text search)\"),\n portName: z.string().optional().describe(\"Filter by port name (full-text search)\"),\n limit: z.number().optional().describe(\"Max results per page\"),\n nextToken: z.string().optional().describe(\"Pagination token from previous response\"),\n },\n async (params) => {\n try {\n const data = await client.portEvents.list({\n timeFrom: params.timeFrom,\n timeTo: params.timeTo,\n filterCountry: params.country,\n filterUnlocode: params.unlocode,\n filterEventType: params.eventType,\n filterVesselName: params.vesselName,\n filterPortName: params.portName,\n paginationLimit: params.limit,\n paginationNextToken: params.nextToken,\n });\n return formatResult(data);\n } catch (error) {\n return handleToolError(error);\n }\n },\n );\n\n server.tool(\n \"search_port_events_by_port\",\n \"Search port events by port name\",\n {\n portName: z.string().describe(\"Port name to search for\"),\n limit: z.number().optional().describe(\"Max results per page\"),\n nextToken: z.string().optional().describe(\"Pagination token from previous response\"),\n },\n async (params) => {\n try {\n const data = await client.portEvents.byPorts({\n filterPortName: params.portName,\n paginationLimit: params.limit,\n paginationNextToken: params.nextToken,\n });\n return formatResult(data);\n } catch (error) {\n return handleToolError(error);\n }\n },\n );\n\n server.tool(\n \"search_port_events_by_vessel\",\n \"Search port events by vessel name\",\n {\n vesselName: z.string().describe(\"Vessel name to search for\"),\n limit: z.number().optional().describe(\"Max results per page\"),\n nextToken: z.string().optional().describe(\"Pagination token from previous response\"),\n },\n async (params) => {\n try {\n const data = await client.portEvents.byVessels({\n filterVesselName: params.vesselName,\n paginationLimit: params.limit,\n paginationNextToken: params.nextToken,\n });\n return formatResult(data);\n } catch (error) {\n return handleToolError(error);\n }\n },\n );\n\n server.tool(\n \"get_vessel_last_port_event\",\n \"Get the most recent port event (arrival or departure) for a vessel\",\n {\n vesselId: z.string().describe(\"Vessel identifier (IMO number by default)\"),\n idType: z.string().optional().describe(\"Identifier type: imo (default), mmsi, or vesselId\"),\n },\n async (params) => {\n try {\n const data = await client.portEvents.lastByVessel(params.vesselId, {\n filterIdType: params.idType,\n });\n return formatResult(data);\n } catch (error) {\n return handleToolError(error);\n }\n },\n );\n\n server.tool(\n \"list_emissions\",\n \"List global vessel emissions data with optional year filter\",\n {\n period: z.number().optional().describe(\"Reporting year filter (e.g. 2024)\"),\n limit: z.number().optional().describe(\"Max results per page\"),\n nextToken: z.string().optional().describe(\"Pagination token from previous response\"),\n },\n async (params) => {\n try {\n const data = await client.emissions.list({\n filterPeriod: params.period,\n paginationLimit: params.limit,\n paginationNextToken: params.nextToken,\n });\n return formatResult(data);\n } catch (error) {\n return handleToolError(error);\n }\n },\n );\n}\n","import type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { VesselClient } from \"vesselapi\";\nimport { z } from \"zod\";\nimport { formatResult, handleToolError } from \"../errors.js\";\n\nexport function registerSafetyTools(server: McpServer, client: VesselClient): void {\n server.tool(\n \"get_navtex_messages\",\n \"Get NAVTEX maritime safety messages (navigational warnings, weather forecasts)\",\n {\n timeFrom: z.string().optional().describe(\"Start time (ISO 8601 format)\"),\n timeTo: z.string().optional().describe(\"End time (ISO 8601 format)\"),\n limit: z.number().optional().describe(\"Max results per page\"),\n nextToken: z.string().optional().describe(\"Pagination token from previous response\"),\n },\n async (params) => {\n try {\n const data = await client.navtex.list({\n timeFrom: params.timeFrom,\n timeTo: params.timeTo,\n paginationLimit: params.limit,\n paginationNextToken: params.nextToken,\n });\n return formatResult(data);\n } catch (error) {\n return handleToolError(error);\n }\n },\n );\n}\n","import type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { VesselClient } from \"vesselapi\";\nimport { z } from \"zod\";\nimport { formatResult, handleToolError } from \"../errors.js\";\n\nexport function registerVesselTools(server: McpServer, client: VesselClient): void {\n server.tool(\n \"search_vessels\",\n \"Search for vessels by name, IMO, MMSI, flag, type, callsign, year built, class society, or owner\",\n {\n name: z.string().optional().describe(\"Vessel name (partial match)\"),\n imo: z.string().optional().describe(\"IMO number\"),\n mmsi: z.string().optional().describe(\"MMSI number\"),\n flag: z.string().optional().describe(\"Flag state (ISO country code)\"),\n vesselType: z.string().optional().describe(\"Vessel type\"),\n callsign: z.string().optional().describe(\"Radio callsign\"),\n yearBuiltMin: z.number().optional().describe(\"Minimum year built\"),\n yearBuiltMax: z.number().optional().describe(\"Maximum year built\"),\n classSociety: z.string().optional().describe(\"Classification society (case-insensitive)\"),\n owner: z.string().optional().describe(\"Owner name (partial match, case-insensitive)\"),\n limit: z.number().optional().describe(\"Max results per page\"),\n nextToken: z.string().optional().describe(\"Pagination token from previous response\"),\n },\n async (params) => {\n try {\n const data = await client.search.vessels({\n filterName: params.name,\n filterImo: params.imo,\n filterMmsi: params.mmsi,\n filterFlag: params.flag,\n filterVesselType: params.vesselType,\n filterCallsign: params.callsign,\n filterYearBuiltMin: params.yearBuiltMin,\n filterYearBuiltMax: params.yearBuiltMax,\n filterClassSociety: params.classSociety,\n filterOwner: params.owner,\n paginationLimit: params.limit,\n paginationNextToken: params.nextToken,\n });\n return formatResult(data);\n } catch (error) {\n return handleToolError(error);\n }\n },\n );\n\n server.tool(\n \"get_vessel\",\n \"Get detailed information about a specific vessel\",\n {\n vesselId: z.string().describe(\"Vessel identifier (IMO number by default)\"),\n idType: z.string().optional().describe(\"Identifier type: imo (default), mmsi, or vesselId\"),\n },\n async (params) => {\n try {\n const data = await client.vessels.get(params.vesselId, {\n filterIdType: params.idType,\n });\n return formatResult(data);\n } catch (error) {\n return handleToolError(error);\n }\n },\n );\n\n server.tool(\n \"get_vessel_position\",\n \"Get the current position of a vessel (latitude, longitude, speed, heading)\",\n {\n vesselId: z.string().describe(\"Vessel identifier (IMO number by default)\"),\n idType: z.string().optional().describe(\"Identifier type: imo (default), mmsi, or vesselId\"),\n },\n async (params) => {\n try {\n const data = await client.vessels.position(params.vesselId, {\n filterIdType: params.idType,\n });\n return formatResult(data);\n } catch (error) {\n return handleToolError(error);\n }\n },\n );\n\n server.tool(\n \"get_vessel_eta\",\n \"Get the estimated time of arrival for a vessel\",\n {\n vesselId: z.string().describe(\"Vessel identifier (IMO number by default)\"),\n idType: z.string().optional().describe(\"Identifier type: imo (default), mmsi, or vesselId\"),\n },\n async (params) => {\n try {\n const data = await client.vessels.eta(params.vesselId, {\n filterIdType: params.idType,\n });\n return formatResult(data);\n } catch (error) {\n return handleToolError(error);\n }\n },\n );\n\n server.tool(\n \"get_vessel_classification\",\n \"Get the classification details for a vessel (class society, surveys, hull info)\",\n {\n vesselId: z.string().describe(\"Vessel identifier (IMO number by default)\"),\n idType: z.string().optional().describe(\"Identifier type: imo (default), mmsi, or vesselId\"),\n },\n async (params) => {\n try {\n const data = await client.vessels.classification(params.vesselId, {\n filterIdType: params.idType,\n });\n return formatResult(data);\n } catch (error) {\n return handleToolError(error);\n }\n },\n );\n\n server.tool(\n \"get_vessel_ownership\",\n \"Get the ownership details for a vessel (owner, manager, operator)\",\n {\n vesselId: z.string().describe(\"Vessel identifier (IMO number by default)\"),\n idType: z.string().optional().describe(\"Identifier type: imo (default), mmsi, or vesselId\"),\n },\n async (params) => {\n try {\n const data = await client.vessels.ownership(params.vesselId, {\n filterIdType: params.idType,\n });\n return formatResult(data);\n } catch (error) {\n return handleToolError(error);\n }\n },\n );\n\n server.tool(\n \"get_vessel_emissions\",\n \"Get emissions data for a vessel (CO2, fuel consumption)\",\n {\n vesselId: z.string().describe(\"Vessel identifier (IMO number by default)\"),\n idType: z.string().optional().describe(\"Identifier type: imo (default), mmsi, or vesselId\"),\n limit: z.number().optional().describe(\"Max results per page\"),\n nextToken: z.string().optional().describe(\"Pagination token from previous response\"),\n },\n async (params) => {\n try {\n const data = await client.vessels.emissions(params.vesselId, {\n filterIdType: params.idType,\n paginationLimit: params.limit,\n paginationNextToken: params.nextToken,\n });\n return formatResult(data);\n } catch (error) {\n return handleToolError(error);\n }\n },\n );\n\n server.tool(\n \"get_vessel_inspections\",\n \"Get port state control inspections for a vessel\",\n {\n vesselId: z.string().describe(\"Vessel identifier (IMO number by default)\"),\n idType: z.string().optional().describe(\"Identifier type: imo (default), mmsi, or vesselId\"),\n limit: z.number().optional().describe(\"Max results per page\"),\n nextToken: z.string().optional().describe(\"Pagination token from previous response\"),\n },\n async (params) => {\n try {\n const data = await client.vessels.inspections(params.vesselId, {\n filterIdType: params.idType,\n paginationLimit: params.limit,\n paginationNextToken: params.nextToken,\n });\n return formatResult(data);\n } catch (error) {\n return handleToolError(error);\n }\n },\n );\n\n server.tool(\n \"get_vessel_casualties\",\n \"Get marine casualty records for a vessel\",\n {\n vesselId: z.string().describe(\"Vessel identifier (IMO number by default)\"),\n idType: z.string().optional().describe(\"Identifier type: imo (default), mmsi, or vesselId\"),\n limit: z.number().optional().describe(\"Max results per page\"),\n nextToken: z.string().optional().describe(\"Pagination token from previous response\"),\n },\n async (params) => {\n try {\n const data = await client.vessels.casualties(params.vesselId, {\n filterIdType: params.idType,\n paginationLimit: params.limit,\n paginationNextToken: params.nextToken,\n });\n return formatResult(data);\n } catch (error) {\n return handleToolError(error);\n }\n },\n );\n\n server.tool(\n \"get_vessel_inspection_detail\",\n \"Get detailed information about a specific vessel inspection\",\n {\n vesselId: z.string().describe(\"Vessel identifier (IMO number by default)\"),\n detailId: z.string().describe(\"Inspection detail ID\"),\n idType: z.string().optional().describe(\"Identifier type: imo (default), mmsi, or vesselId\"),\n },\n async (params) => {\n try {\n const data = await client.vessels.inspectionDetail(params.vesselId, params.detailId, {\n filterIdType: params.idType,\n });\n return formatResult(data);\n } catch (error) {\n return handleToolError(error);\n }\n },\n );\n\n server.tool(\n \"get_vessel_positions_batch\",\n \"Get positions for multiple vessels at once by MMSI or IMO numbers\",\n {\n ids: z.string().describe(\"Comma-separated list of MMSI or IMO numbers\"),\n idType: z.string().optional().describe(\"Identifier type: imo (default) or mmsi\"),\n timeFrom: z.string().optional().describe(\"Start time filter in RFC3339 format (defaults to 2 hours ago)\"),\n timeTo: z.string().optional().describe(\"End time filter in RFC3339 format (defaults to current time)\"),\n limit: z.number().optional().describe(\"Max results per page\"),\n nextToken: z.string().optional().describe(\"Pagination token from previous response\"),\n },\n async (params) => {\n try {\n const data = await client.vessels.positions({\n filterIds: params.ids,\n filterIdType: params.idType,\n timeFrom: params.timeFrom,\n timeTo: params.timeTo,\n paginationLimit: params.limit,\n paginationNextToken: params.nextToken,\n });\n return formatResult(data);\n } catch (error) {\n return handleToolError(error);\n }\n },\n );\n}\n"],"mappings":"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","names":["server","client","z","server","client","z","z","server","client","z","z","server","client","z"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/version.ts","../src/tools/location.ts","../src/errors.ts","../src/tools/ports.ts","../src/tools/vessels.ts"],"sourcesContent":["import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { VesselClient } from \"vesselapi\";\n\nimport { VERSION } from \"./version.js\";\nimport { registerLocationTools } from \"./tools/location.js\";\nimport { registerPortTools } from \"./tools/ports.js\";\nimport { registerVesselTools } from \"./tools/vessels.js\";\n\n// Fail with a readable line rather than a stack trace. Without a key the client\n// throws while this module is still evaluating, so the transport never connects\n// and the calling application sees the process die mid-handshake with no reason.\nif (!process.env.VESSELAPI_API_KEY) {\n process.stderr.write(\n \"vesselapi-mcp: VESSELAPI_API_KEY is not set. Add it to the env block of your \" +\n \"MCP client configuration. Keys are issued at https://dashboard.vesselapi.com\\n\",\n );\n process.exit(1);\n}\n\nconst client = new VesselClient(undefined, { userAgent: `vesselapi-mcp/${VERSION}` });\n\nconst server = new McpServer({\n name: \"vesselapi\",\n version: VERSION,\n});\n\nregisterVesselTools(server, client);\nregisterPortTools(server, client);\nregisterLocationTools(server, client);\n\nconst transport = new StdioServerTransport();\nawait server.connect(transport);\n","// Version advertised by the McpServer handshake. package.json and server.json\n// carry their own copies and are NOT derived from this — keep all three in step\n// when bumping.\nexport const VERSION = \"2.0.1\";\n","import type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { VesselClient } from \"vesselapi\";\nimport { z } from \"zod\";\nimport { formatResult, handleToolError } from \"../errors.js\";\n\nexport function registerLocationTools(server: McpServer, client: VesselClient): void {\n server.tool(\n \"get_vessels_in_area\",\n \"Find vessels with an AIS position inside a rectangular bounding box during the time window (default the last 2 hours, at most 4 hours). The latitude span plus the longitude span may not exceed 4 degrees.\",\n {\n latMin: z.number().describe(\"Southern boundary latitude\"),\n latMax: z.number().describe(\"Northern boundary latitude\"),\n lonMin: z.number().describe(\"Western boundary longitude\"),\n lonMax: z.number().describe(\"Eastern boundary longitude\"),\n timeFrom: z.string().optional().describe(\"Start of the time window, RFC3339. Defaults to 2 hours ago. The window may not exceed 4 hours.\"),\n timeTo: z.string().optional().describe(\"End of the time window, RFC3339. Defaults to now. The window may not exceed 4 hours.\"),\n limit: z.number().int().min(1).max(50).optional().describe(\"Results per page, 1 to 50. Defaults to 20.\"),\n nextToken: z.string().optional().describe(\"Pagination token from previous response\"),\n },\n async (params) => {\n try {\n const data = await client.location.vesselsBoundingBox({\n latMin: params.latMin,\n latMax: params.latMax,\n lonMin: params.lonMin,\n lonMax: params.lonMax,\n timeFrom: params.timeFrom,\n timeTo: params.timeTo,\n paginationLimit: params.limit,\n paginationNextToken: params.nextToken,\n });\n return formatResult(data);\n } catch (error) {\n return handleToolError(error);\n }\n },\n );\n\n server.tool(\n \"get_vessels_in_radius\",\n \"Find vessels with an AIS position within a radius of a point during the time window (default the last 2 hours, at most 4 hours). The radius is in METRES, not nautical miles or kilometres.\",\n {\n latitude: z.number().describe(\"Center latitude\"),\n longitude: z.number().describe(\"Center longitude\"),\n radius: z.number().describe(\"Search radius in METRES, maximum 100000 (100 km). One nautical mile is 1852 metres.\"),\n timeFrom: z.string().optional().describe(\"Start of the time window, RFC3339. Defaults to 2 hours ago. The window may not exceed 4 hours.\"),\n timeTo: z.string().optional().describe(\"End of the time window, RFC3339. Defaults to now. The window may not exceed 4 hours.\"),\n limit: z.number().int().min(1).max(50).optional().describe(\"Results per page, 1 to 50. Defaults to 20.\"),\n nextToken: z.string().optional().describe(\"Pagination token from previous response\"),\n },\n async (params) => {\n try {\n const data = await client.location.vesselsRadius({\n latitude: params.latitude,\n longitude: params.longitude,\n radius: params.radius,\n timeFrom: params.timeFrom,\n timeTo: params.timeTo,\n paginationLimit: params.limit,\n paginationNextToken: params.nextToken,\n });\n return formatResult(data);\n } catch (error) {\n return handleToolError(error);\n }\n },\n );\n}\n","import {\n VesselAPIError,\n VesselAuthError,\n VesselForbiddenError,\n VesselNotFoundError,\n VesselPaymentRequiredError,\n VesselRateLimitError,\n VesselServerError,\n} from \"vesselapi\";\n\nexport function formatResult(data: unknown): { content: { type: \"text\"; text: string }[] } {\n return {\n content: [{ type: \"text\", text: JSON.stringify(data, null, 2) }],\n };\n}\n\n/**\n * Turn an SDK error into something a model can act on.\n *\n * The distinction that matters to a caller is whether retrying can ever help.\n * A 4xx is the request's fault and will fail identically until the caller\n * changes something, so each one says what to change. Only 429 and 5xx are\n * worth trying again. Where the API supplies a machine-readable `code` it is\n * included, since the prose message is free-form and may be reworded.\n */\nexport function handleToolError(error: unknown): { isError: true; content: { type: \"text\"; text: string }[] } {\n let message: string;\n\n if (error instanceof VesselAuthError) {\n message = \"Authentication failed. Check your VESSELAPI_API_KEY. Do not retry.\";\n } else if (error instanceof VesselPaymentRequiredError) {\n message =\n \"Out of satellite credits, and no stored position was available to fall back on. \" +\n \"Retry without the satellite option to use stored data, or top up the balance at \" +\n \"https://dashboard.vesselapi.com. Retrying the same request will not help.\";\n } else if (error instanceof VesselForbiddenError) {\n message =\n error.code === \"feature_not_available\"\n ? \"This endpoint is not included in the current plan. Do not retry; a different plan is required.\"\n : \"The API key is suspended, usually for sustained quota abuse. Do not retry; \" +\n \"check the account at https://dashboard.vesselapi.com.\";\n } else if (error instanceof VesselNotFoundError) {\n message = `Resource not found. Verify the ID or parameters. ${error.message}`;\n } else if (error instanceof VesselRateLimitError) {\n message = \"Rate limit exceeded. Retrying later may succeed; reduce request frequency.\";\n } else if (error instanceof VesselServerError) {\n message = `Server error, retrying later may succeed: ${error.message}`;\n } else if (error instanceof VesselAPIError) {\n // Remaining 4xx: the request itself is wrong. Name the code so the model can\n // tell an unparseable time range from an out-of-range coordinate.\n const code = error.code ? ` (code: ${error.code})` : \"\";\n const retry = error.statusCode >= 400 && error.statusCode < 500 ? \" Do not retry without changing the request.\" : \"\";\n message = `Request rejected${code}: ${error.message}.${retry}`;\n } else if (error instanceof Error) {\n message = error.message;\n } else {\n message = String(error);\n }\n\n return {\n isError: true,\n content: [{ type: \"text\", text: message }],\n };\n}\n","import type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { VesselClient } from \"vesselapi\";\nimport { z } from \"zod\";\nimport { formatResult, handleToolError } from \"../errors.js\";\n\nexport function registerPortTools(server: McpServer, client: VesselClient): void {\n server.tool(\n \"search_ports\",\n \"Search for ports by name, country, type, size, region, harbor size, or harbor use\",\n {\n name: z.string().optional().describe(\"Port name (partial match)\"),\n country: z.string().optional().describe(\"Country (ISO code)\"),\n portType: z.string().optional().describe(\"Port type classification\"),\n size: z.string().optional().describe(\"Port size classification\"),\n region: z.string().optional().describe(\"Geographic region (partial match)\"),\n harborSize: z.string().optional().describe(\"Harbor size classification\"),\n harborUse: z.string().optional().describe(\"Primary harbor use\"),\n limit: z.number().int().min(1).max(50).optional().describe(\"Results per page, 1 to 50. Defaults to 20.\"),\n nextToken: z.string().optional().describe(\"Pagination token from previous response\"),\n },\n async (params) => {\n try {\n const data = await client.search.ports({\n filterName: params.name,\n filterCountry: params.country,\n filterPortType: params.portType,\n filterSize: params.size,\n filterRegion: params.region,\n filterHarborSize: params.harborSize,\n filterHarborUse: params.harborUse,\n paginationLimit: params.limit,\n paginationNextToken: params.nextToken,\n });\n return formatResult(data);\n } catch (error) {\n return handleToolError(error);\n }\n },\n );\n\n server.tool(\n \"get_port\",\n \"Get detailed information about a specific port by UN/LOCODE\",\n {\n unlocode: z.string().describe(\"UN/LOCODE of the port (e.g. NLRTM for Rotterdam)\"),\n },\n async (params) => {\n try {\n const data = await client.ports.get(params.unlocode);\n return formatResult(data);\n } catch (error) {\n return handleToolError(error);\n }\n },\n );\n\n server.tool(\n \"get_port_inbound\",\n \"Get vessels whose own reported destination is this port, with a declared ETA inside the arrival window. ETAs are reported by the vessels, not predicted.\",\n {\n unlocode: z.string().describe(\"UN/LOCODE of the destination port (e.g. NLRTM for Rotterdam)\"),\n etaFrom: z.string().optional().describe(\"Start of ETA arrival window (RFC3339). Omit to default to now.\"),\n etaTo: z.string().optional().describe(\"End of ETA arrival window (RFC3339). Omit to default to 72 hours ahead.\"),\n timeFrom: z.string().optional().describe(\"Only use reports received after this time, RFC3339. Defaults to 24 hours ago.\"),\n timeTo: z.string().optional().describe(\"Only use reports received before this time, RFC3339. Defaults to now.\"),\n limit: z.number().int().min(1).max(50).optional().describe(\"Results per page, 1 to 50. Defaults to 20.\"),\n nextToken: z.string().optional().describe(\"Pagination token from previous response\"),\n },\n async (params) => {\n try {\n const data = await client.ports.inbound(params.unlocode, {\n filterEtaFrom: params.etaFrom,\n filterEtaTo: params.etaTo,\n timeFrom: params.timeFrom,\n timeTo: params.timeTo,\n paginationLimit: params.limit,\n paginationNextToken: params.nextToken,\n });\n return formatResult(data);\n } catch (error) {\n return handleToolError(error);\n }\n },\n );\n\n server.tool(\n \"get_port_events\",\n \"Get port events (arrivals/departures) for a specific port. Covers only the last 2 hours unless timeFrom is given.\",\n {\n unlocode: z.string().describe(\"UN/LOCODE of the port\"),\n timeFrom: z.string().optional().describe(\"Start of the time window, RFC3339. Without it the service returns only the last 2 hours.\"),\n timeTo: z.string().optional().describe(\"End of the time window, RFC3339. Defaults to now.\"),\n limit: z.number().int().min(1).max(50).optional().describe(\"Results per page, 1 to 50. Defaults to 20.\"),\n nextToken: z.string().optional().describe(\"Pagination token from previous response\"),\n },\n async (params) => {\n try {\n const data = await client.portEvents.byPort(params.unlocode, {\n timeFrom: params.timeFrom,\n timeTo: params.timeTo,\n paginationLimit: params.limit,\n paginationNextToken: params.nextToken,\n });\n return formatResult(data);\n } catch (error) {\n return handleToolError(error);\n }\n },\n );\n\n server.tool(\n \"get_port_events_by_vessel\",\n \"Get port events (arrivals/departures) for a specific vessel. Covers only the last 2 hours unless timeFrom is given. Events are kept for 31 days.\",\n {\n vesselId: z.string().describe(\"Vessel identifier (IMO number by default)\"),\n idType: z.enum([\"imo\", \"mmsi\"]).optional().describe(\"Identifier type: imo (default) or mmsi\"),\n eventType: z.enum([\"arrival\", \"departure\", \"all\"]).optional().describe(\"Filter by event type. Omit for both arrivals and departures\"),\n sortOrder: z.enum([\"asc\", \"desc\"]).optional().describe(\"Sort order by timestamp\"),\n timeFrom: z.string().optional().describe(\"Start of the time window, RFC3339. Without it the service returns only the last 2 hours.\"),\n timeTo: z.string().optional().describe(\"End of the time window, RFC3339. Defaults to now.\"),\n limit: z.number().int().min(1).max(50).optional().describe(\"Results per page, 1 to 50. Defaults to 20.\"),\n nextToken: z.string().optional().describe(\"Pagination token from previous response\"),\n },\n async (params) => {\n try {\n const data = await client.portEvents.byVessel(params.vesselId, {\n filterIdType: params.idType,\n filterEventType: params.eventType,\n filterSortOrder: params.sortOrder,\n timeFrom: params.timeFrom,\n timeTo: params.timeTo,\n paginationLimit: params.limit,\n paginationNextToken: params.nextToken,\n });\n return formatResult(data);\n } catch (error) {\n return handleToolError(error);\n }\n },\n );\n\n server.tool(\n \"list_port_events\",\n \"List port events (arrivals/departures) across all covered ports, with optional filters for time, country, port, vessel, or event type. Covers only the last 2 hours unless timeFrom is given. Events are kept for 31 days.\",\n {\n timeFrom: z.string().optional().describe(\"Start of the time window, RFC3339. Without it the service returns only the last 2 hours.\"),\n timeTo: z.string().optional().describe(\"End of the time window, RFC3339. Defaults to now.\"),\n country: z.string().optional().describe(\"Filter by port country (case-insensitive)\"),\n unlocode: z.string().optional().describe(\"Filter by port UN/LOCODE\"),\n eventType: z.enum([\"arrival\", \"departure\", \"all\"]).optional().describe(\"Filter by event type. Omit for both arrivals and departures\"),\n vesselName: z.string().optional().describe(\"Filter by vessel name (full-text search)\"),\n portName: z.string().optional().describe(\"Filter by port name (full-text search)\"),\n limit: z.number().int().min(1).max(50).optional().describe(\"Results per page, 1 to 50. Defaults to 20.\"),\n nextToken: z.string().optional().describe(\"Pagination token from previous response\"),\n },\n async (params) => {\n try {\n const data = await client.portEvents.list({\n timeFrom: params.timeFrom,\n timeTo: params.timeTo,\n filterCountry: params.country,\n filterUnlocode: params.unlocode,\n filterEventType: params.eventType,\n filterVesselName: params.vesselName,\n filterPortName: params.portName,\n paginationLimit: params.limit,\n paginationNextToken: params.nextToken,\n });\n return formatResult(data);\n } catch (error) {\n return handleToolError(error);\n }\n },\n );\n\n server.tool(\n \"search_port_events_by_port\",\n \"Search port events by port name. Covers only the last 2 hours unless timeFrom is given.\",\n {\n portName: z.string().describe(\"Port name to search for\"),\n timeFrom: z.string().optional().describe(\"Start of the time window, RFC3339. Without it the service returns only the last 2 hours.\"),\n timeTo: z.string().optional().describe(\"End of the time window, RFC3339. Defaults to now.\"),\n limit: z.number().int().min(1).max(50).optional().describe(\"Results per page, 1 to 50. Defaults to 20.\"),\n nextToken: z.string().optional().describe(\"Pagination token from previous response\"),\n },\n async (params) => {\n try {\n const data = await client.portEvents.byPorts({\n filterPortName: params.portName,\n timeFrom: params.timeFrom,\n timeTo: params.timeTo,\n paginationLimit: params.limit,\n paginationNextToken: params.nextToken,\n });\n return formatResult(data);\n } catch (error) {\n return handleToolError(error);\n }\n },\n );\n\n server.tool(\n \"search_port_events_by_vessel\",\n \"Search port events by vessel name. Covers only the last 2 hours unless timeFrom is given.\",\n {\n vesselName: z.string().describe(\"Vessel name to search for\"),\n timeFrom: z.string().optional().describe(\"Start of the time window, RFC3339. Without it the service returns only the last 2 hours.\"),\n timeTo: z.string().optional().describe(\"End of the time window, RFC3339. Defaults to now.\"),\n limit: z.number().int().min(1).max(50).optional().describe(\"Results per page, 1 to 50. Defaults to 20.\"),\n nextToken: z.string().optional().describe(\"Pagination token from previous response\"),\n },\n async (params) => {\n try {\n const data = await client.portEvents.byVessels({\n filterVesselName: params.vesselName,\n timeFrom: params.timeFrom,\n timeTo: params.timeTo,\n paginationLimit: params.limit,\n paginationNextToken: params.nextToken,\n });\n return formatResult(data);\n } catch (error) {\n return handleToolError(error);\n }\n },\n );\n\n server.tool(\n \"get_vessel_last_port_event\",\n \"Get the most recent port event (arrival or departure) for a vessel\",\n {\n vesselId: z.string().describe(\"Vessel identifier (IMO number by default)\"),\n idType: z.enum([\"imo\", \"mmsi\"]).optional().describe(\"Identifier type: imo (default) or mmsi\"),\n },\n async (params) => {\n try {\n const data = await client.portEvents.lastByVessel(params.vesselId, {\n filterIdType: params.idType,\n });\n return formatResult(data);\n } catch (error) {\n return handleToolError(error);\n }\n },\n );\n\n server.tool(\n \"list_emissions\",\n \"List EU MRV annual emissions reports (ships calling at EU and EEA ports), with an optional reporting-year filter\",\n {\n period: z.number().optional().describe(\"Reporting year filter (e.g. 2024)\"),\n limit: z.number().int().min(1).max(50).optional().describe(\"Results per page, 1 to 50. Defaults to 20.\"),\n nextToken: z.string().optional().describe(\"Pagination token from previous response\"),\n },\n async (params) => {\n try {\n const data = await client.emissions.list({\n filterPeriod: params.period,\n paginationLimit: params.limit,\n paginationNextToken: params.nextToken,\n });\n return formatResult(data);\n } catch (error) {\n return handleToolError(error);\n }\n },\n );\n}\n","import type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { VesselClient } from \"vesselapi\";\nimport { z } from \"zod\";\nimport { formatResult, handleToolError } from \"../errors.js\";\n\nexport function registerVesselTools(server: McpServer, client: VesselClient): void {\n server.tool(\n \"search_vessels\",\n \"Search for vessels. Use q when you have an identifier but do not know which kind it is; use the specific filters to narrow a fleet.\",\n {\n q: z.string().optional().describe(\"Free-text search across name, IMO, MMSI, ENI and callsign. Use this when the type of identifier is unknown.\"),\n name: z.string().optional().describe(\"Vessel name (partial match)\"),\n imo: z.string().optional().describe(\"IMO number\"),\n mmsi: z.string().optional().describe(\"MMSI number\"),\n eni: z.string().optional().describe(\"ENI number, used for inland waterway vessels\"),\n flag: z.string().optional().describe(\"Flag state (ISO country code)\"),\n vesselType: z.string().optional().describe(\"Vessel type\"),\n callsign: z.string().optional().describe(\"Radio callsign\"),\n yearBuiltMin: z.number().optional().describe(\"Minimum year built\"),\n yearBuiltMax: z.number().optional().describe(\"Maximum year built\"),\n limit: z.number().int().min(1).max(50).optional().describe(\"Results per page, 1 to 50. Defaults to 20.\"),\n nextToken: z.string().optional().describe(\"Pagination token from previous response\"),\n },\n async (params) => {\n try {\n const data = await client.search.vessels({\n q: params.q,\n filterEni: params.eni,\n filterName: params.name,\n filterImo: params.imo,\n filterMmsi: params.mmsi,\n filterFlag: params.flag,\n filterVesselType: params.vesselType,\n filterCallsign: params.callsign,\n filterYearBuiltMin: params.yearBuiltMin,\n filterYearBuiltMax: params.yearBuiltMax,\n paginationLimit: params.limit,\n paginationNextToken: params.nextToken,\n });\n return formatResult(data);\n } catch (error) {\n return handleToolError(error);\n }\n },\n );\n\n server.tool(\n \"get_vessel\",\n \"Get detailed information about a specific vessel\",\n {\n vesselId: z.string().describe(\"Vessel identifier (IMO number by default)\"),\n idType: z.enum([\"imo\", \"mmsi\"]).optional().describe(\"Identifier type: imo (default) or mmsi\"),\n },\n async (params) => {\n try {\n const data = await client.vessels.get(params.vesselId, {\n filterIdType: params.idType,\n });\n return formatResult(data);\n } catch (error) {\n return handleToolError(error);\n }\n },\n );\n\n server.tool(\n \"get_vessel_position\",\n \"Get the latest stored position of a vessel (latitude, longitude, speed, heading, timestamp). Check the timestamp: the fix may be hours or days old, especially for a vessel away from the coast.\",\n {\n vesselId: z.string().describe(\"Vessel identifier (IMO number by default)\"),\n idType: z.enum([\"imo\", \"mmsi\"]).optional().describe(\"Identifier type: imo (default) or mmsi\"),\n sat: z.boolean().optional().describe(\"Fall back to a satellite position when no recent terrestrial one exists. Charged per call against a prepaid balance, so use it only when a stored position is genuinely insufficient.\"),\n },\n async (params) => {\n try {\n const data = await client.vessels.position(params.vesselId, {\n filterSat: params.sat,\n filterIdType: params.idType,\n });\n return formatResult(data);\n } catch (error) {\n return handleToolError(error);\n }\n },\n );\n\n server.tool(\n \"get_vessel_eta\",\n \"Get the most recent ETA the vessel itself reported in its AIS voyage data. This is the declared ETA, not a prediction.\",\n {\n vesselId: z.string().describe(\"Vessel identifier (IMO number by default)\"),\n idType: z.enum([\"imo\", \"mmsi\"]).optional().describe(\"Identifier type: imo (default) or mmsi\"),\n },\n async (params) => {\n try {\n const data = await client.vessels.eta(params.vesselId, {\n filterIdType: params.idType,\n });\n return formatResult(data);\n } catch (error) {\n return handleToolError(error);\n }\n },\n );\n\n server.tool(\n \"get_vessel_emissions\",\n \"Get EU MRV annual emissions reports for a vessel (CO2, fuel consumption). Only ships that report under EU MRV have data.\",\n {\n vesselId: z.string().describe(\"Vessel identifier (IMO number by default)\"),\n idType: z.enum([\"imo\", \"mmsi\"]).optional().describe(\"Identifier type: imo (default) or mmsi\"),\n limit: z.number().int().min(1).max(50).optional().describe(\"Results per page, 1 to 50. Defaults to 20.\"),\n nextToken: z.string().optional().describe(\"Pagination token from previous response\"),\n },\n async (params) => {\n try {\n const data = await client.vessels.emissions(params.vesselId, {\n filterIdType: params.idType,\n paginationLimit: params.limit,\n paginationNextToken: params.nextToken,\n });\n return formatResult(data);\n } catch (error) {\n return handleToolError(error);\n }\n },\n );\n\n server.tool(\n \"get_vessel_casualties\",\n \"Get marine casualty records for a vessel\",\n {\n vesselId: z.string().describe(\"Vessel identifier (IMO number by default)\"),\n idType: z.enum([\"imo\", \"mmsi\"]).optional().describe(\"Identifier type: imo (default) or mmsi\"),\n limit: z.number().int().min(1).max(50).optional().describe(\"Results per page, 1 to 50. Defaults to 20.\"),\n nextToken: z.string().optional().describe(\"Pagination token from previous response\"),\n },\n async (params) => {\n try {\n const data = await client.vessels.casualties(params.vesselId, {\n filterIdType: params.idType,\n paginationLimit: params.limit,\n paginationNextToken: params.nextToken,\n });\n return formatResult(data);\n } catch (error) {\n return handleToolError(error);\n }\n },\n );\n\n server.tool(\n \"get_vessel_positions_batch\",\n \"Get positions for multiple vessels at once by MMSI or IMO numbers\",\n {\n ids: z.string().describe(\"Comma-separated list of MMSI or IMO numbers\"),\n idType: z.enum([\"imo\", \"mmsi\"]).optional().describe(\"Identifier type: imo (default) or mmsi\"),\n timeFrom: z.string().optional().describe(\"Start time filter in RFC3339 format (defaults to 2 hours ago)\"),\n timeTo: z.string().optional().describe(\"End time filter in RFC3339 format (defaults to current time)\"),\n limit: z.number().int().min(1).max(50).optional().describe(\"Results per page, 1 to 50. Defaults to 20.\"),\n nextToken: z.string().optional().describe(\"Pagination token from previous response\"),\n },\n async (params) => {\n try {\n const data = await client.vessels.positions({\n filterIds: params.ids,\n filterIdType: params.idType,\n timeFrom: params.timeFrom,\n timeTo: params.timeTo,\n paginationLimit: params.limit,\n paginationNextToken: params.nextToken,\n });\n return formatResult(data);\n } catch (error) {\n return handleToolError(error);\n }\n },\n );\n}\n"],"mappings":"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","names":["server","client","z","server","client","z","z","server","client","z"]}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vesselapi-mcp",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"mcpName": "io.github.vessel-api/vesselapi-mcp",
|
|
5
|
-
"description": "MCP server for the VesselAPI
|
|
5
|
+
"description": "MCP server for the VesselAPI: maritime vessel tracking, port events and emissions",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "VesselAPI",
|
|
8
8
|
"repository": {
|
|
@@ -30,7 +30,8 @@
|
|
|
30
30
|
"vesselapi-mcp": "./dist/index.js"
|
|
31
31
|
},
|
|
32
32
|
"files": [
|
|
33
|
-
"dist"
|
|
33
|
+
"dist",
|
|
34
|
+
"CHANGELOG.md"
|
|
34
35
|
],
|
|
35
36
|
"scripts": {
|
|
36
37
|
"prepublishOnly": "npm run build",
|
|
@@ -42,9 +43,9 @@
|
|
|
42
43
|
"node": ">=18"
|
|
43
44
|
},
|
|
44
45
|
"dependencies": {
|
|
45
|
-
"vesselapi": "^1.2.0",
|
|
46
46
|
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
47
|
-
"
|
|
47
|
+
"vesselapi": "^2.0.0",
|
|
48
|
+
"zod": "^3.25.0"
|
|
48
49
|
},
|
|
49
50
|
"devDependencies": {
|
|
50
51
|
"@types/node": "^25.3.0",
|