| name | ov-nl-travel |
| description | Dutch rail travel helper for NS Reisinformatie via the ovNlGateway MCP tool.
Use this for stations, departures, arrivals, trips, journey details, and disruptions.
|
| license | MIT |
| metadata | {"author":"ovnl-codex-plugin","version":"0.1.0","purpose":"ov-nl-travel-assistant"} |
OV-NL Travel
Use ovNlGateway first for Dutch railway and NS questions.
Preferred behavior
- Prefer
ovNlGateway for anything that can change minute-to-minute: departures, delays, cancellations, platforms, disruptions, or best current trip options.
- Do not use web search for live rail data when
ovNlGateway can answer it.
- If a station name is ambiguous, ask a short disambiguation question or show the candidates from the tool result.
- Never claim something is live unless
ovNlGateway was used in this turn.
- For requests asking for all train legs, changes, or intermediate stations on an itinerary, use
trips.search first and then trips.detail with the selected trip's ctxRecon.
- Do not fall back to web search for intermediate stops when
trips.detail is available.
- Use
journey.detail for a specific train or journeyDetailRef, not for describing a whole itinerary. When passing a journeyDetailRef, map it to args.id.
Tool contract
The tool expects:
{ "action": "<action>", "args": { } }
Supported actions:
stations.search -> { query, limit?, countryCodes?, intent? }
stations.nearest -> { latitude/longitude or lat/lng, limit?, intent? }
departures.list -> { station? | stationCode? | uicCode?, dateTime?, maxJourneys?, lang?, intent? }
departures.window -> { station? | stationCode? | uicCode?, fromDateTime+toDateTime OR date+fromTime+toTime, maxJourneys?, lang?, intent? }
arrivals.list -> { station? | stationCode? | uicCode?, dateTime?, maxJourneys?, lang?, intent? }
trips.search -> { from, to, via?, dateTime?, searchForArrival?, limit?, lang?, intent? }
trips.detail -> { ctxRecon, date?, lang? }
journey.detail -> { id? | train?, dateTime?, departureUicCode?, transferUicCode?, arrivalUicCode?, omitCrowdForecast? }
disruptions.list -> { type?, isActive?, lang?, intent? }
disruptions.by_station -> { station, intent? }
disruptions.detail -> { type, id }
Intent guidance
Use args.intent.hard for strict constraints:
directOnly
maxTransfers
maxDurationMinutes
departureAfter
departureBefore
arrivalAfter
arrivalBefore
includeModes
excludeModes
includeOperators
excludeOperators
includeTrainCategories
excludeTrainCategories
avoidStations
excludeCancelled
requireRealtime
platformEquals
disruptionTypes
activeOnly
Use args.intent.soft.rankBy as a list for preferences, for example { "rankBy": ["fastest"] }:
fastest
fewest_transfers
earliest_departure
earliest_arrival
realtime_first
least_walking
Use hard constraints for wording like must, only, without, geen, alleen, zonder, or niet.
Use soft ranking for wording like prefer, liefst, best, or bij voorkeur.
Output handling
The tool normally returns a matching kind, for example trips.search or departures.list.
Special cases:
kind: "disambiguation" means the tool could not uniquely resolve a station.
- Show the candidates succinctly.
- Ask the user to choose one.
- Re-run the original action with the chosen station.
kind: "error" means the request failed or no valid result exists.
- Surface the message directly.
- If the error is actionable, suggest the smallest next step.
Practical recipes
- “Next train from X” ->
departures.list
- “Departures between 17:00 and 18:00 from X” ->
departures.window
- “Arrivals at X” ->
arrivals.list
- “Best route from A to B” ->
trips.search
- “Show more details for this trip” ->
trips.detail
- “Show all train legs and intermediate stations for this trip” ->
trips.search, then trips.detail with the chosen ctxRecon
- “What’s going on with this train?” ->
journey.detail
- “Show NS disruptions” ->
disruptions.list
- “Disruptions near station X” ->
disruptions.by_station