Skip to main content
Glama
timeaissr

datetime-mcp-server

by timeaissr

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

  • Ноль сторонних библиотек времени: полностью на встроенном Intl (ICU) Node.js, без зависимостей moment/luxon/dayjs

  • Serverless-развёртывание: один bundle-файл (~2 МБ) + Lambda Web Adapter, после холодного старта горячие экземпляры отвечают за миллисекунды

  • Соответствие последним стандартам MCP: транспортировка Streamable HTTP, stateless-режим работы, согласование версий протокола обрабатывается официальным SDK

Related MCP server: date-today-mcp

Архитектура

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

Единственная рекомендуемая в настоящее время HTTP-транспортировка MCP; HTTP+SSE устарел

Stateless-режим

Каждый запрос самодостаточен, сессии не поддерживаются, что соответствует модели заморозки/разморозки Lambda

enableJsonResponse: true

Ответ идёт обычным JSON, а не потоком SSE, что обходит ограничения буферизации ответов Lambda

Lambda Web Adapter (LWA)

Официальный публичный Layer AWS, преобразующий вызов Lambda в реальный HTTP-запрос к localhost:8080

Скрипт 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

Источник времени и точность

Время считывается из системных часов среды выполнения (new Date()). Локально — это часы машины (зависит от калибровки NTP); на Lambda часы хоста автоматически синхронизируются Amazon Time Sync Service (источник GPS/атомные часы, PTP/NTP), погрешность в пределах миллисекунд, никакой настройки не требуется.

Намеренно не выполняется внешний NTP-запрос при каждом вызове: часы AWS уже постоянно синхронизированы, внешний запрос лишь добавит задержку (+10~100 мс), внесёт сетевую точку отказа и проблемы с лимитами, а точность выше не станет.

Разрешение вывода — до секунды (миллисекунды отбрасываются). Преобразование часовых поясов — чистая арифметика: все часовые пояса получают один и тот же абсолютный момент, различается лишь представление в местном времени.

Локальная разработка

Требуется 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 должен объявлять оба типа media — это проверка протокола 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, основные приёмы:

  1. Дата: локаль en-CA естественным образом выводит YYYY-MM-DD, ручная сборка не нужна

  2. Время со смещением: formatToParts берёт поля местного времени целевого пояса → с помощью Date.UTC() обратно вычисляет его как UTC → вычитает из исходного момента, получая смещение в минутах → форматирует как ±HH:MM или Z

  3. hourCycle: "h23": позволяет избежать граничного бага с часом "24", который возникает с hour12: false в некоторых локалях

  4. DST и особые часовые пояса: смещение вычисляется на момент запроса, переход на летнее время обрабатывается корректно (Нью-Йорк -04:00→-05:00), пояса с получасовым/четвертьчасовым сдвигом (Индия +05:30, Непал +05:45, Чатем +12:45) покрыты юнит-тестами

  5. Кэш форматтеров: экземпляры Intl.DateTimeFormat кэшируются по часовому поясу, повторные вызовы на горячем экземпляре не несут затрат на создание

  6. Проверка часового пояса: 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

Способ 1: 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, 512 МБ, таймаут 10 с) → создание Function URL без аутентификации и разрешение публичного вызова → вывод endpoint. Повторный запуск безопасен, автоматически идёт по пути обновления.

Способ 2: Консоль AWS

  1. Локальная упаковка:

    npm run build && bsdtar --format zip -cf function.zip bootstrap dist/index.js
  2. Консоль Lambda → Create function → Author from scratch

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

    • Permissions: Create a new role with basic Lambda permissions

  3. Вкладка Code → Upload from → .zip file → выбрать function.zip (внутренняя структура должна быть: корневой bootstrap + dist/index.js)

  4. Раздел Layers → Add a layer → AWS layers → LambdaAdapterLayerArm64 (выбрать последнюю версию)

  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

При создании Function URL типа NONE через консоль ресурсная политика публичного вызова добавляется автоматически, выполнять add-permission не нужно (в этом отличие от CLI).

Прямой доступ браузером к Function URL с ответом 405 — это нормально (разрешён только POST). При последующем обновлении кода: пересобрать и упаковать, затем заново загрузить на вкладке Code.

Подключение MCP-клиента

На примере opencode — добавить remote MCP server в конфигурацию:

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

Журнал проектных решений

Решение

Вывод

Обоснование

Язык

TypeScript

Встроенная поддержка часовых поясов Intl без зависимостей; самый быстрый холодный старт Lambda (~100-200 мс против ~300-800 мс у Python); маленький bundle. Преимущество Python — более лаконичный синтаксис декораторов

Транспорт

Streamable HTTP + stateless + JSON response

У Lambda нет постоянного процесса, stdio неприменим; отсутствие состояния сессии естественно соответствует модели заморозки/разморозки; чистый JSON обходит ограничения потоковой передачи SSE

Версия SDK

Стабильная @modelcontextprotocol/sdk@1.x (1.30.0)

Корректно реализует согласование версий протокола, обратная совместимость со старыми клиентами; новые возможности редакции от 2026-07-28 (кэш TTL и др.) бессмысленны для статического списка инструментов; API бета-раздельных пакетов нестабилен

Реализация часовых поясов

Intl, а не сторонние библиотеки

Ноль зависимостей, не нужно доустанавливать tzdata на Lambda, точности достаточно

Источник времени

Системные часы, а не 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-режим не поддерживает серверные push-потоки, принимается только 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

Лицензия

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