feat: add get_steps and get_daily_stats tools
This commit is contained in:
34
server.py
34
server.py
@@ -232,6 +232,40 @@ def get_spo2(date: str = "") -> str:
|
|||||||
return f"Error fetching SpO2 data: {exc}"
|
return f"Error fetching SpO2 data: {exc}"
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
def get_steps(date: str = "") -> str:
|
||||||
|
"""Get step count and daily goal for a date (YYYY-MM-DD). Defaults to today."""
|
||||||
|
if err := _check_auth():
|
||||||
|
return err
|
||||||
|
cdate = date or _today()
|
||||||
|
try:
|
||||||
|
result = _client.get_steps_data(cdate)
|
||||||
|
if not result:
|
||||||
|
return f"No steps data found for {cdate}"
|
||||||
|
return json.dumps(result, indent=2)
|
||||||
|
except GarminConnectAuthenticationError:
|
||||||
|
return "Authentication error. Call authenticate() again."
|
||||||
|
except Exception as exc:
|
||||||
|
return f"Error fetching steps data: {exc}"
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
def get_daily_stats(date: str = "") -> str:
|
||||||
|
"""Get daily summary for a date (YYYY-MM-DD): calories, floors, intensity minutes. Defaults to today."""
|
||||||
|
if err := _check_auth():
|
||||||
|
return err
|
||||||
|
cdate = date or _today()
|
||||||
|
try:
|
||||||
|
result = _client.get_stats(cdate)
|
||||||
|
if not result:
|
||||||
|
return f"No daily stats found for {cdate}"
|
||||||
|
return json.dumps(result, indent=2)
|
||||||
|
except GarminConnectAuthenticationError:
|
||||||
|
return "Authentication error. Call authenticate() again."
|
||||||
|
except Exception as exc:
|
||||||
|
return f"Error fetching daily stats: {exc}"
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
_startup_login()
|
_startup_login()
|
||||||
mcp.run()
|
mcp.run()
|
||||||
|
|||||||
@@ -212,3 +212,38 @@ def test_health_tools_unauthenticated():
|
|||||||
for fn in (server.get_sleep, server.get_heart_rate, server.get_stress,
|
for fn in (server.get_sleep, server.get_heart_rate, server.get_stress,
|
||||||
server.get_body_battery, server.get_hrv, server.get_spo2):
|
server.get_body_battery, server.get_hrv, server.get_spo2):
|
||||||
assert "Not authenticated" in fn("2026-05-17")
|
assert "Not authenticated" in fn("2026-05-17")
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_steps_success():
|
||||||
|
server._auth_state = "authenticated"
|
||||||
|
server._client = MagicMock()
|
||||||
|
server._client.get_steps_data.return_value = [{"steps": 8342, "primaryActivityLevel": "active"}]
|
||||||
|
data = json.loads(server.get_steps("2026-05-17"))
|
||||||
|
assert data[0]["steps"] == 8342
|
||||||
|
server._client.get_steps_data.assert_called_once_with("2026-05-17")
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_steps_no_data():
|
||||||
|
server._auth_state = "authenticated"
|
||||||
|
server._client = MagicMock()
|
||||||
|
server._client.get_steps_data.return_value = []
|
||||||
|
assert server.get_steps("2026-05-17") == "No steps data found for 2026-05-17"
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_daily_stats_success():
|
||||||
|
server._auth_state = "authenticated"
|
||||||
|
server._client = MagicMock()
|
||||||
|
server._client.get_stats.return_value = {
|
||||||
|
"totalSteps": 9231,
|
||||||
|
"totalKilocalories": 2100.0,
|
||||||
|
"floorsAscended": 5,
|
||||||
|
}
|
||||||
|
data = json.loads(server.get_daily_stats("2026-05-17"))
|
||||||
|
assert data["totalSteps"] == 9231
|
||||||
|
server._client.get_stats.assert_called_once_with("2026-05-17")
|
||||||
|
|
||||||
|
|
||||||
|
def test_steps_and_stats_unauthenticated():
|
||||||
|
server._auth_state = "unauthenticated"
|
||||||
|
for fn in (server.get_steps, server.get_daily_stats):
|
||||||
|
assert "Not authenticated" in fn("2026-05-17")
|
||||||
|
|||||||
Reference in New Issue
Block a user