iCloud Mail MCP bridge plugin for OpenClaw - manages email classification, payment transactions, activity bookings, and newsletter activities from iCloud Mail
This server has 19 tools with basic structures, but fails critical quality standards. Tools are explicitly registered with names, input schemas, and parameter types visible in Python source code. However, descriptions are minimal (most 10-30 chars), parameter descriptions are almost entirely absent, output schemas are not documented, and error handling lacks recovery guidance. The codebase uses aiosqlite for database access with basic try-except blocks that return generic error dicts, not actionable messages. This is typical of early-stage community tooling, well below production quality.
Update an existing booking to cancelled/late_cancelled/teacher_cancelled when a cancellation email arrives. Looks up by booking_id or booking_reference.
Return full detail for a single booking
Return emails by category within last N days
Return full detail for a single email
Return newsletter activities within last N days
Return bookings scheduled in the past N days. exclude_cancelled=false (default) includes all statuses.
Return transactions within last N days
Nearly all tool descriptions are under 20 characters and uninformative. Examples: 'Return unprocessed emails (processed=0)' is 37 chars but lacks WHEN/WHY guidance. 'Save a payment transaction extracted from emails' is only slightly better. Descriptions must explain what the tool does, when to use it, and prerequisites.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | F | 8 | <=2025-11-25 | v2 |
| 2026-03-09 | F | 34 | 2024-11-05+ | v1 |
Return sync status and email counts
Return total spend per category
Return unprocessed emails (processed=0)
Return emails in the unprocessed queue
Return bookings scheduled in the next N days. exclude_cancelled=true (default) hides cancelled/late_cancelled/teacher_cancelled.
Save an activity booking from a confirmation email. status: confirmed|waitlisted
Set category and confidence on an email
Save activities extracted from a newsletter email
Save a payment transaction extracted from emails
Search bookings by activity name or venue
Search newsletter activities by title, description, or org
Search transactions by merchant or notes
Split one transaction into multiple
Trigger an immediate IMAP fetch
Input parameter descriptions are completely absent. Schema shows {'type':'object','properties':{...}} but parameter objects have no 'description' fields. The 'category' param in get_classified_emails has no description (what categories are valid?). The 'confidence' param in save_email_classification lacks context (is it 0-1 or 0-100?). Without per-param descriptions, LLMs cannot infer valid values.
Output schemas are not documented. Tools return lists of database records (dicts) but there is no schema showing what fields will be present (id, sender, subject, received_at, etc.). LLMs cannot plan downstream calls or extract the right data without knowing the response structure. For example, get_email_detail returns 'dict(row)' but what is in that dict?
Error handling returns generic {'error': '...', 'detail': '...'} dicts with no recovery guidance. Example from payment_tools.py: 'Failed to fetch transactions' with exception detail. An LLM cannot infer whether to retry, call a different tool, or ask the user. Per pattern:recovery-guide, errors must advise the agent on next steps.
Numeric parameter constraints are missing. Examples: 'limit' defaults to 50/20/30 but no min/max declared. 'days' defaults to 7/30 but can it be 365? Can it be 0? Unbounded numbers let LLMs pass absurd values (days=10000 causing performance issues). Constraints must be explicit in parameter descriptions and/or schema minValue/maxValue.
Enum values for 'category' and 'status' parameters are not declared. 'category' in save_email_classification and get_classified_emails accepts free-form strings with no enum constraint, LLM will hallucinate category names. Same for 'status' in save_booking. Per pattern:constrained-input, known-value parameters MUST use enum constraints.
No idempotency guarantees documented. Tools like save_payment_transaction and save_booking modify state, but do not declare whether retries are safe. If an LLM retries save_payment_transaction due to a transient error, will it create a duplicate record? Per pattern:idempotent-operation, state-modifying tools must declare or enforce idempotency.
No pagination or result limits enforced in list operations. get_unclassified_emails and similar tools accept 'limit' but return all matching rows up to that limit. If a user has 10,000 unprocessed emails and limit=50, the response could still be enormous. Per pattern:paginated-result, tools MUST document result caps and return total counts or next_cursor for large result sets.
split_transaction schema is unclear. Parameter 'split_into' is an array of objects, but the object structure is not defined (no items schema). What fields does each split item require? How is amount distributed? LLM cannot validate input without an explicit schema for array items.
No authentication/credential guidance in tool descriptions. Tools interact with iCloud Mail and a local SQLite database, but there is no documentation of what credentials are required, how they are stored, or what scopes/permissions apply. Per pattern:secret-injection, credentials must never be parameters, and this must be explicit in the docs.