资讯详情

Klavis 12306-mcp:基于 Model Context Protocol 的火车票查询 MCP 服务器——工具参数与源码实现全解析

📅 2026/9/17 20:47:05 | 华诺云谱 👁 阅读
Klavis 12306-mcp:基于 Model Context Protocol 的火车票查询 MCP 服务器——工具参数与源码实现全解析
Klavis 12306-mcp基于 Model Context Protocol 的火车票查询 MCP 服务器——工具参数与源码实现全解析【免费下载链接】klavisKlavis AI: MCP integration platforms that let AI agents use tools reliably at any scale项目地址: https://gitcode.com/GitHub_Trending/kl/klavis本篇技术指南围绕 Klavis 仓库中的 12306-mcp 服务器 展开先完整介绍其安装、MCP 客户端配置与 Docker 部署方式再逐一解析其暴露的 7 个 MCP 工具查票、中转查询、经停站查询、车站编码解析等的参数与调用链最后结合 src/index.ts 与 src/types.ts 的源码讲清 12306 原始接口数据是如何被解析、过滤并转换成大模型可读文本的。读完本文你可以将该服务器接入任意 MCP 客户端并理解其字段级解析与过滤排序的内部机制。一、项目定位与功能边界12306-mcp 是一个基于 Model Context ProtocolMCP的 TypeScript 服务器提供简单 API 接口允许大模型通过 MCP 工具调用查询 12306 余票信息。其源码位于仓库的 mcp_servers/12306/ 目录核心实现集中在src/index.ts入口与工具注册和src/types.ts12306 原始报文与解析后数据的类型定义。根据 README 声明的功能状态表功能描述状态查询 12306 购票信息已完成过滤列车信息已完成过站查询经停站已完成中转查询已完成其余接口计划内package.json 显示当前版本为0.3.5依赖modelcontextprotocol/sdk ^1.12.1、express ^5.1.0、axios、date-fns/date-fns-tz上海时区日期处理、zod参数校验与https-proxy-agent。构建产物为dist/index.js并以bin: { 12306-mcp: ./dist/index.js }暴露为可执行命令。二、安装与快速开始以下命令完整继承自 README可复制执行。2.1 本地克隆安装git clone https://github.com/Joooook/12306-mcp.git npm i注意该命令克隆的是上游独立仓库。若你已在 Klavis 仓库内可直接进入mcp_servers/12306/执行npm iprepare脚本会自动触发tsc构建。2.2 CLI 运行方式stdio 模式本地进程方式接入客户端npx -y 12306-mcpHTTP 模式指定端口npx -y 12306-mcp --port [端口号]2.3 MCP 客户端配置标准的mcpServersJSON 配置{ mcpServers: { 12306-mcp: { command: npx, args: [ -y, 12306-mcp ] } } }2.4 Docker 部署stdio 方式docker build . -t 12306-mcp docker run --rm -it 12306-mcp npx 12306-mcpHTTP 方式docker build . -t 12306-mcp docker run -p [your_port]:8080 -d 12306-mcp npx 12306-mcp --port 8080仓库内的 Dockerfile 采用双阶段构建node:22-alpine构建阶段执行npm run buildnode:22-slim运行阶段仅拷贝dist/与生产依赖EXPOSE 5000并以node --dns-result-orderipv4first dist/index.js作为启动命令。Dockerfile 注释中还明确了代理相关的环境变量详见第六节。2.5 HTTP 传输层的源码实现从仓库当前源码看src/index.ts 末尾基于 Express 提供了两种 MCP 传输Streamable HTTP协议版本 2025-03-26POST /mcp每次请求新建一个StreamableHTTPServerTransport并完成server.connect(transport)GET /mcp与DELETE /mcp均返回 JSON-RPC 的Method not allowed错误。HTTPSSE协议版本 2024-11-05已标记弃用GET /sse建立SSEServerTransport并以sessionId存入内存 MapPOST /messages按sessionId路由消息。入口监听端口为硬编码的5000app.listen(5000, ...)。README 中的--port参数对应发布到 npm 的包行为本仓库源码中未见对应的命令行参数解析逻辑使用仓库源码直接运行时应以 5000 端口为准。三、MCP 工具全集参数、用途与调用关系服务器通过McpServer注册了 1 个 resource 和 7 个 tool。其中instructions字段index.ts内置了给大模型的路由指引优先理解意图查票 / 查经停站 / 查车站信息、注意日期格式与地点编码、信息不足时追问、尽量利用筛选参数缩短上下文。3.1 get-current-date相对日期解析入口参数说明无无入参获取当前日期以Asia/ShanghaiUTC8时区为准返回yyyy-MM-dd格式。其设计意图是让模型把明天下周三等相对日期先换算成绝对日期再传给其他需要date参数的工具实现见 index.ts。3.2 车站编码查询工具12306 接口要求使用station_code如VNP而非中文站名因此服务器提供了 4 个编码解析工具覆盖城市 → 车站与车站 → 车站两类需求工具参数说明get-station-code-of-cityscitys中文城市名多个用\|分割如北京\|上海查询代表城市的station_code内部取station_name city的车站见CITY_CODES构建逻辑get-stations-code-in-citycity单个中文城市名返回该城市所有火车站的名称与station_code列表CITY_STATIONSget-station-code-by-namesstationNames具体车站名多个用\|分割如北京南\|上海虹桥按车站名查station_code会自动剥掉末尾的站字get-station-by-telecodestationTelecode3 位字母 telecode已知 telecode 反查车站详情名称、拼音、城市等文档标注一般对话流程中较少直接触发这些工具全部是纯内存查询——不发起 12306 请求数据来源见下节的车站字典引导。3.3 get-tickets余票查询核心工具调用https://kyfw.12306.cn/otn/leftTicket/query参数完整定义含 zod 校验规则如下表参数类型/约束默认值说明datestring长度 10必填查询日期yyyy-MM-dd相对日期必须先调get-current-datefromStationstring必填出发地station_code严禁直接使用中文地名toStationstring必填到达地station_codetrainFilterFlagsstring正则^[GDZTKOFS]*$最长 8车次筛选G(高铁/城际)、D(动车)、Z(直达特快)、T(特快)、K(快速)、O(其他)、F(复兴号)、S(智能动车组)多标志为或关系earliestStartTimenumber0–240最早出发时间小时latestStartTimenumber0–2424最迟出发时间小时sortFlagstring排序startTime出发时间早到晚、arriveTime到达时间早到晚、duration历时短到长仅支持单一标识sortReversebooleanfalse是否逆向排序仅在设置sortFlag时生效limitedNumnumber≥00返回条数限制0 表示不限制csvFormatbooleanfalse是否以 CSV 格式返回处理流程index.ts先做日期合法性检查checkDate以上海时区比较早于当天直接报错与车站编码存在性检查再获取 cookie、发起查询最后依次执行parseTicketsData → parseTicketsInfo → filterTicketsInfo输出可读文本或 CSV。查询 URL 的 query 参数为leftTicketDTO.train_date、leftTicketDTO.from_station、leftTicketDTO.to_station与purpose_codesADULT成人票。3.4 get-interline-tickets中转查询查询中转余票当前实现仅支持前十条limitedNum约束min(1)默认 10。参数参数类型/约束默认值说明datestring长度 10必填同上fromStation/toStationstring必填起/终点station_codemiddleStationstring中转站station_code可选showWZbooleanfalse是否显示无座车trainFilterFlagsstring同get-ticketsearliestStartTime/latestStartTimenumber0–240/24同上sortFlag/sortReverse—/false同上limitedNumnumber≥110返回条数限制底层接口路径在启动时通过getLCQueryPath()从https://kyfw.12306.cn/otn/lcQuery/init页面中动态解析var lc_search_url得到index.ts请求参数含result_index0、can_queryY、purpose_codes00成人票、channelE。源码用一个while循环配合result_index递增与can_query N终止条件实现分页拉取直到凑够limitedNum条index.ts。返回文本包含出发→到达时间、出发站→中转站→到达站、换乘标志同车/同站/换站换乘、换乘等待时间与总历时并内嵌两段车票明细。3.5 get-train-route-stations经停站查询查询特定车次在指定区间内的经停站、到发时间与停留时间。参数参数说明trainNo实际车次编号train_no形如240000G10336而非G1033通常来自get-tickets结果中的train_no字段fromStationTelecode行程出发站的 3 位station_telecodetoStationTelecode行程到达站的 3 位station_telecodedepartDate出发日期yyyy-MM-dd相对日期先调get-current-date实现调用https://kyfw.12306.cn/otn/czxx/queryByTrainNoindex.ts经parseRouteStationsInfo把原始RouteStationDatatypes.ts映射为精简的RouteStationInfo首站取start_time作为arrive_time占位其余站取arrive_time输出 JSON 数组。3.6 stations resource除工具外服务器注册了一个 MCP resourceserver.resource(stations, data://all-stations, ...)index.ts将完整车站字典STATIONS以 JSON 形式暴露供支持 resource 的客户端直接订阅全量车站数据。四、车站字典的启动期引导STATIONS等字典是**模块加载时top-level await**预取的这是理解该服务器运行特性的关键getStations()index.ts先请求 12306 官网首页 HTML用正则./(\/script\/core\/common\/station_name.?\.js)/定位车站名 JS 文件地址再下载该 JS把var station_names ...去掉前缀后eval出原始字符串parseStationsData将这条以|分隔的大字符串按每 10 个字段一组切分对应 types.ts 中的StationDataKeys顺序station_id / station_name / station_code / station_pinyin / station_short / station_index / code / city / r1 / r2以station_code为键存入字典补充MISSING_STATIONS兜底数据目前硬编码了 12306 站点表中缺失的成都东WEI在此基础上派生三张索引表CITY_STATIONS城市 → 车站列表、CITY_CODES城市 → 城市名同名的代表车站、NAME_STATIONS车站名 → 车站。由此可以推断服务器启动依赖对 12306 官网的可达性若 12306 页面结构调整导致正则失配启动阶段会抛出Error: get station name js file failed.一类错误。五、12306 报文解析从管道分隔串到模型可读文本这是该服务器实现中最有技术含量的部分全部逻辑集中在 src/index.ts 的解析函数群。5.1 Cookie 获取每次业务请求前都会调用getCookie()index.tsGEThttps://kyfw.12306.cn/otn/leftTicket/init从响应头set-cookie中解析键值对parseCookies去掉Path、HttpOnly等属性再经formatCookies拼回k1v1; k2v2形式随后续请求带上。cookie 获取失败会直接返回Error: get cookie failed. Check your network.。5.2 余票数据按字段位序解析/otn/leftTicket/query返回的data.result是若干以|分隔的字符串字段没有 key。parseTicketsDataindex.ts严格按 types.ts 中TicketDataKeys的 57 个字段顺序逐一取值还原出结构化TicketData——其中包含train_no、station_train_code、start_time/arrive_time/lishi、57 位中的dw_flag、yp_info_new、seat_discount_info以及各坐席余票数swz_num/gr_num/.../srrb_num等。parseTicketsInfo再完成日期推算用date-fns将start_train_dateyyyyMMdd解析后叠加start_time得出发时刻叠加lishi历时得到达时刻输出start_date/arrive_dateyyyy-MM-dd跨天列车由此获得正确的到达日期站点翻译用响应体data.map把from_station_telecode/to_station_telecode翻译为中文站名。5.3 票价与折扣定长分段协议extractPricesindex.ts解析两段定长字符串seat_discount_info按每 5 字符一段第 1 位是坐席类型码后 4 位是折扣值yp_info_new按每 10 字符一段price_str[0]为坐席类型码slice(1, 6)为价格除以 10 得元slice(6, 10)≥ 3000 时按 12306 前端 JS 逆向规则判定为无座源码注释原文根据12306的js逆向出来的不懂未收录的类型码归入H其他坐席。坐席类型码表SEAT_TYPESindex.ts覆盖了9商务座、P特等座、M/D一等/优选一等、O/S二等、6/A高软卧/高级动卧、4/I/F软卧类、3/J硬卧类、2软座、1硬座、W/WZ无座等并映射到中文短名swz/tz/zy/ze/gr/rw/yw/rz/yz/wz/qt。余票数从TicketData中按短名取xxx_num字段formatTicketStatus再把数字/状态串语义化数字 0 → 无票N→ 剩余N张票有/充足→ 有票候补→ 无票需候补无/--/空→ 无票。5.4 特色标签dw_flag 位段解码extractDWFlagsindex.ts把dw_flag按#分段后按位解码第 0 段为5表示智能动车组第 1 段为1表示复兴号第 2 段以Q/R开头分别表示静音车厢/温馨动卧第 5 段为D表示动感号第 6/7 段非z分别表示支持选铺/老年优惠。解码结果进入TicketInfo.dw_flag数组在输出中以连接没有标签时显示/。5.5 过滤、排序与截断filterTicketsInfoindex.ts实现了 README 宣称的过滤列车信息能力对直连与中转结果通用泛型T extends TicketInfo | InterlineInfo车次类型过滤TRAIN_FILTERS表按首位字母匹配start_train_code——G同时匹配G与C开头城际O是以上都不是的补集过滤器F复兴号、S智能动车组则依赖dw_flag文本包含判断对中转结果取ticketList[0].dw_flag判定出发时间窗过滤保留earliestStartTime 出发时点 latestStartTime的车次排序TIME_COMPARETOR提供startTime/arriveTime先比日期再比时分与duration历时hh:mm数值比较三组比较器sortReverse时整体反转截断limitedNum 0时slice(0, limitedNum)。最终输出由formatTicketsInfo或formatTicketsInfoCSV渲染。注意两种输出格式都刻意保留了train_no与telecode如G1234(实际车次train_no: 240000G12336)正是为了让模型拿到get-train-route-stations所需的衔接参数形成查票 → 查经停站的工具链闭环。5.6 中转历时解析中转接口的all_lishi是 H小时M分钟 的自然语言格式extractLishiindex.ts用正则/(?:(\d)小时)?(\d?)分钟/归一为与直连数据一致的hh:mm供同一套duration排序器使用。六、代理支持与网络配置服务器对代理的支持通过环境变量完成getProxyUrl/getHttpsAgentindex.ts的优先级与取值如下变量说明HTTPS_PROXY/HTTP_PROXY直接给出完整代理 URL优先生效PROXY_HOSTPROXY_PORT组合构造http://[user:pass]host:port端口默认80PROXY_USERNAME/PROXY_PASSWORD与上组配合的鉴权信息配置代理后使用HttpsProxyAgentrejectUnauthorized: false否则使用普通https.Agent并显式family: 4强制 IPv4——与 Dockerfile 中--dns-result-orderipv4first的启动参数相互印证意在规避 12306 侧 IPv6 可达性问题。所有 12306 请求make12306Request统一 30 秒超时异常时打印Error making 12306 request:并返回null由上层工具转成模型可读的错误文本。七、运行前提与限制数据源依赖查询能力完全依赖kyfw.12306.cn相关接口与官网页面的可用性接口返回格式如 57 字段位序、yp_info_new定长分段变化会直接影响解析结果README 亦声明本项目仅用于学习。启动期网络依赖车站字典在模块加载期同步拉取网络不可达会导致进程启动失败而非运行期报错。端口仓库内源码固定监听5000Docker 场景按 Dockerfile 的EXPOSE 5000映射即可。中转查询深度get-interline-tickets当前实现仅支持前十条结果limitedNum下限为 1。日期边界get-tickets与get-interline-tickets均拒绝早于当天上海时区的日期。八、延伸阅读路径mcp_servers/12306/src/index.ts全部工具注册、传输层与解析函数mcp_servers/12306/src/types.tsTicketData/InterlineData/StationData等原始报文与TicketInfo/InterlineInfo/Price等输出模型的定义mcp_servers/12306/package.json、mcp_servers/12306/tsconfig.json构建配置ES2022 Node16 模块、tsc产出dist/mcp_servers/12306/Dockerfile双阶段构建与代理环境变量注释仓库内其他同类 MCP 服务器可对照 mcp_servers/README.md 浏览。【免费下载链接】klavisKlavis AI: MCP integration platforms that let AI agents use tools reliably at any scale项目地址: https://gitcode.com/GitHub_Trending/kl/klavis创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。