datetime-mcp-server
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-FormatOptionaler Zeitzonenparameter: Unterstützt IANA-Zeitzonennamen (
Asia/Shanghai) und UTC-Offsets (+08:00), Standard ist UTCKeine Drittanbieter-Zeitbibliotheken: Vollständig auf Node.js-eingebautem
Intl(ICU) basierend, keine moment/luxon/dayjs-AbhängigkeitenServerless-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 |
| 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 |
| Der eigentliche Prozesseinstieg nach Übernahme durch LWA ( |
MCP-Tools
get_date
Gibt das aktuelle Kalenderdatum zurück, ISO 8601 YYYY-MM-DD.
Parameter | Typ | Pflicht | Beschreibung |
| string | Nein | IANA-Zeitzonenname oder UTC-Offset, Standard |
{"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.jsLokaler 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_proxygesetzt 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:
Datum: Das
en-CA-Locale erzeugt nativYYYY-MM-DD, kein manuelles Zusammensetzen nötigZeit mit Offset:
formatToPartsextrahiert die Wanduhrzeit-Felder der Zielzeitzone → mitDate.UTC()als UTC zurückrechnen → vom ursprünglichen Zeitpunkt subtrahieren, um den Minuten-Offset zu erhalten → als±HH:MModerZformatierenhourCycle: "h23": Vermeidet den Randfall-Bug mit Stunde"24", denhour12: falsein manchen Locales erzeugtDST 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 abgedecktFormatter-Cache:
Intl.DateTimeFormat-Instanzen werden pro Zeitzone gecacht, wiederholte Aufrufe auf warmen Instanzen haben null KonstruktionsaufwandZeitzonenvalidierung: try/catch beim Konstruieren von
Intl.DateTimeFormat, ein geworfenerRangeErrorgilt 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/AWSLambdaBasicExecutionRoleMethode 1: CLI-Skript
ROLE_ARN=arn:aws:iam::<账号ID>:role/datetime-mcp-role ./deploy.shOptionale 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
Lokal paketieren:
npm run build && bsdtar --format zip -cf function.zip bootstrap dist/index.jsLambda-Konsole → Create function → Author from scratch
Runtime: Node.js 22.x; Architecture: arm64
Permissions: Create a new role with basic Lambda permissions
Code-Tab → Upload from → .zip file →
function.zipauswählen (die interne Struktur mussbootstrap+dist/index.jsim Wurzelverzeichnis sein)Layers-Bereich → Add a layer → AWS layers → LambdaAdapterLayerArm64 (neueste Version wählen)
Configuration → Environment variables:
Key
Value
AWS_LAMBDA_EXEC_WRAPPER/opt/bootstrapPORT8080Configuration → General configuration → Memory 512 MB, Timeout 10 s
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-permissionist 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 |
|
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 | 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 |
| 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 |
| Anfrage ohne Accept-Header. curl-Tests benötigen |
| LWA-Layer vergessen oder |
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. |
Erste Anfrage an Function URL nach Kaltstart ist langsam | Durch den Lambda-Freeze/Thaw-Mechanismus bedingt, Folgeanfragen sind im Millisekundenbereich |
Beim Paketieren: | zip-Paket nicht installiert (auf Arch ein separates Paket von unzip). Dieses Projekt nutzt bereits |
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 BeispieleBeim 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
This server cannot be deployed
Maintenance
Related MCP Connectors
Timezone MCP — wraps timeapi.io (free, no auth)
A real clock for AI agents: current time, timezone conversion, and DST facts from the IANA tzdb.
Current time in any IANA time zone, plus the full time-zone list. Via timeapi.io.
Related MCP Servers
- FlicenseAqualityNot gradedmaintenanceProvides 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-
- AlicenseAqualityDmaintenanceProvides the current date in multiple formats (e.g., European, ISO, US) via a simple MCP tool.1ISC
- AlicenseAqualityDmaintenanceA simple MCP server that returns the current date and time with timezone information in ISO 8601, Unix timestamp, and human-readable formats.1MIT
- AlicenseNot gradedqualityDmaintenanceProvides time-related tools including current time retrieval, timezone conversion, time formatting, and timezone info via MCP.7 npmMIT