feat: improve date formatting using local start times and add sport-specific emoji icons to activity summaries
CI/CD Pipeline / Lint & Check (push) Successful in 11s
CI/CD Pipeline / Publish to PyPI (push) Has been skipped
CI/CD Pipeline / Build & Push Docker Image (push) Successful in 1m30s

This commit is contained in:
2026-05-30 11:47:08 +02:00
parent 90e23c26b8
commit e7ec16abe5
4 changed files with 89 additions and 11 deletions
+10 -9
View File
@@ -7,6 +7,7 @@ from strava_mcp_server.utils import (
format_date_iso,
format_date_human,
format_duration_markdown,
get_sport_emoji,
)
@@ -59,13 +60,14 @@ def register(mcp: FastMCP, strava: StravaClient) -> None:
essential_data = []
for a in activities:
start_date_raw = a.get("start_date")
start_date_local_raw = a.get("start_date_local") or start_date_raw
essential_data.append(
{
"id": a["id"],
"name": a["name"],
"sport_type": a.get("sport_type") or a.get("type"),
"start_date": format_date_iso(start_date_raw),
"start_date_local": format_date_human(start_date_raw),
"start_date_local": format_date_human(start_date_local_raw),
"distance": f"{a.get('distance', 0) / 1000:.2f} km",
"moving_time": f"{a.get('moving_time', 0) / 60:.1f} min",
"total_elevation_gain": f"{a.get('total_elevation_gain', 0):.0f} m",
@@ -80,12 +82,8 @@ def register(mcp: FastMCP, strava: StravaClient) -> None:
)
else:
markdown_summary = f"### 🚴 Aktivitäten (Seite {page})\n"
markdown_summary += (
"| Datum | Sport | Name | Distanz | Zeit | Höhenmeter | Ø HR |\n"
)
markdown_summary += (
"|-------|-------|------|---------|------|------------|------|\n"
)
markdown_summary += "| 📅 Datum | 🏃 Icon | 🏷️ Name | 📐 Distanz | ⏱️ Zeit | 🏔️ Höhenmeter | ❤️ Ø HR |\n"
markdown_summary += "|----------|--------|--------|-----------|--------|--------------|--------|\n"
for a, raw_act in zip(essential_data, activities):
hr = (
f"{a['average_heartrate']:.0f} bpm"
@@ -93,7 +91,8 @@ def register(mcp: FastMCP, strava: StravaClient) -> None:
else "-"
)
time_md = format_duration_markdown(raw_act.get("moving_time"))
markdown_summary += f"| {a['start_date_local']} | {a['sport_type']} | {a['name']} | {a['distance']} | {time_md} | {a['total_elevation_gain']} | {hr} |\n"
sport_icon = get_sport_emoji(a["sport_type"])
markdown_summary += f"| {a['start_date_local']} | {sport_icon} | {a['name']} | {a['distance']} | {time_md} | {a['total_elevation_gain']} | {hr} |\n"
return [
_user_text(markdown_summary.strip()),
@@ -125,7 +124,9 @@ def register(mcp: FastMCP, strava: StravaClient) -> None:
name = activity.get("name", "N/A")
sport = activity.get("sport_type") or activity.get("type", "N/A")
date = format_date_human(activity.get("start_date"))
date = format_date_human(
activity.get("start_date_local") or activity.get("start_date")
)
dist = f"{activity.get('distance', 0) / 1000:.2f} km"
time = format_duration_markdown(activity.get("moving_time"))
elev = f"{activity.get('total_elevation_gain', 0):.0f} m"
@@ -59,10 +59,13 @@ def register(mcp: FastMCP, strava: StravaClient) -> None:
)
time_elapsed = format_duration_markdown(e.get("elapsed_time"))
time_moving = format_duration_markdown(e.get("moving_time"))
date_local = format_date_human(
e.get("start_date_local") or e.get("start_date")
)
md = f"""### 🏅 Segment-Effort: {data["name"]}
| Feld | Wert |
|------|------|
| Datum | {format_date_human(data["start_date"])} |
| Datum | {date_local} |
| Distanz | {data["distance"]} |
| Zeit (gesamt) | {time_elapsed} |
| Fahrzeit | {time_moving} |
@@ -124,7 +127,10 @@ def register(mcp: FastMCP, strava: StravaClient) -> None:
pr = f"#{effort['pr_rank']}" if effort["pr_rank"] else "-"
elapsed_md = format_duration_markdown(raw_eff.get("elapsed_time"))
moving_md = format_duration_markdown(raw_eff.get("moving_time"))
md += f"| {format_date_human(effort['start_date'])} | {elapsed_md} | {moving_md} | {pr} |\n"
date_local = format_date_human(
raw_eff.get("start_date_local") or raw_eff.get("start_date")
)
md += f"| {date_local} | {elapsed_md} | {moving_md} | {pr} |\n"
return [
_user_text(md.strip()),
_resource(f"internal://segments/{segment_id}/efforts", data),
+36
View File
@@ -125,3 +125,39 @@ def format_duration_markdown(seconds_input: Optional[float | int]) -> str:
return f"{minutes}min"
except Exception:
return str(seconds_input)
def get_sport_emoji(sport_type: Optional[str]) -> str:
"""
Returns an emoji corresponding to the given sport type.
"""
if not sport_type:
return ""
sport_lower = sport_type.lower()
if "run" in sport_lower:
return "🏃"
elif "ride" in sport_lower or "bike" in sport_lower:
return "🚴"
elif "swim" in sport_lower:
return "🏊"
elif "walk" in sport_lower:
return "🚶"
elif "hike" in sport_lower:
return "🥾"
elif "ski" in sport_lower or "snowboard" in sport_lower:
return "🎿"
elif "row" in sport_lower or "canoe" in sport_lower or "kayak" in sport_lower:
return "🚣"
elif (
"weight" in sport_lower or "workout" in sport_lower or "crossfit" in sport_lower
):
return "🏋️"
elif "yoga" in sport_lower:
return "🧘"
elif "surf" in sport_lower:
return "🏄"
elif "skate" in sport_lower:
return "🛹"
else:
return "🏃"
+35
View File
@@ -9,6 +9,7 @@ from strava_mcp_server.utils import (
format_duration_text,
format_duration_table,
format_duration_markdown,
get_sport_emoji,
)
@@ -188,3 +189,37 @@ class TestFormatDurationMarkdown:
def test_fractional_input(self):
assert format_duration_markdown(2700.2) == "45min"
class TestGetSportEmoji:
def test_none_returns_question_mark(self):
assert get_sport_emoji(None) == ""
def test_empty_string_returns_question_mark(self):
assert get_sport_emoji("") == ""
def test_running(self):
assert get_sport_emoji("Run") == "🏃"
assert get_sport_emoji("VirtualRun") == "🏃"
def test_riding(self):
assert get_sport_emoji("Ride") == "🚴"
assert get_sport_emoji("VirtualRide") == "🚴"
assert get_sport_emoji("MountainBikeRide") == "🚴"
def test_swimming(self):
assert get_sport_emoji("Swim") == "🏊"
def test_walking_and_hiking(self):
assert get_sport_emoji("Walk") == "🚶"
assert get_sport_emoji("Hike") == "🥾"
def test_workout(self):
assert get_sport_emoji("Workout") == "🏋️"
assert get_sport_emoji("WeightTraining") == "🏋️"
def test_yoga(self):
assert get_sport_emoji("Yoga") == "🧘"
def test_unknown_returns_default(self):
assert get_sport_emoji("SomeOddSport") == "🏃"