Skip to main content
Glama

get-interline-tickets

Find available interline train tickets on China's 12306 railway system by specifying departure, destination, and optional transfer stations. This tool displays up to 10 results for planning multi-leg journeys.

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` 接口查询得到的编码,严禁直接使用中文地名。
middleStationNo中转地的 `station_code` ,可选。必须是通过 `get-station-code-by-name` 或 `get-station-code-of-city` 接口查询得到的编码,严禁直接使用中文地名。
showWZNo是否显示无座车,默认不显示无座车。
trainFilterFlagsNo车次筛选条件,默认为空。从以下标志中选取多个条件组合[G(高铁/城际),D(动车),Z(直达特快),T(特快),K(快速),O(其他),F(复兴号),S(智能动车组)]

Implementation Reference

  • The main handler function for 'get-interline-tickets' tool. It validates input, fetches data from 12306 interline API (/lcquery/queryG), handles errors, parses the response using parseInterlinesInfo, applies train filters, and formats the output using formatInterlinesInfo.
    async ({
      date,
      fromStation,
      toStation,
      middleStation,
      showWZ,
      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 queryUrl = `${API_BASE}/lcquery/queryG`;
      const queryParams = new URLSearchParams({
        train_date: date,
        from_station_telecode: fromStation,
        to_station_telecode: toStation,
        middle_station: middleStation,
        result_index: '0',
        can_query: 'Y',
        isShowWZ: showWZ ? 'Y' : 'N',
        purpose_codes: '00', // 00: 成人票 0X: 学生票
        channel: 'E', // 没搞清楚什么用
      });
      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<InterlineQueryResponse>(
        queryUrl,
        queryParams,
        { Cookie: formatCookies(cookies) }
      );
      // 处理请求错误
      if (queryResponse === null || queryResponse === undefined) {
        return {
          content: [
            {
              type: 'text',
              text: 'Error: request interline tickets data failed. ',
            },
          ],
        };
      }
      // 请求成功,但查询有误
      if (typeof queryResponse.data == 'string') {
        return {
          content: [{ type: 'text', text: queryResponse.errorMsg }],
        };
      }
      // 请求和查询都没问题
      let interlineTicketsInfo: InterlineInfo[];
      try {
        interlineTicketsInfo = parseInterlinesInfo(queryResponse.data.middleList);
      } catch (error) {
        return {
          content: [
            { type: 'text', text: `Error: parse tickets info failed. ${error}` },
          ],
        };
      }
      const filteredInterlineTicketsInfo = filterTicketsInfo<InterlineInfo>(
        interlineTicketsInfo,
        trainFilterFlags
      );
      return {
        content: [
          {
            type: 'text',
            text: formatInterlinesInfo(filteredInterlineTicketsInfo),
          },
        ],
      };
    }
  • Zod schema defining the input parameters for the 'get-interline-tickets' tool, including date, stations, middle station, showWZ flag, and train filters.
      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` 接口查询得到的编码,严禁直接使用中文地名。'
        ),
      middleStation: z
        .string()
        .optional()
        .default('')
        .describe(
          '中转地的 `station_code` ,可选。必须是通过 `get-station-code-by-name` 或 `get-station-code-of-city` 接口查询得到的编码,严禁直接使用中文地名。'
        ),
      showWZ: z
        .boolean()
        .optional()
        .default(false)
        .describe('是否显示无座车,默认不显示无座车。'),
      trainFilterFlags: z
        .string()
        .regex(/^[GDZTKOFS]*$/)
        .max(8)
        .optional()
        .default('')
        .describe(
          '车次筛选条件,默认为空。从以下标志中选取多个条件组合[G(高铁/城际),D(动车),Z(直达特快),T(特快),K(快速),O(其他),F(复兴号),S(智能动车组)]'
        ),
    },
  • src/index.ts:809-947 (registration)
    Registration of the 'get-interline-tickets' tool using server.tool, including name, description, input schema, and handler function.
    server.tool(
      'get-interline-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` 接口查询得到的编码,严禁直接使用中文地名。'
          ),
        middleStation: z
          .string()
          .optional()
          .default('')
          .describe(
            '中转地的 `station_code` ,可选。必须是通过 `get-station-code-by-name` 或 `get-station-code-of-city` 接口查询得到的编码,严禁直接使用中文地名。'
          ),
        showWZ: z
          .boolean()
          .optional()
          .default(false)
          .describe('是否显示无座车,默认不显示无座车。'),
        trainFilterFlags: z
          .string()
          .regex(/^[GDZTKOFS]*$/)
          .max(8)
          .optional()
          .default('')
          .describe(
            '车次筛选条件,默认为空。从以下标志中选取多个条件组合[G(高铁/城际),D(动车),Z(直达特快),T(特快),K(快速),O(其他),F(复兴号),S(智能动车组)]'
          ),
      },
      async ({
        date,
        fromStation,
        toStation,
        middleStation,
        showWZ,
        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 queryUrl = `${API_BASE}/lcquery/queryG`;
        const queryParams = new URLSearchParams({
          train_date: date,
          from_station_telecode: fromStation,
          to_station_telecode: toStation,
          middle_station: middleStation,
          result_index: '0',
          can_query: 'Y',
          isShowWZ: showWZ ? 'Y' : 'N',
          purpose_codes: '00', // 00: 成人票 0X: 学生票
          channel: 'E', // 没搞清楚什么用
        });
        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<InterlineQueryResponse>(
          queryUrl,
          queryParams,
          { Cookie: formatCookies(cookies) }
        );
        // 处理请求错误
        if (queryResponse === null || queryResponse === undefined) {
          return {
            content: [
              {
                type: 'text',
                text: 'Error: request interline tickets data failed. ',
              },
            ],
          };
        }
        // 请求成功,但查询有误
        if (typeof queryResponse.data == 'string') {
          return {
            content: [{ type: 'text', text: queryResponse.errorMsg }],
          };
        }
        // 请求和查询都没问题
        let interlineTicketsInfo: InterlineInfo[];
        try {
          interlineTicketsInfo = parseInterlinesInfo(queryResponse.data.middleList);
        } catch (error) {
          return {
            content: [
              { type: 'text', text: `Error: parse tickets info failed. ${error}` },
            ],
          };
        }
        const filteredInterlineTicketsInfo = filterTicketsInfo<InterlineInfo>(
          interlineTicketsInfo,
          trainFilterFlags
        );
        return {
          content: [
            {
              type: 'text',
              text: formatInterlinesInfo(filteredInterlineTicketsInfo),
            },
          ],
        };
      }
    );
  • Helper function to parse raw InterlineData from API into structured InterlineInfo array, used in the handler.
    function parseInterlinesInfo(interlineData: InterlineData[]): InterlineInfo[] {
      const result: InterlineInfo[] = [];
      for (const ticket of interlineData) {
        const interlineTickets = parseInterlinesTicketInfo(ticket.fullList);
        result.push({
          all_lishi: ticket.all_lishi,
          start_time: ticket.start_time,
          start_date: ticket.train_date,
          middle_date: ticket.middle_date,
          arrive_date: ticket.arrive_date,
          arrive_time: ticket.arrive_time,
          from_station_code: ticket.from_station_code,
          from_station_name: ticket.from_station_name,
          middle_station_code: ticket.middle_station_code,
          middle_station_name: ticket.middle_station_name,
          end_station_code: ticket.end_station_code,
          end_station_name: ticket.end_station_name,
          start_train_code: interlineTickets[0].start_train_code,
          first_train_no: ticket.first_train_no,
          second_train_no: ticket.second_train_no,
          train_count: ticket.train_count,
          ticketList: interlineTickets,
          same_station: ticket.same_station == '0' ? true : false,
          same_train: ticket.same_train == 'Y' ? true : false,
          wait_time: ticket.wait_time,
        });
      }
      return result;
    }
  • Helper function to format InterlineInfo array into a readable text summary for the tool response.
    function formatInterlinesInfo(interlinesInfo: InterlineInfo[]): string {
      let result =
        '出发时间 -> 到达时间 | 出发车站 -> 中转车站 -> 到达车站 | 换乘标志 |换乘等待时间| 总历时\n\n';
      interlinesInfo.forEach((interlineInfo) => {
        result += `${interlineInfo.start_date} ${interlineInfo.start_time} -> ${interlineInfo.arrive_date} ${interlineInfo.arrive_time} | `;
        result += `${interlineInfo.from_station_name} -> ${interlineInfo.middle_station_name} -> ${interlineInfo.end_station_name} | `;
        result += `${
          interlineInfo.same_train
            ? '同车换乘'
            : interlineInfo.same_station
            ? '同站换乘'
            : '换站换乘'
        } | ${interlineInfo.wait_time} | ${interlineInfo.all_lishi}\n\n`;
        result +=
          '\t' + formatTicketsInfo(interlineInfo.ticketList).replace(/\n/g, '\n\t');
        result += '\n';
      });
      return result;
    }

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