Skip to content

fix(ecs-mcp-server): accept ISO-8601 string start_time/end_time in calculate_time_window#3788

Open
valter-silva-au wants to merge 1 commit into
awslabs:mainfrom
valter-silva-au:fix/ecs-mcp-server-datetime-string-params
Open

fix(ecs-mcp-server): accept ISO-8601 string start_time/end_time in calculate_time_window#3788
valter-silva-au wants to merge 1 commit into
awslabs:mainfrom
valter-silva-au:fix/ecs-mcp-server-datetime-string-params

Conversation

@valter-silva-au

@valter-silva-au valter-silva-au commented Jun 8, 2026

Copy link
Copy Markdown

Problem

ecs_troubleshooting_tool documents and exposes start_time/end_time parameters on three actions — fetch_task_failures, fetch_service_events, and fetch_task_logs. Because MCP serializes all tool arguments as JSON, these values always arrive as ISO-8601 strings, never datetime objects. The documented parameters are therefore completely unusable: any call that supplies them crashes with AttributeError: 'str' object has no attribute 'tzinfo'.

Root cause

awslabs/ecs_mcp_server/utils/time_utils.py::calculate_time_window assumed its start_time/end_time arguments were datetime objects and accessed .tzinfo directly:

actual_end_time = end_time if end_time.tzinfo else end_time.replace(tzinfo=datetime.timezone.utc)

When a string is passed, the first attribute access raises. The per-action transformers in api/ecs_troubleshooting.py forward params.get("start_time") / params.get("end_time") straight through, so the string reaches calculate_time_window unconverted.

Fix

Add a small _ensure_datetime(value) helper in time_utils.py and call it on both start_time and end_time at the very top of calculate_time_window, before the existing tz-awareness logic. The helper:

  • returns None for None,
  • passes datetime objects through unchanged,
  • parses strings via datetime.fromisoformat, first normalizing a trailing "Z" to "+00:00" (Python 3.10 — the project's minimum — doesn't accept the Z suffix), and re-raises a clear ValueError on malformed input.

This is a single boundary fix that covers all three calling sites without modifying the transformers. Naive strings (no timezone) are coerced to UTC, matching the function's existing behavior for naive datetime objects.

Testing

Added 7 unit tests in tests/unit/utils/test_time_utils.py: Z-suffix strings, explicit +00:00 offset, naive-string→UTC coercion, start-only-as-string, end-only-as-string, malformed-string→ValueError, and a regression test confirming datetime objects still work. time_utils tests: 6 → 13, all passing. Lint/format/type checks (ruff, ruff-format, mypy, pyright) pass.

Backward compatibility

Fully backward compatible. Existing datetime callers are unaffected — _ensure_datetime passes datetime objects through untouched, covered by a dedicated regression test.

Fixes #2858


By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of the project license.

@codecov

codecov Bot commented Jun 8, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.93%. Comparing base (b1e7686) to head (9825a10).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #3788   +/-   ##
=======================================
  Coverage   92.93%   92.93%           
=======================================
  Files         987      987           
  Lines       82364    82378   +14     
  Branches    13043    13046    +3     
=======================================
+ Hits        76545    76559   +14     
  Misses       3508     3508           
  Partials     2311     2311           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

…lculate_time_window

MCP serializes all tool arguments as JSON, so the start_time/end_time
parameters exposed by ecs_troubleshooting_tool (fetch_task_failures,
fetch_service_events, fetch_task_logs) always arrive as ISO-8601 strings,
never datetime objects. calculate_time_window assumed datetime objects and
accessed `.tzinfo` directly, so the first attribute access raised
`AttributeError: 'str' object has no attribute 'tzinfo'`, making the
documented parameters completely unusable.

Add an `_ensure_datetime` helper that returns None for None, parses strings
via `datetime.fromisoformat` (normalizing a trailing "Z" to "+00:00" for
Python 3.10 compatibility) and raises a clear ValueError on malformed input,
and passes datetime objects through unchanged. Call it on both start_time
and end_time at the top of calculate_time_window. This single boundary fix
covers all three calling sites without touching the transformers.

Naive strings (no timezone) are coerced to UTC, matching the existing
behavior for naive datetime objects.

Backward compatible: datetime callers are unaffected (regression-tested).

Fixes awslabs#2858
@valter-silva-au valter-silva-au force-pushed the fix/ecs-mcp-server-datetime-string-params branch from c967009 to 9825a10 Compare June 8, 2026 06:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: To triage

Development

Successfully merging this pull request may close these issues.

ecs-mcp-server: calculate_time_window crashes when start_time/end_time are passed as strings via MCP

1 participant