Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 23 additions & 21 deletions src/rtm_mcp/response_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,27 +198,29 @@ def parse_tasks_response(result: dict[str, Any]) -> list[dict[str, Any]]:
notes = [notes]

for t in task_data:
tasks.append({
"id": t.get("id"),
"taskseries_id": ts.get("id"),
"list_id": list_id,
"name": ts.get("name"),
"due": t.get("due") or None,
"has_due_time": t.get("has_due_time") == "1",
"start": t.get("start") or None,
"has_start_time": t.get("has_start_time") == "1",
"completed": t.get("completed") or None,
"deleted": t.get("deleted") or None,
"priority": t.get("priority", "N"),
"postponed": int(t.get("postponed", 0)),
"estimate": t.get("estimate") or None,
"tags": tags if tags else [],
"notes": notes,
"url": ts.get("url") or None,
"location_id": ts.get("location_id") or None,
"created": ts.get("created") or None,
"modified": ts.get("modified") or None,
})
tasks.append(
{
"id": t.get("id"),
"taskseries_id": ts.get("id"),
"list_id": list_id,
"name": ts.get("name"),
"due": t.get("due") or None,
"has_due_time": t.get("has_due_time") == "1",
"start": t.get("start") or None,
"has_start_time": t.get("has_start_time") == "1",
"completed": t.get("completed") or None,
"deleted": t.get("deleted") or None,
"priority": t.get("priority", "N"),
"postponed": int(t.get("postponed", 0)),
"estimate": t.get("estimate") or None,
"tags": tags if tags else [],
"notes": notes,
"url": ts.get("url") or None,
"location_id": ts.get("location_id") or None,
"created": ts.get("created") or None,
"modified": ts.get("modified") or None,
}
)

return tasks

Expand Down
16 changes: 9 additions & 7 deletions src/rtm_mcp/tools/notes.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,13 +228,15 @@ async def get_task_notes(

formatted_notes = []
for note in notes:
formatted_notes.append({
"id": note.get("id"),
"title": note.get("title", ""),
"body": note.get("$t", note.get("body", "")),
"created": note.get("created"),
"modified": note.get("modified"),
})
formatted_notes.append(
{
"id": note.get("id"),
"title": note.get("title", ""),
"body": note.get("$t", note.get("body", "")),
"created": note.get("created"),
"modified": note.get("modified"),
}
)

return build_response(
data={
Expand Down
10 changes: 3 additions & 7 deletions src/rtm_mcp/tools/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -971,22 +971,18 @@ def _analyze_tasks(tasks: list[dict[str, Any]], timezone: str | None = None) ->
without_estimate = 0
tags_used: set[str] = set()

import contextlib
from datetime import UTC, datetime
from zoneinfo import ZoneInfo

# Get current date in user's timezone for accurate comparison
# RTM due dates are relative to the user's timezone
user_tz = None
if timezone:
try:
with contextlib.suppress(Exception):
user_tz = ZoneInfo(timezone)
except Exception:
pass

if user_tz:
now = datetime.now(user_tz)
else:
now = datetime.now(UTC)
now = datetime.now(user_tz) if user_tz else datetime.now(UTC)
today = now.date()

for task in tasks:
Expand Down
54 changes: 32 additions & 22 deletions src/rtm_mcp/tools/utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,11 @@ async def get_tags(ctx: Context) -> dict[str, Any]:
if isinstance(tag, str):
tags.append({"name": tag})
else:
tags.append({
"name": tag.get("name", tag.get("$t", "")),
})
tags.append(
{
"name": tag.get("name", tag.get("$t", "")),
}
)

return build_response(
data={
Expand Down Expand Up @@ -134,14 +136,16 @@ async def get_locations(ctx: Context) -> dict[str, Any]:

locations = []
for loc in locations_data:
locations.append({
"id": loc.get("id"),
"name": loc.get("name"),
"latitude": float(loc.get("latitude", 0)),
"longitude": float(loc.get("longitude", 0)),
"zoom": int(loc.get("zoom", 0)) if loc.get("zoom") else None,
"address": loc.get("address"),
})
locations.append(
{
"id": loc.get("id"),
"name": loc.get("name"),
"latitude": float(loc.get("latitude", 0)),
"longitude": float(loc.get("longitude", 0)),
"zoom": int(loc.get("zoom", 0)) if loc.get("zoom") else None,
"address": loc.get("address"),
}
)

return build_response(
data={
Expand All @@ -166,7 +170,9 @@ async def get_settings(ctx: Context) -> dict[str, Any]:
settings = result.get("settings", {})

# Format settings nicely
date_format = "European (DD/MM/YY)" if settings.get("dateformat") == "0" else "American (MM/DD/YY)"
date_format = (
"European (DD/MM/YY)" if settings.get("dateformat") == "0" else "American (MM/DD/YY)"
)
time_format = "12-hour" if settings.get("timeformat") == "0" else "24-hour"

return build_response(
Expand Down Expand Up @@ -276,11 +282,13 @@ async def get_contacts(ctx: Context) -> dict[str, Any]:

contacts = []
for contact in contacts_data:
contacts.append({
"id": contact.get("id"),
"fullname": contact.get("fullname"),
"username": contact.get("username"),
})
contacts.append(
{
"id": contact.get("id"),
"fullname": contact.get("fullname"),
"username": contact.get("username"),
}
)

return build_response(
data={
Expand Down Expand Up @@ -312,11 +320,13 @@ async def get_groups(ctx: Context) -> dict[str, Any]:
if isinstance(contacts, dict):
contacts = [contacts]

groups.append({
"id": group.get("id"),
"name": group.get("name"),
"member_count": len(contacts),
})
groups.append(
{
"id": group.get("id"),
"name": group.get("name"),
"member_count": len(contacts),
}
)

return build_response(
data={
Expand Down
2 changes: 1 addition & 1 deletion tests/test_tools/test_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def test_analyze_overdue_tasks(self) -> None:

def test_analyze_tasks_with_timezone(self) -> None:
"""Test that timezone is properly applied for date comparisons."""
from datetime import UTC, datetime, timedelta
from datetime import UTC, datetime
from zoneinfo import ZoneInfo

from rtm_mcp.tools.tasks import _analyze_tasks
Expand Down
Loading