Skip to main content
Glama

search_travel

Search for hotels on Rakuten Travel by entering a keyword like hotel name or area.

Instructions

Search for hotels on Rakuten Travel by keyword. For availability/date/price search, use search_travel_vacancy instead.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
keywordYesSearch keyword (e.g., hotel name, area)
hitsNoNumber of results
pageNoPage number

Implementation Reference

  • The async handler function that executes the search_travel tool logic. Calls rakutenRequest to the travelKeywordHotelSearch endpoint, maps hotelBasicInfo from the response into a simplified result array, and returns JSON content.
    async ({ keyword, hits, page }) => {
      const data = (await rakutenRequest(
        ENDPOINTS.travelKeywordHotelSearch,
        { keyword, hits: String(hits), page: String(page) }
      )) as { hotels?: Array<{ hotel: Array<{ hotelBasicInfo: Record<string, unknown> }> }> };
    
      const hotels =
        data.hotels?.map((h) => {
          const info = h.hotel[0]?.hotelBasicInfo ?? {};
          return {
            name: info.hotelName,
            address: `${info.address1 ?? ""}${info.address2 ?? ""}`,
            price: info.hotelMinCharge,
            rating: info.reviewAverage,
            url: info.hotelInformationUrl,
            imageUrl: info.hotelImageUrl,
          };
        }) ?? [];
    
      return {
        content: [{ type: "text", text: JSON.stringify(hotels, null, 2) }],
      };
    }
  • Input schema for search_travel using zod: keyword (string, required), hits (number 1-30, default 10), page (number min 1, default 1).
    {
      keyword: z.string().describe("Search keyword (e.g., hotel name, area)"),
      hits: z.number().min(1).max(30).default(10).describe("Number of results"),
      page: z.number().min(1).default(1).describe("Page number"),
    },
  • src/index.ts:291-322 (registration)
    Registration of the tool named 'search_travel' on the MCP server via server.tool(), with a description string.
    server.tool(
      "search_travel",
      "Search for hotels on Rakuten Travel by keyword. For availability/date/price search, use search_travel_vacancy instead.",
      {
        keyword: z.string().describe("Search keyword (e.g., hotel name, area)"),
        hits: z.number().min(1).max(30).default(10).describe("Number of results"),
        page: z.number().min(1).default(1).describe("Page number"),
      },
      async ({ keyword, hits, page }) => {
        const data = (await rakutenRequest(
          ENDPOINTS.travelKeywordHotelSearch,
          { keyword, hits: String(hits), page: String(page) }
        )) as { hotels?: Array<{ hotel: Array<{ hotelBasicInfo: Record<string, unknown> }> }> };
    
        const hotels =
          data.hotels?.map((h) => {
            const info = h.hotel[0]?.hotelBasicInfo ?? {};
            return {
              name: info.hotelName,
              address: `${info.address1 ?? ""}${info.address2 ?? ""}`,
              price: info.hotelMinCharge,
              rating: info.reviewAverage,
              url: info.hotelInformationUrl,
              imageUrl: info.hotelImageUrl,
            };
          }) ?? [];
    
        return {
          content: [{ type: "text", text: JSON.stringify(hotels, null, 2) }],
        };
      }
    );
  • The ENDPOINTS constant defining the travelKeywordHotelSearch URL used by the search_travel handler.
    const ENDPOINTS = {
      ichibaItemSearch: "https://openapi.rakuten.co.jp/ichibams/api/IchibaItem/Search/20260401",
      ichibaItemRanking: "https://openapi.rakuten.co.jp/ichibaranking/api/IchibaItem/Ranking/20220601",
      ichibaGenreSearch: "https://openapi.rakuten.co.jp/ichibagt/api/IchibaGenre/Search/20170711",
      booksTotalSearch: "https://openapi.rakuten.co.jp/services/api/BooksTotal/Search/20170404",
      booksBookSearch: "https://openapi.rakuten.co.jp/services/api/BooksBook/Search/20170404",
      travelKeywordHotelSearch: "https://openapi.rakuten.co.jp/engine/api/Travel/KeywordHotelSearch/20170426",
      travelVacantHotelSearch: "https://openapi.rakuten.co.jp/engine/api/Travel/VacantHotelSearch/20170426",
    } as const;
  • The rakutenRequest helper function that makes authenticated API calls to Rakuten endpoints, used by the search_travel handler.
    async function rakutenRequest(
      endpointUrl: string,
      params: Record<string, string> = {}
    ): Promise<unknown> {
      const appId = getAppId();
      const accessKey = getAccessKey();
      const origin = getOrigin();
      const searchParams = new URLSearchParams({
        applicationId: appId,
        accessKey,
        format: "json",
        ...params,
      });
      const url = `${endpointUrl}?${searchParams}`;
      const res = await fetch(url, {
        headers: {
          Origin: origin,
          Referer: origin,
        },
      });
    
      if (!res.ok) {
        const status = res.status;
        const body = await res.text();
        throw new Error(`Rakuten API error (HTTP ${status}) on ${endpointUrl}: ${body.slice(0, 200)}`);
      }
    
      const text = await res.text();
      if (!text) return { success: true };
      try {
        return JSON.parse(text);
      } catch {
        throw new Error(`Rakuten API returned malformed JSON on ${endpointUrl}`);
      }
    }
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. It discloses the basic behavior (search by keyword) but omits details such as pagination behavior, rate limits, or what happens on no results. The mention of the vacancy tool hints at missing date-related functionality.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences, efficient and to the point. Every sentence adds value: the first states purpose, the second provides usage guidance.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers purpose and usage differentiation but lacks details about return values (no output schema). It would benefit from describing what the search results contain (e.g., hotel names, basic info).

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has 100% description coverage for all three parameters. The description reinforces that the keyword parameter is the main input but adds no new meaning beyond the schema. Baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description explicitly states the action ('Search for hotels'), the platform ('Rakuten Travel'), and the input method ('by keyword'). It clearly distinguishes itself from the sibling tool 'search_travel_vacancy' by specifying its scope.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit guidance on when to use this tool ('by keyword') and when to use the alternative ('For availability/date/price search, use search_travel_vacancy instead'), helping the agent choose correctly.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mrslbt/rakuten-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server