fix: address PR #574 third review round

- Guard board.labels against None in deck_get_labels and resource
- Add TODO comments for calendar_display_name in single-calendar paths
- Document _raw_contact_to_model scope limitation (maps only what the
  client returns; expanding requires changes to vCard parsing)
- Log debug warning when event has no start_datetime
- Verified Table model is safe with extra fields (Pydantic v2 ignores)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Chris Coutinho
2026-02-20 13:49:55 +01:00
parent 76e6c12b56
commit f51b27ba19
3 changed files with 20 additions and 5 deletions
+10 -2
View File
@@ -29,10 +29,14 @@ def _event_dict_to_summary(event: dict) -> CalendarEventSummary:
else:
categories = raw_categories
start = event.get("start_datetime", "")
if not start:
logger.debug("Event %s has no start_datetime", event.get("uid", "unknown"))
return CalendarEventSummary(
uid=event.get("uid", ""),
summary=event.get("title", ""),
start=event.get("start_datetime", ""),
start=start,
end=event.get("end_datetime"),
all_day=event.get("all_day", False),
location=event.get("location") or None,
@@ -240,7 +244,10 @@ def configure_calendar_tools(mcp: FastMCP):
limit=limit,
)
# Enrich events with calendar context for per-event mapping
# Enrich events with calendar context for per-event mapping.
# Note: calendar_display_name is not available here without an
# extra list_calendars() call; the response-level calendar_name
# already identifies the calendar for single-calendar queries.
for event in events:
event["calendar_name"] = calendar_name
@@ -463,6 +470,7 @@ def configure_calendar_tools(mcp: FastMCP):
end_datetime=end_datetime,
limit=limit,
)
# calendar_display_name not available without extra API call
for event in events:
event["calendar_name"] = calendar_name
else:
+7 -1
View File
@@ -19,7 +19,13 @@ logger = logging.getLogger(__name__)
def _raw_contact_to_model(raw: dict) -> Contact:
"""Convert a raw contact dict from the contacts client to a Contact model."""
"""Convert a raw contact dict from the contacts client to a Contact model.
Only maps fields the client's list_contacts() currently returns:
fullname, nickname, birthday, and email. Additional Contact model fields
(phones, addresses, organization, etc.) require expanding the client's
vCard parsing in ContactsClient.list_contacts().
"""
contact_info = raw.get("contact", {})
# Convert email field (str, list, or None) to list[ContactField]
+3 -2
View File
@@ -107,7 +107,7 @@ def configure_deck_tools(mcp: FastMCP):
)
client = await get_client(ctx)
board = await client.deck.get_board(board_id)
return [label.model_dump() for label in board.labels]
return [label.model_dump() for label in (board.labels or [])]
@mcp.resource("nc://Deck/boards/{board_id}/labels/{label_id}")
async def deck_label_resource(board_id: int, label_id: int):
@@ -209,7 +209,8 @@ def configure_deck_tools(mcp: FastMCP):
"""Get all labels in a Nextcloud Deck board"""
client = await get_client(ctx)
board = await client.deck.get_board(board_id)
return ListLabelsResponse(labels=board.labels, total=len(board.labels))
labels = board.labels or []
return ListLabelsResponse(labels=labels, total=len(labels))
@mcp.tool(
title="Get Deck Label",