jinko-mcp-dev
Version:
MCP server for Jinko Travel BFF
180 lines (179 loc) • 7.49 kB
JavaScript
/**
* Place-related tools for the hotel MCP server
*/
import { makeApiRequest, createJsonResponse } from "../utils.js";
import { session } from "../state.js";
import { facilities } from "../const.js";
import { v4 as uuidv4 } from 'uuid';
import { DEFAULT_MARKET, DEFAULT_CURRENCY, DEFAULT_COUNTRY_CODE } from "../config.js";
/**
* Create a new session and normalize place for hotel search
*/
export async function createSession(params) {
// Reset session data to start fresh
session.hotels = {};
session.placeSuggestions = [];
session.confirmedPlace = null;
session.language = params.language || "en";
// Generate a UUID for the conversation_id
session.conversation_id = uuidv4();
// Set context information from config and params
session.user_ip_address = "127.0.0.1"; // Will be detected automatically by backend
session.market = DEFAULT_MARKET;
session.currency = params.currency || DEFAULT_CURRENCY;
session.country_code = params.country_code || DEFAULT_COUNTRY_CODE;
// Validate place parameter
if (!params.place || params.place.trim() === "") {
return createJsonResponse({
status: "error",
message: "Place parameter is required for creating a session."
});
}
// Make API request to get place suggestions
const request = {
"input": params.place,
"language": "en",
};
const autocompleteResult = await makeApiRequest("/api/v1/hotels/places/autocomplete", "POST", request);
if (!autocompleteResult) {
return createJsonResponse({
status: "error",
message: "Failed to retrieve place suggestions. Please try again with a different query."
});
}
if (!autocompleteResult.predictions || autocompleteResult.predictions.length === 0) {
return createJsonResponse({
status: "empty",
message: "No places found matching your query. Please try a different search term."
});
}
// Store place suggestions in session
session.placeSuggestions = autocompleteResult.predictions;
// Format results for response
const placeSummaries = autocompleteResult.predictions.map((place, index) => ({
id: place.place_id,
name: place.structured_formatting?.main_text || place.description,
type: place.types || "Unknown",
location: place.description || ""
}));
// Automatically select the first place if available
if (autocompleteResult.predictions.length > 0) {
session.confirmedPlace = autocompleteResult.predictions[0];
}
// Prepare response with helpful information
const available_facilities = facilities.map((facility) => {
// Try to find translation for the current session language
const translation = facility.translation?.find((t) => t.lang === session.language);
return {
id: facility.facility_id,
name: translation?.facility || facility.facility
};
});
const response = {
status: "success",
session_created: true,
user_request: params.raw_request || null,
selected_place: {
id: session.confirmedPlace?.place_id,
name: session.confirmedPlace?.structured_formatting?.main_text || session.confirmedPlace?.description,
location: session.confirmedPlace?.description
},
alternative_places: placeSummaries,
next_steps: [
"Use search-hotels to find hotels in the selected place",
"You can specify place_id in search-hotels to use a different place from alternative_places",
"You can use the available_facilities list to find the right facilities id to filter hotels by facilities in search-hotels",
],
available_facilities: available_facilities,
context: {
conversation_id: session.conversation_id,
user_ip_address: session.user_ip_address,
market: session.market,
language: session.language,
currency: session.currency,
country_code: session.country_code,
}
};
return createJsonResponse(response);
}
/**
* Get place suggestions based on user input
*/
export async function autocompletePlaces(params) {
// Make API request to get place suggestions
const request = {
"input": params.query,
"language": "en",
};
if (params.language) {
request.language = params.language;
}
const autocompleteResult = await makeApiRequest("/api/v1/hotels/places/autocomplete", "POST", request);
if (!autocompleteResult) {
return createJsonResponse({
status: "error",
message: "Failed to retrieve place suggestions. Please try again with a different query."
});
}
if (!autocompleteResult.predictions || autocompleteResult.predictions.length === 0) {
return createJsonResponse({
status: "empty",
message: "No places found matching your query. Please try a different search term."
});
}
// Store place suggestions in session
session.placeSuggestions = autocompleteResult.predictions;
// Format results for YAML response
const placeSummaries = autocompleteResult.predictions.map((place, index) => ({
id: place.place_id,
name: place.structured_formatting?.main_text || place.description,
type: place.types || "Unknown",
location: place.description || ""
}));
const response = {
places: placeSummaries,
count: autocompleteResult.predictions.length,
message: ""
};
if (autocompleteResult.predictions.length === 1) {
// If only one place is found, automatically confirm it
session.confirmedPlace = autocompleteResult.predictions[0];
response.message = "This place has been automatically selected for your search. You can now use the search-hotels tool to find hotels in this location.";
}
else {
// If multiple places are found, ask user to confirm
response.message = "Please use the confirm-place tool with the ID of the place you want to select.";
}
return createJsonResponse(response);
}
/**
* Confirm a place from the suggestions for hotel search
*/
export async function confirmPlace(params) {
// Check if we have place suggestions
if (session.placeSuggestions.length === 0) {
return createJsonResponse({
status: "error",
message: "No place suggestions available. Please use the autocomplete-place tool first."
});
}
// Find the place in suggestions
const selectedPlace = session.placeSuggestions.find((place) => place.place_id === params.place_id);
if (!selectedPlace) {
return createJsonResponse({
status: "error",
message: `Place with ID ${params.place_id} not found in the suggestions. Please use a valid place ID from the autocomplete results.`
});
}
// Store the confirmed place
session.confirmedPlace = selectedPlace;
return createJsonResponse({
status: "success",
place: {
id: selectedPlace.place_id,
name: selectedPlace.structured_formatting?.main_text || selectedPlace.description,
location: selectedPlace.description,
},
message: "Place confirmed. You can now use the search-hotels tool to find hotels in this location."
});
}