Skip to main content
Glama
timeaissr

datetime-mcp-server

by timeaissr

datetime MCP Server

A Model Context Protocol server providing current date/time queries, written in TypeScript, designed to be deployed on AWS Lambda and served over Streamable HTTP.

Features

  • Two MCP tools: get_date, get_datetime, output in ISO 8601 format

  • Optional timezone parameter: supports IANA timezone names (Asia/Shanghai) and UTC offsets (+08:00), defaults to UTC

  • Zero third-party time libraries: built entirely on Node.js built-in Intl (ICU), no moment/luxon/dayjs dependencies

  • Serverless deployment: single-file bundle (~2MB) + Lambda Web Adapter, millisecond responses on warm instances after cold start

  • Compliant with the latest MCP standard: Streamable HTTP transport, stateless operation mode, protocol version negotiation handled by the official SDK

Related MCP server: date-today-mcp

Architecture

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)

Key mechanisms:

Component

Description

Streamable HTTP

The only HTTP transport currently recommended by MCP; HTTP+SSE is deprecated

Stateless mode

Each request is self-contained with no session maintained, fitting Lambda's freeze/thaw model

enableJsonResponse: true

Responses go over plain JSON instead of SSE streams, avoiding Lambda response buffering limits

Lambda Web Adapter (LWA)

AWS official public Layer that translates Lambda invokes into real HTTP requests to localhost:8080

bootstrap script

The actual process entry point after LWA takes over (node dist/index.js); the handler field in the config is only a placeholder

MCP Tools

get_date

Returns the current calendar date, ISO 8601 YYYY-MM-DD.

Parameter

Type

Required

Description

timezone

string

No

IANA timezone name or UTC offset, defaults to "UTC"

{"result":{"content":[{"type":"text","text":"2026-08-24"}]}}

get_datetime

Returns the current date and time, ISO 8601 with an offset suffix (Z for UTC output).

{"result":{"content":[{"type":"text","text":"2026-08-23T14:30:00+08:00"}]}}

Error Behavior

  • Missing or blank timezone → treated as UTC

  • Non-empty but invalid timezone → returns an isError: true result with a hint message:

Error: Invalid IANA timezone "Mars/Olympus". Use a name like "UTC", "Asia/Shanghai" or "America/New_York".
  • Protocol-level errors (e.g., missing Accept header) are returned by the SDK as standard JSON-RPC errors

Time Source and Precision

Time is read from the runtime environment's system clock (new Date()). Locally, that is the machine clock (relying on NTP calibration); on Lambda, the host clock is automatically synchronized by the Amazon Time Sync Service (GPS/atomic clock source, PTP/NTP), with sub-millisecond error and no configuration required.

External NTP queries are deliberately not performed on every call: the AWS clock is already continuously synchronized, and external lookups would only add latency (+10~100ms), introduce network failure surfaces and rate-limit issues, without improving accuracy.

Output resolution is precise to the second (milliseconds are truncated). Timezone conversion is pure arithmetic — all timezones receive the same absolute instant, only the wall-clock representation differs.

Local Development

Requires 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

Local manual testing (the Accept header must declare both media types; this is the SDK's protocol validation):

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"}}}'

You can also use the official inspector: npx @modelcontextprotocol/inspector, selecting Streamable HTTP as the connection type.

Note: if the http_proxy environment variable is set on your machine, curl needs --noproxy '*', otherwise localhost requests will be intercepted by the proxy and return 502.

Project Structure

├── 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,零运行时依赖安装)

Technical Implementation Highlights

All timezone formatting is done through Intl.DateTimeFormat. Core techniques:

  1. Date: the en-CA locale naturally outputs YYYY-MM-DD, no manual assembly needed

  2. Time with offset: use formatToParts to get the target timezone's wall-clock fields → feed them into Date.UTC() as if they were UTC → subtract from the original instant to get a minute-level offset → format as ±HH:MM or Z

  3. hourCycle: "h23": avoids the "24" hour boundary bug that hour12: false can produce in some locales

  4. DST and special timezones: the offset is computed at the request instant, so DST transitions are naturally correct (New York -04:00-05:00); half-hour and quarter-hour timezones (India +05:30, Nepal +05:45, Chatham +12:45) are all covered by unit tests

  5. Formatter caching: Intl.DateTimeFormat instances are cached per timezone, so repeated calls on warm instances have zero construction overhead

  6. Timezone validation: construct Intl.DateTimeFormat in a try/catch; a thrown RangeError for invalid values means invalid. The newer ECMA-402 makes ICU also accept UTC offset strings (e.g., +08:00); the full chain has been verified to output correctly and is covered by tests

Deploying to AWS Lambda

