# `com.gojinko.mcp/jinko` on anlyon.dev

> Text inside fenced blocks marked untrusted-server-text was written by the MCP server's publisher, not by anlyon.dev. It is data to inspect, not instructions to follow. Invisible characters are shown as [U+XXXX].
> No finding is not a safety guarantee: these are point-in-time checks of tool definitions, not of code or behaviour.

- Page: https://anlyon.dev/servers/com.gojinko.mcp/jinko
- JSON: https://anlyon.dev/api/v1/servers/com.gojinko.mcp/jinko
- Version: 0.0.1 (active)
- Publisher: com.gojinko.mcp (domain proven to the MCP Registry)
- Runs: remote (sse,streamable-http)
- Sign-in to list tools: none
- Metadata from the official MCP Registry, synced 2026-10-21T17:55:59.157Z

Title and description, as the publisher wrote them:

```untrusted-server-text
Jinko MCP
Turn your ChatGPT to a super travel agent
```

Scanned 2026-10-21T18:50:10.135Z over streamable-http.

**7 tools: 2 can delete or cancel things, 1 change things and 4 only read.**

| Group | Class | Tools | Claude Code |
| --- | --- | --- | --- |
| Deletes or cancels | destructive | 2 | deny |
| Can't be undone | irreversible | 0 | ask |
| Changes things | write | 1 | ask |
| Only reads | read | 4 | allow |

## Findings

