India Hotels MCP
An MCP server for finding, comparing, and planning hotel stays across India, with live meta-search prices, travel times, and stay planning (read-only; no booking, payment, or cancellation).
Resolve place names or codes (railway stations, airports, bus stations, landmarks, localities) to coordinates, or coordinates to nearby transport points.
Search hotels near a place for given dates and party size, merging live prices from multiple meta-search sources, with sorting and filters (price, rating, distance, stars, drive time, radius).
Get all known rates for one hotel across booking sites (Booking.com, Agoda, Trip.com, MakeMyTrip, etc.) in INR with tax status, availability, and links.
Compare up to 10 hotels by drive or walk times to up to 6 labelled places, with totals and ranking.
Compute road distance and travel-time matrices between multiple origins and destinations.
Plan per-stop stays from arrival/departure times, ranking candidates by price plus transfer time, with check-in/check-out dates, leave-by times, warnings, and retiring-room options.
Find IRCTC railway retiring rooms near a station or place, with booking rules and portal link.
Inspect data sources: enabled status, official/unofficial, quotas, recent failures, limitations, and bundled dataset dates/licenses.
Supplies bundled OpenStreetMap data for hotel/guest house/hostel locations, railway stations with codes, and bus stations, enabling place resolution and unpriced listings.
Provides geocoding through the public Photon instance to resolve place names or codes to coordinates, with caching.
Provides live hotel prices in INR via trivago's official MCP, merging cheapest advertiser offers per hotel across Booking.com, Agoda, MakeMyTrip, and others.
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., "@India Hotels MCPfind hotels near New Delhi railway station for 2 adults, Dec 12-14"
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.
India Hotels MCP
Contributing · Disclaimer · Security · Changelog
An MCP server for finding, comparing and planning hotel stays across India around the places a trip actually revolves around: railway stations, airports, bus terminals, landmarks, localities and raw coordinates. It merges live prices from free meta-search sources, and adds road distance and drive time to arrival and departure points plus multi-stop stay planning.
It is standalone. Other servers (for example a train-timetable server) work with it through plain values
Claude passes between them: lat/lng, Indian Railways station codes, IATA airport codes and ISO-8601
datetimes.
Tools
Full input and output schemas for every tool: docs/tools.md (generated from the server's
tools/list; npm run docs:tools regenerates it and CI fails if it is out of date).
Tool | What it does |
| Name or code → coordinates (stations, airports, bus stations, landmarks, localities); or coordinates → nearest stations, airports and bus stations |
| Hotels in or near a place for given dates, merged across sources, with a section per source (its own name, rating, amenities, link and offers) and the cheapest live price in INR for the party ( |
| One hotel in full from every source, grouped by source: all offers per booking site (Booking.com, Agoda, Trip.com, MakeMyTrip, …) in INR with tax status, room, meals and links, plus each source's details (description, address, photos, amenities, review highlights, nearby places, house rules) |
| Up to 10 hotels × up to 6 labelled places: drive or walk times, totals, ranking |
| Origin × destination matrix of road km, free-flow and traffic-adjusted minutes |
| Per-stop stay planning from arrival/departure times: dates, candidates ranked by price + transfer time, leave-by times, warnings, retiring rooms |
| IRCTC railway retiring rooms at or near a station, with booking rules and portal link |
| Status, limitations and quotas of every source; bundled dataset dates and licences |
All tools are read-only; nothing books, pays or cancels.
Related MCP server: DIDA Hotel MCP
Data sources
Need | Source | Notes |
Live prices | Free, no key. Cheapest advertiser per hotel (Booking.com, Agoda, MakeMyTrip, …) in INR | |
Live prices + availability | Free, no key, true radius search. EUR, converted to INR | |
Live prices (unofficial) | SerpApi Google Hotels (scrapes Google; not a Google API) | Off by default; needs |
Live prices (unofficial) | Xotelo (derived from TripAdvisor meta-search) | Off by default; enabled only with |
FX | Frankfurter (ECB rates) | Daily reference rates |
Hotel locations | OpenStreetMap snapshot (bundled) | ~24k hotels/guest houses/hostels; no prices ( |
Stations, bus stations | OpenStreetMap snapshot (bundled) | ~9.2k stations with codes, ~5.3k bus stations |
Airports | OurAirports (bundled) | 151 Indian airports |
Retiring rooms | IRCTC public station list (bundled, refreshed by hand) | 356 stations; live availability needs a PNR on the IRCTC portal |
Geocoding | Public instances, cached; Nominatim limited to 1 req/s | |
Routing | FOSSGIS public instance by default, ~1 req/s, cached; self-hostable |
Third-party prices are meta-search prices: they can differ at checkout and may exclude GST
(includes_taxes: null means unknown). Every price carries its source, seller and fetched_at.
OSM routing has no traffic data, so drive times are multiplied by METRO_TRAFFIC_MULTIPLIER (default 1.5)
in the 8 largest metros and OTHER_TRAFFIC_MULTIPLIER (1.2) elsewhere; both raw and adjusted minutes are returned.
None of the free live-price sources has an SLA. Any source can be switched off with PROVIDERS_DISABLED,
and a failing source never fails a search: results come back from the others with sources_failed filled in.
Unofficial sources (Xotelo, and SerpApi's Google Hotels scraper) run only when ENABLE_UNOFFICIAL_SOURCES=true; check the terms that apply
to you first (see DISCLAIMER.md).
Run locally with Docker (recommended)
git clone https://github.com/shubhamyadav8901/hotels-mcp.git && cd hotels-mcp
cp .env.example .env # optional settings; see Configuration
docker compose up -d --build # http://localhost:3001/mcp
curl -s localhost:3001/healthz # {"status":"ok",...}Or run the prebuilt image (amd64 and arm64, published for each release) without cloning:
docker run -d --name india-hotels-mcp --restart unless-stopped \
-p 127.0.0.1:3001:3001 -e HTTP_USER_AGENT="india-hotels-mcp (+https://github.com/you)" \
ghcr.io/shubhamyadav8901/hotels-mcp:latestAdd --env-file .env to pass optional settings. The bundled datasets (data/*.json.gz) are in the repository
and the image; rebuilding them is optional (see "Rebuilding the bundled data"). Run docker compose up -d
after changing .env. The server listens on port 3001 (so it can run next to other local MCP servers on
3000), bound to 127.0.0.1 only.
Connect Claude Code:
claude mcp add --transport http india-hotels http://localhost:3001/mcpClaude Desktop and claude.ai connect to remote URLs only (Settings → Connectors); expose the server through a
tunnel and add its hostname to ALLOWED_HOSTS. The HTTP server has no authentication, so put your own access
control in front of any tunnel.
Inspect or test:
npx @modelcontextprotocol/inspector --cli http://localhost:3001/mcp --transport http --method tools/listWithout Docker
Requires Node 22+.
npm ci
npm run build
npm start -- --http # HTTP on http://localhost:3001/mcpOr let Claude Code start it over stdio:
claude mcp add --transport stdio --env HTTP_USER_AGENT="india-hotels-mcp (+https://github.com/you)" \
india-hotels -- node /path/to/hotels-mcp/dist/src/server.jsSelf-hosted routing (optional)
The public OSRM instance is for light use. To self-host:
scripts/osrm-setup.sh northern-zone # or "india": ~1.7 GB download, ~25 GB disk, 12+ GB Docker RAM
docker compose --profile osrm up -d
# then in .env: OSRM_URL=http://localhost:5001 OSRM_FOOT_URL=http://localhost:5002Configuration
See .env.example. Main settings: HTTP_USER_AGENT, SERPAPI_KEY (optional), ENABLE_UNOFFICIAL_SOURCES
(default false; true enables Xotelo), PROVIDERS_DISABLED, OSRM_URL, OSRM_FOOT_URL,
NOMINATIM_URL, PHOTON_URL, METRO_TRAFFIC_MULTIPLIER, OTHER_TRAFFIC_MULTIPLIER, TRAIN_BUFFER_MIN
(default 30), FLIGHT_BUFFER_MIN (default 120), DEFAULT_MIN_RATING_PCT (default 0 = off; default for the
min_rating_pct filter, which the agent can override per request), PROVIDER_DEADLINE_MS (default 20000; each source's time
limit per search), SERPAPI_MAX_PAGES (default 1) and STATE_DIR (default ~/.cache/india-hotels-mcp;
holds the SerpApi monthly search count so it survives restarts; docker compose keeps it in the hotels-state volume).
HTTP mode only: PORT (default 3001), HOST (bind address, default 127.0.0.1; 0.0.0.0 in the Docker
image) and ALLOWED_HOSTS (comma-separated extra hostnames accepted in the Host header, any port;
localhost, 127.0.0.1 and [::1] are always accepted). Under docker compose, PORT and HOST are fixed by
docker-compose.yml.
Searches are for the party given by adults (1–8) plus children_ages (up to 4 children, ages 0–17), at most 8
guests, in one room: every source is asked for that occupancy, and each quotes the offer it chooses (the room is the
source's choice, so check it on the booking site). Xotelo cannot price children, so it counts them as adults, and trivago prices every child as age 6 whatever ages are given. With sort=price, Google Hotels and
HotelsCasa return their cheapest results rather than their most relevant ones. min_stars (and, for Google,
max_price_inr) is also applied by those sources on their own price basis, before results are merged. A town or city name (place: "Jaipur") searches the town, not its main station.
Coverage: no source returns every hotel. trivago returns ~25 hotels around a point (no radius control), so wider
searches (over 3 km) query up to 13 points across the circle; HotelsCasa returns pages of 10 (up to 5 pages for
wide searches); Google Hotels returns ~20 per page (SERPAPI_MAX_PAGES, default 1, one SerpApi search each);
Xotelo prices only the 5 nearest of the hotels it lists. search_hotels returns a coverage entry per source
(hotels returned, priced, furthest km, and what limited it), so results are not mistaken for every hotel in the
radius.
Guest-rating floor: min_rating_pct (e.g. 60 = 6.0/10 = 3.0/5). Its default comes from the server setting
DEFAULT_MIN_RATING_PCT (0, i.e. off, unless you set it) and shows in the tool schema, so an agent can override
it per request ("at least 80%" → 80, "include unrated hotels" → 0). While it is on, hotels no source rates
are left out, and the notes say how many.
Each hotel comes with a section per source, holding that source's own listing and offers:
Source | What its section adds |
trivago | the cheapest booking site's price, its rating and reviews, top amenities, area, hotel page |
HotelsCasa | a live-checked price with the room name, meals, refundability and availability; property type; rating |
Google Hotels (SerpApi) | the lowest listed price, rating and reviews, property type, amenities, check-in and check-out times |
Xotelo (TripAdvisor) | a price per booking site (Agoda, Booking.com, Trip.com…) with tax, property type, usual price range (USD) |
OpenStreetMap | location and type only (no prices) |
search_hotels shows up to 3 offers per source; get_hotel_details shows them all, with each source's details
(description, address, phone, photos, distance to the centre, location rating, review scores, pros and cons, review
topics, nearby places, important info, missing amenities, badges). For HotelsCasa it calls its free hotel-details
tool; with google_prices: true it also fetches Google's page for the hotel (1 SerpApi search) for a price per
booking site, address and phone. When trivago's area search leaves
a hotel out, get_hotel_details asks trivago for it by name (accepted only if trivago returns the same hotel id); if
the hotel still can't be found live, the prices the search returned for the same stay and party are used.
Beds: no source can filter by bed type. Where the source names the room (HotelsCasa), each price carries it in
room (e.g. "Family Room", "Comfort Quadruple Room", or "Deluxe Double Room" with extra beds), so check it
before booking for four adults.
Example: the cheapest rooms in Jaipur for two adults and two children:
{
"place": "Jaipur",
"radius_km": 6,
"check_in": "2026-11-10",
"check_out": "2026-11-11",
"adults": 2,
"children_ages": [6, 9],
"sort": "price"
}Development
npm run typecheck && npm test && npm run format:check # gate before committing
npm run smoke # live acceptance checks (network, a few minutes)
npm run dev # watch mode, stdioUnit tests use synthetic fixtures only and never touch the network.
Rebuilding the bundled data
Run about once a month:
HTTP_USER_AGENT="india-hotels-mcp/0.1 (you@example.com)" npm run build:data
# add -- --with-irctc to refresh the IRCTC retiring-room list (a single manual request;
# IRCTC's terms forbid automated access, so never schedule it)
# the Xotelo location-key table is rebuilt separately with: npx tsx scripts/build-xotelo-keys.tsLimitations
Coverage of live prices is strong in metros and tourist towns and thin in small towns; use
include_unpricedto see OpenStreetMap-only listings there.Indian OTAs (MakeMyTrip, Goibibo) appear only when trivago lists them as the cheapest advertiser.
No public-transport routing; no live traffic.
IRCTC retiring-room availability and exact prices are not available without a PNR.
The SerpApi monthly quota counter is kept in memory and resets when the server restarts, and SerpApi's 50 searches/hour limit is not enforced locally.
Contributing
Bug reports, data corrections and new sources are welcome. Read CONTRIBUTING.md for the ground rules and checks, and the Code of Conduct. Report security issues privately as described in SECURITY.md.
Disclaimer
This is an independent project, not affiliated with trivago, HotelsCasa, TripAdvisor, Xotelo, Booking.com, Agoda, MakeMyTrip, IRCTC, Indian Railways, Google, SerpApi, OpenStreetMap or any other source. Prices are meta-search prices that may exclude GST; check with the seller before booking. Nothing is booked. See DISCLAIMER.md.
Licences
Code: Apache-2.0 (LICENSE). Bundled OpenStreetMap-derived data: ODbL 1.0, © OpenStreetMap contributors
(data/LICENSE, data/NOTICE). Tool responses that use OSM data carry the attribution. Other bundled and
run-time data sources are listed in NOTICE.
Available Tools
8 toolscompare_hotelsCompare hotels by travel timeARead-onlyIdempotent
Compares up to 10 hotels by travel time to a set of labelled places, such as tonight's arrival station, tomorrow's departure airport and attractions. Hotels are hotel_ids from search_hotels (which also supplies their cheapest price) or name + lat/lng. Places are lat+lng, station code, IATA code or place name. Returns, per hotel, the time and distance to every place, total minutes, the cheapest price from the search that found it (with its source, fetch time and dates) and a rank by total minutes. Does not fetch new prices; get_hotel_details does.
| Name | Required | Description | Default |
|---|---|---|---|
| mode | No | drive (car/taxi, with traffic allowance) or walk. | drive |
| hotels | Yes | Hotels to compare. | |
| places | Yes | Places to measure from each hotel; set label, e.g. 'arrive NDLS 20:10'. |
Output Schema
| Name | Required | Description |
|---|---|---|
| notes | Yes | How times are computed, caveats and attribution. |
| hotels | Yes | Hotels sorted by rank. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, so the bar is lower, and the description still adds real behavioral context: it characterises the returned data (per-place time and distance, total minutes, rank by total minutes), and flags that prices are stale 'from the search that found it' with source, fetch time and dates. No contradiction with the annotations.
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?
One dense but front-loaded block: purpose first, then input sourcing, then return shape, then the 'does not fetch prices' caveat. Every sentence carries information, though the output enumeration is long enough to push against the value of the output schema.
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 explained, yet the description still orients the agent on what comes back, where inputs originate, and the key limitation (no fresh pricing). For a 3-parameter read-only comparison tool, nothing an agent needs to invoke it correctly is missing.
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 100%, so the baseline is 3, but the description adds meaning the schema does not: which values count as a hotel (hotel_id OR name + lat/lng), the mutually exclusive place forms (lat+lng, station code, IATA, place name), and a label convention example ('arrive NDLS 20:10'). This helps an agent build correct payloads rather than merely restating fields.
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?
Opens with a specific verb and resource plus its scope limit ('Compares up to 10 hotels by travel time to a set of labelled places'). It distinguishes itself from siblings by naming where hotel_ids come from (search_hotels) and which tool handles the thing it does not do (get_hotel_details).
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 clear context for inputs (hotel_ids come from search_hotels, which also supplies price) and an explicit exclusion with the alternative named: 'Does not fetch new prices; get_hotel_details does.' It does not, however, say when to prefer this over travel_times or plan_stays.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
find_retiring_roomsFind IRCTC railway retiring roomsARead-onlyIdempotent
Lists Indian Railways stations that have IRCTC retiring rooms (rooms and dormitories inside the station for ticketed passengers), at a station code or within a radius of a place. Returns station code, name, operator and distance, the booking rules, indicative price ranges and the IRCTC booking portal link. Live availability and exact prices are not available here: they need a Confirmed or RAC PNR on the IRCTC portal.
| Name | Required | Description | Default |
|---|---|---|---|
| lat | No | Latitude (India). Use with lng. | |
| lng | No | Longitude (India). Use with lat. | |
| iata | No | Indian airport IATA code, e.g. DEL. | |
| place | No | Place name, e.g. 'Taj Mahal' or 'Paharganj, Delhi'; resolved to its best match. | |
| radius_km | No | Search radius when not giving a station_code. | |
| station_code | No | Indian Railways station code, e.g. NDLS. |
Output Schema
| Name | Required | Description |
|---|---|---|
| notes | Yes | Data source and search caveats. |
| rules | Yes | IRCTC booking rules for retiring rooms. |
| stations | Yes | Stations with IRCTC retiring rooms, nearest first. |
| booking_url | Yes | IRCTC retiring-room booking portal. |
| indicative_prices | Yes | Typical price ranges from secondary sources; not live. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint and openWorldHint, so the safety profile is covered. The description adds genuine behavioral context beyond that: what the records contain (booking rules, indicative price ranges, portal link) and the important limitation that availability/prices are not live and depend on a Confirmed or RAC PNR.
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 sentences, front-loaded with the core purpose, then inputs, then the binding caveat. Very little waste, though the parenthetical definition of retiring rooms is slightly verbose for an agent audience.
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 enumerated, yet the description still summarizes them usefully. With annotations covering the read-only profile and the schema covering all params, nothing needed to invoke the tool correctly is missing; the PNR/portal caveat closes the main expectation 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 100%, so all six parameters (lat/lng, iata, place, radius_km, station_code) are already documented with examples and constraints. The description only restates the station-code and radius-of-a-place modes without adding format or precedence guidance (e.g. what happens if both place and station_code are supplied). Baseline 3.
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 states a specific verb (Lists) and a specific resource (Indian Railways stations with IRCTC retiring rooms), and even defines the domain term in parentheses. It is clearly distinct from siblings such as search_hotels and get_hotel_details, which cover commercial lodging.
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 spells out the two accepted lookup modes (a station code, or a radius around a place) and sets an explicit boundary: live availability and exact prices are 'not available here' and require a PNR on the IRCTC portal. That is clear when-not guidance, though it does not name a sibling tool as the alternative.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_data_sourcesData sources and statusARead-onlyIdempotent
Lists every data source this server uses: hotel price sources, hotel location data, geocoding, routing and bundled datasets. For each it gives whether it is enabled, whether it is official or an unofficial third-party endpoint, recent success/failure, remaining quota and known limitations. Bundled datasets include their build date and licence. Does not fetch any hotel data.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| providers | Yes | Every data source and its current status. |
| snapshots | Yes | Bundled datasets, with build date and licence. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true and destructiveHint=false, so safety is covered; the description goes further by disclosing what each entry contains (enabled flag, official vs unofficial third-party, recent success/failure, remaining quota, known limitations, build date and licence) and explicitly denies fetching hotel data. It stops short of describing ordering or freshness of the reported status, but adds real context beyond the annotations.
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 sentences, front-loaded with the core action, and the final boundary sentence earns its place by preventing an agent from expecting hotel payloads. The middle sentence is a dense comma list of returned fields, which is slightly heavy but still scannable.
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, rich annotations and an output schema present, the description only needs to convey purpose, scope and the negative boundary — all of which it does. Nothing an agent needs in order to call it correctly is missing.
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 the baseline of 4 applies and there is nothing for the description to disambiguate. It correctly avoids inventing parameter-like filtering language.
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 every data source this server uses') and enumerates the scope: price sources, location data, geocoding, routing and bundled datasets. None of the siblings (search_hotels, resolve_place, travel_times, etc.) do anything similar, so the agent can separate this metadata/status tool from the hotel-lookup tools at a glance.
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 implied rather than stated: the enumeration of status/quota/limitation fields suggests it is the diagnostic tool to call before or after a hotel query fails. It closes one boundary explicitly ('Does not fetch any hotel data'), but never says when to prefer it over the sibling tools or what condition should trigger it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_hotel_detailsOne hotel's prices and details from every sourceARead-onlyIdempotent
Everything the sources say about one hotel for the given dates, grouped by source: each source's own name, rating, property type, amenities and link; all its offers (booking site such as Booking.com, Agoda or MakeMyTrip; price in INR and the original currency; taxes; refundability; availability; room and meals as the source names them; link), cheapest first; and its details (description, address, phone, website, photos, distance to the centre, location rating, review scores, pros and cons, review topics, nearby places, important info such as ID rules, amenities it lacks, badges). HotelsCasa's hotel page is fetched for every call; google_prices also fetches Google's page (1 SerpApi search from a monthly quota). The hotel is a hotel_id from search_hotels or plan_stays, or a name with lat/lng. Does not book.
| Name | Required | Description | Default |
|---|---|---|---|
| lat | No | Hotel latitude, when not giving hotel_id. | |
| lng | No | Hotel longitude, when not giving hotel_id. | |
| name | No | Hotel name, when not giving hotel_id. | |
| adults | No | Adults (18+) sharing the one room searched for. | |
| check_in | Yes | Check-in date, YYYY-MM-DD (IST). | |
| hotel_id | No | hotel_id (or any of its also_ids) from search_hotels or plan_stays. | |
| check_out | Yes | Check-out date, YYYY-MM-DD. | |
| children_ages | No | Ages (0–17) of children sharing that room, one entry per child, e.g. [6, 9]; empty for adults only. | |
| google_prices | No | Also fetch Google's page for the hotel (1 SerpApi search from a monthly quota, when enabled): a price per booking site, address, phone and website. |
Output Schema
| Name | Required | Description |
|---|---|---|
| hotel | Yes | The hotel the prices are for, as the sources list it. |
| notes | Yes | Caveats about the prices. |
| sources | Yes | Each source's own listing of the hotel (name, rating, details, link) with all its offers, cheapest source first. |
| check_in | Yes | Check-in date, YYYY-MM-DD. |
| check_out | Yes | Check-out date, YYYY-MM-DD. |
| sources_ok | Yes | Ids of the sources that answered the re-search near the hotel. |
| cheapest_inr | Yes | Lowest bookable per_night_inr across all sources (null if none in INR). |
| priciest_inr | Yes | Highest per_night_inr across all sources (null if none in INR). |
| sources_failed | Yes | Sources or lookups that did not answer, and why. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnlyHint, idempotentHint, destructiveHint=false), so the bar is lower, and the description still adds real cost/side-effect context: HotelsCasa's page is fetched on every call, and google_prices spends 1 SerpApi search from a monthly quota. The 'Does not book' line is redundant with readOnlyHint but harmless.
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 scoping facts (dates, source grouping, quota, identifier source, no booking) are front-loaded, but the long mid-sentence enumeration of every offer and detail field is a run-on list that duplicates the output schema. Much of that bulk does not earn its place.
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?
Given a 9-parameter tool with an output schema, the definition covers inputs, identifier provenance, quota cost, and the read-only non-booking nature, so an agent has what it needs to call correctly. The return-field enumeration is redundant with the output schema rather than filling a genuine 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 coverage is 100%, so all nine parameters including the hotel_id/name+lat/lng alternative and the quota note on google_prices are already documented in the schema. The description corroborates but adds no syntax, format, or default detail beyond it, so baseline 3 applies.
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 names a specific verb and resource — everything the sources say about one hotel for given dates, grouped by source with offers and details — and the 'one hotel' scope cleanly separates it from search_hotels and compare_hotels. An agent can identify the tool without opening the 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?
It states where the identifier comes from ('a hotel_id from search_hotels or plan_stays, or a name with lat/lng') and sets an explicit exclusion ('Does not book'), which is clear context. It stops short of naming compare_hotels as the alternative for multi-hotel comparison, so it is clear but not fully routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
plan_staysPlan hotel stays for an itineraryARead-onlyIdempotent
Plans where to stay for each stop of a trip in India. Each stay is an arrival (place + time) and the next departure (place + time); places are lat+lng, station code, IATA code or place name, so train and flight times from any source can be passed in. For every stay it works out check-in/check-out dates (early-morning arrivals book the previous night), searches hotels near the arrival point and, if elsewhere, the departure point, and ranks them by nightly price plus drive time from arrival and to departure (valued at value_of_time_inr_per_hour). Returns candidates with leave-by times that include a check-in buffer for trains or flights, IRCTC retiring-room options for 3–48 h stays at stations, and warnings for late arrivals, early departures and same-day stays. Does not book.
| Name | Required | Description | Default |
|---|---|---|---|
| stays | Yes | One entry per stop, in trip order. | |
| adults | No | Adults (18+) sharing the one room searched for. | |
| min_stars | No | Minimum hotel class (official stars). | |
| radius_km | No | Hotel search radius around each point. | |
| candidates | No | Hotels to return per stay. | |
| children_ages | No | Ages (0–17) of children sharing that room, one entry per child, e.g. [6, 9]; empty for adults only. | |
| max_price_inr | No | Maximum nightly price in INR. | |
| min_rating_pct | No | Minimum guest rating in percent, e.g. 60 = 6.0/10 = 3.0/5. Default 0 (server setting); 0 turns the filter off. While on, hotels with no guest rating are left out. | |
| value_of_time_inr_per_hour | No | How much an hour of transfer time is worth, to trade travel time against price (0 = price only). |
Output Schema
| Name | Required | Description |
|---|---|---|
| notes | Yes | Buffers used, price and routing caveats, and attribution. |
| stays | Yes | One plan per requested stay, in trip order. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive, openWorld), and the description still adds substantial non-obvious behavior: early-morning arrivals book the previous night, hotels are searched near arrival and if elsewhere also the departure point, ranking blends nightly price with drive time valued at value_of_time_inr_per_hour, leave-by times include a check-in buffer, retiring rooms are offered for 3–48 h stays, and late/early/same-day cases emit warnings.
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?
Purpose is front-loaded in the first sentence and every sentence carries information about distinct behavior; nothing is redundant filler. The third sentence is a long multi-clause run-on bundling check-in logic, search scope, ranking and outputs, which makes it harder to scan.
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?
For a 9-parameter orchestration tool with an output schema, the description covers scope, computation logic, ranking, warnings and the non-booking boundary, so an agent can invoke it correctly. The only real omission is routing guidance against the six sibling tools that overlap it partially (search_hotels, find_retiring_rooms, travel_times).
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 100%, so the baseline is 3 and the schema already documents the point formats, adults/children, radius, candidates and filters. The description adds value by explaining how value_of_time_inr_per_hour is actually applied (drive time from arrival and to departure traded against nightly price), which the schema only states abstractly.
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 ('Plans where to stay for each stop of a trip in India') and immediately defines the unit of work: one stay = arrival point/time + next departure point/time. The itinerary-level, multi-stop scope makes it distinguishable from the single-search siblings like search_hotels.
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?
Clear context for when the tool applies (planning lodging across all stops of a trip, with train/flight times passed in from any source) and an explicit exclusion ('Does not book'). It never names an alternative, though — nothing tells the agent to fall back to search_hotels for a single stay or find_retiring_rooms for a lone retiring-room query.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
resolve_placeResolve a place in IndiaARead-onlyIdempotent
Turns a name or code into coordinates, or coordinates into nearby transport points. With query: matches railway station codes and names, airport IATA codes and names, bus stations, and landmarks or localities via OpenStreetMap geocoding, returning ranked matches with kind, code and lat/lng. With lat/lng: returns the nearest railway stations (within 10 km), airports with IATA codes (within 60 km) and bus stations (within 5 km), with straight-line distances. Does not search hotels.
| Name | Required | Description | Default |
|---|---|---|---|
| lat | No | Latitude, for nearby transport points. | |
| lng | No | Longitude, for nearby transport points. | |
| kind | No | Only return this kind of place. | |
| limit | No | Maximum matches for a query. | |
| query | No | Name or code, e.g. 'Howrah', 'BLR', 'Hawa Mahal'. |
Output Schema
| Name | Required | Description |
|---|---|---|
| notes | Yes | Caveats, unavailable geocoders and attribution. |
| nearby | Yes | Transport points near the given lat/lng, nearest first (null when query was given). |
| matches | Yes | Places matching query, best first (empty when lat/lng was given). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, openWorld, idempotent, and non-destructive behavior. Beyond that, the description adds concrete behavioral details: ranked matches with kind/code/lat/lng, radius limits of 10 km for stations, 60 km for airports, 5 km for bus stations, straight-line distances, and the explicit exclusion of hotels.
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 front-loaded, dense, and free of filler. It covers the dual-mode behavior and the key exclusion in three efficient sentences.
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?
For a five-parameter, dual-mode geospatial resolution tool with annotations and an output schema already present, the description provides enough context to call the tool correctly. It explains both input modes, the kinds of results, distance limits, and a notable exclusion.
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 100%, so the baseline is 3. The description adds meaningful semantics by explaining what `query` matches (railway station codes and names, airport IATA codes and names, bus stations, landmarks/localities via OpenStreetMap) and what lat/lng returns, going beyond the schema's brief parameter descriptions.
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 gives a specific verb+resource and clearly describes the two operating modes: name/code into coordinates, or coordinates into nearby transport points. It also explicitly distinguishes itself from hotel search with 'Does not search hotels,' which helps against siblings like search_hotels.
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 clearly states when to use each mode: `query` for station/airport/bus/landmark lookup and lat/lng for nearby transport discovery, with specific distance thresholds. It does not name a specific sibling alternative for non-hotel place resolution, but the mode selection guidance is explicit and useful.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_hotelsSearch hotels near a placeARead-onlyIdempotent
Finds hotels around a place in India for given dates, with live prices from several sources (trivago, HotelsCasa, Google Hotels via SerpApi, Xotelo/TripAdvisor) merged per hotel. The place is lat+lng, an Indian Railways station code, an airport IATA code, or a place name. Each hotel has its distance, stars, best-supported guest rating and cheapest price in INR, and a section per source with that source's own name, rating, property type, amenities, link and offers (booking site, price, taxes, refundability, room and meals as the source names them). Every source is asked for one room for the party, and each quotes the offer it chooses. With max_drive_minutes, keeps only hotels within that drive time (OpenStreetMap routing with a traffic allowance) and adds drive_minutes. Results are paginated. Every offer per source is in get_hotel_details; times to other places are in compare_hotels. coverage reports what each source returned and what limited it (sources return limited pages, so the list is not exhaustive). Does not book.
| Name | Required | Description | Default |
|---|---|---|---|
| lat | No | Latitude (India). Use with lng. | |
| lng | No | Longitude (India). Use with lat. | |
| iata | No | Indian airport IATA code, e.g. DEL. | |
| sort | No | Sort order; drive_time needs max_drive_minutes. | distance |
| limit | No | Hotels per page. | |
| place | No | Place name, e.g. 'Taj Mahal' or 'Paharganj, Delhi'; resolved to its best match. | |
| adults | No | Adults (18+) sharing the one room searched for. | |
| offset | No | Number of hotels to skip, for paging. | |
| check_in | Yes | Check-in date, YYYY-MM-DD (IST). | |
| check_out | Yes | Check-out date, YYYY-MM-DD, after check_in. | |
| min_stars | No | Minimum hotel class (official stars). | |
| radius_km | No | Search radius in km. | |
| station_code | No | Indian Railways station code, e.g. NDLS. | |
| children_ages | No | Ages (0–17) of children sharing that room, one entry per child, e.g. [6, 9]; empty for adults only. | |
| max_price_inr | No | Only hotels with a known nightly price at or below this, in INR. | |
| min_rating_pct | No | Minimum guest rating in percent, e.g. 60 = 6.0/10 = 3.0/5. Default 0 (server setting); 0 turns the filter off. While on, hotels with no guest rating are left out. | |
| include_unpriced | No | Also list hotels with no live price (OpenStreetMap listings), for places with thin price coverage. | |
| max_drive_minutes | No | Only hotels within this many minutes' drive of the place (traffic-adjusted). |
Output Schema
| Name | Required | Description |
|---|---|---|
| notes | Yes | Caveats about the results, sources and attribution. |
| query | Yes | The search as run. |
| total | Yes | Number of hotels matching all filters, across all pages. |
| anchor | Yes | The resolved search place. |
| hotels | Yes | This page of hotels, in the requested sort order. |
| showing | Yes | Which slice of the results this page holds, e.g. 'Showing 1–10 of 42'. |
| coverage | Yes | What each source returned within the radius and what limited it; sources return limited pages. |
| sources_ok | Yes | Ids of the sources that answered. |
| sources_failed | Yes | Sources that did not answer, and why. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover safety (readOnly/idempotent/openWorld/non-destructive), and the description adds genuinely non-obvious behavior: per-hotel merging across sources, one room searched for the whole party, drive-time filtering via OpenStreetMap routing with a traffic allowance, pagination, and the key caveat that results are not exhaustive because sources return limited pages. It omits auth/rate-limit or latency expectations, so it stops short of 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?
Front-loaded with what the tool does before constraints and routing, and every clause carries information. It is long (roughly eight sentences) and the sentence enumerating per-hotel fields largely restates the output schema, which is the only real waste.
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?
For an 18-parameter, multi-source, paginated search with an output schema present, the description covers the aggregation model, sorting/filtering caveats, and non-exhaustiveness. It need not repeat return fields, and its doing so is harmless rather than required; nothing an agent needs to call it correctly appears missing.
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 100%, so baseline is 3. The description adds interpretation the schema cannot: that adults/children_ages describe a single shared room, that each source quotes the offer it chooses, that max_drive_minutes injects a drive_minutes field, and that coverage explains which source limited the result. That is meaningful semantic value beyond per-field docs.
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?
Starts with a specific verb+resource+scope ('Finds hotels around a place in India for given dates') and immediately states the value proposition: live prices merged per hotel from trivago, HotelsCasa, Google Hotels/SerpApi, Xotelo/TripAdvisor. It also distinguishes itself from siblings by naming where the detail lives (get_hotel_details) and what it does not do ('Does not book').
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?
Explicitly routes the agent: full per-source offers go to get_hotel_details, travel times to compare_hotels, and it states the tool never books. However, it gives no positioning against other siblings such as plan_stays, find_retiring_rooms, or resolve_place, and offers no explicit 'when not to use this' beyond the booking exclusion.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
travel_timesTravel times between placesARead-onlyIdempotent
Computes road distance and travel time from each origin to each destination in India (a matrix), by car or on foot. Each place is lat+lng, a railway station code, an airport IATA code or a place name. Returns straight-line km, road km, free-flow minutes and traffic-adjusted minutes per pair, with a warning when a point is far from any road. Does not cover public transport or flights.
| Name | Required | Description | Default |
|---|---|---|---|
| mode | No | drive (car/taxi, with traffic allowance) or walk. | drive |
| origins | Yes | Starting places. | |
| destinations | Yes | Destination places. |
Output Schema
| Name | Required | Description |
|---|---|---|
| legs | Yes | One leg per origin–destination pair, origin by origin. |
| notes | Yes | How times are computed, and attribution. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, non-destructive and open-world behavior, so the safety profile is covered. The description adds genuinely useful behavior beyond that: the exact per-pair outputs (straight-line km, road km, free-flow and traffic-adjusted minutes) and the warning emitted when a point is far from any road, plus the fact that place names are resolved to a 'best match'.
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 tight sentences: purpose and scope first, accepted input identifiers second, returned values plus failure warning third. No filler, no repetition of the title, and the most decision-relevant constraint (India, road/walk 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?
An output schema exists, so return values did not need to be spelled out, yet the description helpfully names the key per-pair metrics and the far-from-road warning. Combined with the schema's bounds (max 10 origins, 25 destinations, India lat/lng limits) and the annotations' read-only profile, an agent has everything needed to call this correctly.
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 100%, so the baseline is 3 and the schema already documents every parameter including the four point identifier kinds and the drive/walk enum. The description adds meaning on top by summarizing that each place may be lat+lng, a station code, an IATA code or a place name, and by noting that names are resolved to their best match rather than exact-matched.
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 ('Computes road distance and travel time from each origin to each destination in India (a matrix)') plus the supported modes, so the agent knows exactly what operation this is. It also delineates scope by naming what it does not cover (public transport, flights), which no sibling does, cleanly separating it from the hotel/place siblings.
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 description establishes clear context for use: India-only, drive-vs-walk mode, and the matrix (each-to-each) semantics, plus an explicit exclusion of public transport and flights. It stops short of naming an alternative tool (e.g. resolve_place for ambiguous place resolution), so it is strong but not fully routing-oriented.
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.
9 tool updates
v0.3.0- Changed
compare_hotels19 fields changed- added
Output schema / properties / hotels / descriptionAdded value: +"Hotels sorted by rank." - changed
Output schema / properties / hotels / items / properties / cheapest / anyOfPrevious value: -[ - { - "additionalProperties": false, - "properties": { - "check_in": { - "type": "string" - }, - "check_out": { - "type": "string" - }, - "fetched_at": { - "type": "string" - }, - "per_night_inr": { - "type": [ - "number", - "null" - ] - }, - "seller": { - "type": "string" - }, - "source": { - "type": "string" - } - }, - "required": [ - "per_night_inr", - "seller", - "source", - "fetched_at", - "check_in", - "check_out" - ], - "type": "object" - }, - { - "type": "null" - } -]New value: +[ + { + "additionalProperties": false, + "properties": { + "adults": { + "description": "Adults in that search.", + "type": "number" + }, + "check_in": { + "description": "Check-in date of that search, YYYY-MM-DD.", + "type": "string" + }, + "check_out": { + "description": "Check-out date of that search, YYYY-MM-DD.", + "type": "string" + }, + "children_ages": { + "description": "Ages of children in that search.", + "items": { + "type": "number" + }, + "type": "array" + }, + "fetched_at": { + "description": "ISO time the source returned this price.", + "type": "string" + }, + "per_night_inr": { + "description": "Per-night price converted to INR (null if no exchange rate).", + "type": [ + "number", + "null" + ] + }, + "seller": { + "description": "Booking site the price is from; the source id when the source names no seller.", + "type": "string" + }, + "source": { + "description": "Id of the data source that returned the price.", + "type": "string" + } + }, + "required": [ + "per_night_inr", + "seller", + "source", + "fetched_at", + "check_in", + "check_out", + "adults", + "children_ages" + ], + "type": "object" + }, + { + "type": "null" + } +] - changed
Output schema / properties / hotels / items / properties / cheapest / descriptionPrevious value: -"Cheapest price from the search that returned this hotel, for that search's dates."New value: +"Lowest per-night INR price across sources from that search, for its dates and party." - added
Output schema / properties / hotels / items / properties / hotel_id / descriptionAdded value: +"hotel_id as given (null when the hotel was given by lat/lng)." - added
Output schema / properties / hotels / items / properties / lat / descriptionAdded value: +"Hotel latitude." - added
Output schema / properties / hotels / items / properties / legs / descriptionAdded value: +"Travel from this hotel to each place, in the order given." - added
Output schema / properties / hotels / items / properties / legs / items / properties / from / descriptionAdded value: +"Label of the origin." - added
Output schema / properties / hotels / items / properties / legs / items / properties / minutes / descriptionAdded value: +"Travel time after the traffic multiplier, minutes; equals minutes_raw for walking (null when no route)." - added
Output schema / properties / hotels / items / properties / legs / items / properties / minutes_raw / descriptionAdded value: +"Free-flow travel time from the router, minutes (null when no route)." - added
Output schema / properties / hotels / items / properties / legs / items / properties / road_km / descriptionAdded value: +"Road distance along the route, km (null when no route was found)." - added
Output schema / properties / hotels / items / properties / legs / items / properties / straight_km / descriptionAdded value: +"Straight-line distance, km." - added
Output schema / properties / hotels / items / properties / legs / items / properties / to / descriptionAdded value: +"Label of the destination." - added
Output schema / properties / hotels / items / properties / legs / items / properties / traffic_multiplier / descriptionAdded value: +"Factor applied to free-flow drive time for traffic, higher in metro areas; 1 for walking." - added
Output schema / properties / hotels / items / properties / legs / items / properties / warning / descriptionAdded value: +"Set when no route was found or a point is over 500 m from the nearest road." - added
Output schema / properties / hotels / items / properties / lng / descriptionAdded value: +"Hotel longitude." - added
Output schema / properties / hotels / items / properties / name / descriptionAdded value: +"Hotel name (the coordinates when no name was given)." - added
Output schema / properties / hotels / items / properties / rank / descriptionAdded value: +"Position by total_minutes, then per_night_inr; 1 is best." - added
Output schema / properties / hotels / items / properties / total_minutes / descriptionAdded value: +"Sum of minutes over all legs (null when any leg has no route)." - added
Output schema / properties / notes / descriptionAdded value: +"How times are computed, caveats and attribution."
- Changed
find_retiring_rooms11 fields changed- added
Output schema / properties / booking_url / descriptionAdded value: +"IRCTC retiring-room booking portal." - added
Output schema / properties / indicative_prices / descriptionAdded value: +"Typical price ranges from secondary sources; not live." - added
Output schema / properties / notes / descriptionAdded value: +"Data source and search caveats." - added
Output schema / properties / rules / descriptionAdded value: +"IRCTC booking rules for retiring rooms." - added
Output schema / properties / stations / descriptionAdded value: +"Stations with IRCTC retiring rooms, nearest first." - added
Output schema / properties / stations / items / properties / distance_km / descriptionAdded value: +"Straight-line distance from the search place, km; 0 for the station itself." - added
Output schema / properties / stations / items / properties / lat / descriptionAdded value: +"Station latitude (null if unknown)." - added
Output schema / properties / stations / items / properties / lng / descriptionAdded value: +"Station longitude (null if unknown)." - added
Output schema / properties / stations / items / properties / managed_by / descriptionAdded value: +"Who runs the retiring rooms, as IRCTC lists it." - added
Output schema / properties / stations / items / properties / station_code / descriptionAdded value: +"Station code." - added
Output schema / properties / stations / items / properties / station_name / descriptionAdded value: +"Station name."
- Changed
get_data_sources20 fields changed- added
Output schema / properties / providers / descriptionAdded value: +"Every data source and its current status." - added
Output schema / properties / providers / items / properties / disabled_reason / descriptionAdded value: +"Why the source is disabled (null when enabled)." - added
Output schema / properties / providers / items / properties / enabled / descriptionAdded value: +"Whether the source is in use." - added
Output schema / properties / providers / items / properties / id / descriptionAdded value: +"Source id, as used in source fields elsewhere." - added
Output schema / properties / providers / items / properties / kind / descriptionAdded value: +"What the source provides: hotel-prices, hotel-locations, geocoding, routing, fx or dataset." - changed
Output schema / properties / providers / items / properties / last_error / anyOfPrevious value: -[ - { - "additionalProperties": false, - "properties": { - "at": { - "type": "string" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - } - }, - "required": [ - "at", - "code", - "message" - ], - "type": "object" - }, - { - "type": "null" - } -]New value: +[ + { + "additionalProperties": false, + "properties": { + "at": { + "description": "ISO time of the error.", + "type": "string" + }, + "code": { + "description": "Error code, e.g. UPSTREAM_UNAVAILABLE.", + "type": "string" + }, + "message": { + "description": "What went wrong.", + "type": "string" + } + }, + "required": [ + "at", + "code", + "message" + ], + "type": "object" + }, + { + "type": "null" + } +] - added
Output schema / properties / providers / items / properties / last_error / descriptionAdded value: +"The most recent failed call since the server started (null if none)." - added
Output schema / properties / providers / items / properties / last_success_at / descriptionAdded value: +"ISO time of the last successful call since the server started (null if none)." - added
Output schema / properties / providers / items / properties / limitations / descriptionAdded value: +"Known limitations of the source." - added
Output schema / properties / providers / items / properties / name / descriptionAdded value: +"Human-readable source name." - added
Output schema / properties / providers / items / properties / needsKey / descriptionAdded value: +"Whether the source needs an API key." - added
Output schema / properties / providers / items / properties / official / descriptionAdded value: +"true for an official API, false for an unofficial third-party endpoint with no SLA." - added
Output schema / properties / providers / items / properties / quota_remaining / descriptionAdded value: +"Calls left in the source's current quota window (null when the source has no tracked quota)." - added
Output schema / properties / snapshots / descriptionAdded value: +"Bundled datasets, with build date and licence." - added
Output schema / properties / snapshots / items / properties / built_at / descriptionAdded value: +"When the dataset was built (null if unknown)." - added
Output schema / properties / snapshots / items / properties / description / descriptionAdded value: +"What the dataset contains." - added
Output schema / properties / snapshots / items / properties / id / descriptionAdded value: +"Dataset id." - added
Output schema / properties / snapshots / items / properties / licence / descriptionAdded value: +"Licence of the data." - added
Output schema / properties / snapshots / items / properties / rows / descriptionAdded value: +"Number of records in the dataset." - added
Output schema / properties / snapshots / items / properties / source / descriptionAdded value: +"Where the data comes from."
- Added
get_hotel_details - Removed
get_hotel_rates - Changed
plan_stays49 fields changed- changed
Input schema / properties / adults / descriptionPrevious value: -"Guests in the room; searches are for one room."New value: +"Adults (18+) sharing the one room searched for." - added
Input schema / properties / children_agesAdded value: +{ + "default": [], + "description": "Ages (0–17) of children sharing that room, one entry per child, e.g. [6, 9]; empty for adults only.", + "items": { + "maximum": 17, + "minimum": 0, + "type": "integer" + }, + "maxItems": 4, + "type": "array" +} - added
Input schema / properties / min_rating_pctAdded value: +{ + "default": 0, + "description": "Minimum guest rating in percent, e.g. 60 = 6.0/10 = 3.0/5. Default 0 (server setting); 0 turns the filter off. While on, hotels with no guest rating are left out.", + "maximum": 100, + "minimum": 0, + "type": "number" +} - added
Input schema / properties / min_stars / descriptionAdded value: +"Minimum hotel class (official stars)." - added
Output schema / properties / notes / descriptionAdded value: +"Buffers used, price and routing caveats, and attribution." - added
Output schema / properties / stays / descriptionAdded value: +"One plan per requested stay, in trip order." - added
Output schema / properties / stays / items / properties / arrive / descriptionAdded value: +"Where and when the traveller arrives." - added
Output schema / properties / stays / items / properties / arrive / properties / at / descriptionAdded value: +"Arrival or departure time in IST, ISO-8601 with +05:30." - added
Output schema / properties / stays / items / properties / arrive / properties / code / descriptionAdded value: +"Railway station code or airport IATA code (null when the place has none)." - added
Output schema / properties / stays / items / properties / arrive / properties / kind / descriptionAdded value: +"Kind of place: station, airport, bus_station, landmark, locality or point (raw coordinates)." - added
Output schema / properties / stays / items / properties / arrive / properties / label / descriptionAdded value: +"Label of the point: as given, else its code or name." - added
Output schema / properties / stays / items / properties / arrive / properties / name / descriptionAdded value: +"Resolved place name." - added
Output schema / properties / stays / items / properties / candidates / descriptionAdded value: +"Hotels for this stay, lowest score_inr first, then cheapest." - added
Output schema / properties / stays / items / properties / candidates / items / properties / hotel_id / descriptionAdded value: +"Hotel id as source:source_id of the first source that listed it." - added
Output schema / properties / stays / items / properties / candidates / items / properties / lat / descriptionAdded value: +"Hotel latitude." - added
Output schema / properties / stays / items / properties / candidates / items / properties / leave_by / descriptionAdded value: +"Latest time to leave the hotel, IST ISO-8601: departure minus drive time and the train or flight buffer." - added
Output schema / properties / stays / items / properties / candidates / items / properties / lng / descriptionAdded value: +"Hotel longitude." - added
Output schema / properties / stays / items / properties / candidates / items / properties / minutes_from_arrival / descriptionAdded value: +"Traffic-adjusted drive from the arrival point, minutes (null when not routed)." - added
Output schema / properties / stays / items / properties / candidates / items / properties / minutes_to_departure / descriptionAdded value: +"Traffic-adjusted drive to the departure point, minutes (null when not routed)." - added
Output schema / properties / stays / items / properties / candidates / items / properties / name / descriptionAdded value: +"Hotel name." - added
Output schema / properties / stays / items / properties / candidates / items / properties / per_night_inr / descriptionAdded value: +"Lowest per-night INR price across sources." - added
Output schema / properties / stays / items / properties / candidates / items / properties / rating_10 / descriptionAdded value: +"Guest review score on a 0–10 scale (null if unrated)." - added
Output schema / properties / stays / items / properties / candidates / items / properties / score_inr / descriptionAdded value: +"per_night_inr × nights plus both drives valued at value_of_time_inr_per_hour, INR; lower is better." - added
Output schema / properties / stays / items / properties / candidates / items / properties / seller / descriptionAdded value: +"Booking site of per_night_inr; the source id when the source names no seller." - added
Output schema / properties / stays / items / properties / candidates / items / properties / stars / descriptionAdded value: +"Official hotel class, 1–5 stars (null if unknown)." - added
Output schema / properties / stays / items / properties / check_in / descriptionAdded value: +"Hotel check-in date, YYYY-MM-DD; the previous day for arrivals before 06:00 IST." - added
Output schema / properties / stays / items / properties / check_out / descriptionAdded value: +"Hotel check-out date, YYYY-MM-DD." - added
Output schema / properties / stays / items / properties / depart / descriptionAdded value: +"Where and when the traveller leaves." - added
Output schema / properties / stays / items / properties / depart / properties / at / descriptionAdded value: +"Arrival or departure time in IST, ISO-8601 with +05:30." - added
Output schema / properties / stays / items / properties / depart / properties / code / descriptionAdded value: +"Railway station code or airport IATA code (null when the place has none)." - added
Output schema / properties / stays / items / properties / depart / properties / kind / descriptionAdded value: +"Kind of place: station, airport, bus_station, landmark, locality or point (raw coordinates)." - added
Output schema / properties / stays / items / properties / depart / properties / label / descriptionAdded value: +"Label of the point: as given, else its code or name." - added
Output schema / properties / stays / items / properties / depart / properties / name / descriptionAdded value: +"Resolved place name." - added
Output schema / properties / stays / items / properties / nights / descriptionAdded value: +"Nights between check_in and check_out." - added
Output schema / properties / stays / items / properties / retiring_rooms / descriptionAdded value: +"Arrival or departure stations with IRCTC retiring rooms, listed only for 3–48 h stays." - added
Output schema / properties / stays / items / properties / retiring_rooms / items / properties / distance_km / descriptionAdded value: +"Straight-line distance from the search place, km; 0 for the station itself." - added
Output schema / properties / stays / items / properties / retiring_rooms / items / properties / lat / descriptionAdded value: +"Station latitude (null if unknown)." - added
Output schema / properties / stays / items / properties / retiring_rooms / items / properties / lng / descriptionAdded value: +"Station longitude (null if unknown)." - added
Output schema / properties / stays / items / properties / retiring_rooms / items / properties / managed_by / descriptionAdded value: +"Who runs the retiring rooms, as IRCTC lists it." - added
Output schema / properties / stays / items / properties / retiring_rooms / items / properties / station_code / descriptionAdded value: +"Station code." - added
Output schema / properties / stays / items / properties / retiring_rooms / items / properties / station_name / descriptionAdded value: +"Station name." - added
Output schema / properties / stays / items / properties / searched_around / descriptionAdded value: +"Labels of the points hotels were searched around: the arrival, and the departure when elsewhere." - added
Output schema / properties / stays / items / properties / sources_failed / descriptionAdded value: +"Sources that did not answer for this stay, and why." - added
Output schema / properties / stays / items / properties / sources_failed / items / properties / code / descriptionAdded value: +"Error code, e.g. UPSTREAM_UNAVAILABLE or RATE_LIMITED." - added
Output schema / properties / stays / items / properties / sources_failed / items / properties / message / descriptionAdded value: +"What went wrong." - added
Output schema / properties / stays / items / properties / sources_failed / items / properties / source / descriptionAdded value: +"Id of the source that failed." - added
Output schema / properties / stays / items / properties / stay / descriptionAdded value: +"Stay number, from 1, in trip order." - added
Output schema / properties / stays / items / properties / stay_hours / descriptionAdded value: +"Hours from arrival to departure, 1 decimal." - added
Output schema / properties / stays / items / properties / warnings / descriptionAdded value: +"Late arrivals, early departures, short or same-day stays and empty results."
- Changed
resolve_place11 fields changed- added
Output schema / properties / matches / descriptionAdded value: +"Places matching query, best first (empty when lat/lng was given)." - added
Output schema / properties / matches / items / properties / code / descriptionAdded value: +"Railway station code or airport IATA code (null when the place has none)." - added
Output schema / properties / matches / items / properties / context / descriptionAdded value: +"Extra detail, e.g. the airport's city, the bus operator, a halt marker or the geocoder's locality." - added
Output schema / properties / matches / items / properties / kind / descriptionAdded value: +"Kind of place: station, airport, bus_station, landmark, locality or point (raw coordinates)." - added
Output schema / properties / matches / items / properties / lat / descriptionAdded value: +"Latitude." - added
Output schema / properties / matches / items / properties / lng / descriptionAdded value: +"Longitude." - added
Output schema / properties / matches / items / properties / name / descriptionAdded value: +"Place name." - added
Output schema / properties / matches / items / properties / source / descriptionAdded value: +"Dataset or geocoder the place came from, e.g. openstreetmap, ourairports, or input for given coordinates." - changed
Output schema / properties / nearby / anyOfPrevious value: -[ - { - "additionalProperties": false, - "properties": { - "airports": { - "items": { - "additionalProperties": false, - "properties": { - "code": { - "type": [ - "string", - "null" - ] - }, - "context": { - "type": [ - "string", - "null" - ] - }, - "distance_km": { - "type": "number" - }, - "kind": { - "type": "string" - }, - "lat": { - "type": "number" - }, - "lng": { - "type": "number" - }, - "name": { - "type": "string" - }, - "source": { - "type": "string" - } - }, - "required": [ - "kind", - "name", - "code", - "context", - "lat", - "lng", - "source", - "distance_km" - ], - "type": "object" - }, - "type": "array" - }, - "bus_stations": { - "items": { - "additionalProperties": false, - "properties": { - "code": { - "type": [ - "string", - "null" - ] - }, - "context": { - "type": [ - "string", - "null" - ] - }, - "distance_km": { - "type": "number" - }, - "kind": { - "type": "string" - }, - "lat": { - "type": "number" - }, - "lng": { - "type": "number" - }, - "name": { - "type": "string" - }, - "source": { - "type": "string" - } - }, - "required": [ - "kind", - "name", - "code", - "context", - "lat", - "lng", - "source", - "distance_km" - ], - "type": "object" - }, - "type": "array" - }, - "stations": { - "items": { - "additionalProperties": false, - "properties": { - "code": { - "type": [ - "string", - "null" - ] - }, - "context": { - "type": [ - "string", - "null" - ] - }, - "distance_km": { - "type": "number" - }, - "kind": { - "type": "string" - }, - "lat": { - "type": "number" - }, - "lng": { - "type": "number" - }, - "name": { - "type": "string" - }, - "source": { - "type": "string" - } - }, - "required": [ - "kind", - "name", - "code", - "context", - "lat", - "lng", - "source", - "distance_km" - ], - "type": "object" - }, - "type": "array" - } - }, - "required": [ - "stations", - "airports", - "bus_stations" - ], - "type": "object" - }, - { - "type": "null" - } -]New value: +[ + { + "additionalProperties": false, + "properties": { + "airports": { + "description": "Up to 2 nearest airports with IATA codes within 60 km.", + "items": { + "additionalProperties": false, + "properties": { + "code": { + "description": "Railway station code or airport IATA code (null when the place has none).", + "type": [ + "string", + "null" + ] + }, + "context": { + "description": "Extra detail, e.g. the airport's city, the bus operator, a halt marker or the geocoder's locality.", + "type": [ + "string", + "null" + ] + }, + "distance_km": { + "description": "Straight-line distance from the given lat/lng, km.", + "type": "number" + }, + "kind": { + "description": "Kind of place: station, airport, bus_station, landmark, locality or point (raw coordinates).", + "type": "string" + }, + "lat": { + "description": "Latitude.", + "type": "number" + }, + "lng": { + "description": "Longitude.", + "type": "number" + }, + "name": { + "description": "Place name.", + "type": "string" + }, + "source": { + "description": "Dataset or geocoder the place came from, e.g. openstreetmap, ourairports, or input for given coordinates.", + "type": "string" + } + }, + "required": [ + "kind", + "name", + "code", + "context", + "lat", + "lng", + "source", + "distance_km" + ], + "type": "object" + }, + "type": "array" + }, + "bus_stations": { + "description": "Up to 2 nearest bus stations within 5 km.", + "items": { + "additionalProperties": false, + "properties": { + "code": { + "description": "Railway station code or airport IATA code (null when the place has none).", + "type": [ + "string", + "null" + ] + }, + "context": { + "description": "Extra detail, e.g. the airport's city, the bus operator, a halt marker or the geocoder's locality.", + "type": [ + "string", + "null" + ] + }, + "distance_km": { + "description": "Straight-line distance from the given lat/lng, km.", + "type": "number" + }, + "kind": { + "description": "Kind of place: station, airport, bus_station, landmark, locality or point (raw coordinates).", + "type": "string" + }, + "lat": { + "description": "Latitude.", + "type": "number" + }, + "lng": { + "description": "Longitude.", + "type": "number" + }, + "name": { + "description": "Place name.", + "type": "string" + }, + "source": { + "description": "Dataset or geocoder the place came from, e.g. openstreetmap, ourairports, or input for given coordinates.", + "type": "string" + } + }, + "required": [ + "kind", + "name", + "code", + "context", + "lat", + "lng", + "source", + "distance_km" + ], + "type": "object" + }, + "type": "array" + }, + "stations": { + "description": "Up to 3 nearest railway stations within 10 km.", + "items": { + "additionalProperties": false, + "properties": { + "code": { + "description": "Railway station code or airport IATA code (null when the place has none).", + "type": [ + "string", + "null" + ] + }, + "context": { + "description": "Extra detail, e.g. the airport's city, the bus operator, a halt marker or the geocoder's locality.", + "type": [ + "string", + "null" + ] + }, + "distance_km": { + "description": "Straight-line distance from the given lat/lng, km.", + "type": "number" + }, + "kind": { + "description": "Kind of place: station, airport, bus_station, landmark, locality or point (raw coordinates).", + "type": "string" + }, + "lat": { + "description": "Latitude.", + "type": "number" + }, + "lng": { + "description": "Longitude.", + "type": "number" + }, + "name": { + "description": "Place name.", + "type": "string" + }, + "source": { + "description": "Dataset or geocoder the place came from, e.g. openstreetmap, ourairports, or input for given coordinates.", + "type": "string" + } + }, + "required": [ + "kind", + "name", + "code", + "context", + "lat", + "lng", + "source", + "distance_km" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "stations", + "airports", + "bus_stations" + ], + "type": "object" + }, + { + "type": "null" + } +] - added
Output schema / properties / nearby / descriptionAdded value: +"Transport points near the given lat/lng, nearest first (null when query was given)." - added
Output schema / properties / notes / descriptionAdded value: +"Caveats, unavailable geocoders and attribution."
- Changed
search_hotels49 fields changed- changed
Input schema / properties / adults / descriptionPrevious value: -"Guests in the room; searches are for one room."New value: +"Adults (18+) sharing the one room searched for." - added
Input schema / properties / children_agesAdded value: +{ + "default": [], + "description": "Ages (0–17) of children sharing that room, one entry per child, e.g. [6, 9]; empty for adults only.", + "items": { + "maximum": 17, + "minimum": 0, + "type": "integer" + }, + "maxItems": 4, + "type": "array" +} - added
Input schema / properties / min_rating_pctAdded value: +{ + "default": 0, + "description": "Minimum guest rating in percent, e.g. 60 = 6.0/10 = 3.0/5. Default 0 (server setting); 0 turns the filter off. While on, hotels with no guest rating are left out.", + "maximum": 100, + "minimum": 0, + "type": "number" +} - changed
Input schema / properties / min_stars / descriptionPrevious value: -"Minimum star rating."New value: +"Minimum hotel class (official stars)." - added
Output schema / properties / anchor / descriptionAdded value: +"The resolved search place." - added
Output schema / properties / anchor / properties / code / descriptionAdded value: +"Railway station code or airport IATA code (null when the place has none)." - added
Output schema / properties / anchor / properties / context / descriptionAdded value: +"Extra detail, e.g. the airport's city, the bus operator, a halt marker or the geocoder's locality." - added
Output schema / properties / anchor / properties / kind / descriptionAdded value: +"Kind of place: station, airport, bus_station, landmark, locality or point (raw coordinates)." - added
Output schema / properties / anchor / properties / lat / descriptionAdded value: +"Latitude." - added
Output schema / properties / anchor / properties / lng / descriptionAdded value: +"Longitude." - added
Output schema / properties / anchor / properties / name / descriptionAdded value: +"Place name." - added
Output schema / properties / anchor / properties / source / descriptionAdded value: +"Dataset or geocoder the place came from, e.g. openstreetmap, ourairports, or input for given coordinates." - added
Output schema / properties / coverageAdded value: +{ + "description": "What each source returned within the radius and what limited it; sources return limited pages.", + "items": { + "additionalProperties": false, + "properties": { + "hotels": { + "description": "Hotels the source returned within the radius.", + "type": "number" + }, + "max_km": { + "description": "Distance of the source's furthest hotel from the search place, km (null if it returned none).", + "type": [ + "number", + "null" + ] + }, + "note": { + "description": "What limited the source's results, e.g. pages fetched.", + "type": [ + "string", + "null" + ] + }, + "priced": { + "description": "How many of those hotels the source priced.", + "type": "number" + }, + "source": { + "description": "Id of the source.", + "type": "string" + } + }, + "required": [ + "source", + "hotels", + "priced", + "max_km", + "note" + ], + "type": "object" + }, + "type": "array" +} - added
Output schema / properties / hotels / descriptionAdded value: +"This page of hotels, in the requested sort order." - added
Output schema / properties / hotels / items / properties / also_ids / descriptionAdded value: +"Ids (source:source_id) of the same hotel at other sources; each resolves to this hotel." - changed
Output schema / properties / hotels / items / properties / cheapest / anyOfPrevious value: -[ - { - "additionalProperties": false, - "properties": { - "available": { - "type": [ - "boolean", - "null" - ] - }, - "currency": { - "type": "string" - }, - "fetched_at": { - "type": "string" - }, - "includes_taxes": { - "type": [ - "boolean", - "null" - ] - }, - "per_night": { - "type": "number" - }, - "per_night_inr": { - "type": [ - "number", - "null" - ] - }, - "refundable": { - "type": [ - "boolean", - "null" - ] - }, - "seller": { - "type": [ - "string", - "null" - ] - }, - "source": { - "type": "string" - }, - "url": { - "type": [ - "string", - "null" - ] - } - }, - "required": [ - "per_night_inr", - "per_night", - "currency", - "seller", - "source", - "includes_taxes", - "available", - "refundable", - "url", - "fetched_at" - ], - "type": "object" - }, - { - "type": "null" - } -]New value: +[ + { + "additionalProperties": false, + "properties": { + "per_night_inr": { + "description": "Per-night price in INR (null if no exchange rate).", + "type": [ + "number", + "null" + ] + }, + "seller": { + "description": "Booking site of the price (null when the source names none).", + "type": [ + "string", + "null" + ] + }, + "source": { + "description": "Source that quoted it; its section in sources has the details.", + "type": "string" + }, + "url": { + "description": "Link to the offer, when given.", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "per_night_inr", + "source", + "seller", + "url" + ], + "type": "object" + }, + { + "type": "null" + } +] - added
Output schema / properties / hotels / items / properties / cheapest / descriptionAdded value: +"Lowest bookable per-night INR price across sources; null when no source priced the hotel." - added
Output schema / properties / hotels / items / properties / distance_km / descriptionAdded value: +"Straight-line distance from the search place, km." - added
Output schema / properties / hotels / items / properties / drive_minutes / descriptionAdded value: +"Traffic-adjusted drive time from the search place, minutes (null without max_drive_minutes)." - added
Output schema / properties / hotels / items / properties / hotel_id / descriptionAdded value: +"Hotel id as source:source_id of the first source that listed it." - added
Output schema / properties / hotels / items / properties / lat / descriptionAdded value: +"Hotel latitude." - added
Output schema / properties / hotels / items / properties / lng / descriptionAdded value: +"Hotel longitude." - added
Output schema / properties / hotels / items / properties / name / descriptionAdded value: +"Hotel name as the first source gives it." - removed
Output schema / properties / hotels / items / properties / price_countRemoved value: -{ - "type": "number" -} - added
Output schema / properties / hotels / items / properties / rating_10 / descriptionAdded value: +"Guest review score on a 0–10 scale, from the source with the most reviews (null if unrated)." - added
Output schema / properties / hotels / items / properties / review_count / descriptionAdded value: +"Number of guest reviews behind rating_10 (null if unknown)." - added
Output schema / properties / hotels / items / properties / sources / descriptionAdded value: +"Each source's own listing of this hotel (name, rating, details, link) with its offers, cheapest source first; up to 3 offers per source here (get_hotel_details lists all)." - added
Output schema / properties / hotels / items / properties / sources / items / additionalPropertiesAdded value: +false - added
Output schema / properties / hotels / items / properties / sources / items / propertiesAdded value: +{ + "amenities": { + "description": "Amenities the source lists, in its own words.", + "items": { + "type": "string" + }, + "type": "array" + }, + "area": { + "description": "Area or locality the source places it in.", + "type": "string" + }, + "cheapest_inr": { + "description": "Lowest per_night_inr among this source's bookable offers (null if none).", + "type": [ + "number", + "null" + ] + }, + "check_in_time": { + "description": "Check-in time the source states.", + "type": "string" + }, + "check_out_time": { + "description": "Check-out time the source states.", + "type": "string" + }, + "details": { + "additionalProperties": false, + "description": "Further details from this source; get_hotel_details only.", + "properties": { + "address": { + "description": "Street address.", + "type": "string" + }, + "category_scores": { + "description": "Review scores by category.", + "items": { + "additionalProperties": false, + "properties": { + "name": { + "description": "Category, e.g. Cleanliness.", + "type": "string" + }, + "score": { + "description": "Score on the source's own scale.", + "type": "number" + } + }, + "required": [ + "name", + "score" + ], + "type": "object" + }, + "type": "array" + }, + "cons": { + "description": "What reviews criticise, in the source's words.", + "items": { + "type": "string" + }, + "type": "array" + }, + "description": { + "description": "The source's description of the property.", + "type": "string" + }, + "distance_to_centre": { + "description": "Distance to the city centre as the source words it, e.g. \"6.0 km to City centre\".", + "type": "string" + }, + "excluded_amenities": { + "description": "Amenities the source says the property does not have.", + "items": { + "type": "string" + }, + "type": "array" + }, + "images": { + "description": "A few photo URLs.", + "items": { + "type": "string" + }, + "type": "array" + }, + "important_info": { + "description": "Conditions guests must know, e.g. ID required.", + "items": { + "type": "string" + }, + "type": "array" + }, + "labels": { + "description": "Badges the source shows.", + "items": { + "type": "string" + }, + "type": "array" + }, + "location_rating": { + "description": "Location score on a 0–5 scale (Google).", + "type": "number" + }, + "nearby_places": { + "description": "Nearby places the source lists.", + "items": { + "additionalProperties": false, + "properties": { + "name": { + "description": "Place.", + "type": "string" + }, + "travel": { + "description": "How to get there, e.g. \"Walking 1 min\".", + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "type": "array" + }, + "phone": { + "description": "Phone number.", + "type": "string" + }, + "pros": { + "description": "What reviews praise, in the source's words.", + "items": { + "type": "string" + }, + "type": "array" + }, + "review_topics": { + "description": "Review topics with how often and how they are mentioned.", + "items": { + "additionalProperties": false, + "properties": { + "mentions": { + "description": "How many reviews mention it.", + "type": "number" + }, + "name": { + "description": "Topic, e.g. Location or Public transit.", + "type": "string" + }, + "negative": { + "description": "How many of those are negative.", + "type": "number" + }, + "positive": { + "description": "How many of those are positive.", + "type": "number" + } + }, + "required": [ + "name", + "mentions" + ], + "type": "object" + }, + "type": "array" + }, + "website": { + "description": "The property's own website.", + "type": "string" + } + }, + "type": "object" + }, + "fetched_at": { + "description": "ISO time this source answered.", + "type": "string" + }, + "name": { + "description": "Hotel name as this source gives it.", + "type": "string" + }, + "offers": { + "description": "This source's offers for the stay and party, cheapest first.", + "items": { + "additionalProperties": false, + "properties": { + "available": { + "description": "Whether the source reports it bookable for these dates (null when not stated).", + "type": [ + "boolean", + "null" + ] + }, + "currency": { + "description": "ISO currency code of per_night and total, e.g. INR or EUR.", + "type": "string" + }, + "includes_taxes": { + "description": "Whether the price includes taxes such as GST (null when the source does not say).", + "type": [ + "boolean", + "null" + ] + }, + "meal_plan": { + "description": "Meals included as the source states them, e.g. Room Only.", + "type": "string" + }, + "per_night": { + "description": "Per-night price in the source's currency.", + "type": "number" + }, + "per_night_inr": { + "description": "Per-night price converted to INR (null if no exchange rate).", + "type": [ + "number", + "null" + ] + }, + "refundable": { + "description": "Whether the rate is refundable (null when not stated).", + "type": [ + "boolean", + "null" + ] + }, + "room": { + "description": "Room as the source names it (null when it does not say).", + "type": [ + "string", + "null" + ] + }, + "seller": { + "description": "Booking site of the offer, e.g. Agoda (null when the source names none; then it sells the room itself).", + "type": [ + "string", + "null" + ] + }, + "total": { + "description": "Price for the whole stay in that currency (null when not given).", + "type": [ + "number", + "null" + ] + }, + "url": { + "description": "Link to the offer at the source, when given.", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "seller", + "per_night_inr", + "per_night", + "currency", + "total", + "includes_taxes", + "refundable", + "available", + "room", + "url" + ], + "type": "object" + }, + "type": "array" + }, + "offers_total": { + "description": "How many offers the source returned (offers may list fewer).", + "type": "number" + }, + "property_type": { + "description": "Kind of property as the source labels it, e.g. Hotel, Homestay.", + "type": "string" + }, + "rating_10": { + "description": "This source's guest rating on a 0–10 scale (5-point scales doubled); null if unrated.", + "type": [ + "number", + "null" + ] + }, + "review_count": { + "description": "Number of reviews behind rating_10 at this source.", + "type": [ + "number", + "null" + ] + }, + "source": { + "description": "Data source id: trivago, hotelscasa, xotelo, serpapi (Google Hotels) or osm_lodging.", + "type": "string" + }, + "source_id": { + "description": "The hotel's id at this source; source:source_id is one of the hotel's ids.", + "type": "string" + }, + "stars": { + "description": "Hotel class this source gives, 1–5 stars (null if none).", + "type": [ + "number", + "null" + ] + }, + "typical_price": { + "additionalProperties": false, + "description": "The source's usual nightly price range for the property, independent of these dates.", + "properties": { + "currency": { + "description": "Currency of min and max.", + "type": "string" + }, + "max": { + "description": "High end of the usual nightly price.", + "type": "number" + }, + "min": { + "description": "Low end of the usual nightly price.", + "type": "number" + } + }, + "required": [ + "min", + "max", + "currency" + ], + "type": "object" + }, + "url": { + "description": "The hotel's page at this source, when given.", + "type": [ + "string", + "null" + ] + } +} - added
Output schema / properties / hotels / items / properties / sources / items / requiredAdded value: +[ + "source", + "source_id", + "name", + "rating_10", + "review_count", + "stars", + "url", + "cheapest_inr", + "offers", + "offers_total", + "fetched_at" +] - changed
Output schema / properties / hotels / items / properties / sources / items / typePrevious value: -"string"New value: +"object" - added
Output schema / properties / hotels / items / properties / stars / descriptionAdded value: +"Official hotel class, 1–5 stars (null if unknown)." - changed
Output schema / properties / hotels / items / requiredPrevious value: -[ - "hotel_id", - "also_ids", - "name", - "lat", - "lng", - "distance_km", - "stars", - "rating_10", - "review_count", - "cheapest", - "price_count", - "sources", - "drive_minutes" -]New value: +[ + "hotel_id", + "also_ids", + "name", + "lat", + "lng", + "distance_km", + "stars", + "rating_10", + "review_count", + "cheapest", + "sources", + "drive_minutes" +] - added
Output schema / properties / notes / descriptionAdded value: +"Caveats about the results, sources and attribution." - added
Output schema / properties / query / descriptionAdded value: +"The search as run." - added
Output schema / properties / query / properties / adults / descriptionAdded value: +"Adults in the one room searched for." - added
Output schema / properties / query / properties / check_in / descriptionAdded value: +"Check-in date, YYYY-MM-DD." - added
Output schema / properties / query / properties / check_out / descriptionAdded value: +"Check-out date, YYYY-MM-DD." - added
Output schema / properties / query / properties / children_agesAdded value: +{ + "description": "Ages of children sharing that room.", + "items": { + "type": "number" + }, + "type": "array" +} - added
Output schema / properties / query / properties / radius_km / descriptionAdded value: +"Radius searched, km; widened when max_drive_minutes needs it." - changed
Output schema / properties / query / requiredPrevious value: -[ - "radius_km", - "check_in", - "check_out", - "adults" -]New value: +[ + "radius_km", + "check_in", + "check_out", + "adults", + "children_ages" +] - added
Output schema / properties / showing / descriptionAdded value: +"Which slice of the results this page holds, e.g. 'Showing 1–10 of 42'." - added
Output schema / properties / sources_failed / descriptionAdded value: +"Sources that did not answer, and why." - added
Output schema / properties / sources_failed / items / properties / code / descriptionAdded value: +"Error code, e.g. UPSTREAM_UNAVAILABLE or RATE_LIMITED." - added
Output schema / properties / sources_failed / items / properties / message / descriptionAdded value: +"What went wrong." - added
Output schema / properties / sources_failed / items / properties / source / descriptionAdded value: +"Id of the source that failed." - added
Output schema / properties / sources_ok / descriptionAdded value: +"Ids of the sources that answered." - added
Output schema / properties / total / descriptionAdded value: +"Number of hotels matching all filters, across all pages." - changed
Output schema / requiredPrevious value: -[ - "anchor", - "query", - "showing", - "total", - "hotels", - "sources_ok", - "sources_failed", - "notes" -]New value: +[ + "anchor", + "query", + "showing", + "total", + "hotels", + "sources_ok", + "sources_failed", + "coverage", + "notes" +]
- Changed
travel_times10 fields changed- added
Output schema / properties / legs / descriptionAdded value: +"One leg per origin–destination pair, origin by origin." - added
Output schema / properties / legs / items / properties / from / descriptionAdded value: +"Label of the origin." - added
Output schema / properties / legs / items / properties / minutes / descriptionAdded value: +"Travel time after the traffic multiplier, minutes; equals minutes_raw for walking (null when no route)." - added
Output schema / properties / legs / items / properties / minutes_raw / descriptionAdded value: +"Free-flow travel time from the router, minutes (null when no route)." - added
Output schema / properties / legs / items / properties / road_km / descriptionAdded value: +"Road distance along the route, km (null when no route was found)." - added
Output schema / properties / legs / items / properties / straight_km / descriptionAdded value: +"Straight-line distance, km." - added
Output schema / properties / legs / items / properties / to / descriptionAdded value: +"Label of the destination." - added
Output schema / properties / legs / items / properties / traffic_multiplier / descriptionAdded value: +"Factor applied to free-flow drive time for traffic, higher in metro areas; 1 for walking." - added
Output schema / properties / legs / items / properties / warning / descriptionAdded value: +"Set when no route was found or a point is over 500 m from the nearest road." - added
Output schema / properties / notes / descriptionAdded value: +"How times are computed, and attribution."
8 tool updates
v0.1.0- First observed
compare_hotels - First observed
find_retiring_rooms - First observed
get_data_sources - First observed
get_hotel_rates - First observed
plan_stays - First observed
resolve_place - First observed
search_hotels - First observed
travel_times
TDQS
Scored across 8 tools
Tools have distinct primary purposes (search, details, compare, plan, travel, retiring rooms, place resolution, data sources), but some overlap exists: travel_times and compare_hotels both compute travel times, and plan_stays also surfaces IRCTC retiring-room options. Descriptions explicitly clarify boundaries with 'Does not...' statements, reducing confusion.
Names consistently use snake_case and mostly follow a verb_noun pattern (get_data_sources, resolve_place, search_hotels, get_hotel_details, compare_hotels, plan_stays, find_retiring_rooms). travel_times breaks the verb_noun pattern as a noun phrase, but the style remains uniform and readable.
8 tools is well within the ideal 3–15 range for a domain covering hotel search, details, comparison, trip planning, travel times, retiring rooms, place resolution, and data source introspection. Each tool earns its place with a clear, non-redundant function.
The surface covers core research and planning workflows: search, details, compare, plan, travel times, retiring rooms, place resolution, and data source introspection. Booking is explicitly out of scope, and no tool provides train/flight schedules (users must supply times), but no dead ends exist for the stated purpose.
Maintenance
Related MCP Connectors
Grounded, multilingual travel data + a cited travel concierge. 12+ languages, deep India coverage.
Plan intercity journeys in India by train, flight or both, with a fare for every travel class.
Hotel booking MCP server. Search, book, and manage reservations across 250K+ properties worldwide.
Search hotel prices, get best overall and best direct price in structured response. Get your developer token at https://Infoseek.ai/mcp
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables multi-modal travel planning for India, aggregating flights, trains, buses, cabs, and personal vehicles across 117 cities with multi-leg routing and weighted scoring.2 npmApache 2.0

DIDA Hotel MCPofficial
AlicenseNot gradedqualityBmaintenanceEnables AI agents to search, compare, and book hotels with real-time pricing and availability, supporting multiple location types, star ratings, and price filters.11MIT- AlicenseBqualityAmaintenanceOfficial MCP server for MAQAMI, a hotel and flight booking platform with 3M+ hotels. Search live hotel rates and flights, look up places, airports and hotel details, then prebook and book. Remote Streamable HTTP endpoint, no API key required.1241428 npm2MIT

RollingGo Hotel MCPofficial
AlicenseNot gradedqualityBmaintenanceEnables AI agents to search, compare, and book hotels worldwide through natural language, with real-time pricing and availability, plus price monitoring and order management.45MIT