Skip to main content
Glama

get-tickets

Query available train tickets on China's 12306 railway system by providing departure date, station codes, and optional train type filters.

Instructions

查询12306余票信息。

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
dateYes查询日期,格式为 "yyyy-MM-dd"。如果用户提供的是相对日期(如“明天”),请务必先调用 `get-current-date` 接口获取当前日期,并计算出目标日期。
fromStationYes出发地的 `station_code` 。必须是通过 `get-station-code-by-name` 或 `get-station-code-of-city` 接口查询得到的编码,严禁直接使用中文地名。
toStationYes到达地的 `station_code` 。必须是通过 `get-station-code-by-name` 或 `get-station-code-of-city` 接口查询得到的编码,严禁直接使用中文地名。
trainFilterFlagsNo车次筛选条件,默认为空,即不筛选。例如用户说“高铁票”,则应使用 "G"。可选标志:[G(高铁/城际),D(动车),Z(直达特快),T(特快),K(快速),O(其他),F(复兴号),S(智能动车组)]

Implementation Reference

  • The asynchronous handler function for the 'get-tickets' tool. It validates inputs, fetches ticket data from 12306 API using cookies, parses raw data into structured TicketInfo, applies train filters, and returns formatted text output.
    async ({ date, fromStation, toStation, trainFilterFlags }) => {
      // 检查日期是否早于当前日期
      if (!checkDate(date)) {
        return {
          content: [
            {
              type: 'text',
              text: 'Error: The date cannot be earlier than today.',
            },
          ],
        };
      }
      if (
        !Object.keys(STATIONS).includes(fromStation) ||
        !Object.keys(STATIONS).includes(toStation)
      ) {
        return {
          content: [{ type: 'text', text: 'Error: Station not found. ' }],
        };
      }
      const queryParams = new URLSearchParams({
        'leftTicketDTO.train_date': date,
        'leftTicketDTO.from_station': fromStation,
        'leftTicketDTO.to_station': toStation,
        purpose_codes: 'ADULT',
      });
      const queryUrl = `${API_BASE}/otn/leftTicket/query`;
      const cookies = await getCookie(API_BASE);
      if (cookies == null) {
        return {
          content: [
            {
              type: 'text',
              text: 'Error: get cookie failed. Check your network.',
            },
          ],
        };
      }
      const queryResponse = await make12306Request<LeftTicketsQueryResponse>(
        queryUrl,
        queryParams,
        { Cookie: formatCookies(cookies) }
      );
      if (queryResponse === null || queryResponse === undefined) {
        return {
          content: [{ type: 'text', text: 'Error: get tickets data failed. ' }],
        };
      }
      const ticketsData = parseTicketsData(queryResponse.data.result);
      let ticketsInfo: TicketInfo[];
      try {
        ticketsInfo = parseTicketsInfo(ticketsData, queryResponse.data.map);
      } catch (error) {
        console.error('Error: parse tickets info failed. ',error);
        return {
          content: [{ type: 'text', text: 'Error: parse tickets info failed. ' }],
        };
      }
      const filteredTicketsInfo = filterTicketsInfo<TicketInfo>(
        ticketsInfo,
        trainFilterFlags
      );
      return {
        content: [{ type: 'text', text: formatTicketsInfo(filteredTicketsInfo) }],
      };
    }
  • Zod schema defining the input parameters for the 'get-tickets' tool: date (yyyy-MM-dd), fromStation and toStation codes, and optional trainFilterFlags.
    {
      date: z
        .string()
        .length(10)
        .describe(
          '查询日期,格式为 "yyyy-MM-dd"。如果用户提供的是相对日期(如“明天”),请务必先调用 `get-current-date` 接口获取当前日期,并计算出目标日期。'
        ),
      fromStation: z
        .string()
        .describe(
          '出发地的 `station_code` 。必须是通过 `get-station-code-by-name` 或 `get-station-code-of-city` 接口查询得到的编码,严禁直接使用中文地名。'
        ),
      toStation: z
        .string()
        .describe(
          '到达地的 `station_code` 。必须是通过 `get-station-code-by-name` 或 `get-station-code-of-city` 接口查询得到的编码,严禁直接使用中文地名。'
        ),
      trainFilterFlags: z
        .string()
        .regex(/^[GDZTKOFS]*$/)
        .max(8)
        .optional()
        .default('')
        .describe(
          '车次筛选条件,默认为空,即不筛选。例如用户说“高铁票”,则应使用 "G"。可选标志:[G(高铁/城际),D(动车),Z(直达特快),T(特快),K(快速),O(其他),F(复兴号),S(智能动车组)]'
        ),
    },
  • src/index.ts:684-780 (registration)
    Registration of the 'get-tickets' tool using McpServer.tool(), including name, description, input schema, and handler function.
    server.tool(
      'get-tickets',
      '查询12306余票信息。',
      {
        date: z
          .string()
          .length(10)
          .describe(
            '查询日期,格式为 "yyyy-MM-dd"。如果用户提供的是相对日期(如“明天”),请务必先调用 `get-current-date` 接口获取当前日期,并计算出目标日期。'
          ),
        fromStation: z
          .string()
          .describe(
            '出发地的 `station_code` 。必须是通过 `get-station-code-by-name` 或 `get-station-code-of-city` 接口查询得到的编码,严禁直接使用中文地名。'
          ),
        toStation: z
          .string()
          .describe(
            '到达地的 `station_code` 。必须是通过 `get-station-code-by-name` 或 `get-station-code-of-city` 接口查询得到的编码,严禁直接使用中文地名。'
          ),
        trainFilterFlags: z
          .string()
          .regex(/^[GDZTKOFS]*$/)
          .max(8)
          .optional()
          .default('')
          .describe(
            '车次筛选条件,默认为空,即不筛选。例如用户说“高铁票”,则应使用 "G"。可选标志:[G(高铁/城际),D(动车),Z(直达特快),T(特快),K(快速),O(其他),F(复兴号),S(智能动车组)]'
          ),
      },
      async ({ date, fromStation, toStation, trainFilterFlags }) => {
        // 检查日期是否早于当前日期
        if (!checkDate(date)) {
          return {
            content: [
              {
                type: 'text',
                text: 'Error: The date cannot be earlier than today.',
              },
            ],
          };
        }
        if (
          !Object.keys(STATIONS).includes(fromStation) ||
          !Object.keys(STATIONS).includes(toStation)
        ) {
          return {
            content: [{ type: 'text', text: 'Error: Station not found. ' }],
          };
        }
        const queryParams = new URLSearchParams({
          'leftTicketDTO.train_date': date,
          'leftTicketDTO.from_station': fromStation,
          'leftTicketDTO.to_station': toStation,
          purpose_codes: 'ADULT',
        });
        const queryUrl = `${API_BASE}/otn/leftTicket/query`;
        const cookies = await getCookie(API_BASE);
        if (cookies == null) {
          return {
            content: [
              {
                type: 'text',
                text: 'Error: get cookie failed. Check your network.',
              },
            ],
          };
        }
        const queryResponse = await make12306Request<LeftTicketsQueryResponse>(
          queryUrl,
          queryParams,
          { Cookie: formatCookies(cookies) }
        );
        if (queryResponse === null || queryResponse === undefined) {
          return {
            content: [{ type: 'text', text: 'Error: get tickets data failed. ' }],
          };
        }
        const ticketsData = parseTicketsData(queryResponse.data.result);
        let ticketsInfo: TicketInfo[];
        try {
          ticketsInfo = parseTicketsInfo(ticketsData, queryResponse.data.map);
        } catch (error) {
          console.error('Error: parse tickets info failed. ',error);
          return {
            content: [{ type: 'text', text: 'Error: parse tickets info failed. ' }],
          };
        }
        const filteredTicketsInfo = filterTicketsInfo<TicketInfo>(
          ticketsInfo,
          trainFilterFlags
        );
        return {
          content: [{ type: 'text', text: formatTicketsInfo(filteredTicketsInfo) }],
        };
      }
    );

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/freestylefly/12306-mcp'

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