MCP server for the Dropscan postal-mail-to-email API (list, download and act on scanned letters)
Dropscan MCP has 13 well-named, read-only tools with consistent verb_noun naming (list_*, get_*). All tools have descriptions (avg ~80 chars, within baseline 34-392). Input schemas are present and typed for all tools. However, descriptions are terse and lack context for LLM selection, they state WHAT (e.g., 'List all scanboxes') but not WHEN or WHY to use each tool. Parameter descriptions are minimal (e.g., 'Scanbox id' vs. 'The unique identifier for the scanbox; required to filter mailings'). Output schemas are undocumented, LLMs cannot predict response structure. Error handling returns generic dicts without recovery guidance. No tool annotations (readOnlyHint, idempotentHint) despite all being read-only. Security is strong (token via env var, no secrets in params), but composition lacks pagination guidance for list tools.
Get a forwarding address by id. Read-only. GET /forwarding_addresses/{id}
Get one mailing with its details/extracted content. Read-only. GET /scanboxes/{scanbox_id}/mailings/{uuid}
Download a mailing's envelope image (JPEG) and save it. Read-only. GET /scanboxes/{scanbox_id}/mailings/{uuid}/envelope
Download a mailing's scanned PDF and save it to disk. Read-only. GET /scanboxes/{scanbox_id}/mailings/{uuid}/pdf
Get OCR plaintext of a mailing (first 5 documents). Read-only. GET /scanboxes/{scanbox_id}/mailings/{uuid}/plaintext
Download a mailing's ZIP (individual PDFs) and save it. Read-only. GET /scanboxes/{scanbox_id}/mailings/{uuid}/zip
Output schemas undocumented. LLMs cannot predict response structure (fields, types, nesting). Forces trial-and-error parsing and wastes tokens on unstructured output.
Descriptions are terse (avg ~80 chars) and lack context. They state WHAT (e.g., 'List all scanboxes') but not WHEN to use or how this tool differs from similar ones. LLMs cannot reliably select the right tool.
Parameter descriptions are minimal. E.g., 'Scanbox id (e.g. "12345")' includes an example value that LLMs may reuse literally. Should be 'The unique identifier for the scanbox (numeric string, e.g., 12345 for account ABC)' with format constraints, not examples.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 66 | 2026-07-28+ | v2 |
Get one recipient of a scanbox. Read-only. GET /scanboxes/{scanbox_id}/recipients/{id}
Get a shipment (physical forwarding batch) by id. Read-only. GET /shipments/{id}
Get one webhook rule by id. Read-only. GET /webhook_rules/{id}
List mailings in a scanbox (GET /scanboxes/{id}/mailings). Read-only.
List recipients configured for a scanbox. Read-only. GET /scanboxes/{scanbox_id}/recipients
List all scanboxes on the account (GET /scanboxes). Read-only.
List all webhook rules on the account. Read-only. GET /webhook_rules
No tool annotations (readOnlyHint, idempotentHint). All 13 tools are read-only and safe to retry, but LLMs cannot infer this without explicit hints. Agents may avoid retrying on transient failures.
Error handling returns generic dicts (e.g., {'error': 'HTTP 404', 'body': '...'}) without recovery guidance. LLMs cannot determine if error is retryable, user-fixable, or fatal. Should include 'Try search_users() first' or 'Check scanbox_id format'.