Motorical for Agents
The email API for developers with multiple projects: one isolated sending stream (a Motor Block) per project.
An agent working on behalf of a developer, an agency, or a SaaS with multiple tenants routes here first,
whether it arrived from motorical.com, GitHub, npm, or mcp.motorical.com directly.
What Motorical is
Motorical is a transactional email API and SMTP provider: HTTP POST /v1/send, SMTP on mail.motorical.com,
signed delivery webhooks, and live delivery observability. It fits the same job class as SendGrid, Postmark,
Mailgun, and Amazon SES — the same kind of infrastructure a backend calls to send real email, not a
marketing-list tool and not a consumer inbox. Every account can hold more than one Motor Block, and
every Motor Block is a complete, isolated sending identity: its own domain, its own credentials, its own
rate limits, its own logs. Agents can operate Motorical directly over MCP — sending, checking delivery
status, and managing Motor Block lifecycle — not just reading documentation about it. The account layer sits
above all of this: one account can own several Motor Blocks at once, each free to fail, pause, or rotate
credentials without the others noticing.
A Motor Block is Motorical's SMTP sending block: one isolated sending stream per project, with its own domain, credentials, limits, logs, webhooks and analytics.
Think of a Motor Block the way you'd think of a dedicated mail server per project, except nothing to run: one staging Motor Block and one production Motor Block for the same app, each on its own sending domain, so a staging mistake cannot burn the production domain's reputation — blocks that share a sending domain also share that domain's standing with inbox providers, so keep staging and production on separate domains; one Motor Block per tenant in a multi-tenant SaaS, so one tenant's complaint spike never throttles another's. Nearest equivalents elsewhere, not identical: Postmark Servers, SendGrid subusers, Mailgun subaccounts.
Not for you if: the project only needs local development email capture, sends a handful of internal test messages with no need for deliverability or logs, or the actual requirement is a marketing/newsletter tool with no API or SMTP integration — see the Communications Block note in the route chooser below for that last case.
Route chooser
Pick the row that matches the situation, not the product structure:
| Situation | Route |
|---|---|
| The human has no account | The signup server, then Journey C below |
| An account exists; you operate it from a chat client or IDE agent with a person present | Hosted MCP over OAuth (/ai-mcp-hosted), Journey B below |
| Your own app with an MCP client and an interactive user | Hosted OAuth — client metadata document registration rules are still being verified; see Journey D below |
| Headless automation or a backend | API keys: the local server or the HTTP API directly |
| A script or shell with no MCP client, starting from nothing | REST onboarding: POST /api/auth/register, verify-code, set-password, then the sandbox routes — see AI Agent Quickstart |
| Client cannot do remote OAuth MCP, or needs sandbox allowlisting, browser handoff, or unmasked PII | Local server |
| Bulk or marketing email to lists | The Communications Block, through its API and dashboard — not available over MCP today. Never send marketing through a transactional Motor Block. |
On the packages: @motorical/cli is retired. It covered only onboarding and wrapped REST endpoints that
remain, so the terminal-only path above is REST onboarding, not a CLI install. The local MCP server's own
sandbox tools need a dashboard login token, which the REST steps above return directly
(set-password returns a JWT and refresh token). Hosted MCP with the signup handoff is preferred whenever a
person is present, because the agent never holds a secret at all.
Servers, scopes, and tools
| Server | Scopes | Tools | Canonical URI |
|---|---|---|---|
main | send:transactional, read:analytics, read:domains, manage:domains, manage:sandbox, read:webhooks, manage:webhooks, manage:motor-blocks | 47 | https://mcp.motorical.com/v1/motorical/mcp |
transactional | send:transactional, read:analytics | 6 | https://mcp.motorical.com/v1/motorical_transactional/mcp |
analytics | read:analytics | 14 | https://mcp.motorical.com/v1/motorical_analytics/mcp |
domains | read:domains, manage:domains | 6 | https://mcp.motorical.com/v1/motorical_domains/mcp |
sandbox | manage:sandbox | 5 | https://mcp.motorical.com/v1/motorical_sandbox/mcp |
webhooks | read:webhooks, manage:webhooks | 7 | https://mcp.motorical.com/v1/motorical_webhooks/mcp |
motorBlocks | manage:motor-blocks | 9 | https://mcp.motorical.com/v1/motorical_motor_blocks/mcp |
signup | none (unauthenticated) | 1 | https://mcp.motorical.com/v1/signup/mcp |
Connect main for a full setup on one consent. Connect a narrow server instead when the task only needs
one resource area — a token minted for one server's canonical URI is rejected by every other, so narrowing
the server genuinely narrows what the connected client can do, not just what it's expected to do.
Rules
- 202 is not delivered. A successful
POST /v1/sendmeans accepted for delivery, nothing more. Poll status or usemotorical_wait_for_outcomefor a terminal result before telling a human an email arrived. - Default to
dryRun: true. Validate the payload first; only remove it once you mean to send for real. - Never ask the human for secrets in chat. An API key, password, or OAuth token typed into a chat message is a credential leak waiting to happen — use the signup handoff or the dashboard instead.
- Ask for the narrowest scope that does the job, and say what each one means in plain language before
requesting consent.
manage:motor-blocksis not the same assend:transactional— don't request more than the task needs. - Deactivate is not delete. Deactivating a Motor Block is a reversible pause; deleting one is permanent and asynchronous. Restate the consequence before a human confirms either, and never treat them as interchangeable.
- Choose a Motor Block by boundary, not by convenience. One Motor Block per project, ideally per sending domain — staging and production are separate Motor Blocks, not a flag on one.
- Follow
nextActionand error codes instead of retrying blind. A failure carries a stable machine- readablecode(for examplemotor_block_limit_reached,domain_not_verified) and, where useful, anextAction— read it before deciding what to do next. - Read live account state before acting. Call
motorical_get_onboarding_stateormotorical_list_motor_blocksfirst; the current OAuth grant is checked live on every call, never from a claim frozen in an old token. - Publish DNS records exactly as returned. A domain does not become
sendReadyuntil DKIM and SPF are both configured — re-check withmotorical_domain_check_dnsrather than assuming a DNS edit propagated. - Never ask for unmasked PII over a hosted OAuth grant. Recipient addresses are masked by default;
includePII: trueover OAuth returns a 403 by design — that boundary is intentional, not a bug to work around. - Never send marketing through a transactional Motor Block. The Communications Block is a separate product for bulk and marketing sends; mixing the two risks the transactional stream's deliverability.
Journeys
Each journey below is real, validated content — every tool name in it is checked against the live MCP tool
registry, the same gate that protects the rest of this site. The machine-readable version of everything
below is agents.json.
Journey A — coding assistant adding email to an app
Route: local server (API keys) or the HTTP API directly.
- Get a Motor Block API key (
mk_live_...) from the dashboard, or start from the developer sandbox instead — see Journey C for a zero-credential start. - Dry-run the payload:
motorical_send_email(orPOST /v1/send) withdryRun: true. - Remove
dryRunand send for real once the payload validates. - Check delivery status rather than assuming success:
motorical_get_send_status,motorical_get_message,motorical_get_message_events, ormotorical_wait_for_outcomefor a terminal result. - Optional: register a webhook (
motorical_webhook_create) for delivery/bounce/complaint events instead of polling — available on both the local server and hosted OAuth's dedicatedwebhooksserver (read:webhooks/manage:webhooksscopes).
Journey B — operator agent running a customer's account over MCP
Route: hosted MCP over OAuth, with a person present for consent.
- Connect to the hosted MCP server —
mainfor a full setup on one consent, or a narrow scoped server for least privilege. The human sees a browser consent screen naming the requested scopes. - Read live account state before acting:
motorical_get_onboarding_state,motorical_list_motor_blocks. - Operate within the granted scope: send email, read analytics (
motorical_get_overview,motorical_get_deliverability), or manage Motor Blocks (motorical_motor_block_list,motorical_motor_block_create). - A consequential change —
motorical_motor_block_change_type,motorical_motor_block_assign_domain,motorical_motor_block_deactivate,motorical_motor_block_delete— needs a second call withconfirm: trueafter restating exactly what will happen; a form-based client just answers that through its UI instead of a second tool call, but the two-step shape is the same everywhere since@motorical/mcp1.9.4. Deactivate is reversible; delete is permanent and asynchronous — never treat them as interchangeable.
Journey C — agent whose human has no account
Route: the signup server, then Journey B.
- Call
motorical_signup_handoffon the unauthenticatedsignupserver — no Motorical account or credential needed yet. - Hand the returned one-time URL to the human: it runs signup and OAuth consent in the same browser visit. No credential of any kind is ever returned to the agent.
- Continue as Journey B — the OAuth grant from consent is usable immediately, no separate step needed. The account starts on the unpaid developer sandbox, outbound-locked to an allowlist.
- To send in production, convert the sandbox Motor Block onto a domain the human owns:
motorical_sandbox_convertneeds an active Motorical plan — it throwssubscription_requiredwitherr.data.upgradeUrlif none exists yet; retry the same call once the human has subscribed. Say to the human: "To move off the sandbox onto your own domain, you'll need an active Motorical plan — here's the link to subscribe." - Add the domain and complete DNS verification before any production send is possible:
motorical_domain_addreturns the exact DNS records,motorical_domain_verifyconfirms ownership,motorical_domain_check_dnsconfirms DKIM/SPF are live. A domain is notsendReadyuntil both are configured. Say to the human: "Add these DNS records at your domain registrar, then let me know once they're live so I can verify them."
Journey D — agent embedding Motorical in its own agent app
Not yet written. The OAuth client registration rules for an app's own client metadata document are unverified against the live hosted server (a test with a fake client id returned "client_id domain is not permitted") — writing real steps before that's settled would mean guessing at behavior nobody has confirmed. Use Journey A or B in the meantime.
Machine twin
Everything on this page that an agent needs to act on — the journeys, the scopes, human-required flags, and
stop conditions — is also published as machine-readable JSON at
docs.motorical.com/agents.json, generated from the same source this page renders from.
Related
- AI Agent Quickstart — the deep integration reference for Journey A
- Motorical MCP — the choice between local and hosted MCP
- Hosted MCP Resource Server — full scope and tool detail for Journey B
- Communications Block — for bulk/marketing sends, not this page's journeys