Maritime Vessel Data MCP Server
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| AISSTREAM_API_KEY | No | Your aisstream.io API key. Without it, the server uses a bundled sample dataset. |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": false
} |
| prompts | {
"listChanged": false
} |
| resources | {
"subscribe": false,
"listChanged": false
} |
| experimental | {} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| search_vesselsA | Search the vessel dataset by type, flag state, and/or navigational status. Any argument left blank is ignored, and surrounding whitespace is ignored. Returns JSON with a "data" block stating the source, a "matches" count of everything that matched, a "returned" count of how many are included, and a "vessels" list. When returned is less than matches the list was capped by the limit argument: raise it or narrow the search to see the rest. When data.source is "snapshot" the positions are from a fixed sample dataset and are not current: say so when answering. Fields that AIS has not reported yet are null, never guessed. |
| vessels_near_portA | List vessels within a radius (nautical miles) of a named port. Recognized ports: Port Klang, Tanjung Pelepas, Penang, Malacca, Langkawi. Returns JSON with a "data" block stating the source, a "matches" count of everything inside the radius, a "returned" count of how many are included, and a "vessels" list annotated with distance_nm, nearest first. When returned is less than matches the nearest were kept and the rest omitted. When data.source is "snapshot" the positions are not current: say so when answering. |
| vessel_detailsA | Look up a single vessel by exact MMSI or by (partial) name. Returns JSON with a "data" block stating the source and a "vessel" record, or an error object if no unique match is found. When data.source is "snapshot" the position is not current. Null fields mean AIS has not reported that detail, not that the value is zero or unknown to the vessel. |
| vessel_trackA | Where a vessel has been over the last few hours. Returns JSON with a "data" block and a "track" list of positions, oldest first. Each position is one AIS report that was actually received: the gaps between them are real, and nothing is interpolated to fill them. History only exists from the point this server started keeping it. An empty track means nothing was heard, not that the vessel did not move. |
| fleet_trackA | Where every vessel has been over the last few hours. Returns JSON with a "data" block and a "fleet" list, one entry per vessel, each with its identity and its positions oldest first. Intended for playback and for checking work against what was actually observed. Each position is one AIS report that was received. The gaps between them are real: the median vessel reports only a handful of times an hour, so two fixes an hour apart are two observations and not a path. Nothing is interpolated. When "truncated" is true the row cap was reached and this is not the whole picture. Narrow the window rather than assuming the missing vessels are gone. |
| list_regionsA | List the sea areas this server can watch, and what each one costs. The feed is rationed by throughput rather than by area. A subscription above roughly 25 messages a second is closed by the vendor within a couple of minutes, and a whole-world subscription dies inside one, so a selection has to be chosen to fit a budget rather than simply widened. Each region reports its measured message rate. A rate of null means nobody has measured that region yet, and a selection containing one has an unknown total: that is reported as unknown rather than as a partial sum. Use set_regions to change what is being watched. |
| set_regionsA | Change which sea areas the live subscription watches. Applied to the open connection where possible, so the feed is not interrupted. Vessels already collected are not discarded: the store keeps them until they age out of its 30-minute window, so a region just switched away from fades rather than vanishing. A selection over the throughput budget is accepted and reported, not refused. The caller asked for it, and the honest answer is that the feed will drop and reconnect repeatedly rather than a limit that does not exist. |
| vessels_in_areaA | Vessels inside one area of sea, rather than everywhere the server watches. This exists because a selection covering several regions can hold far more vessels than any one caller wants at once, and sending all of them is expensive for an answer about one strait. Ask for the water you care about. The area filters what has already been collected, which is a different question from what is subscribed to: a region switched away from still has vessels in the store until they age out, and an area nobody is subscribed to simply returns nothing. |
| vessels_watchedA | Vessels inside the regions currently being watched, and nothing else. The store keeps every vessel it has collected until the position ages out of the thirty minute window, which includes vessels from a region that has since been deselected. That is the right thing for the store to do and the wrong thing to show: someone who selects Malaysia means show me Malaysia, not Malaysia plus whatever was on screen ten minutes ago. With no live subscription there is nothing being watched, so no filter applies and everything is returned with a note saying so. |
| port_callsA | When a vessel stopped, where, for how long, and whether she was working. This is the skeleton of a Statement of Facts, read out of the recorded track rather than typed from memory: arrival, time alongside or at anchor, departure. Anchored and moored are kept apart, because in laytime terms one is waiting and the other is working. Everything reported was observed. A vessel that has not been seen to leave has no departure time rather than an assumed one; a stop spanning a hole in coverage is cut at the hole rather than claimed as continuous; and a stop far from any known port is reported as at sea rather than given the name of the nearest one. Where an arrival was not witnessed, because the record starts mid-stop or follows a coverage hole, arrival_observed is false and the arrival time is only when this server first saw her there. |
| congestionA | How busy an area has been, hour by hour, from the recorded track. Counts distinct vessels per hour by what they were reporting: at anchor, moored, or under way. The anchored count is the one that answers "how long is the queue", which is what a charterer rings an agent about. Each vessel is counted once per hour it was heard in, so a vessel reporting twenty times in an hour counts once. An hour with no coverage reads as zero and is indistinguishable from an hour with no ships, which is why the response reports how many positions each hour was built from. |
| traffic_densityA | Where vessels have actually been, as a grid of counts. Read this as coverage as much as traffic. It shows where positions were received, so an empty cell means either that no ship went there or that nothing was listening. Port Klang reads as empty on this map and it is one of the busiest ports in the world. Each cell reports distinct vessels and total positions separately, because they answer different questions: one ship anchored for two days makes hundreds of positions in a single cell, which is a fact about that ship and not about how busy the cell is. |
| anchoragesA | Where vessels actually anchor, found in the recorded positions. No chart is consulted. This looks for water where a lot of vessels reported "At anchor" and groups the touching parts into one place, so what comes back is where ships really wait rather than where they are permitted to. For a question about queueing, the first is the useful one. Nothing is named. The cluster off eastern Singapore is obviously the eastern anchorage to anyone who works there, but AIS does not say so and this will not invent it. Each is given its extent, not a radius: an anchorage is usually a long thin thing along a coast and a circle would claim water nobody anchors in. Bear the coverage caveat in mind. An anchorage nothing is listening to does not appear here, and that is not the same as an anchorage nobody uses. |
| passage_timeA | How long this leg actually takes, from ships that made it. Not distance divided by an assumed speed. That knows nothing about the strait, the traffic, the pilot boarding, or the hour spent waiting for a berth at the far end. This is measured from recorded tracks. The spread comes with the middle, always. A leg whose median is fourteen hours and whose range is seven to sixty two is not a leg anyone should schedule to fourteen, and reporting the median alone would invite exactly that. Below five observed passages no median is given at all. Time spent waiting at the origin is not passage time: the clock starts when the vessel leaves the origin's reach, not when it was first seen there. A vessel seen arriving but never departing is not counted, because a record that starts mid-voyage is not evidence of a voyage. |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
| all_vessels | The full vessel dataset as a JSON resource. |
TDQS
Scored across 14 tools
Each tool targets a clearly distinct resource or analytical question: vessel search, nearby vessels, area/watched filters, single/fleet tracks, region subscription, and derived metrics like passage time, port calls, congestion, density, and anchorages. Even the geographically overlapping tools are differentiated by their exact filter semantics and described with enough precision to prevent misselection.
Names are readable and consistently snake_case, but the pattern is mixed: some are verb-first (search_vessels, list_regions, set_regions) while most are descriptive noun phrases (vessel_track, port_calls, traffic_density, anchorages). There is no single consistent convention, though the names remain self-explanatory.
Fourteen tools is within the ideal range and each tool earns its place: discovery, details, tracks, region subscription, and specialized maritime analytics are all represented without redundant or filler tools. The count matches the breadth of the domain well.
The server covers the full read-only AIS workflow: finding vessels, retrieving details, viewing current positions and historical tracks, managing region subscriptions, and producing derived insights like passage times, port calls, congestion, traffic density, and anchorages. No obvious dead ends or missing operations are apparent for its stated purpose.