from __future__ import annotations
from fastmcp import FastMCP
from typing import Any, Dict
from datetime import datetime, date
import time as time_module
import zoneinfo
mcp = FastMCP("datetime")
def error_response(message: str) -> Dict[str, Any]:
"""
Create a standardized error response for MCP tools.
Parameters
----------
message : str
Human-readable description of the error.
Returns
-------
Dict[str, Any]
Dictionary containing error status and message.
"""
return {"status": "error", "error": message}
# ===================== Tools =====================
@mcp.tool()
async def current_datetime() -> Dict[str, Any]:
"""
Return the current or today's local date and time in ISO 8601 format.
Returns
-------
Dict[str, Any]
A dictionary containing:
- status : str
Indicates successful execution.
- datetime : str
Current local date and time in ISO 8601 format.
"""
return {
"status": "success",
"datetime": datetime.now().isoformat()
}
@mcp.tool()
async def current_date() -> Dict[str, Any]:
"""
Return today's local date.
Returns
-------
Dict[str, Any]
A dictionary containing:
- status : str
Indicates successful execution.
- date : str
Current date in YYYY-MM-DD format.
"""
return {
"status": "success",
"date": date.today().isoformat()
}
@mcp.tool()
async def current_time() -> Dict[str, Any]:
"""
Return the current local time.
Returns
-------
Dict[str, Any]
A dictionary containing:
- status : str
Indicates successful execution.
- time : str
Current time in HH:MM:SS format.
"""
return {
"status": "success",
"time": datetime.now().time().strftime("%H:%M:%S")
}
@mcp.tool()
async def current_day() -> Dict[str, Any]:
"""
Return the name of the current day.
Returns
-------
Dict[str, Any]
A dictionary containing:
- status : str
Indicates successful execution.
- day : str
Name of the current day (e.g., Monday).
"""
return {
"status": "success",
"day": datetime.now().strftime("%A")
}
@mcp.tool()
async def current_month() -> Dict[str, Any]:
"""
Return the name of the current month.
Returns
-------
Dict[str, Any]
A dictionary containing:
- status : str
Indicates successful execution.
- month : str
Name of the current month (e.g., January).
"""
return {
"status": "success",
"month": datetime.now().strftime("%B")
}
@mcp.tool()
async def current_year() -> Dict[str, Any]:
"""
Return the current year.
Returns
-------
Dict[str, Any]
A dictionary containing:
- status : str
Indicates successful execution.
- year : int
Current year.
"""
return {
"status": "success",
"year": datetime.now().year
}
@mcp.tool()
async def unix_timestamp() -> Dict[str, Any]:
"""
Return the current Unix timestamp.
Returns
-------
Dict[str, Any]
A dictionary containing:
- status : str
Indicates successful execution.
- timestamp : int
Number of seconds since the Unix epoch.
"""
return {
"status": "success",
"timestamp": int(time_module.time())
}
@mcp.tool()
async def timezone_datetime(timezone: str = "UTC") -> Dict[str, Any]:
"""
Return the current date and time for a specified timezone.
Parameters
----------
timezone : str, optional
IANA timezone name (e.g., "UTC", "Asia/Kolkata").
Defaults to "UTC".
Returns
-------
Dict[str, Any]
A dictionary containing:
- status : str
Indicates successful execution or error.
- timezone : str
Requested timezone.
- datetime : str
Current datetime in ISO 8601 format for the given timezone.
If an invalid timezone is provided, an error response is returned.
"""
try:
tz = zoneinfo.ZoneInfo(timezone)
return {
"status": "success",
"timezone": timezone,
"datetime": datetime.now(tz).isoformat()
}
except Exception:
return error_response(f"Invalid timezone: {timezone}")
@mcp.tool()
async def formatted_datetime(format: str = "%Y-%m-%d %H:%M:%S") -> Dict[str, Any]:
"""
Return the current date and time using a custom format.
Parameters
----------
format : str, optional
strftime-compatible format string.
Defaults to "%Y-%m-%d %H:%M:%S".
Returns
-------
Dict[str, Any]
A dictionary containing:
- status : str
Indicates successful execution or error.
- formatted : str
Current datetime formatted according to the provided format string.
If the format string is invalid, an error response is returned.
"""
try:
return {
"status": "success",
"formatted": datetime.now().strftime(format)
}
except Exception:
return error_response("Invalid datetime format string")
# ===================== Resource =====================
@mcp.resource("datetime://tools-summary")
async def tools_summary() -> str:
"""
Provide a human-readable summary of all datetime tools.
This resource is intended for documentation, discovery,
and client-side help interfaces.
"""
return """
# Datetime MCP Tools Summary
This MCP server provides tools for retrieving and formatting
date and time information.
---
## Available Tools
### 1. `current_datetime`
**Description:**
Returns the current local date and time in ISO 8601 format.
**Arguments:**
None
---
### 2. `current_date`
**Description:**
Returns today's date.
**Arguments:**
None
---
### 3. `current_time`
**Description:**
Returns the current local time.
**Arguments:**
None
---
### 4. `current_day`
**Description:**
Returns the current day name (e.g., Monday).
**Arguments:**
None
---
### 5. `current_month`
**Description:**
Returns the current month name (e.g., January).
**Arguments:**
None
---
### 6. `current_year`
**Description:**
Returns the current year.
**Arguments:**
None
---
### 7. `unix_timestamp`
**Description:**
Returns the current Unix timestamp.
**Arguments:**
None
---
### 8. `timezone_datetime`
**Description:**
Returns the current datetime for a specified timezone.
**Arguments:**
- `timezone` (str, optional) — IANA timezone name
Default: `"UTC"`
---
### 9. `formatted_datetime`
**Description:**
Returns the current datetime formatted using a custom format string.
**Arguments:**
- `format` (str, optional) — strftime-compatible format
Default: `%Y-%m-%d %H:%M:%S`
---
## Notes
- All tools are asynchronous.
- All responses are JSON-serializable.
- Timezone handling uses the IANA database.
- This resource is read-only and safe to fetch at any time.
"""
# ================= Server Entry =================
if __name__ == "__main__":
"""
Start the MCP server.
"""
mcp.run()