server.py•4.01 kB
#!/usr/bin/env python3
import os
from datetime import datetime
from zoneinfo import ZoneInfo
from typing import Optional
from fastmcp import FastMCP, Context
from fastmcp.tools.tool import ToolResult
from mcp.types import TextContent
# Initialize the MCP server
mcp = FastMCP(
name="DateTime Server",
instructions="Provides onfigurable timezone-aware date and time information."
)
def load_config(context: Optional[Context] = None) -> tuple[str, str]:
"""
Load timezone and time format configuration.
For HTTP transport, configuration comes from headers.
For stdio transport, configuration comes from environment variables.
Returns:
tuple: (timezone_string, time_format)
"""
# Default values
default_tz = "UTC"
default_timefmt = "24"
# Try to get from context headers first (HTTP transport)
if context and hasattr(context, 'meta') and context.meta:
headers = context.meta.get('headers', {})
tz_string = headers.get('DEFAULT_TZ', headers.get('default_tz'))
time_format = headers.get('TIMEFMT', headers.get('timefmt'))
if tz_string and time_format:
return tz_string, time_format
# Fall back to environment variables (stdio transport)
tz_string = os.getenv('DEFAULT_TZ', default_tz)
time_format = os.getenv('TIMEFMT', default_timefmt)
return tz_string, time_format
def get_timezone(tz_string: str) -> ZoneInfo:
"""
Convert timezone string to ZoneInfo object.
Args:
tz_string: Timezone identifier (e.g., "America/New_York", "UTC")
Returns:
ZoneInfo object, defaults to UTC if invalid timezone
"""
try:
return ZoneInfo(tz_string)
except Exception:
# Graceful fallback to UTC for invalid timezones
return ZoneInfo("UTC")
@mcp.tool
def get_current_date(include_weekday: bool = False, ctx: Context = None) -> ToolResult:
"""
Get the current date in ISO format (YYYY-MM-DD).
Args:
include_weekday: Whether to append the day of the week
Returns:
ISO date string, optionally with weekday
Examples:
get_current_date() -> "2024-01-15"
get_current_date(include_weekday=True) -> "2024-01-15 (Monday)"
"""
tz_string, _ = load_config(ctx)
timezone = get_timezone(tz_string)
# Get current date in the specified timezone
now = datetime.now(timezone)
date_str = now.strftime("%Y-%m-%d")
if include_weekday:
weekday = now.strftime("%A")
result_text = f"{date_str} ({weekday})"
else:
result_text = date_str
# Return raw text without JSON wrapping - more efficient per policy
return ToolResult(content=[TextContent(type="text", text=result_text)])
@mcp.tool
def get_current_time(ctx: Context = None) -> ToolResult:
"""
Get the current time in the configured format.
Returns:
Time string in 12-hour or 24-hour format based on TIMEFMT setting
Examples:
With TIMEFMT="12": "2:30 PM"
With TIMEFMT="24": "14:30"
"""
tz_string, time_format = load_config(ctx)
timezone = get_timezone(tz_string)
# Get current time in the specified timezone
now = datetime.now(timezone)
if time_format == "12":
# 12-hour format with AM/PM
result_text = now.strftime("%I:%M %p").lstrip('0')
else:
# 24-hour format (default)
result_text = now.strftime("%H:%M")
# Return raw text without JSON wrapping - more efficient per policy
return ToolResult(content=[TextContent(type="text", text=result_text)])
def main():
"""Entry point function for running the server."""
mcp_host = os.getenv("HOST", "127.0.0.1")
mcp_port = os.getenv("PORT", None)
if mcp_port:
mcp.run(port=int(mcp_port), host=mcp_host, transport="streamable-http")
else:
mcp.run()
if __name__ == "__main__":
main()