modelcontextprotocol/servers · error · McpError
INVALID_PARAMS
INVALID_PARAMS
Error message
Invalid timezone: {str(e)} What it means
get_zoneinfo (server.py:53-57) wraps ZoneInfo(timezone_name); any failure is re-raised as McpError(INVALID_PARAMS, 'Invalid timezone: ...'). ZoneInfo fails on non-IANA names ('PST', 'EST', 'UTC+5'), typos, or when the host lacks tz data (notably Windows without the 'tzdata' package). IMPORTANT: when reached via get_current_time/convert_time this McpError is caught by the outer except Exception (error 49) and downgraded to a plain ValueError, so the structured INVALID_PARAMS code never reaches the client.
Source
Thrown at src/time/src/mcp_server_time/server.py:57
def get_local_tz(local_tz_override: str | None = None) -> ZoneInfo:
if local_tz_override:
return ZoneInfo(local_tz_override)
# Get local timezone from datetime.now()
local_tzname = get_localzone_name()
if local_tzname is not None:
return ZoneInfo(local_tzname)
# Default to UTC if local timezone cannot be determined
return ZoneInfo("UTC")
def get_zoneinfo(timezone_name: str) -> ZoneInfo:
try:
return ZoneInfo(timezone_name)
except Exception as e:
raise McpError(ErrorData(code=INVALID_PARAMS, message=f"Invalid timezone: {str(e)}"))
class TimeServer:
def get_current_time(self, timezone_name: str) -> TimeResult:
"""Get current time in specified timezone"""
timezone = get_zoneinfo(timezone_name)
current_time = datetime.now(timezone)
return TimeResult(
timezone=timezone_name,
datetime=current_time.isoformat(timespec="seconds"),
day_of_week=current_time.strftime("%A"),
is_dst=bool(current_time.dst()),
)
def convert_time(
self, source_tz: str, time_str: str, target_tz: str
) -> TimeConversionResult:View on GitHub (pinned to 76d64c822f)
Solutions
- Use a full IANA name: 'America/Los_Angeles', 'Europe/Berlin', 'UTC'.
- On Windows or slim images, install tzdata (uv add tzdata / pip install tzdata).
- Validate/normalize the timezone client-side against zoneinfo.available_timezones() before sending.
- If you maintain the server, narrow the outer except (error 49) so McpError is re-raised unchanged and the code survives.
Example fix
// before // timezone: "PST" -> Invalid timezone // after // timezone: "America/Los_Angeles"
Defensive patterns
Strategy: try-catch
Validate before calling
from zoneinfo import ZoneInfo, available_timezones
def valid_tz(name: str) -> str:
if not isinstance(name, str) or name not in available_timezones():
raise ValueError(f"not an IANA timezone: {name!r}")
ZoneInfo(name) # smoke test; catches missing tzdata on Windows
return name Type guard
from zoneinfo import available_timezones
def is_iana_tz(v: object) -> bool:
return isinstance(v, str) and v in available_timezones() Try / catch
from mcp.shared.exceptions import McpError
try:
result = time_server.get_current_time(timezone)
except McpError as e:
# INVALID_PARAMS; surface to user, suggest an IANA name
handle_bad_timezone(e) Prevention
- Use full IANA names only (America/Los_Angeles, Europe/Berlin, UTC).
- Install tzdata in Windows hosts and slim containers.
- Surface available_timezones() to users in the UI prompt.
When it happens
Trigger: Passing a POSIX abbreviation ('PST','EST'), an offset string ('UTC+2'), a typo ('America/LosAngelos'), or running on Windows/a slim container without tzdata installed.
Common situations: Users used to tz abbreviations. Windows dev hosts. Minimal Docker images missing the tzdata wheel. LLM-supplied timezone strings.
Related errors
- -32602
- Invalid time format. Expected HH:MM [24-hour format]
- Missing required argument: timezone
- Missing required arguments
- Unknown tool: {name}
AI-assisted analysis of modelcontextprotocol/servers@76d64c822f (2026-08-12).
Data as JSON: /api/errors/0c45fbf29603777b.
Report an issue: GitHub.