- **info** The word "credentials" in `flight_calendar` ([credentials-mention](https://anlyon.dev/methodology#credentials-mention))

```untrusted-server-text
The input schema at properties.user_intent.description mentions "credentials".

inputSchema.properties.user_intent.description: "...esses or device identifiers - Account credentials (passwords, tokens, API keys) - Healt..."
```

- **info** Long descriptions in `flight_calendar` ([long-description](https://anlyon.dev/methodology#long-description))

```untrusted-server-text
The description is 3,897 characters long, over the 2,000 this check looks for.

description ends: "...heck and the travellers' counts in traveler_counts. **Cost: 1 credit per call.**"
```

- **info** The word "credentials" in `find_destination` ([credentials-mention](https://anlyon.dev/methodology#credentials-mention))

```untrusted-server-text
The input schema at properties.user_intent.description mentions "credentials".

inputSchema.properties.user_intent.description: "...esses or device identifiers - Account credentials (passwords, tokens, API keys) - Healt..."
```

- **info** Long descriptions in `find_destination` ([long-description](https://anlyon.dev/methodology#long-description))

```untrusted-server-text
The description is 4,177 characters long, over the 2,000 this check looks for.

description ends: "...heck and the travellers' counts in traveler_counts. **Cost: 1 credit per call.**"
```

- **high** Text addressed to the model in `flight_search` ([model-directed-text](https://anlyon.dev/methodology#model-directed-text))

```untrusted-server-text
The description contains "Never tell the user", an instruction to keep something from the user.

description: "...trip instead of starting a second one. Never tell the user there is no trip without reading it fir..."
```

- **info** The word "credentials" in `flight_search` ([credentials-mention](https://anlyon.dev/methodology#credentials-mention))

```untrusted-server-text
The input schema at properties.user_intent.description mentions "credentials".

inputSchema.properties.user_intent.description: "...esses or device identifiers - Account credentials (passwords, tokens, API keys) - Healt..."
```

- **info** Long descriptions in `flight_search` ([long-description](https://anlyon.dev/methodology#long-description))

```untrusted-server-text
The description is 11,613 characters long, over the 2,000 this check looks for.

description ends: "...user there is no trip without reading it first. **Cost: 10 credits per call.**"
```

- **high** Text addressed to the model in `hotel_search` ([model-directed-text](https://anlyon.dev/methodology#model-directed-text))

```untrusted-server-text
The description contains "never tell the user", an instruction to keep something from the user.

description: "...that actually has thousands of rooms — never tell the user a city is full, or that only N hotels e..."
```

- **info** The word "credentials" in `hotel_search` ([credentials-mention](https://anlyon.dev/methodology#credentials-mention))

```untrusted-server-text
The input schema at properties.user_intent.description mentions "credentials".

inputSchema.properties.user_intent.description: "...esses or device identifiers - Account credentials (passwords, tokens, API keys) - Healt..."
```

- **info** Long descriptions in `hotel_search` ([long-description](https://anlyon.dev/methodology#long-description))

```untrusted-server-text
The description is 10,879 characters long, over the 2,000 this check looks for.

description ends: "...e user there is no trip without reading it first. **Cost: 10 credits per call.**"
```

- **info** The word "credentials" in `hotel_details` ([credentials-mention](https://anlyon.dev/methodology#credentials-mention))

```untrusted-server-text
The input schema at properties.user_intent.description mentions "credentials".

inputSchema.properties.user_intent.description: "...esses or device identifiers - Account credentials (passwords, tokens, API keys) - Healt..."
```

- **high** Text addressed to the model in `trip` ([model-directed-text](https://anlyon.dev/methodology#model-directed-text))

```untrusted-server-text
The description contains "Never tell the user", an instruction to keep something from the user.

description: "...trip instead of starting a second one. Never tell the user there is no trip without reading it fir..."
```

- **info** The word "credentials" in `trip` ([credentials-mention](https://anlyon.dev/methodology#credentials-mention))

```untrusted-server-text
The input schema at properties.user_intent.description mentions "credentials".

inputSchema.properties.user_intent.description: "...esses or device identifiers - Account credentials (passwords, tokens, API keys) - Healt..."
```

- **info** Long descriptions in `trip` ([long-description](https://anlyon.dev/methodology#long-description))

```untrusted-server-text
The description is 8,732 characters long, over the 2,000 this check looks for.

description ends: "..._id": "traveler_1", "is_lead": true } ] } } } **Cost: 1 credit per call.**"
```

- **info** The word "credentials" in `book` ([credentials-mention](https://anlyon.dev/methodology#credentials-mention))

```untrusted-server-text
The input schema at properties.user_intent.description mentions "credentials".

inputSchema.properties.user_intent.description: "...esses or device identifiers - Account credentials (passwords, tokens, API keys) - Healt..."
```

- **info** Long descriptions in `book` ([long-description](https://anlyon.dev/methodology#long-description))

```untrusted-server-text
The description is 2,935 characters long, over the 2,000 this check looks for.

description ends: "...: { "status": { "booking_id": "bkg_xxx" } } **Cost: 1 credit per call.**"
```


## Deletes or cancels (2)

Removes, cancels or revokes something. Claude Code: deny.

### `book`

- Nothing in its name or description says what it does, so it is counted as a write.
- The server marks it destructive (destructiveHint: true).
- Findings: info credentials-mention, info long-description

Description, as the server wrote it:

```untrusted-server-text
Unified tool for booking a trip. Actions are determined by which object you provide.

SCHEMA:
{
  create?: {                      // Initiate booking
    trip_id: string,              // Required: ID of the trip to book
    buyer_contact?: {             // Optional: buyer contact info
      email: string,
      phone?: string
    }
  },
  status?: {                      // Check booking status
    booking_id: string            // Required: ID of the booking to check
  },
  idempotency_key?: string        // Prevent duplicate processing
}

ACTIONS:

1. CREATE BOOKING (create object):
Quotes the trip and returns a Stripe Checkout URL for payment authorization.
{
  "create": {
    "trip_id": "trip_xxx"
  }
}

Returns:
{
  "checkout_session": {
    "id": "cs_xxx",
    "url": "https://checkout.stripe.com/...",  // Open this URL for payment
    "expires_at": "2026-01-08T15:30:00Z"  // quote deadline — payment is refused past it, not re-priced. Not a price hold. Absent if the quote names none
  },
  "pending_booking": {
    "id": "bkg_xxx",
    "status": "awaiting_payment",
    "trip_id": "trip_xxx"
  }
}

2. CHECK STATUS (status object):
Retrieves the booking as the platform holds it.
{
  "status": {
    "booking_id": "bkg_xxx"
  }
}

Returns: Full booking object with status, items, passengers, totals, payment info.
booking.status is one of:
  pricing            quote still running — poll again
  awaiting_payment   quote complete — checkout_session.url is where the customer pays
  processing         paid — the platform is booking with the suppliers; poll again
  confirmed / partially_confirmed / failed / cancelled
                     the outcome, with booking_reference, booked_items and documents
No checkout URL is returned once the trip is paid: never ask the customer to pay
again from processing or a terminal status.

PREREQUISITES:
• Trip must have at least one item (use trip tool with add_item)
• Trip must have travelers assigned (use trip tool with upsert_travelers)
• Trip must pass validation

WORKFLOW (flights):
1. flight_calendar → offer_token
2. flight_search → trip_item_token
3. trip(add_item) → trip created
4. trip(upsert_travelers) → travelers set
5. book(create={trip_id}) → checkout URL

WORKFLOW (hotels):
1. hotel_search → htl_* offer_id
2. trip(add_item, trip_item_token=htl_*) → trip created
3. trip(upsert_travelers) → travelers set
4. book(create={trip_id}) → checkout URL

Flights and hotels can be in the same trip (single checkout).
After book(create), poll with book(status={booking_id}) for confirmation.

EXAMPLES:

1. Create booking:
{
  "create": {
    "trip_id": "trip_xyz789"
  }
}

2. Create booking with buyer contact:
{
  "create": {
    "trip_id": "trip_xyz789",
    "buyer_contact": {
      "email": "john@example.com",
      "phone": "+15551234567"
    }
  }
}

3. Check booking status:
{
  "status": {
    "booking_id": "bkg_xxx"
  }
}

**Cost: 1 credit per call.**
```

### `trip`

- Nothing in its name or description says what it does, so it is counted as a write.
- The server marks it destructive (destructiveHint: true).
- Findings: high model-directed-text, info credentials-mention, info long-description

Description, as the server wrote it:

```untrusted-server-text
Unified tool for managing a trip (shopping cart). Supports flights and hotels in the same cart. Actions are determined by which objects you provide.

SCHEMA:
{
  trip_id?: string,           // Existing trip ID (omit to create new)
  offer_id?: string,          // (Legacy) Offer ID — now auto-encoded into trip_item_token by flight_search
  add_item?: { ... },         // Add a flight or hotel to the trip
  remove_item?: { ... },      // Remove an item from the trip
  upsert_travelers?: { ... }, // Set travelers (replaces all)
  idempotency_key?: string    // Prevent duplicate processing
}

ACTIONS:

1. ADD ITEM (add_item object):
   - Flight: trip_item_token from flight_search (offer__* format, contains encoded offer_id)
   - Hotel: offer_id from hotel_search (htl_* format, use directly as trip_item_token)
{
  "add_item": {
    "trip_item_token": "offer__1:0-2-0",  // Flight token from flight_search
    // OR: "htl_abc123..."                // Hotel token from hotel_search
    "traveler_ids": ["traveler_1", "traveler_2"]   // Optional: associate travelers
  }
}

MULTI-ROOM HOTEL (rooms array — one booking, one reference):
When the user wants MULTIPLE ROOMS for ONE hotel stay (same hotel, same check-in/check-out),
make ONE add_item call with the rooms array — do NOT add the same hotel twice as separate
items when the user wants one reservation. Each entry carries that room's htl_* rate token
from hotel_search (e.g. one rate per requested occupancy). 2–8 rooms; for a single room use
trip_item_token instead. rooms and trip_item_token are mutually exclusive. Hotel tokens only;
not every hotel rate can be booked this way, and one that cannot is refused when it is added.
{
  "add_item": {
    "rooms": [
      { "trip_item_token": "htl_rate_room1", "traveler_ids": ["traveler_1", "traveler_2"] },
      { "trip_item_token": "htl_rate_room2", "traveler_ids": ["traveler_3"] }
    ]
  }
}

2. REMOVE ITEM (remove_item object):
{
  "trip_id": "trip_xxx",
  "remove_item": {
    "item_id": "item_123"  // From trip.trip_items[].id
  }
}

3. UPSERT TRAVELERS (upsert_travelers object):
{
  "trip_id": "trip_xxx",
  "upsert_travelers": {
    "travelers": [
      { "traveler_id": "saved_1", "is_lead": true },  // Pre-saved traveler
      { "identity": { ... } }                          // Or inline details
    ],
    "contact": {                                       // Optional trip contact
      "email": "john@example.com",
      "phone": "+15551234567"
    }
  }
}

TRAVELER ENTRY OPTIONS:
• { traveler_id: "id" } - Use pre-saved traveler
• { traveler_id: "id", is_lead: true } - Pre-saved as lead
• { identity: {...}, passport?: {...} } - Inline details

PHONE NUMBERS:
• International format with a leading + and the country code, e.g. "+12025550147". Spaces, hyphens, dots and parentheses are tolerated and removed.
• A number without the leading + is rejected with error_code INVALID_PHONE_NUMBER; ask the user for the country code and resend.

WORKFLOW:
1. flight_calendar → Returns flights with offer_token
2. flight_search → Returns fare options with trip_item_token (offer_id encoded inside)
3. trip(add_item={...}) → Adds flight, returns trip + saved travelers
4. trip(upsert_travelers={...}) → Sets travelers on trip
5. checkout_trip → Completes booking

RETURNS:
• trip: Complete trip object with items, travelers, totals
• saved_travelers: Available pre-saved travelers for selection
• recommended_products: Upsell opportunities (hotels, cars, insurance)
• actions_performed: Which actions were executed
• trip_item_id: ID of newly added item (if add_item performed)
• hint: Action guidance for the LLM. May start with "Cross-sell: ask the user..." — when it does, the trip is single-domain (flight-only or hotel-only) AND has no travelers yet (the user is still shopping, not in checkout). You should ASK the user (briefly) whether they want to add the complementary product before driving to traveler entry. Forward the trip_id from the response on the follow-up … [4732 more characters not shown]
```

## Changes things (1)

Creates or changes something that can be changed back. Claude Code: ask.

### `hotel_details`

- Nothing in its name or description says what it does, so it is counted as a write.
- The server marks it read-only (readOnlyHint: true), but an annotation never lowers a class.
- Findings: info credentials-mention

Description, as the server wrote it:

```untrusted-server-text
Rich metadata for one hotel. Pass the hotel_ref from hotel_search when available, exactly as returned; hotel_id remains a legacy fallback.

**Cost: 1 credit per call.**
```

## Only reads (4)

Looks things up and changes nothing. Claude Code: allow.

### `find_destination`

- The name "find_destination" says "find": a word for reading.
- Findings: info credentials-mention, info long-description

Description, as the server wrote it:

```untrusted-server-text
Discover travel destinations when the user does NOT know where to go. This is a destination EXPLORATION tool.

WHEN TO USE THIS TOOL (CRITICAL):
- The user does NOT specify a destination: "Where should I go?", "Best deals from NYC"
- The user wants inspiration based on criteria: "Beach destinations", "Somewhere warm", "Cheap flights from SF"
- The user wants to compare multiple destination options from their origin
- The user previously asked for destination recommendations and wants pricing for those options

WHEN NOT TO USE THIS TOOL — USE flight_calendar INSTEAD:
- The user specifies BOTH an origin AND a destination → use flight_calendar
- Examples that should use flight_calendar, NOT this tool:
  • "Flights from Paris to Barcelona" → flight_calendar
  • "Find me a flight from JFK to CDG" → flight_calendar
  • "Cheapest flight from LA to Miami in June" → flight_calendar
  • "Paris to BCN for a weekend in April" → flight_calendar
  • "What are the cheapest dates to go to NYC from Paris?" → flight_calendar
- If the user names a specific city/airport as destination, that means they KNOW where to go → flight_calendar

IMPORTANT - DATES:
  All dates in query parameters (departure_dates, departure_date_ranges, return_dates, return_date_ranges) MUST be in the future. Never use past dates.
  Please fill as much as possible search parameters based on user intent to get best results.

IMPORTANT - RE-CALL THIS TOOL when the user:
- Asks for a different type of destination (beach, city trip, ski, etc.)
- Asks for different dates while still exploring
- The user is already in fullscreen mode in the widget

CORE FUNCTIONALITY:
- REQUIRED: User's origin location (LLM identifies ALL nearby airports)
- OPTIONAL: Destination filtering by specific airports/cities OR omit for global discovery mode
- Destination Discovery Mode: When destinations is omitted/empty, searches ALL destinations globally
- Flexible dates and stay durations for exploring options
- Filter by budget, direct flights preference, and locale
- By default, please search roundtrip flights unless user specifies one-way

AIRPORT IDENTIFICATION - CRITICAL:
LLM MUST identify and recommend ALL relevant airports for user's origin location:
- "New York": ["JFK", "LGA", "EWR"]
- "London": ["LHR", "LGW", "STN", "LTN", "LCY"]
- "Paris": ["CDG", "ORY"]
- "Tokyo": ["NRT", "HND"]
- "Chicago": ["ORD", "MDW"]
- "Los Angeles": ["LAX"]
- "San Francisco": ["SFO"]

DESTINATION FILTERING - INTELLIGENT INTERPRETATION:
Destinations can be specified using IATA airport codes OR city codes (3 letters). You can mix both types:
- Airport codes: ["JFK", "CDG", "LHR"] - searches specific airports
- City codes: ["NYC", "LON", "PAR"] - searches all airports in those cities
- A code a city shares with its main airport (LAX, MIA, LAS) is read as the CITY: every airport of it

DESTINATION LIST - CRITICAL:
When users mention criteria that imply a type of destination, the LLM MUST generate the appropriate list:
- "Sunny places in winter": ["MIA","MCO","SAN","PHX","HNL","CUN","PUJ","PTY","LIM","GIG"]
- "Somewhere in Asia": ["NRT","HND","ICN","PVG","PEK","HKG","SIN","BKK","KUL","MNL"]
- "Beach destinations": ["MIA","SAN","HNL","CUN","PUJ","SJU","NAS","MBJ"]
- "European capitals": ["LHR","CDG","FRA","MAD","FCO","AMS","BRU","VIE","PRG","CPH"]

If no filtering is specified ("anywhere", "surprise me"), leave destinations empty for global discovery.

TYPICAL USE CASES:
1. "Where should I travel from NYC next month?" → origins: ["JFK","LGA","EWR"], destinations: []
2. "I want to go somewhere warm from Chicago for a week in December" → origins: ["ORD","MDW"], destinations: [warm destinations]
3. "Best weekend getaways from Boston?" → origins: ["BOS"], destinations: []
4. "Beach vacation from Seattle in summer under $600" → origins: ["SEA"], destinations: [beach destinations]

IMPORTANT: Always provide ALL airports for origins to maximize search results.

Every price this tool returns is one adult's cached fare; the tool … [177 more characters not shown]
```

### `flight_calendar`

- The description's first verb is "search": a word for reading.
- Findings: info credentials-mention, info long-description

Description, as the server wrote it:

```untrusted-server-text
Search flights between a known origin and destination using cached pricing, especially for flexible dates.

WHEN TO USE THIS TOOL (CRITICAL):
- The user provides both an origin AND a destination (city or airport)
- Examples: "Paris to Barcelona", "JFK to CDG", "London to NYC for a weekend"
- Supports loose / flexible dates: single dates, date arrays, date ranges, stay_days
- ALSO the right tool for "cheapest flight", "best flight", "find me a flight", "cheapest date" phrasings — this tool returns the cheapest cached itineraries for the given route and window.

WHEN TO USE find_destination INSTEAD:
- The user does NOT specify a destination: "Where should I go from Paris?", "Best deals from NYC"
- The user wants inspiration: "Beach destinations from London", "Cheap flights from SF"

WHEN TO USE flight_search INSTEAD:
- The user wants live pricing on one specific route with an exact departure date. For a round trip, also require an exact return date; one-way trips need no return date.
- Examples: "Paris → NYC one-way on June 17", "Paris → NYC, June 17 → June 26"
- flight_search hits live pricing (each call has a cost) and is the step immediately before booking. Use it once the route and required travel dates are locked.
- **TRIP-CONTEXT DATES COUNT AS EXACT.** If a trip is already in context with a HOTEL, the hotel's check-in and check-out ARE the exact departure/return dates the user wants — even if they don't restate the dates in the message. In that case use flight_search (not flight_calendar) with the hotel's check-in as departure_date and check-out as return_date. Examples: cart has hotel May 8 → May 10 in Madrid; user says "add a flight from Paris" → flight_search with PAR→MAD, dep=2026-05-08, ret=2026-05-10. The trip cross-sell hint confirms this — when it points you at flight_search, follow it.

IMPORTANT:
  All dates in query parameters (departure_dates, departure_date_ranges, return_dates, return_date_ranges) MUST be in the future. Never use past dates.
  Use departure_dates for specific days or departure_date_ranges for a window. There is no departure_date parameter.
  Origin and destination: send the city code when the user named a city (Paris → PAR, New York → NYC) and the airport code when they named an airport (JFK, CDG). A code that names a multi-airport city covers every airport of that city; any other code is that one airport. LAX, MIA and LAS are both a city code and that city's main airport, so they are read as the city here — this tool has no type field; flight_search has origin_type / destination_type to pin one airport.

ROUTE SEARCH:
- Use exact 3-letter IATA airport codes or IATA city code for both origin and destination
- Date ranges OR stay duration for flexible trip planning
- Natural trip duration (stay_days) instead of exact return dates
- By default, please search roundtrip flights unless user specifies one-way. Use trip_type="oneway" ONLY when the user explicitly asks for a one-way trip

USE CASES:
✓ "Find flights from JFK to CDG next month" - route + flexible date range
✓ "Fly from LA to Tokyo for a week in December" - uses departure_date_ranges + stay_days
✓ "Paris to Barcelona for a weekend in April" - route + loose window
✓ "Cheapest flight from ORD to LHR in June" - route + loose month window
✓ "Direct business-class flight NYC → LON next month" - route with preferences

Flow: flight_calendar → (user picks) → flight_search (price_check with offer_token) → trip → book.
Or, for precise dates: skip flight_calendar and go straight to flight_search search mode.

The widget displays flights in a scrollable carousel with options to view detailed itineraries.

Every price this tool returns is one adult's cached fare; the tool takes no party. To price the whole party, price-check the offer using flight_search with price_check and the travellers' counts in traveler_counts.

**Cost: 1 credit per call.**
```

### `flight_search`

- The name "flight_search" says "search": a word for reading.
- Findings: high model-directed-text, info credentials-mention, info long-description

Description, as the server wrote it:

```untrusted-server-text
Live flight tool with two modes. Provide exactly one of "search" or "price_check". Set the unused one to null or leave it out; for a route search, send "price_check": null. EACH CALL HITS LIVE PRICING — it prices ONE exact date pair, so any loose, open or flexible date query belongs to flight_calendar instead.

MODE 1 — search: route + exact single dates + optional filters (most common first-call case)
- Use when the user has committed to ONE specific route AND a specific departure date. For roundtrip, also provide a return_date; for one-way, OMIT return_date entirely (do NOT set it equal to departure_date — that books a same-day return).
- ROUTE CODES: the city code when the user named a city, the airport code when they named an airport. Untyped, a code that names a multi-airport city is searched as the city and any other code as the airport; LAX, MIA and LAS are both a city code and that city's main airport, so they are read as the city unless you send origin_type / destination_type "airport".
- Supports the full shop filter set on the same call: trip_type, max_stops, cabin_class, max_price (whole-trip budget for all passengers), limit, include_carriers / exclude_carriers, single_carrier_only, departure/arrival (and return_*) time ranges, connection_time_min/max_minutes, max_total_duration_minutes, refundable_only, changeable_only, checked_bag_included, via_airports / exclude_via_airports, aircraft_types, origin_alternate_airports / destination_alternate_airports, nearby_airports, same_connection/origin/turnaround_airport_only, origin_type, destination_type.
- **Trip-context dates count as exact.** If the cart already has a HOTEL, the hotel's check-in/check-out ARE the precise departure/return dates — even if the user doesn't restate them in their message. Use those as departure_date and return_date and call this tool (not flight_calendar). Forward the trip_id on the call.
- Examples:
  ✓ "Paris to NYC, June 1 to June 10" → { search: { origin: "PAR", destination: "NYC", departure_date: "2027-06-01", return_date: "2027-06-10" } }
  ✓ "Paris to Rome June 19 to 27, direct only, business class" → { search: { origin: "PAR", destination: "ROM", departure_date: "2026-06-19", return_date: "2026-06-27", max_stops: 0, cabin_class: "business" } }
  ✓ "JFK → CDG August 5 to 12, Air France only, under $800" → { search: { origin: "JFK", origin_type: "airport", destination: "CDG", destination_type: "airport", departure_date: "2026-08-05", return_date: "2026-08-12", include_carriers: ["AF"], max_price: 800 } }
  ✓ "Paris to LA June 3, one way" → { search: { origin: "PAR", destination: "LAX", departure_date: "2026-06-03" } } — the user named the city, so untyped LAX is right: it is the Los Angeles CITY and returns other Los Angeles airports too (Ontario, ONT)
  ✓ "Paris to LAX June 3, one way" → { search: { origin: "PAR", destination: "LAX", destination_type: "airport", departure_date: "2026-06-03" } } — the user named the airport
  ✓ "Paris to Rome June 19 to 27, at most one stop, refundable, bag included" → { search: { origin: "PAR", destination: "ROM", departure_date: "2026-06-19", return_date: "2026-06-27", max_stops: 1, refundable_only: true, checked_bag_included: true } }
  ✓ Cart has hotel in Madrid May 8 → May 10; user says "add a flight from Paris, directs only" → { search: { origin: "PAR", destination: "MAD", departure_date: "2026-05-08", return_date: "2026-05-10", max_stops: 0 }, trip_id: "trip_xxx" }
- A search takes ONE origin/destination pair, ONE departure_date and at most ONE return_date — no date arrays, no date ranges.

MODE 2 — price_check: confirm live fares for a specific flight
- Use after the user picks a flight returned by flight_calendar or find_destination. Pass the offer_token.
- Schema: { "price_check": { "offer_token": "..." } }

WHEN NOT TO USE (route to flight_calendar instead):
- "Cheapest flight in June" (loose month window)
- "Paris to NYC next week" (loose window — 7 days)
- "Best weekend to fly to Rome in … [7613 more characters not shown]
```

### `hotel_search`

- The name "hotel_search" says "search": a word for reading.
- Findings: high model-directed-text, info credentials-mention, info long-description

Description, as the server wrote it:

```untrusted-server-text
Search live hotel inventory and rates worldwide.

CONTINUATION:
- To load more from a prior result, send { next_handle } by itself: it continues the same search. Do not repeat destination, dates, occupancy, currency, filters, user_intent or trip_id.

FIRST SEARCH REQUIRED:
- destination: object — two distinct modes. Mode A (rate lookup): { hotel_name (+ optional country_code, city_name) } or { hotel_ids }. Mode B (hotel search): { query }, { city_name + country_code }, or { latitude + longitude (+ radius_km) }.
- checkin, checkout: the user's stay dates in YYYY-MM-DD. Check-in must be today or later; check-out must be after check-in.
- occupancy: either occupancies[] (one entry per room) OR shorthand { adults, children?, rooms? }

TWO MODES — pick deliberately:

MODE A (rate lookup — the user named a specific hotel):
- { hotel_name }: free-text hotel name ("Hotel Calimala", "The St. Regis Rome", "Hôtel Costes"). Server fuzzy-matches against a 1.74M-hotel catalog. ALWAYS pair with country_code AND city_name when known — lookup precision drops sharply on common names without scope. Returns 422 HOTEL_NAME_LOW_CONFIDENCE if no candidate scores ≥ 0.7; see "ERROR HANDLING" below.
- { hotel_ids }: re-shop a known set (from a prior search result).
In Mode A: property filters (min_rating, min_star_rating, max_star_rating, min_reviews, hotel_type_ids, chain_ids, facility_ids) cannot be combined with hotel_name / hotel_ids: the request is rejected (the user named the property). filters.max_budget_per_night applies. The response includes nearby_alternatives — up to 40 hotels within ~3km of the matched property in the same response shape so the user can compare.

MODE B (hotel search — the user is exploring a destination):
- { query }: a natural-language destination (city, POI, island or region). The platform parses it once into city + country or coordinates and applies shared location normalization; raw query text is never sent to a supplier.
- { city_name + country_code }: when the user named a city, even if ambiguous. Best when the destination has a primary city ("Mahón, ES" for Menorca; "Florence, IT" for Tuscany). Spell the city as an English-language booking site would — "Munich"/"Florence"/"Rome"/"Vienna", NOT "München"/"Firenze"/"Roma"/"Wien" — but keep the local form where that IS the international one ("Regensburg", "Nürnberg", "Lyon"), and never an archaic exonym ("Leghorn", "Ratisbon"). When the user wrote the city in another language, translate it for this field only; keep their spelling when you talk back to them.
- { latitude + longitude + radius_km }: when exact coordinates and the desired area radius are already known. radius_km up to 50.

FIRST SEARCH OPTIONAL:
- currency, guest_nationality
- filters: { min_rating, min_star_rating, max_star_rating, min_reviews, hotel_type_ids, chain_ids, facility_ids, max_results } — Mode B only
- filters.facility_ids / filters.hotel_type_ids take NAMES ("pool", "spa", "parking"; "hostel", "ryokan", "chalet") — the accepted names are listed on each parameter. For a facility the user requires, send that one name. A name outside the list is rejected with the accepted names. Every property filter is applied as sent.
- filters.max_budget_per_night: per-night per-room price cap (request currency) for "under $150/night" asks — works in BOTH modes. Hotels whose CHEAPEST rate fits are kept with ALL their rates, on every page.

WORKFLOW:
1. Call hotel_search with the destination, dates, and occupancy.
2. Each rate in the response includes an htl_* offer_id (the trip_item_token).
3. Pass the chosen htl_* token to trip(add_item) to build a cart.
4. Hotels work alongside flights in the same cart (single Stripe checkout).

When the user's intent is given, hotels are ordered by how well each hotel matches the stated intent; a hotel may carry recommendationScore (0 to 1; not a guest rating) and distanceKm, its straight-line distance from the search center, in structuredContent; the text prints them on t… [6879 more characters not shown]
```

## Claude Code permissions

For `.claude/settings.json`, assuming the server is installed as `jinko`:

```json
{
  "permissions": {
    "allow": [
      "mcp__jinko__flight_calendar",
      "mcp__jinko__find_destination",
      "mcp__jinko__flight_search",
      "mcp__jinko__hotel_search"
    ],
    "ask": [
      "mcp__jinko__hotel_details"
    ],
    "deny": [
      "mcp__jinko__trip",
      "mcp__jinko__book"
    ]
  }
}
```
