MCP server for the Purelymail API — manage domains, mailboxes, and routing rules from Claude Code
The server presents 14 well-named tools with consistent verb-noun patterns (list_, get_, create_, delete_, modify_). Descriptions are present and contextual (averaging 130-160 chars), exceeding the 10-char minimum but generally below the 200-char optimum for LLM clarity. All tools expose Zod schemas with type declarations and parameter descriptions. However, critical gaps exist: (1) NO output schemas are documented, the server returns JSON blobs via `ok()` helper without type hints, forcing LLMs to infer response structure; (2) parameter descriptions lack constraints (e.g., targetAddresses is 'Email addresses to forward matching mail to' but lacks examples or format hints); (3) error handling is minimal, the `call()` wrapper attempts to parse JSON but returns raw API text on failure with no recovery guidance; (4) the delete_routing_rule tool has an unusual schema requiring id + (domainName, prefix, matchUser, targetAddresses) simultaneously, making the API contract unclear; (5) no pagination support despite potential for large result sets (list_domains, list_users, list_routing_rules). Input schemas are visible and properly typed (Zod), but the composition and chaining story is weak, tools don't document what IDs/references downstream operations require.
Add a domain to Purelymail. The ownership TXT record and MX record must be set in DNS first. Use get_ownership_code to get the exact TXT value.
Run live DNS deliverability checks for a domain — MX, SPF, DKIM (all 3 Purelymail keys), and DMARC. Returns a scored report with issues and recommendations.
Create an email routing rule to forward or alias addresses. E.g. forward support@example.com to another inbox.
Create a new email mailbox on a Purelymail domain
Delete a domain and all its associated users from Purelymail
Delete an email routing rule. Get the rule ID from list_routing_rules.
No output schemas documented for any tool. All tools return JSON via the `ok()` helper, but LLMs have no type hint for what fields/structure to expect. Forces agents to infer response shape from examples, increasing hallucination and misdirected chaining.
delete_routing_rule schema is incoherent. Requires id + (domainName, prefix, matchUser, targetAddresses) but description only mentions 'Get the rule ID from list_routing_rules.' Unclear if all fields are mandatory or if id alone is sufficient. Violates pattern:tool-chain, the output of list_routing_rules must unambiguously provide all inputs for delete_routing_rule.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | B | 71 | 2026-07-28+ | v2 |
Delete an email mailbox from Purelymail
Get the TXT record value needed to prove domain ownership. Add this as a TXT record at the root of your domain before calling add_domain.
Returns the exact DNS records needed to configure a domain with Purelymail — ownership proof, MX, SPF, DKIM, and DMARC. Call this before adding records to any DNS provider to get the correct values.
Get details for a specific Purelymail user
List all domains on the Purelymail account with their DNS validation status (MX, SPF, DKIM, DMARC)
List all email routing/forwarding rules on the Purelymail account
List all email users/mailboxes on the Purelymail account
Modify an existing Purelymail mailbox (password, recovery email, search indexing)
No pagination support for list operations (list_domains, list_users, list_routing_rules). No limit, offset, or cursor parameters, and no total count returned. Large result sets will blow context windows. Violates pattern:paginated-result.
Error handling is minimal. The `call()` function attempts JSON.parse() on API responses and returns raw text on failure with no recovery guidance. No error categorization (retryable vs user-fixable vs fatal). LLMs cannot determine what to do next on failure.
Destructive operations (delete_domain, delete_user, delete_routing_rule) lack confirmation or dry-run patterns. Agents can invoke irreversible deletes without safeguards. Violates pattern:confirmation-request.
Parameter descriptions lack concrete constraints. E.g., targetAddresses described as 'Email addresses to forward matching mail to' but no format hints or examples. Password field in create_user and modify_user has no complexity/length requirements documented. Violates pattern:constrained-input.
Tool descriptions include example values (e.g., 'hello' for userName, 'example.com' for domainName). LLMs tend to reuse these literally in real calls. Should use parameter constraints (enums, patterns) instead. Violates pattern:tool-description best practice.
No tool annotations (readOnlyHint, destructiveHint, idempotentHint). LLMs must infer which operations are safe to retry, readonly, or destructive. Current spec (2026-07-28) supports tool annotations; this server does not use them.
No documentation of tool chaining prerequisites. E.g., create_user requires domainName, but there's no hint that get_ownership_code → add_domain must precede user creation. Violates pattern:tool-description (should include dependency hints).