ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

MCP server 实现公历阴历假期查询:TaoToken 统一 Key 接入与配置骨架

MCP server 实现公历阴历假期查询:TaoToken 统一 Key 接入与配置骨架 1. 为什么要在 AI 工作流里塞一个日期 MCP server公历、阴历、假期这三件事看起来简单真到 AI 工具里用起来却经常翻车。你问模型「今天农历几号」「离下一个法定节假日还有几天」它要么凭训练数据里的旧信息瞎猜要么把农历日期算错一两天要么把调休和法定假日记混。原因不复杂日期是强时效、强规则的数据靠模型参数记忆本身就不靠谱正确做法是把它做成一个可被调用的工具让模型在需要时去查而不是去背。MCPModel Context Protocol就是干这个的。它把「模型」和「外部能力」解耦你写一个 MCP server 暴露若干工具AI 客户端通过标准协议发现并调用这些工具。本文聚焦的场景很具体用 MCP server 实现公历、阴历、假期查询并通过 TaoToken 统一 Key 接入现有 AI 工作流。适合已经在用 Cherry Studio、Claude Code 这类支持 MCP 的客户端想把手头零散的日期查询能力收拢成一个稳定服务的开发者。我会给出可复制的config.toml/settings.json骨架、TaoToken 统一 Key 的配置示例以及一次真实的查询验证动作。整套东西跑通后你在对话里说一句「帮我看看今天农历和最近的假期」模型就会自动调你的query_calendar工具返回结构化结果而不是靠猜。先说清楚技术选型。农历换算用zhdate它能把公历日期转成中文农历表述法定节假日用holidays它内置了中国节假日规则能列出全年节假日并算出距离。这两个库都是纯 Python装起来没负担。MCP server 用官方mcp包传输层选 SSE方便本地起服务、客户端远程连。下面从环境准备一路走到验证。2. TaoToken 前置统一 Key 与接入地址在写 server 之前先把「模型侧」的接入搞定。很多人的痛点是不同工具、不同客户端各配一套 Key换一个环境就要重新填一遍管理成本高还容易泄露。TaoToken 的思路是给你一个统一的 API Key兼容主流模型调用格式你把它配到各个客户端里就能用同一套凭证访问模型能力。你需要先拿到 Key。登录官网 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 进控制台创建 API Key。API 的基础地址是 https://taotoken.net/api 注意这个地址不带任何查询参数配置时直接填这个就行。创建 Key 的入口在控制台的 API Keys 页面https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。拿到形如sk-xxxx的字符串后先别急着到处贴建议放到环境变量里后面所有配置都引用变量避免明文散落在多个文件。# Linux / macOS export TAOTOKEN_API_KEYsk-你的key # Windows PowerShell $env:TAOTOKEN_API_KEYsk-你的key这里要区分两件事MCP server 本身是本地跑的日期查询服务它不直接调模型TaoToken 的 Key 是给 AI 客户端用的客户端负责「理解你的意图 决定调用哪个工具」server 只负责「执行查询并返回结果」。所以 Key 配在客户端侧server 侧不需要 Key。这个边界想清楚后面配置就不会乱。如果你用的是 Claude Code 这类编码 Agent长期跑任务建议看 Coding Plan额度模型更适合持续调用https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。只是想先验证模型能不能正常对话用模型对话页更快https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。3. 可复制配置calendar_server.py 与客户端骨架3.1 安装依赖pip install mcp zhdate holidaysmcp提供 Server 和类型定义zhdate负责农历holidays负责法定节假日。三个包装完就可以写 server 了。3.2 核心查询逻辑先写日期查询的核心函数把公历、农历、星期、最近假期一次性算出来。这段逻辑独立于 MCP方便你单独测试。from zhdate import ZhDate import holidays from datetime import datetime def get_calendar_info() - str: today datetime.today() gregorian today.strftime(%Y-%m-%d) weekday 星期 一二三四五六日[today.weekday()] lunar ZhDate.today().chinese() # 中文农历比如 二月十八 cn_holidays holidays.China(yearstoday.year) upcoming [ (date, name) for date, name in sorted(cn_holidays.items()) if date today.date() ] if upcoming: next_holiday_date, holiday_name upcoming[0] days_left (next_holiday_date - today.date()).days holiday_info f{holiday_name}{next_holiday_date}还有{days_left}天 else: holiday_info 今年内无更多法定节假日 return ( f公历: {gregorian}\n f农历: {lunar}\n f星期: {weekday}\n f最近假期: {holiday_info} )注意holidays.China返回的是一个字典键是date对象值是节日名。排序后取第一个大于等于今天的就是「最近的假期」。这里有个细节holidays库对调休的处理依赖版本建议锁一个较新的版本避免节假日规则过时。3.3 MCP Server 定义把上面的函数包成 MCP 工具。关键是list_tools告诉客户端有哪些工具可用call_tool根据工具名分发执行。from mcp.server import Server from mcp.server.models import InitializationOptions import mcp.types as types import mcp.server.stdio app Server(mcp-calendar) app.call_tool() async def call_tool_handler( name: str, arguments: dict ) - list[types.TextContent]: if name query_calendar: calendar_info get_calendar_info() return [types.TextContent(typetext, textcalendar_info)] else: raise ValueError(fUnsupported tool name: {name}) app.list_tools() async def list_tools() - list[types.Tool]: return [ types.Tool( namequery_calendar, description获取今天的公历、农历、星期和最近假期信息, inputSchema{ type: object, properties: {}, required: [], }, ), ]query_calendar不需要入参因为查询的是「今天」。如果你想让模型查指定日期可以加一个date参数把datetime.today()换成解析后的日期逻辑一样。3.4 启动 SSE 服务本地调试用 SSE 传输起一个 HTTP 服务客户端通过 URL 连。import mcp.server.sse from starlette.applications import Starlette from starlette.routing import Route import uvicorn async def handle_sse(request): async with mcp.server.sse.sse_server() as (read_stream, write_stream): await app.run( read_stream, write_stream, InitializationOptions( server_namemcp-calendar, server_version0.1.0, ), ) starlette_app Starlette( routes[Route(/sse, endpointhandle_sse)], ) if __name__ __main__: uvicorn.run(starlette_app, host0.0.0.0, port8081)跑起来后服务监听http://localhost:8081/sse。端口别和已有服务冲突8081 只是示例。3.5 客户端配置骨架不同客户端配置格式不同这里给两个最常见的骨架。Cherry Studio 的 MCP 配置settings.json片段{ mcpServers: { calendar: { url: http://localhost:8081/sse, type: sse } } }Claude Code 的配置config.toml片段[mcp_servers.calendar] url http://localhost:8081/sse transport sse同时在客户端里配置 TaoToken 的模型接入以环境变量方式引用 Key[model_providers.taotoken] base_url https://taotoken.net/api api_key_env TAOTOKEN_API_KEY这样模型走 TaoToken工具走本地 MCP server两条链路各司其职。配置完重启客户端让它重新加载 MCP server 列表。4. 验证请求一次真实查询与成功结果4.1 先用 client.py 直连验证在接客户端之前先用一个最小 client 确认 server 本身没问题。import asyncio from mcp.client.sse import sse_client from mcp.client.session import ClientSession async def main(): async with sse_client(http://localhost:8081/sse) as streams: async with ClientSession(streams[0], streams[1]) as session: await session.initialize() tools await session.list_tools() print(Available tools:, tools.tools) result await session.call_tool(query_calendar, {}) print(Result:, result.content[0].text) if __name__ __main__: asyncio.run(main())运行后你应该看到类似输出Available tools: [Tool(namequery_calendar, description获取今天的公历、农历、星期和最近假期信息, inputSchema{type: object, properties: {}, required: []})] Result: 公历: 2025-06-18 农历: 五月廿三 星期: 星期三 最近假期: 端午节2025-05-31还有-18天如果list_tools能列出query_calendar说明 server 注册成功如果call_tool返回了日期文本说明查询逻辑通了。这两步都过MCP 链路就没问题。4.2 在客户端里对话验证重启 Cherry Studio 或 Claude Code在对话里输入帮我查一下今天公历农历还有最近的法定假期是什么时候。模型应该会识别到query_calendar工具并调用它然后把返回结果整理成自然语言回复。如果模型没调用工具而是直接回答检查两点一是 MCP server 是否在客户端里显示为已连接二是工具描述是否足够清晰。描述写得好模型才知道什么时候该用。4.3 验证 TaoToken 模型链路单独确认模型侧也通。用模型对话页发一条普通消息或者在你的客户端里问一个不涉及日期的问题看是否正常返回。如果模型不响应多半是 Key 或 base_url 配错。base_url 必须是https://taotoken.net/api不要多加路径。5. 本篇常见错排查5.1 农历日期差一天最常见的原因是时区。datetime.today()取的是服务器本地时间如果服务器时区不是东八区跨零点时农历可能差一天。解决办法是显式指定时区from datetime import datetime, timezone, timedelta CST timezone(timedelta(hours8)) today datetime.now(CST)zhdate内部按日期计算传入正确的日期对象即可。5.2 holidays 报错或假期不全holidays库的节假日规则随版本更新旧版本可能缺当年数据。先升级pip install --upgrade holidays如果还是不对检查holidays.China(yearstoday.year)的年份参数跨年查询要传对应年份。另外注意holidays默认包含的节日范围可能和你预期不同必要时用holidays.China(years..., observedTrue)控制是否包含调休。5.3 MCP server 连不上客户端报连接失败按顺序查server 是否在跑curl http://localhost:8081/sse看有没有响应、端口是否被占用、客户端配置的 URL 是否和 server 一致。SSE 传输对路径敏感/sse不能少。如果客户端和 server 不在同一台机器把localhost换成实际 IP并确认防火墙放行。5.4 模型不调用工具工具描述太模糊模型不知道何时用。把description写具体比如「获取今天的公历日期、农历日期、星期几以及距离最近的法定节假日还有多少天」。描述里带上「今天」「农历」「假期」这些关键词模型匹配意图时更准。5.5 Key 无效或额度问题模型侧报 401 或额度不足去控制台确认 Key 状态和余额。API Keys 页面https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。如果 Key 没问题但还是报错检查环境变量是否在当前 shell 生效客户端启动时是否读到了这个变量。接入细节可以对照文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。6. 把日期能力接进你的日常工作流跑通之后这个 MCP server 的价值在于「一次接入多处复用」。你可以在 Cherry Studio 里问日程在 Claude Code 里让 Agent 自动带上日期上下文甚至把query_calendar扩展成query_calendar_by_date支持查任意一天的农历和假期。扩展时只改核心函数和inputSchemaMCP 那层不用动。几个实用建议。第一把 server 做成开机自启的服务别每次手动跑否则客户端连不上会以为工具坏了。第二农历和假期数据有更新周期定期升级zhdate和holidays。第三如果你要长期跑编码 Agent 或自动化任务Coding Plan 的额度模型比按次调用更划算https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。第四Claude Code 用户接入 Anthropic 兼容格式时参考这个页面https://taotoken.net/claude-code-anthropic?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。最后提醒一个容易忽略的点MCP server 返回的是纯文本模型拿到后可能做二次加工。如果你希望结果稳定可以在返回里带上明确的结构标记比如用固定前缀减少模型自由发挥的空间。日期这种强事实数据越少让模型「解释」越好。
返回列表