Skip to main content
Glama
timeaissr

datetime-mcp-server

by timeaissr

datetime MCP Server

Ein Model Context Protocol-Server für aktuelle Datums-/Zeitabfragen, geschrieben in TypeScript, konzipiert für die Bereitstellung auf AWS Lambda und bereitgestellt über Streamable HTTP.

Funktionen

  • Zwei MCP-Tools: get_date, get_datetime, Ausgabe im ISO-8601-Format

  • Optionaler Zeitzonenparameter: Unterstützt IANA-Zeitzonennamen (Asia/Shanghai) und UTC-Offsets (+08:00), Standard ist UTC

  • Keine Drittanbieter-Zeitbibliotheken: Vollständig auf Node.js-eingebautem Intl (ICU) basierend, keine moment/luxon/dayjs-Abhängigkeiten

  • Serverless-Bereitstellung: Single-File-Bundle (ca. 2 MB) + Lambda Web Adapter, nach Kaltstart Millisekunden-Antwortzeiten auf warmen Instanzen

  • Entspricht dem neuesten MCP-Standard: Streamable-HTTP-Transport, stateless-Betriebsmodus, Protokollversionsaushandlung vom offiziellen SDK übernommen

Related MCP server: date-today-mcp

Architektur

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)

Wichtige Mechanismen:

Komponente

Beschreibung

Streamable HTTP

Der einzige derzeit empfohlene HTTP-Transport für MCP; HTTP+SSE ist veraltet

Stateless-Modus

Jede Anfrage ist in sich abgeschlossen, keine Sitzungen, passt zum Freeze/Thaw-Modell von Lambda

enableJsonResponse: true

Antwort läuft über normales JSON statt SSE-Stream, umgeht Lambda-Antwortpuffer-Beschränkungen

Lambda Web Adapter (LWA)

Offizielle öffentliche AWS-Layer, übersetzt Lambda-Invokes in echte HTTP-Anfragen an localhost:8080

bootstrap-Skript

Der eigentliche Prozesseinstieg nach Übernahme durch LWA (node dist/index.js); das handler-Feld in der Konfiguration ist nur ein Platzhalter

MCP-Tools

get_date

Gibt das aktuelle Kalenderdatum zurück, ISO 8601 YYYY-MM-DD.

Parameter

Typ

Pflicht

Beschreibung

timezone

string

Nein

IANA-Zeitzonenname oder UTC-Offset, Standard "UTC"

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

get_datetime

Gibt das aktuelle Datum und die aktuelle Uhrzeit zurück, ISO 8601 mit Offset-Suffix (Z für UTC-Ausgabe).

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

Fehlerverhalten

  • Fehlende oder leere Zeitzone → wird als UTC behandelt

  • Nicht leere, aber ungültige Zeitzone → gibt ein isError: true-Ergebnis zurück, mit Hinweistext:

Error: Invalid IANA timezone "Mars/Olympus". Use a name like "UTC", "Asia/Shanghai" or "America/New_York".
  • Protokollebene-Fehler (z. B. fehlender Accept-Header) werden vom SDK als standardmäßiger JSON-RPC-Fehler zurückgegeben

Zeitquelle und Genauigkeit

Die Zeit wird aus der Systemuhr der Laufzeitumgebung gelesen (new Date()). Lokal ist das die lokale Maschinenuhr (abhängig von NTP-Synchronisierung); auf Lambda wird die Host-Uhr automatisch vom Amazon Time Sync Service (GPS/Atomuhr-Quelle, PTP/NTP) synchronisiert, mit Fehlern im Millisekundenbereich, ohne jegliche Konfiguration.

Bewusst wird kein externes NTP pro Abfrage durchgeführt: Die AWS-Uhr ist bereits kontinuierlich synchronisiert, eine externe Abfrage würde nur Latenz erhöhen (+10~100 ms), eine Netzwerk-Fehlerfläche und Rate-Limit-Probleme einführen, ohne höhere Genauigkeit zu bringen.

Die Ausgabeauflösung ist auf Sekunden genau (Millisekunden werden abgeschnitten). Die Zeitzonenumrechnung ist reine Arithmetik – alle Zeitzonen erhalten denselben absoluten Zeitpunkt, nur die Wanduhrzeit-Darstellung unterscheidet sich.

Lokale Entwicklung

Erfordert 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

