fix(mail): guard empty message payload in processor (PR #935 round-6)

- processor.py: raise on an empty mail_message payload (OCS data=null with a
  <400 meta) so the task dead-letters instead of indexing a near-empty
  placeholder — mirrors the nc_mail_get_message tool guard. (the round-6
  approve-gating item)
- server/mail.py: clamp limit once in nc_mail_list_messages and base has_more on
  the effective (post-clamp) limit, so a caller passing limit<=0 doesn't get a
  misleading count.
- server/mail.py: note in nc_mail_get_message that attachments with id=null are
  inline body parts and can't be fetched via nc_mail_get_attachment.
- tests: add the first-time-missing incremental scanner case (enters the grace
  period, nothing queued/deleted).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Chris Coutinho
2026-06-20 13:35:49 +02:00
co-authored by Claude Opus 4.8
parent d006145444
commit 10e768e414
3 changed files with 39 additions and 2 deletions
+11 -2
View File
@@ -143,15 +143,22 @@ def configure_mail_tools(mcp: FastMCP):
messages; page with ``cursor`` and stop on an empty result.
"""
client = await get_client(ctx)
# Clamp to the same window the client/OCS API enforce so the has_more
# heuristic compares against the limit actually applied (a caller passing
# limit<=0 otherwise gets a misleading count).
effective_limit = min(max(1, limit), 100)
try:
messages_data = await client.mail.list_messages(
mailbox_id, cursor=cursor, search_filter=search_filter, limit=limit
mailbox_id,
cursor=cursor,
search_filter=search_filter,
limit=effective_limit,
)
messages = [MailMessageSummary(**m) for m in messages_data]
return ListMessagesResponse(
results=messages,
total_count=len(messages),
has_more=len(messages) == limit and limit > 0,
has_more=len(messages) == effective_limit,
)
except RequestError as e:
raise McpError(
@@ -181,6 +188,8 @@ def configure_mail_tools(mcp: FastMCP):
Returns:
GetMessageResponse with the full message including body and attachments.
Attachments with ``id: null`` are inline body parts and cannot be
fetched via nc_mail_get_attachment (which requires a string id).
"""
client = await get_client(ctx)
try: