airbnb_listing_details
Retrieve comprehensive property details for specific Airbnb listings, including amenities, policies, pricing, and direct booking links.
Instructions
Get detailed information about a specific Airbnb listing. Provide direct links to the user
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | The Airbnb listing ID | |
| checkin | No | Check-in date (YYYY-MM-DD) | |
| checkout | No | Check-out date (YYYY-MM-DD) | |
| adults | No | Number of adults | |
| children | No | Number of children | |
| infants | No | Number of infants | |
| pets | No | Number of pets | |
| ignoreRobotsText | No | Ignore robots.txt rules for this request |
Implementation Reference
- index.ts:428-597 (handler)The primary handler function that implements the core logic of the 'airbnb_listing_details' tool. It constructs the Airbnb listing URL with optional check-in/out dates and guest counts, respects robots.txt rules, fetches the page HTML, parses the embedded JSON data, filters specific sections (location, policies, highlights, description, amenities), and returns a JSON object with the listing details.async function handleAirbnbListingDetails(params: any) { const { id, checkin, checkout, adults = 1, children = 0, infants = 0, pets = 0, ignoreRobotsText = false, } = params; const listingUrl = new URL(`${BASE_URL}/rooms/${id}`); if (checkin) listingUrl.searchParams.append("check_in", checkin); if (checkout) listingUrl.searchParams.append("check_out", checkout); const adults_int = parseInt(adults.toString()); const children_int = parseInt(children.toString()); const infants_int = parseInt(infants.toString()); const pets_int = parseInt(pets.toString()); const totalGuests = adults_int + children_int; if (totalGuests > 0) { listingUrl.searchParams.append("adults", adults_int.toString()); listingUrl.searchParams.append("children", children_int.toString()); listingUrl.searchParams.append("infants", infants_int.toString()); listingUrl.searchParams.append("pets", pets_int.toString()); } const path = listingUrl.pathname + listingUrl.search; if (!ignoreRobotsText && !isPathAllowed(path)) { log('warn', 'Listing details blocked by robots.txt', { path, url: listingUrl.toString() }); return { content: [{ type: "text", text: JSON.stringify({ error: robotsErrorMessage, url: listingUrl.toString(), suggestion: "Consider enabling 'ignore_robots_txt' in extension settings if needed for testing" }, null, 2) }], isError: true }; } const allowSectionSchema = { "LOCATION_DEFAULT": { lat: true, lng: true, subtitle: true, title: true }, "POLICIES_DEFAULT": { title: true, houseRulesSections: { title: true, items : { title: true } } }, "HIGHLIGHTS_DEFAULT": { highlights: { title: true } }, "DESCRIPTION_DEFAULT": { htmlDescription: { htmlText: true } }, "AMENITIES_DEFAULT": { title: true, seeAllAmenitiesGroups: { title: true, amenities: { title: true } } }, }; try { log('info', 'Fetching listing details', { id, checkin, checkout, adults, children }); const response = await fetchWithUserAgent(listingUrl.toString()); const html = await response.text(); const $ = cheerio.load(html); let details = {}; try { const scriptElement = $("#data-deferred-state-0").first(); if (scriptElement.length === 0) { throw new Error("Could not find data script element - page structure may have changed"); } const scriptContent = $(scriptElement).text(); if (!scriptContent) { throw new Error("Data script element is empty"); } const clientData = JSON.parse(scriptContent).niobeClientData[0][1]; const sections = clientData.data.presentation.stayProductDetailPage.sections.sections; sections.forEach((section: any) => cleanObject(section)); details = sections .filter((section: any) => allowSectionSchema.hasOwnProperty(section.sectionId)) .map((section: any) => { return { id: section.sectionId, ...flattenArraysInObject(pickBySchema(section.section, allowSectionSchema[section.sectionId as keyof typeof allowSectionSchema])) } }); log('info', 'Listing details fetched successfully', { id, sectionsFound: Array.isArray(details) ? details.length : 0 }); } catch (parseError) { log('error', 'Failed to parse listing details', { error: parseError instanceof Error ? parseError.message : String(parseError), id, url: listingUrl.toString() }); return { content: [{ type: "text", text: JSON.stringify({ error: "Failed to parse listing details from Airbnb. The page structure may have changed.", details: parseError instanceof Error ? parseError.message : String(parseError), listingUrl: listingUrl.toString() }, null, 2) }], isError: true }; } return { content: [{ type: "text", text: JSON.stringify({ listingUrl: listingUrl.toString(), details: details }, null, 2) }], isError: false }; } catch (error) { log('error', 'Listing details request failed', { error: error instanceof Error ? error.message : String(error), id, url: listingUrl.toString() }); return { content: [{ type: "text", text: JSON.stringify({ error: error instanceof Error ? error.message : String(error), listingUrl: listingUrl.toString(), timestamp: new Date().toISOString() }, null, 2) }], isError: true }; } }
- index.ts:94-135 (schema)Tool definition object containing the name, description, and input schema (JSON Schema) for validating parameters like required 'id' and optional dates/guests.const AIRBNB_LISTING_DETAILS_TOOL = { name: "airbnb_listing_details", description: "Get detailed information about a specific Airbnb listing. Provide direct links to the user", inputSchema: { type: "object", properties: { id: { type: "string", description: "The Airbnb listing ID" }, checkin: { type: "string", description: "Check-in date (YYYY-MM-DD)" }, checkout: { type: "string", description: "Check-out date (YYYY-MM-DD)" }, adults: { type: "number", description: "Number of adults" }, children: { type: "number", description: "Number of children" }, infants: { type: "number", description: "Number of infants" }, pets: { type: "number", description: "Number of pets" }, ignoreRobotsText: { type: "boolean", description: "Ignore robots.txt rules for this request" } }, required: ["id"] } };
- index.ts:137-141 (registration)Registers the tool by including it in the AIRBNB_TOOLS array, which is exposed via the ListTools MCP request handler.const AIRBNB_TOOLS = [ AIRBNB_SEARCH_TOOL, AIRBNB_LISTING_DETAILS_TOOL, ...photoAnalysisTools, ];
- index.ts:629-631 (registration)MCP server request handler for listing available tools, which returns the AIRBNB_TOOLS array including 'airbnb_listing_details'.server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: AIRBNB_TOOLS, }));
- index.ts:661-664 (registration)Dispatch logic in the CallTool MCP request handler that routes calls to 'airbnb_listing_details' to the specific handler function.case "airbnb_listing_details": { result = await handleAirbnbListingDetails(request.params.arguments); break; }