datetime-mcp-server
Enables querying current date and time via MCP tools, with timezone support and ISO 8601 formatted output.
README
datetime MCP Server
一个提供当前日期/时间查询的 Model Context Protocol 服务器,采用 TypeScript 编写,设计为部署在 AWS Lambda 上,通过 Streamable HTTP 对外提供服务。
功能特性
- 两个 MCP 工具:
get_date、get_datetime,输出 ISO 8601 格式 - 可选时区参数:支持 IANA 时区名(
Asia/Shanghai)和 UTC 偏移量(+08:00),默认 UTC - 零第三方时间库:完全基于 Node.js 内建
Intl(ICU),无 moment/luxon/dayjs 依赖 - Serverless 部署:单文件 bundle(约 2MB)+ Lambda Web Adapter,冷启动后热实例毫秒级响应
- 符合最新 MCP 标准:Streamable HTTP 传输、stateless 运行模式、协议版本协商由官方 SDK 处理
架构
MCP Client ──HTTP POST /mcp──▶ Function URL ──▶ Lambda 函数
│
├─ LWA Layer (AWS_LAMBDA_EXEC_WRAPPER=/opt/bootstrap)
│ └─ 执行 zip 根目录 bootstrap → node dist/index.js
│
└─ Express app (端口 8080)
└─ POST /mcp → StreamableHTTPServerTransport
(stateless:每请求新建 transport,
enableJsonResponse 返回普通 JSON)
关键机制:
| 组件 | 说明 |
|---|---|
| Streamable HTTP | MCP 当前唯一推荐的 HTTP 传输;HTTP+SSE 已废弃 |
| Stateless 模式 | 每个请求自包含、不维护会话,与 Lambda 的冻结/解冻模型契合 |
enableJsonResponse: true |
响应走普通 JSON 而非 SSE 流,避开 Lambda 响应缓冲限制 |
| Lambda Web Adapter (LWA) | AWS 官方公共 Layer,把 Lambda invoke 翻译成对 localhost:8080 的真实 HTTP 请求 |
bootstrap 脚本 |
LWA 接管后的真正进程入口(node dist/index.js);配置里的 handler 字段只是占位符 |
MCP 工具
get_date
返回当前日历日期,ISO 8601 YYYY-MM-DD。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
timezone |
string | 否 | IANA 时区名或 UTC 偏移量,默认 "UTC" |
{"result":{"content":[{"type":"text","text":"2026-08-24"}]}}
get_datetime
返回当前日期时间,ISO 8601 带偏移量后缀(UTC 输出用 Z)。
{"result":{"content":[{"type":"text","text":"2026-08-23T14:30:00+08:00"}]}}
错误行为
- 时区缺失或空白字符串 → 视为 UTC
- 非空但非法的时区 → 返回
isError: true结果,附提示信息:
Error: Invalid IANA timezone "Mars/Olympus". Use a name like "UTC", "Asia/Shanghai" or "America/New_York".
- 协议层错误(如缺少 Accept 头)由 SDK 返回标准 JSON-RPC error
时间来源与精度
时间读取自运行环境的系统时钟(new Date())。本地即本机时钟(依赖 NTP 校准);在 Lambda 上宿主机时钟由 Amazon Time Sync Service(GPS/原子钟源,PTP/NTP)自动同步,误差毫秒级以内,无需任何配置。
刻意不做每次查询外部 NTP:AWS 时钟已持续同步,外查只会增加延迟(+10~100ms)、引入网络故障面和限流问题,准确度不会更高。
输出分辨率精确到秒(毫秒被截断)。时区转换是纯算术——所有时区拿到的是同一绝对瞬间,只是墙上时间表示不同。
本地开发
要求 Node.js ≥ 22。
npm install # 安装依赖
npm run dev # 构建 + 启动(默认 http://localhost:3000/mcp)
npm test # vitest 单测(14 个用例)
npm run typecheck # tsc --noEmit
npm run lint # eslint
npm run build # esbuild 打包为 CJS 单文件 dist/index.js
本地手动测试(Accept 头必须同时声明两种媒体类型,这是 SDK 的协议校验):
curl -s http://localhost:3000/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_datetime","arguments":{"timezone":"Asia/Shanghai"}}}'
也可使用官方调试器:npx @modelcontextprotocol/inspector,连接类型选 Streamable HTTP。
注意本机若设置了
http_proxy环境变量,curl 需加--noproxy '*',否则 localhost 请求会被代理拦截返回 502。
项目结构
├── src/
│ ├── time.ts # 核心纯函数:ISO 格式化、时区校验(可独立单测)
│ ├── server.ts # McpServer 实例 + 工具注册
│ └── index.ts # Express app + stateless transport 挂载 + 进程入口
├── test/
│ └── time.test.ts # 固定时间戳验证多时区/DST/半小时偏移/错误输入
├── build.mjs # esbuild 构建脚本(bundle: platform=node22, format=cjs)
├── bootstrap # LWA 进入口(zip 根目录,需可执行位 755)
├── deploy.sh # CLI 一键部署脚本
├── function.zip # 部署包(构建产物,不入库)
└── dist/index.js # 打包产物(约 2MB,零运行时依赖安装)
技术实现要点
时区格式化全部通过 Intl.DateTimeFormat 完成,核心技巧:
- 日期:
en-CAlocale 天然输出YYYY-MM-DD,无需手工拼装 - 带偏移量的时间:
formatToParts取目标时区的墙上时间各字段 → 用Date.UTC()把它当作 UTC 反算 → 与原始 instant 相减得到分钟级 offset → 格式化为±HH:MM或Z hourCycle: "h23":避免hour12: false在某些 locale 下产生"24"小时的边界 bug- DST 与特殊时区:offset 按请求时刻计算,夏令时切换自然正确(纽约
-04:00→-05:00),半小时/刻钟时区(印度+05:30、尼泊尔+05:45、查塔姆+12:45)均被单测覆盖 - Formatter 缓存:按 timezone 缓存
Intl.DateTimeFormat实例,热实例上重复调用零构造开销 - 时区校验:try/catch 构造
Intl.DateTimeFormat,非法值抛RangeError即视为无效。新版 ECMA-402 使 ICU 同时接受 UTC 偏移量字符串(如+08:00),已验证整条链路输出正确并纳入测试
部署到 AWS Lambda
前置条件:AWS CLI 已配置凭证;一个含 AWSLambdaBasicExecutionRole 权限的执行角色(没有可用下面命令创建):
aws iam create-role --role-name datetime-mcp-role \
--assume-role-policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"},"Action":"sts:AssumeRole"}]}'
aws iam attach-role-policy --role-name datetime-mcp-role \
--policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
方式一:CLI 脚本
ROLE_ARN=arn:aws:iam::<账号ID>:role/datetime-mcp-role ./deploy.sh
可选环境变量:AWS_REGION(默认 us-east-1)、FUNCTION_NAME(默认 datetime-mcp)、ARCH(arm64/x86_64,默认 arm64)。
脚本流程:动态查询区域最新的 LWA Layer 版本 → esbuild 构建 → bsdtar 打包(系统无 zip 命令)→ create/update 函数(nodejs22.x、512MB、超时 10s)→ 创建无鉴权 Function URL 并授权公开调用 → 输出 endpoint。重复运行安全,自动走更新路径。
方式二:AWS 控制台
- 本地打包:
npm run build && bsdtar --format zip -cf function.zip bootstrap dist/index.js - Lambda 控制台 → Create function → Author from scratch
- Runtime:Node.js 22.x;Architecture:arm64
- Permissions:Create a new role with basic Lambda permissions
- Code 页签 → Upload from → .zip file → 选择
function.zip(内部结构必须是根目录bootstrap+dist/index.js) - Layers 区 → Add a layer → AWS layers → LambdaAdapterLayerArm64(选最新版本)
- Configuration → Environment variables:
Key Value AWS_LAMBDA_EXEC_WRAPPER/opt/bootstrapPORT8080 - Configuration → General configuration → Memory 512 MB、Timeout 10 s
- Configuration → Function URL → Create → Auth type NONE
控制台创建 NONE 类型 Function URL 时会自动添加公开调用的资源策略,无需再执行
add-permission(这是与 CLI 的差异)。
浏览器直接访问 Function URL 返回 405 属正常(仅允许 POST)。以后更新代码:重新构建打包后在 Code 页签重新 Upload 即可。
MCP 客户端接入
以 opencode 为例,在配置中添加 remote MCP server:
{
"mcp": {
"datetime": {
"type": "remote",
"url": "https://<identifier>.lambda-url.<region>.on.aws/mcp"
}
}
}
设计决策记录
| 决策 | 结论 | 理由 |
|---|---|---|
| 语言 | TypeScript | Intl 内建时区支持零依赖;Lambda 冷启动最快(~100-200ms vs Python ~300-800ms);bundle 小。Python 优势是装饰器写法更简洁 |
| 传输模式 | Streamable HTTP + stateless + JSON response | Lambda 无持久进程,stdio 不可行;无会话状态天然匹配冻结/解冻模型;纯 JSON 避开 SSE 流式限制 |
| SDK 版本 | 稳定版 @modelcontextprotocol/sdk@1.x(1.30.0) |
正确实现协议版本协商,向后兼容旧客户端;2026-07-28 修订版的新特性(TTL 缓存等)对静态工具列表无意义;beta 拆分包 API 未稳定 |
| 时区实现 | Intl 而非第三方库 |
零依赖、Lambda 上无需补装 tzdata、精度足够 |
| 时间源 | 系统时钟而非每次查 NTP | AWS 已做亚毫秒同步;NTP 外查增加延迟/故障面/成本且无准确度收益 |
| 部署 | 手动 CLI/控制台 + LWA Layer | 不引入 SAM/CDK/Terraform 的前期投入;deploy.sh 仅是命令批处理,非 IaC |
故障排查
| 现象 | 原因与解决 |
|---|---|
Not Acceptable: Client must accept both application/json and text/event-stream |
请求缺 Accept 头。curl 测试需带 -H "Accept: application/json, text/event-stream";真实 MCP 客户端自动携带 |
Handler 'handler' missing on module 'index' |
忘记挂 LWA Layer 或漏设 AWS_LAMBDA_EXEC_WRAPPER,运行时按默认路径找 handler 导致。补齐 Layer 和环境变量即可 |
| GET /mcp 返回 405 | 符合预期。stateless 模式不支持服务端推送流,仅接受 POST |
| curl 本地测试返回 502 且响应极快 | 系统代理拦截了 localhost。加 --noproxy '*' |
| Function URL 冷启动首个请求慢 | Lambda 冻结/解冻机制所致,后续请求毫秒级 |
打包时报 zip: command not found |
本机未装 zip 包(Arch 上与 unzip 是两个包)。本项目已改用 bsdtar(libarchive 自带),保留权限位 |
已知限制与未来改进
- 防御性 handler 未添加:若裸跑于默认 Node.js 运行时(无 LWA),报错信息晦涩。可导出一个提示性的占位 handler 改善误配置时的报错体验,对正常路径零影响
- 输出仅到秒级精度,未暴露毫秒
- 未做鉴权与限流——公开 endpoint 可能被滥用刷调用量(虽然单次成本趋近于零)
Intl.supportedValuesOf("timeZone")的别名表未用于参数提示,错误信息只给了三个示例- SDK 未来从稳定版 1.x 迁移到拆分包(支持 2026-07-28 修订版)时需跟进 API 变更
License
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。