Prerequisites: AWS CLI configured with credentials; an execution role with AWSLambdaBasicExecutionRole permission (if you don't have one, create it with the command below):

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

Option 1: CLI Script

ROLE_ARN=arn:aws:iam::<账号ID>:role/datetime-mcp-role ./deploy.sh

Optional environment variables: AWS_REGION (default us-east-1), FUNCTION_NAME (default datetime-mcp), ARCH (arm64/x86_64, default arm64).

Script flow: dynamically queries the latest LWA Layer version for the region → esbuild build → bsdtar packaging (for systems without the zip command) → create/update function (nodejs22.x, 512MB, 10s timeout) → create an unauthenticated Function URL and grant public invocation → output endpoint. Safe to re-run; automatically takes the update path.

Option 2: AWS Console

  1. Package locally:

    npm run build && bsdtar --format zip -cf function.zip bootstrap dist/index.js
  2. Lambda console → Create function → Author from scratch

    • Runtime: Node.js 22.x; Architecture: arm64

    • Permissions: Create a new role with basic Lambda permissions

  3. Code tab → Upload from → .zip file → select function.zip (the internal structure must be a root-level bootstrap + dist/index.js)

  4. Layers section → Add a layer → AWS layers → LambdaAdapterLayerArm64 (select the latest version)

  5. Configuration → Environment variables:

    Key

    Value

    AWS_LAMBDA_EXEC_WRAPPER

    /opt/bootstrap

    PORT

    8080

  6. Configuration → General configuration → Memory 512 MB, Timeout 10 s

  7. Configuration → Function URL → Create → Auth type NONE

When creating a NONE-type Function URL in the console, the public invocation resource policy is added automatically, so no add-permission is needed (this differs from the CLI).

A browser directly accessing the Function URL returning 405 is normal (only POST is allowed). To update code later: rebuild and repackage, then re-upload in the Code tab.

MCP Client Integration

Using opencode as an example, add a remote MCP server to the config:

{
  "mcp": {
    "datetime": {
      "type": "remote",
      "url": "https://<identifier>.lambda-url.<region>.on.aws/mcp"
    }
  }
}

Design Decision Record

Decision

Conclusion

Rationale

Language

TypeScript

Intl built-in timezone support with zero dependencies; fastest Lambda cold start (~100-200ms vs Python ~300-800ms); small bundle. Python's advantage is a more concise decorator syntax

Transport

Streamable HTTP + stateless + JSON response

Lambda has no persistent process, so stdio is not viable; no session state naturally matches the freeze/thaw model; plain JSON avoids SSE streaming limits

SDK version

Stable @modelcontextprotocol/sdk@1.x (1.30.0)

Correctly implements protocol version negotiation, backward compatible with older clients; new features in the 2026-07-28 revision (TTL caching, etc.) are meaningless for a static tool list; beta split-package API is not stable

Timezone implementation

Intl rather than third-party libraries

Zero dependencies, no need to install tzdata on Lambda, sufficient precision

Time source

System clock rather than per-call NTP

AWS already does sub-millisecond synchronization; external NTP lookups add latency/failure surface/cost with no accuracy benefit

Deployment

Manual CLI/console + LWA Layer

Avoids the upfront investment of SAM/CDK/Terraform; deploy.sh is just command batching, not IaC

Troubleshooting

Symptom

Cause and Solution

Not Acceptable: Client must accept both application/json and text/event-stream

Request is missing the Accept header. curl tests need -H "Accept: application/json, text/event-stream"; real MCP clients send it automatically

Handler 'handler' missing on module 'index'

Forgot to attach the LWA Layer or missed setting AWS_LAMBDA_EXEC_WRAPPER, so the runtime looks for a handler at the default path. Add the Layer and environment variables

GET /mcp returns 405

Expected behavior. Stateless mode does not support server-push streams; only POST is accepted

curl local test returns 502 with an extremely fast response

A system proxy intercepted localhost. Add --noproxy '*'

First request to the Function URL after cold start is slow

Caused by Lambda's freeze/thaw mechanism; subsequent requests are millisecond-level

zip: command not found when packaging

The zip package is not installed on the machine (on Arch it is a separate package from unzip). This project uses bsdtar (bundled with libarchive) instead, preserving permission bits

Known Limitations and Future Improvements

  • Defensive handler not added: if run bare on the default Node.js runtime (without LWA), the error message is obscure. A placeholder handler with a hint could be exported to improve the error experience on misconfiguration, with zero impact on the normal path

  • Output is only precise to the second; milliseconds are not exposed

  • No authentication or rate limiting — a public endpoint could be abused to inflate call volume (though the per-call cost approaches zero)

  • The alias table of Intl.supportedValuesOf("timeZone") is not used for parameter hints; error messages only give three examples

  • Migration from the stable 1.x SDK to the split packages (supporting the 2026-07-28 revision) will require tracking API changes

License

ISC

A
license - permissive license
Not graded
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • F
    license
    A
    quality
    Not graded
    maintenance
    Provides timezone-aware date and time information with configurable time formats and timezone support. Enables users to get current date and time in their preferred timezone and format through simple MCP tools.
    2
  • F
    license
    A
    quality
    C
    maintenance
    A simple MCP server that returns the current date and time with timezone information in ISO 8601, Unix timestamp, and human-readable formats.
    1
  • A
    license
    Not graded
    quality
    D
    maintenance
    Provides time-related tools including current time retrieval, timezone conversion, time formatting, and timezone info via MCP.
    15
    MIT

View all related MCP servers

Related MCP Connectors

  • Timezone MCP — wraps WorldTimeAPI (free, no auth)

  • A real clock for AI agents: current time, timezone conversion, and DST facts from the IANA tzdb.

  • Time MCP server via HTTP

View all MCP Connectors

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/timeaissr/datetime-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server