Timezone MCP Server
A dual-interface timezone server supporting both MCP (Model Context Protocol) for LLM discovery and REST API for direct HTTP access. Get available regions, cities, and current time in any timezone with ISO 8601 formatted timestamps.
Features
π€ MCP Protocol Support - LLMs can auto-discover and use timezone tools via JSON-RPC
π REST API - Traditional HTTP endpoints with Swagger/OpenAPI documentation
π OAuth2 Authentication - Secure access with user allowlisting and client credentials
β° Timezone Operations - Get regions, cities, and current time in any timezone
π ISO 8601 Timestamps - Local datetime with offset, UTC datetime, and timezone offset
π§ͺ 100% Test Coverage - Comprehensive unit and e2e tests (Vitest)
π§ NestJS & TypeScript - Modern, type-safe development
π Dual Documentation - Swagger UI for humans, MCP schema for LLMs
π¨ Code Quality - ESLint, Prettier, and automated formatting
Getting Started
Prerequisites
Node.js 22.20.0+ (LTS recommended)
pnpm 10.13.1 (managed via Corepack)
π¦ Package Manager: This project uses pnpm exclusively via Corepack (built into Node.js). The exact pnpm version is enforced by the
packageManager
field in package.json. After installing Node.js, runcorepack enable
to activate pnpm support.π§ Version Management: This project uses fnm (Fast Node Manager) or nvm to manage Node.js versions. The
.node-version
file will automatically switch to the correct Node.js version when youcd
into the project directory (if you have fnm/nvm shell integration enabled).
Installation
Authentication Setup
This server requires OAuth2 authentication for all endpoints except /health
. You need to configure authentication before running the server.
Step 1: Configure Environment Variables
Copy the example environment file and edit it:
Edit .env
and configure:
JWT Settings (required):
JWT_SECRET=your-super-secret-jwt-key-change-this-in-production JWT_EXPIRES_IN=3600OAuth2 Provider (choose one - Google, GitHub, or any OAuth2-compliant provider):
For Google:
OAUTH2_AUTHORIZATION_URL=https://accounts.google.com/o/oauth2/v2/auth OAUTH2_TOKEN_URL=https://oauth2.googleapis.com/token OAUTH2_USER_INFO_URL=https://www.googleapis.com/oauth2/v2/userinfo OAUTH2_CLIENT_ID=your-google-client-id.apps.googleusercontent.com OAUTH2_CLIENT_SECRET=your-google-client-secret OAUTH2_CALLBACK_URL=http://localhost:3000/auth/callback OAUTH2_SCOPE=openid email profileFor GitHub:
OAUTH2_AUTHORIZATION_URL=https://github.com/login/oauth/authorize OAUTH2_TOKEN_URL=https://github.com/login/oauth/access_token OAUTH2_USER_INFO_URL=https://api.github.com/user OAUTH2_CLIENT_ID=your-github-client-id OAUTH2_CLIENT_SECRET=your-github-client-secret OAUTH2_CALLBACK_URL=http://localhost:3000/auth/callback OAUTH2_SCOPE=user:emailUser Allowlist (required):
ALLOWED_EMAILS=user1@example.com,user2@example.com,admin@company.com
Step 2: Set Up OAuth2 Provider
Create OAuth2 credentials with your provider:
Google: Google Cloud Console
GitHub: GitHub Developer Settings
Set the Authorized redirect URI to: http://localhost:3000/auth/callback
Step 3: Authentication Flow
Visit
http://localhost:3000/auth/login
Redirected to OAuth2 provider (Google/GitHub/etc.)
Sign in and authorize
Redirected back with JWT token displayed on screen
Copy the token and use it in API requests:
curl -H "Authorization: Bearer YOUR_TOKEN" http://localhost:3000/timezones/regions
Running the Server
This project provides three interfaces that can run independently:
Option 1: MCP Server via stdio (for local LLM clients)
Uses stdio transport - launches as a subprocess. Perfect for Claude Desktop config file.
Option 2: MCP Server via HTTP (for remote LLM clients)
Uses Streamable HTTP over HTTP - accessible at http://localhost:3001/mcp
Perfect for Claude Desktop's "Add Custom Connector" UI! π―
Option 3: REST API Server (for HTTP clients)
The REST API will start on http://localhost:3000
Interactive Swagger/OpenAPI documentation is available at http://localhost:3000/api
Available Endpoints
Authentication:
GET /auth/login
- Initiate OAuth2 login (redirects to provider)GET /auth/callback
- OAuth2 callback (returns JWT token)
Health:
GET /health
- Health check endpoint (public, no authentication required){ "status": "ok", "timestamp": "2025-10-17T18:30:45.123Z" }
Timezone API: (requires authentication - include Authorization: Bearer TOKEN
header)
GET /timezones/regions
- Get all available timezone regions{ "regions": [ "Africa", "America", "Antarctica", "Asia", "Atlantic", "Australia", "Europe", "Indian", "Pacific" ], "count": 15 }GET /timezones/regions/:region/cities
- Get all cities in a specific region{ "region": "America", "cities": ["New_York", "Los_Angeles", "Chicago", "Denver", "Phoenix"], "count": 150 }GET /timezones/:region/:city
- Get current time in a specific timezone{ "timezone": "America/New_York", "datetime_local": "2025-10-17T13:47:23-04:00", "datetime_utc": "2025-10-17T17:47:23.345Z", "timezone_offset": "-04:00", "timestamp": 1760723243345 }
MCP Protocol Integration
What is MCP?
Model Context Protocol (MCP) is a standardized protocol that allows LLMs to discover and use tools automatically. Instead of manually telling an LLM about your API endpoints, MCP-enabled clients like Claude Desktop can:
Auto-discover available tools via
tools/list
Inspect schemas to understand input parameters
Execute tools via JSON-RPC
tools/call
requests
Testing with MCP Inspector (Quickest)
The MCP Inspector is a web UI for testing your MCP server without needing Claude Desktop:
This opens http://localhost:5173
where you can:
See all 3 tools listed
Inspect tool schemas and parameters
Execute tools and see JSON responses
Debug without installing anything else
Setting Up with Claude Desktop
Method 1: Local stdio Connection (Recommended)
Build the project:
pnpm install pnpm buildEdit Claude Desktop config (
~/Library/Application Support/Claude/claude_desktop_config.json
on macOS):{ "mcpServers": { "timezone": { "command": "node", "args": ["/absolute/path/to/demo-mcp/dist/main.js"] } } }Restart Claude Desktop
Claude can now auto-discover and use the timezone tools!
Available MCP Tools
Tool | Parameters | Description |
| None | Get list of all timezone regions |
|
| Get cities in a specific region |
|
| Get current time with ISO 8601 formats |
Architecture
All three interfaces use the same TimezoneService
, ensuring consistent behavior across REST API, remote MCP, and local MCP connections.
Testing
Test Coverage: 103/109 tests passing (94.5%). The HTTP MCP transport has comprehensive manual testing via MCP Inspector but automated e2e tests are pending due to SSE timing complexity.
Manual Testing HTTP MCP Server:
Code Quality
Documentation
Additional guides and documentation are available in the docs/
directory:
Local Testing Guide - Step-by-step instructions for testing with MCP Inspector
Deployment Guide - Deploy to Google Cloud Run
Deployment Success Guide - Post-deployment verification
Scripts Reference
Server Scripts
pnpm dev
- Start REST API server in development modepnpm start
- Start REST API serverpnpm start:prod
- Start REST API server in production modepnpm mcp:dev
- Start MCP server (stdio) in development modepnpm mcp:start
- Start MCP server (stdio) in production modepnpm mcp:http:dev
- Start MCP server (HTTP/SSE) in development modepnpm mcp:http
- Start MCP server (HTTP/SSE) in production modepnpm mcp:inspector
- Start MCP Inspector (debug/test MCP tools in browser)pnpm swagger
- Open Swagger UI in default browser
Build & Test
pnpm build
- Build the project (compiles TypeScript to dist/)pnpm test
- Run all tests (84 tests including MCP e2e)pnpm test:watch
- Run tests in watch modepnpm test:cov
- Run tests with coverage report (100% coverage)pnpm test:ui
- Run tests with Vitest UIpnpm test:e2e
- Run end-to-end tests only
Code Quality
pnpm lint
- Lint code with ESLintpnpm lint:fix
- Fix linting issues automaticallypnpm format
- Format code with Prettierpnpm format:check
- Check if code is properly formatteddeps:check
- Check if dependencies can be upgraded (minor/patch only)deps:update
- Upgrade dependencies (minor/patch only)
This server cannot be installed
hybrid server
The server is able to function both locally and remotely, depending on the configuration or use case.
Enables LLMs to get current time information for any timezone worldwide, including available regions, cities, and ISO 8601 formatted timestamps with timezone offsets.