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
| Name | Required | Description | Default |
|---|---|---|---|
| date | Yes | 查询日期,格式为 "yyyy-MM-dd"。如果用户提供的是相对日期(如“明天”),请务必先调用 `get-current-date` 接口获取当前日期,并计算出目标日期。 | |
| fromStation | Yes | 出发地的 `station_code` 。必须是通过 `get-station-code-by-name` 或 `get-station-code-of-city` 接口查询得到的编码,严禁直接使用中文地名。 | |
| toStation | Yes | 到达地的 `station_code` 。必须是通过 `get-station-code-by-name` 或 `get-station-code-of-city` 接口查询得到的编码,严禁直接使用中文地名。 | |
| trainFilterFlags | No | 车次筛选条件,默认为空,即不筛选。例如用户说“高铁票”,则应使用 "G"。可选标志:[G(高铁/城际),D(动车),Z(直达特快),T(特快),K(快速),O(其他),F(复兴号),S(智能动车组)] |
Implementation Reference
- src/index.ts:714-779 (handler)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) }], }; }
- src/index.ts:687-713 (schema)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) }], }; } );