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:
co-authored by
Claude Opus 4.6
parent
76e6c12b56
commit
f51b27ba19
@@ -29,10 +29,14 @@ def _event_dict_to_summary(event: dict) -> CalendarEventSummary:
|
|||||||
else:
|
else:
|
||||||
categories = raw_categories
|
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(
|
return CalendarEventSummary(
|
||||||
uid=event.get("uid", ""),
|
uid=event.get("uid", ""),
|
||||||
summary=event.get("title", ""),
|
summary=event.get("title", ""),
|
||||||
start=event.get("start_datetime", ""),
|
start=start,
|
||||||
end=event.get("end_datetime"),
|
end=event.get("end_datetime"),
|
||||||
all_day=event.get("all_day", False),
|
all_day=event.get("all_day", False),
|
||||||
location=event.get("location") or None,
|
location=event.get("location") or None,
|
||||||
@@ -240,7 +244,10 @@ def configure_calendar_tools(mcp: FastMCP):
|
|||||||
limit=limit,
|
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:
|
for event in events:
|
||||||
event["calendar_name"] = calendar_name
|
event["calendar_name"] = calendar_name
|
||||||
|
|
||||||
@@ -463,6 +470,7 @@ def configure_calendar_tools(mcp: FastMCP):
|
|||||||
end_datetime=end_datetime,
|
end_datetime=end_datetime,
|
||||||
limit=limit,
|
limit=limit,
|
||||||
)
|
)
|
||||||
|
# calendar_display_name not available without extra API call
|
||||||
for event in events:
|
for event in events:
|
||||||
event["calendar_name"] = calendar_name
|
event["calendar_name"] = calendar_name
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -19,7 +19,13 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
def _raw_contact_to_model(raw: dict) -> Contact:
|
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", {})
|
contact_info = raw.get("contact", {})
|
||||||
|
|
||||||
# Convert email field (str, list, or None) to list[ContactField]
|
# Convert email field (str, list, or None) to list[ContactField]
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ def configure_deck_tools(mcp: FastMCP):
|
|||||||
)
|
)
|
||||||
client = await get_client(ctx)
|
client = await get_client(ctx)
|
||||||
board = await client.deck.get_board(board_id)
|
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}")
|
@mcp.resource("nc://Deck/boards/{board_id}/labels/{label_id}")
|
||||||
async def deck_label_resource(board_id: int, label_id: int):
|
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"""
|
"""Get all labels in a Nextcloud Deck board"""
|
||||||
client = await get_client(ctx)
|
client = await get_client(ctx)
|
||||||
board = await client.deck.get_board(board_id)
|
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(
|
@mcp.tool(
|
||||||
title="Get Deck Label",
|
title="Get Deck Label",
|
||||||
|
|||||||
Reference in New Issue
Block a user