italian-bus-search
This read-only server lets you search Italian bus and train locations and one-way journeys and inspect provider/status information via MCP tools.
List bus providers and their availability status.
Search bus/coach locations and journeys across providers, with partial results, provider-scoped errors, and official booking links.
List train operators and whether schedule, price, live-status, and station-board capabilities are enabled.
Search Trenitalia/Italo stations and train journeys with schedules, fares, legs, changes, availability, live status, and timetable metadata.
Get live train status by operator, train number, service date, and origin.
Get station arrival/departure boards.
It is read-only and does not support accounts, bookings, payments, seat selection, or CAPTCHA handling.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@italian-bus-searchFind one-way buses from Rome to Milan on 15 June"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Italian Travel Search
An unofficial, read-only TypeScript service for Italian coach searches and local NeTEx rail timetables through HTTP and Model Context Protocol interfaces.
The project hides provider-specific station catalogs, request formats, fare structures, and multi-leg responses behind one shared application core. It never performs login, booking, seat selection, or payment operations.
This project is not affiliated with or endorsed by Itabus, Autoservizi Salemi, Autolinee Federico, MarinoBus, or FlixBus. Provider names and trademarks belong to their owners. Before enabling a live adapter, confirm that your use complies with the provider's terms, applicable law, and any required authorization. This repository does not grant data-extraction or redistribution rights.
Features
One response model for locations and journeys across different booking platforms.
Live adapters for five operators.
Partial results when one provider fails and another succeeds.
MCP over local stdio or stateless Streamable HTTP at
/mcp, with backward-compatible bus tools and separate rail tools.Scheduled Trenitalia and Italo searches from operator datasets installed by the deployer.
Official links for continuing a search manually on provider sites.
Structured, provider-scoped errors instead of leaked upstream responses.
Finite upstream request timeouts and bounded asynchronous quote polling.
One-hour location caches and 60-second journey caches.
Per-client in-memory rate limiting at 60 requests per minute.
Offline tests with synthetic fixtures; the test suite never contacts provider sites.
A small runtime dependency surface: the official MCP SDK, Zod, and the streaming
saxesparser.
Related MCP server: soloway-mcp
Supported providers
Provider ID | Operator | Integration | Locations | Journeys |
| Itabus | Demandware endpoints | Live | Live |
| Autoservizi Salemi | Albatross tenant | Live | Live |
| Autolinee Federico | Albatross tenant | Live | Live |
| MarinoBus | Albatross tenant | Live | Live |
| FlixBus | Global FlixBus search API | Live | Live |
Provider behavior and the evidence behind each integration are recorded in Provider research.
Rail schedule support uses compact local caches refreshed from Italian NAP NeTEx with npm run build && npm run rail:update. Optional TRENITALIA_NETEX_PATH and ITALO_NETEX_PATH variables override their paths. Trenitalia and Italo prices, ViaggiaTreno live data, and Italo live boards/standalone status are enabled. Italo quote searches use an anonymous temporary planning session and clean it up best-effort.
Requirements
Node.js 22.18 or newer
npm
Quick start
git clone https://github.com/Alexxanddr/italian-travel-search.git
cd italian-travel-search
npm install
cp .env.example .env
npm startThe server listens on http://127.0.0.1:3000 by default.
curl http://127.0.0.1:3000/health
curl http://127.0.0.1:3000/providers
curl http://127.0.0.1:3000/train-providers
curl 'http://127.0.0.1:3000/locations?query=Roma&provider=marinobus'For journey searches, use a real future date:
curl 'http://127.0.0.1:3000/journeys?origin=Roma&destination=Milano&date=YYYY-MM-DD&adults=1&children=0&provider=marinobus'YYYY-MM-DD is a placeholder and must be replaced before running the command.
HTTP interface
Method | Path | Purpose |
|
| Process liveness |
|
| Adapter status and operational reason |
|
| Train operators and configured schedule/price/live capabilities |
|
| Provider location search |
|
| Normalized one-way journey search |
|
| Trenitalia/Italo station search |
|
| Live-priced rail journeys with resilient NeTEx fallback |
|
| Standalone live status where enabled |
|
| Live arrivals/departures where enabled |
|
| Stateless MCP Streamable HTTP endpoint |
/locations and /journeys accept an optional provider parameter. Without it, all providers are queried independently and successful data is preserved alongside provider-scoped errors.
The complete contract is split into the Bus API and Train API, with shared behavior indexed in HTTP API.
MCP server
The simplest MCP configuration runs the published package directly with npx:
{
"mcpServers": {
"italian-travel-search": {
"command": "npx",
"args": ["-y", "italian-travel-search@latest"]
}
}
}Alternatively, build and start the local stdio server:
npm run build
npm run mcp:builtThe existing list_providers, search_locations, and search_journeys bus tools are unchanged. Rail adds list_train_providers, search_train_locations, search_train_journeys, get_train_status, and get_station_board. Trenitalia and Italo price and live adapters are enabled; Italo live tools retain date-unverified semantics.
{
"mcpServers": {
"italian-travel-search": {
"command": "node",
"args": ["/absolute/path/to/italian-travel-search/dist/mcp/stdio.js"]
}
}
}For a container or remote MCPHub deployment, start the HTTP process and point the client to http://italian-travel-search:3000/mcp. The container image is ghcr.io/alexxanddr/italian-travel-search:latest; populate the two timetable paths with node dist/rail/update.js before starting it.
See MCP interface for the authoritative tool contract, limits, errors, and development command.
Architecture
The application has four layers:
HTTP and MCP adapters validate their transport-specific requests;
shared validation and
SearchServiceorchestrate searches and partial results;each provider adapter translates a remote protocol into domain types;
the domain module owns normalized data and error contracts.
Provider adapters implement one shared interface, so callers do not know whether a result came from Itabus Demandware or an Albatross tenant. See Architecture for modules, seams, data flow, caches, and test strategy.
Development
npm run dev
npm run mcp
npm run checknpm run check runs the complete offline test suite, TypeScript type checking, and the configured lint check. To add an operator, follow Adding a provider; do not infer a new integration from HTML alone or copy credentials into fixtures.
Deployment
The default server deliberately binds to loopback and keeps rate-limit and cache state in process memory. Read Operations before placing it behind a reverse proxy or running multiple replicas.
Project documentation
HTTP API — shared behavior and error contract.
Bus API — bus providers, locations, journeys, and examples.
Train API — rail schedules, live prices/status, provenance, and examples.
MCP interface — authoritative tools, results, limits, and transport contract.
Architecture — modules, seams, flows, and design decisions.
Adding a provider — research, implementation, and verification checklist.
Operations — configuration, deployment constraints, and failure handling.
Provider research — primary-source evidence and known limitations.
Glossary — stable project terminology.
Contributing — local workflow and pull-request expectations.
Security policy — private vulnerability reporting and supported versions.
Agent instructions — compact routing instructions for coding agents.
Scope and limitations
Searches are one-way only.
Availability is a provider-reported signal, not a seat or price guarantee.
Prices and schedules can change between search and purchase; rail schedule results expose dataset validity and publication metadata.
Caches and rate limits reset when the process restarts and are not shared across replicas.
Upstream interfaces are unofficial and can change without notice.
Both interfaces intentionally exclude accounts, bookings, payments, and CAPTCHA handling.
Always complete and confirm a purchase on the official provider site linked by bookingUrl.
Contributing and security
Contributions are welcome; start with CONTRIBUTING.md. Report vulnerabilities privately according to SECURITY.md, not through a public issue.
License
Source code is available under the MIT License. The license covers this repository's code, not third-party data, provider trademarks, or access rights to upstream systems.
Available Tools
8 toolsget_station_boardGet train station boardBRead-onlyIdempotent
Get an operator station board with its observation timestamp. Live boards may be unavailable independently of schedules.
| Name | Required | Description | Default |
|---|---|---|---|
| provider | Yes | ||
| direction | Yes | ||
| stationId | Yes | ||
| stationName | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| source | Yes | |
| station | Yes | |
| provider | Yes | |
| services | Yes | |
| direction | Yes | |
| observedAt | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, openWorld and non-destructive, so the safety profile is covered. The description adds genuine behavioral value by warning that live boards can be unavailable independently of schedules, but says nothing about how failure is surfaced, rate limits, or freshness of the data.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, zero filler, with the core action and its scope front-loaded. Every clause carries information the agent cannot get from the structured fields.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be described, and the availability caveat is useful. But for a tool with four required parameters at 0% schema coverage and no explanation of the stationId/stationName pairing, the description leaves a real invocation gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0% and the description names none of the four required parameters. The unusual requirement of both stationId and stationName — and where to obtain them (e.g. search_train_locations) — is undocumented, so an agent gets no help resolving these inputs.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Get an operator station board') plus a scope nuance (observation timestamp). It is distinguishable from get_train_status and search_train_journeys by being station-level rather than train- or journey-level, though it never says so explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The sentence 'Live boards may be unavailable independently of schedules' implies this tool covers live station boards and is separate from schedule queries, which hints at usage. However, no sibling is named and there is no explicit when-to-use/when-not-to-use guidance despite six related tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_train_statusGet train statusBRead-onlyIdempotent
Get live status using operator, train number, service date, and origin identity. Live status may be unavailable independently of schedules.
| Name | Required | Description | Default |
|---|---|---|---|
| origin | Yes | ||
| provider | Yes | ||
| serviceDate | Yes | ||
| trainNumber | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| source | Yes | |
| cancelled | No | |
| freshness | Yes | |
| observedAt | Yes | |
| delayMinutes | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, non-destructive and open-world, so safety is covered; the description adds a genuinely useful behavioral caveat that live status data may be missing regardless of schedule availability — important for an agent deciding whether to retry or fall back. It does not mention auth, rate limits, or refresh cadence.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, front-loaded with the action and inputs, with no filler. The second sentence earns its place as a real caveat rather than padding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return-value explanation is not required, and annotations cover the safety profile. What remains missing is input format guidance (date and origin identifier conventions) and the expected behavior/response when live status is unavailable — a notable gap for a 4-parameter, zero-coverage schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0% across four required parameters. The description only restates the parameter names in prose ("operator, train number, service date, and origin identity") and adds no format guidance for serviceDate, trainNumber, or origin, and does not mention the trenitalia/italo enum restriction. "Origin identity" vaguely implies an identifier but leaves the code-vs-name question open.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ("Get live status") and enumerates the identifying inputs, which clearly separates it from the search_* siblings that return schedules rather than live state. It stops short of naming an alternative tool outright, but the retrieved artifact is unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied: the phrase "Live status may be unavailable independently of schedules" hints that schedules are a separate concern, but the description never says when to prefer this over search_train_journeys or get_station_board, nor what to do when status is unavailable. No exclusions or prerequisites are given.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_providersList Italian bus providersARead-onlyIdempotent
BUS ONLY. List configured bus/coach providers and their status. Never use this tool for trains or rail; use list_train_providers instead.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| providers | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, destructiveHint=false and openWorldHint=true, so the safety profile is fully covered by structured data. The description adds only the modal exclusivity rule, which is really routing guidance, and says nothing about what "status" entails or any auth/config prerequisites. Adequate against the lower bar set by annotations, but no extra behavioral value.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, zero filler, with the most important constraint ("BUS ONLY") front-loaded in capitals. Nothing could be removed without losing routing information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no parameters, full annotation coverage and an output schema covering return values, the description supplies nearly everything an agent needs. The only small gap is that "status" is never characterized, though the output schema plausibly covers it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is nothing for the description to disambiguate and the baseline of 4 applies. The description correctly implies a no-argument enumeration by saying "list configured ... providers".
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("List configured bus/coach providers and their status") and immediately constrains domain with "BUS ONLY". It explicitly separates itself from list_train_providers, so an agent can distinguish it from siblings without reading any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit prohibition ("Never use this tool for trains or rail") and names the correct alternative (list_train_providers). Both the when and the when-not are stated with no inference required.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_train_providersList Italian train providersARead-onlyIdempotent
TRAINS ONLY. Use for requests involving trains or rail. Lists train operators and whether schedule, price, live-status, and station-board capabilities are enabled.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| providers | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, non-destructive and openWorld, so the safety profile is covered. The description adds value by disclosing that results are operators annotated with capability flags rather than raw schedule data — useful framing that keeps the agent from expecting journey results.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences with the domain restriction front-loaded, which is the right ordering. There is mild redundancy between "TRAINS ONLY" and "requests involving trains or rail", but nothing that wastes real reading effort.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With zero parameters, rich annotations, and an output schema handling return values, the description is nearly complete. The only substantive gap is that it never distinguishes this provider-listing call from search_train_journeys or get_train_status, which matters given seven siblings.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, which is the baseline-4 case; there is nothing the description could clarify about inputs. Schema description coverage is 100% and there are no required or enum parameters to disambiguate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Lists train operators") plus the payload content (capability enablement for schedule, price, live-status, station-board). The "TRAINS ONLY" qualifier separates it from the sibling list_providers, which presumably spans other transport modes.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
"Use for requests involving trains or rail" gives a domain-level routing cue but no when-not and no alternatives. An agent asking for an actual itinerary could still plausibly land here instead of search_train_journeys or get_train_status, since neither sibling is named or excluded.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_journeysSearch Italian bus journeysARead-onlyIdempotent
BUS ONLY. Search one-way bus/coach journeys. Never use for trains or rail; use search_train_journeys instead. Results include official links for continuing manually on provider sites.
| Name | Required | Description | Default |
|---|---|---|---|
| date | Yes | Real future date in YYYY-MM-DD format | |
| limit | No | ||
| adults | No | ||
| origin | Yes | Exact shared location name for aggregate searches, or a provider-specific ID when provider is set | |
| children | No | ||
| provider | No | Provider ID; omit to search every provider | |
| destination | Yes | Exact shared location name for aggregate searches, or a provider-specific ID when provider is set |
Output Schema
| Name | Required | Description |
|---|---|---|
| total | Yes | |
| errors | Yes | |
| journeys | Yes | |
| truncated | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, openWorld), so the bar is low, and the description still adds real context: results contain official provider links meaning the agent cannot complete a booking here and the user must continue manually on provider sites. It does not mention pagination truncation via limit (max 50) or provider-mixing behavior, which would have pushed this higher.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences with the hard constraint ('BUS ONLY') front-loaded, then purpose, then the sibling redirect, then an output caveat. No filler and nothing buried.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be described, and the safety profile is in annotations. The one meaningful gap for a 7-parameter search tool is that it never says origin/destination require exact shared location names that must first be obtained via search_locations or list_providers.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 57%, so the baseline is around 3; the description only contributes the 'one-way' framing, which implicitly tells the agent no return date/round-trip parameter exists. It adds nothing about provider scoping, passenger counts, or limit truncation beyond what the schema already says.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Search one-way bus/coach journeys') and immediately bounds scope with 'BUS ONLY'. It names the sibling it is not (search_train_journeys), so an agent can route correctly without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit exclusion ('Never use for trains or rail') plus the concrete alternative to use instead, which is exactly the guidance that distinguishes it from the train siblings. It stops short of telling the agent how to resolve origin/destination names (search_locations / list_providers) before calling.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_locationsSearch Italian bus locationsARead-onlyIdempotent
BUS ONLY. Find bus/coach location IDs and exact names. Never use for train stations; use search_train_locations instead. For an aggregate bus search, reuse exact names shared across providers.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| query | Yes | Partial city, stop, or location name | |
| provider | No | Provider ID; omit to search every provider |
Output Schema
| Name | Required | Description |
|---|---|---|
| total | Yes | |
| errors | Yes | |
| locations | Yes | |
| truncated | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, openWorld, non-destructive, so the safety profile is covered. The description adds genuinely new behavioral context: the bus-only domain boundary and the downstream convention that exact names are shared across providers for aggregation, though it says nothing about result-set size or the 50-item cap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, each earning its place: scope, exclusion with alternative, and a workflow tip. The most decision-critical constraint (BUS ONLY) is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return values need no explanation, and the annotations carry the safety profile. The routing guidance and aggregation tip make it nearly complete; only the limit/pagination behavior is left unaddressed.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 67% and documents query, provider, and limit reasonably. The description adds only an implicit note that omitting provider searches everything (via the aggregate-search hint) and emphasizes 'exact names', but never addresses the limit parameter or partial-match semantics beyond what the schema states.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource ('Find bus/coach location IDs and exact names') and immediately scopes it with 'BUS ONLY', which separates it cleanly from the train siblings listed.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives an explicit exclusion ('Never use for train stations') and names the correct alternative, search_train_locations, plus a positive hint about reusing exact names for aggregate bus searches, covering both when and when-not.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_train_journeysSearch Italian train journeysARead-onlyIdempotent
TRAINS ONLY. Requires origin, destination, and date. When the user states passenger counts, always pass adults and children explicitly. Each price is the total for those passengers; never infer discounts or convert it to a per-person price.
| Name | Required | Description | Default |
|---|---|---|---|
| date | Yes | ||
| limit | No | ||
| adults | No | Number of adult passengers; pass explicitly when stated by the user | |
| offset | No | Result offset; paginate by adding the previous limit when truncated is true | |
| origin | Yes | ||
| children | No | Number of child passengers; pass explicitly when stated by the user, including zero | |
| provider | No | ||
| destination | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| total | Yes | |
| errors | Yes | |
| journeys | Yes | |
| truncated | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover read-only, idempotent, open-world, non-destructive. The description adds genuinely non-obvious behavior: prices are totals for the whole passenger set and must not be divided per person or discounted. It omits other traits (date format expectations, what truncation/empty results mean), keeping it from a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences; the hard constraint 'TRAINS ONLY' is front-loaded, followed by prerequisites and then the pricing rule. No filler and nothing is buried.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values needn't be explained, and the price semantics are a good addition. But for an 8-parameter search tool the description leaves the provider enum and the date string format unaddressed, which are things an agent could get wrong when calling it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is only 38% across 8 params, so the description should compensate more. It does clarify the three required params and reinforces the adults/children 'pass explicitly' semantics already in the schema, but says nothing about provider, limit, or date format, leaving several parameters undocumented anywhere.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The combination of 'TRAINS ONLY' and the required origin/destination/date makes it clear this searches rail journeys between two points, and 'TRAINS ONLY' implicitly contrasts it with the broader search_journeys sibling. The verb 'search' itself is only implied (it comes from the title), so it sits just below a full 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives prerequisites (origin, destination, date) and a conditional rule for passenger counts, which is real usage guidance. However, it never names search_journeys or search_train_locations as alternatives, nor states when NOT to use this tool, so an agent must infer routing from the sibling list alone.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_train_locationsSearch Italian train stationsBRead-onlyIdempotent
TRAINS ONLY. Use for every request involving trains or rail to find operator-aware stations. Prefer names across operators; station IDs are operator-specific.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| query | Yes | ||
| provider | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| total | Yes | |
| errors | Yes | |
| locations | Yes | |
| truncated | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish read-only, idempotent, open-world, non-destructive behavior. The description adds useful domain context that station IDs are operator-specific and names should be preferred across operators, but it says nothing about result ordering, pagination, or limit behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is very short and front-loaded, with the most important domain restriction first and operator-specific ID guidance last. No sentence is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema and rich annotations reduce the need to explain returns and safety, but the description still leaves key parameter semantics unexplained and gives overbroad usage guidance. It is adequate for a simple search tool but not fully complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must carry parameter meaning. It gives partial query guidance (prefer names, IDs are operator-specific), but never explains the provider enum, limit default/max, or query syntax.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
"TRAINS ONLY" and "find operator-aware stations" identify a rail-specific station lookup, distinguishing it from generic location search and from journey/status siblings. The purpose is clear, though the verb is less explicit than an ideal "search train stations" statement.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
"Use for every request involving trains or rail" is overbroad and could misroute agents toward this tool for journey searches or train status. It provides no exclusion or explicit alternative routing, even though siblings like search_train_journeys and get_train_status exist.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
7 tool updates
v0.3.2- Added
get_station_board - Added
get_train_status - Added
list_train_providers - Changed
search_journeys4 fields changed- changed
Input schema / properties / destination / descriptionPrevious value: -"Exact location name or ID returned by search_locations"New value: +"Exact shared location name for aggregate searches, or a provider-specific ID when provider is set" - changed
Input schema / properties / limit / defaultPrevious value: -10New value: +50 - changed
Input schema / properties / origin / descriptionPrevious value: -"Exact location name or ID returned by search_locations"New value: +"Exact shared location name for aggregate searches, or a provider-specific ID when provider is set" - changed
Output schema / properties / errors / items / properties / code / enumPrevious value: -[ - "INVALID_INPUT", - "UNKNOWN_LOCATION", - "NO_JOURNEYS", - "PROVIDER_UNAVAILABLE", - "INCOMPATIBLE_RESPONSE", - "RATE_LIMITED" -]New value: +[ + "INVALID_INPUT", + "UNKNOWN_LOCATION", + "NO_JOURNEYS", + "PROVIDER_UNAVAILABLE", + "INCOMPATIBLE_RESPONSE", + "RATE_LIMITED", + "AMBIGUOUS_LOCATION", + "COVERAGE_UNAVAILABLE", + "QUOTE_UNAVAILABLE", + "LIVE_STATUS_UNAVAILABLE", + "TRAIN_NOT_FOUND" +]
- Changed
search_locations2 fields changed- changed
Input schema / properties / limit / defaultPrevious value: -10New value: +50 - changed
Output schema / properties / errors / items / properties / code / enumPrevious value: -[ - "INVALID_INPUT", - "UNKNOWN_LOCATION", - "NO_JOURNEYS", - "PROVIDER_UNAVAILABLE", - "INCOMPATIBLE_RESPONSE", - "RATE_LIMITED" -]New value: +[ + "INVALID_INPUT", + "UNKNOWN_LOCATION", + "NO_JOURNEYS", + "PROVIDER_UNAVAILABLE", + "INCOMPATIBLE_RESPONSE", + "RATE_LIMITED", + "AMBIGUOUS_LOCATION", + "COVERAGE_UNAVAILABLE", + "QUOTE_UNAVAILABLE", + "LIVE_STATUS_UNAVAILABLE", + "TRAIN_NOT_FOUND" +]
- Added
search_train_journeys - Added
search_train_locations
3 tool updates
v0.1.2- First observed
list_providers - First observed
search_journeys - First observed
search_locations
TDQS
Scored across 8 tools
Each tool has a clearly distinct purpose, and the descriptions explicitly separate BUS ONLY and TRAINS ONLY tools. The parallel bus/train pairs (search_journeys vs search_train_journeys, search_locations vs search_train_locations, list_providers vs list_train_providers) are unambiguous because each description names the required mode.
All names follow a readable snake_case verb_noun pattern. There is minor inconsistency in how the train mode is encoded: sometimes as a prefix (search_train_journeys, list_train_providers) and sometimes implicitly absent from the bus counterpart (search_journeys, list_providers).
Eight tools is well-scoped for a bus/train search server. Each tool covers a necessary operation: search, location lookup, provider listing, live status, and station boards, with bus/train variants only where needed.
The surface covers the core search lifecycle for both bus and train: journeys, locations, providers, train status, and station boards. Minor gaps remain, such as no explicit bus live-status tool or journey-detail retrieval, but the main workflows are supported.
Maintenance
Related MCP Connectors
AI marketplace — flights, tours, activities, transport & more via MCP. No auth required.
The Ferryhopper MCP server is a connector for LLMs and AI Agents in maritime travel that exposes ferry routes, schedules, and booking options. It enables AI assistants to search ports and connections across 33 countries and 190+ ferry operators, provide real-time ferry itineraries with indicative prices, and assist users with planning island-hopping or multi-leg journeys by processing natural language queries about ferry times, passenger counts, and travel durations.
Search and compare flight offers through a cache-aware Streamable HTTP MCP server for AI agents.
Live Google Maps business search, review, and photo data for AI agents over MCP.
Related MCP Servers
- AlicenseAqualityDmaintenanceReal-time train, bus, ferry and private transfer prices between 40+ Italian cities4MIT
- AlicenseNot gradedqualityCmaintenanceLive intercity bus-trip search across Ukraine and Europe — real-time prices, seats, carriers, cheapest-day-of-month calendar, and trip details with passenger discounts. Read-only, no API key; also available as a hosted remote endpoint at https://mcp.soloway.com.ua/mcp.MIT
- AlicenseNot gradedqualityBmaintenanceEnables searching for buses and trains, and when direct routes are unavailable, it provides the underlying data needed to assemble multi-leg itineraries with transfers.6 npmISC

virail-mcpofficial
AlicenseAqualityBmaintenanceEnables MCP-compatible AI agents to search live Virail transport connections across trains, buses, flights, ferries, and carpooling, returning real prices, schedules, and booking links.41MIT