modelcontextprotocol/servers · error · ValueError
Invalid time format. Expected HH:MM [24-hour format]
Error message
Invalid time format. Expected HH:MM [24-hour format]
What it means
convert_time parses time_str with datetime.strptime(time_str, '%H:%M') (server.py:80-83); any strptime ValueError is re-raised as ValueError('Invalid time format. Expected HH:MM [24-hour format]'). Only 24-hour HH:MM is accepted (12-hour, AM/PM, seconds, out-of-range, and empty strings are rejected). Like errors 44/46/47/48, the outer handler (error 49) re-wraps this before it leaves the server.
Source
Thrown at src/time/src/mcp_server_time/server.py:83
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:
"""Convert time between timezones"""
source_timezone = get_zoneinfo(source_tz)
target_timezone = get_zoneinfo(target_tz)
try:
parsed_time = datetime.strptime(time_str, "%H:%M").time()
except ValueError:
raise ValueError("Invalid time format. Expected HH:MM [24-hour format]")
now = datetime.now(source_timezone)
source_time = datetime(
now.year,
now.month,
now.day,
parsed_time.hour,
parsed_time.minute,
tzinfo=source_timezone,
)
target_time = source_time.astimezone(target_timezone)
source_offset = source_time.utcoffset() or timedelta()
target_offset = target_time.utcoffset() or timedelta()
hours_difference = (target_offset - source_offset).total_seconds() / 3600
if hours_difference.is_integer():
time_diff_str = f"{hours_difference:+.1f}h"View on GitHub (pinned to 76d64c822f)
Solutions
- Send exactly zero-padded 24-hour HH:MM (e.g. '14:30', '09:05').
- Normalize client-side: parse the user's input, then re-emit strftime('%H:%M').
- Reject empty or None before constructing the call.
Example fix
// before // time: "2:30 PM" -> Invalid time format // after // time: "14:30"
Defensive patterns
Strategy: validation
Validate before calling
from datetime import datetime
def normalize_hhmm(s: str) -> str:
# raises ValueError if not parseable as 24-hour HH:MM
return datetime.strptime(s, "%H:%M").strftime("%H:%M")
time_str = normalize_hhmm(arguments["time"]) Type guard
import re
def is_hhmm(v: object) -> bool:
return isinstance(v, str) and bool(re.fullmatch(r"([01]\d|2[0-3]):[0-5]\d", v)) Prevention
- Format every time to %H:%M at the trust boundary.
- Reject 12-hour/AM-PM/seconds upstream before constructing the call.
- Feed natural-language times through a parser that emits HH:MM.
When it happens
Trigger: Passing '2:30 PM', '14:30:00', '09:00 AM', '25:00', 'noon', or '' as the 'time' argument.
Common situations: 12-hour habits, natural-language times from an LLM ('2pm'), locale-formatted strings, or a stray seconds component.
Related errors
- Missing required argument: timezone
- Missing required arguments
- -32602
- Invalid target: '{target}' - cannot start with '-'
- Invalid path: '{f}'
AI-assisted analysis of modelcontextprotocol/servers@76d64c822f (2026-08-12).
Data as JSON: /api/errors/a9922f095d4ae17f.
Report an issue: GitHub.