search_experiences
Find shows, events, tours and experiences in any city to discover what to do and get ticket recommendations.
Instructions
Search for shows, theatre, events, tours and experiences in a specific city on tickadoo®. Use when a user asks what to do in a city, wants event/show recommendations, or is looking for tickets.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| city | Yes | City name or slug (e.g. 'london', 'new-york', 'paris', 'tokyo', 'dubai') | |
| language | No | Language code (e.g. 'en', 'de', 'fr', 'es') | en |
Implementation Reference
- src/shared/server.ts:80-128 (handler)The tool "search_experiences" is registered and its logic implemented here within the `createTickadooServer` function. It takes city and language as inputs, fetches products, normalizes the city name, and formats the results.
server.tool( "search_experiences", "Search for shows, theatre, events, tours and experiences in a specific city on tickadoo®. Use when a user asks what to do in a city, wants event/show recommendations, or is looking for tickets.", { city: z.string().describe("City name or slug (e.g. 'london', 'new-york', 'paris', 'tokyo', 'dubai')"), language: z.string().optional().default("en").describe("Language code (e.g. 'en', 'de', 'fr', 'es')"), }, READ_ONLY_TOOL_ANNOTATIONS, async ({ city, language }) => { try { let citySlug = normalizeCityInput(city); let products = await getProductsForCitySlug(citySlug, language); let cityName = city; if (!products.length) { const cities = await getCities(language); const match = cities.find(candidate => candidate.name.toLowerCase().includes(city.toLowerCase()) || (candidate.slug && candidate.slug.includes(citySlug)) ); if (match?.slug) { products = await getProductsForCitySlug(match.slug, language); cityName = match.name; citySlug = match.slug; } } if (!products.length) { return createTextResponse(`No experiences found for "${city}". Try a major city like London, New York, Paris, Dubai, or Tokyo.`); } const rankedProducts = sortProductsForDisplay(products); const topProducts = rankedProducts.slice(0, 12); return createTextResponse( `${buildShownResultsLabel(topProducts.length, products.length, `in ${cityName}`)}\n\n${topProducts.map(product => formatProduct(product, `${citySlug}/${product.slug}`)).join("\n\n")}\n\nView all: ${buildBookingUrl(citySlug)}`, { structuredContent: { city: cityName, citySlug, totalExperiences: products.length, experiences: topProducts.map(product => productStructuredData(product, `${citySlug}/${product.slug}`)), }, }, ); } catch (error) { return createTextResponse(`Error: ${getErrorMessage(error)}`, { isError: true }); } }, );