Lokaler manueller Test (der Accept-Header muss beide Medientypen deklarieren, das ist die Protokollvalidierung des 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"}}}'

Alternativ kann der offizielle Debugger verwendet werden: npx @modelcontextprotocol/inspector, Verbindungstyp Streamable HTTP wählen.

Hinweis: Wenn auf dem lokalen Rechner die Umgebungsvariable http_proxy gesetzt ist, muss curl mit --noproxy '*' aufgerufen werden, sonst werden localhost-Anfragen vom Proxy abgefangen und geben 502 zurück.

Projektstruktur

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

Technische Implementierungsdetails

Die Zeitzonenformatierung erfolgt vollständig über Intl.DateTimeFormat, Kerntechniken:

  1. Datum: Das en-CA-Locale erzeugt nativ YYYY-MM-DD, kein manuelles Zusammensetzen nötig

  2. Zeit mit Offset: formatToParts extrahiert die Wanduhrzeit-Felder der Zielzeitzone → mit Date.UTC() als UTC zurückrechnen → vom ursprünglichen Zeitpunkt subtrahieren, um den Minuten-Offset zu erhalten → als ±HH:MM oder Z formatieren

  3. hourCycle: "h23": Vermeidet den Randfall-Bug mit Stunde "24", den hour12: false in manchen Locales erzeugt

  4. DST und spezielle Zeitzonen: Der Offset wird zum Anfragezeitpunkt berechnet, Sommerzeit-Umstellungen funktionieren dadurch natürlich korrekt (New York -04:00→-05:00), Halbstunden-/Viertelstunden-Zeitzonen (Indien +05:30, Nepal +05:45, Chatham +12:45) sind alle durch Unit-Tests abgedeckt

  5. Formatter-Cache: Intl.DateTimeFormat-Instanzen werden pro Zeitzone gecacht, wiederholte Aufrufe auf warmen Instanzen haben null Konstruktionsaufwand

  6. Zeitzonenvalidierung: try/catch beim Konstruieren von Intl.DateTimeFormat, ein geworfener RangeError gilt als ungültig. Das neue ECMA-402 lässt ICU auch UTC-Offset-Strings (z. B. +08:00) akzeptieren, die gesamte Kette wurde auf korrekte Ausgabe verifiziert und in Tests aufgenommen

Bereitstellung auf AWS Lambda

Voraussetzungen: AWS CLI mit konfigurierten Anmeldedaten; eine Ausführungsrolle mit AWSLambdaBasicExecutionRole-Berechtigung (falls nicht vorhanden, kann sie mit dem folgenden Befehl erstellt werden):

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

Methode 1: CLI-Skript

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

Optionale Umgebungsvariablen: AWS_REGION (Standard us-east-1), FUNCTION_NAME (Standard datetime-mcp), ARCH (arm64/x86_64, Standard arm64).

Skriptablauf: Dynamisch die neueste LWA-Layer-Version der Region abfragen → esbuild-Build → bsdtar-Paketierung (System hat keinen zip-Befehl) → create/update-Funktion (nodejs22.x, 512 MB, Timeout 10 s) → unauthentifizierte Function URL erstellen und öffentlichen Aufruf autorisieren → Endpoint ausgeben. Wiederholtes Ausführen ist sicher, der Update-Pfad wird automatisch genutzt.

Methode 2: AWS-Konsole

  1. Lokal paketieren:

    npm run build && bsdtar --format zip -cf function.zip bootstrap dist/index.js
  2. Lambda-Konsole → 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 → function.zip auswählen (die interne Struktur muss bootstrap + dist/index.js im Wurzelverzeichnis sein)

  4. Layers-Bereich → Add a layer → AWS layers → LambdaAdapterLayerArm64 (neueste Version wählen)

  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

Beim Erstellen einer Function URL vom Typ NONE über die Konsole wird automatisch eine Ressourcenrichtlinie für öffentlichen Aufruf hinzugefügt, ein zusätzliches add-permission ist nicht nötig (das ist der Unterschied zur CLI).

Ein direkter Browserzugriff auf die Function URL, der 405 zurückgibt, ist normal (nur POST erlaubt). Für spätere Code-Updates: Neu bauen und paketieren, dann im Code-Tab erneut hochladen.

MCP-Client-Anbindung

Am Beispiel von opencode, einen Remote-MCP-Server in der Konfiguration hinzufügen:

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

Designentscheidungen

Entscheidung

Schlussfolgerung

Begründung

Sprache

TypeScript

Intl-eingebaute Zeitzonenunterstützung ohne Abhängigkeiten; schnellster Lambda-Kaltstart (~100-200 ms vs. Python ~300-800 ms); kleines Bundle. Pythons Vorteil ist die kürzere Decorator-Schreibweise

Transport

Streamable HTTP + stateless + JSON response

Lambda hat keinen persistenten Prozess, stdio ist nicht möglich; zustandslos passt natürlich zum Freeze/Thaw-Modell; reines JSON umgeht SSE-Streaming-Beschränkungen

SDK-Version

Stabile Version @modelcontextprotocol/sdk@1.x (1.30.0)

Implementiert die Protokollversionsaushandlung korrekt, abwärtskompatibel mit alten Clients; die neuen Funktionen der Revision vom 2026-07-28 (TTL-Cache usw.) sind für statische Tool-Listen irrelevant; die Beta-Split-Paket-API ist nicht stabil

Zeitzonenimplementierung

Intl statt Drittanbieter-Bibliothek

Null Abhängigkeiten, kein Nachinstallieren von tzdata auf Lambda nötig, Genauigkeit ausreichend

Zeitquelle

Systemuhr statt NTP pro Abfrage

AWS synchronisiert bereits sub-millisekundengenau; externes NTP erhöht Latenz/Fehlerfläche/Kosten ohne Genauigkeitsgewinn

Bereitstellung

Manuell CLI/Konsole + LWA-Layer

Kein Vorabaufwand für SAM/CDK/Terraform; deploy.sh ist nur Befehls-Batchverarbeitung, kein IaC

Fehlerbehebung

Symptom

Ursache und Lösung

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

Anfrage ohne Accept-Header. curl-Tests benötigen -H "Accept: application/json, text/event-stream"; echte MCP-Clients senden ihn automatisch

Handler 'handler' missing on module 'index'

LWA-Layer vergessen oder AWS_LAMBDA_EXEC_WRAPPER nicht gesetzt, die Laufzeit sucht den Handler über den Standardpfad. Layer und Umgebungsvariablen ergänzen

GET /mcp gibt 405 zurück

Erwartetes Verhalten. Der stateless-Modus unterstützt keine serverseitigen Push-Streams, nur POST wird akzeptiert

Lokaler curl-Test gibt 502 zurück und ist extrem schnell

Systemproxy fängt localhost ab. --noproxy '*' hinzufügen

Erste Anfrage an Function URL nach Kaltstart ist langsam

Durch den Lambda-Freeze/Thaw-Mechanismus bedingt, Folgeanfragen sind im Millisekundenbereich

Beim Paketieren: zip: command not found

zip-Paket nicht installiert (auf Arch ein separates Paket von unzip). Dieses Projekt nutzt bereits bsdtar (in libarchive enthalten), erhält Berechtigungsbits

Bekannte Einschränkungen und zukünftige Verbesserungen

  • Kein defensiver Handler hinzugefügt: Bei nacktem Betrieb auf der Standard-Node.js-Laufzeit (ohne LWA) sind Fehlermeldungen unverständlich. Ein hinweisender Platzhalter-Handler könnte die Fehlererfahrung bei Fehlkonfiguration verbessern, ohne den Normalpfad zu beeinflussen

  • Ausgabe nur bis Sekundengenauigkeit, Millisekunden werden nicht exponiert

  • Keine Authentifizierung und kein Rate-Limiting – ein öffentlicher Endpoint könnte missbraucht werden, um Aufrufvolumen zu erzeugen (obwohl die Einzelkosten gegen null gehen)

  • Die Alias-Tabelle von Intl.supportedValuesOf("timeZone") wird nicht für Parameterhinweise verwendet, die Fehlermeldung gibt nur drei Beispiele

  • Beim zukünftigen Wechsel des SDK von der stabilen 1.x-Version zu den Split-Paketen (Unterstützung der Revision vom 2026-07-28) müssen API-Änderungen nachverfolgt werden

Lizenz

ISC

Related MCP Connectors

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
    -
  • A
    license
    A
    quality
    D
    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
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Provides time-related tools including current time retrieval, timezone conversion, time formatting, and timezone info via MCP.
    7 npm
    MIT