
Your agent needs to send email through Resend. Maybe it is a trial-expiry notice, a support reply drafted from an inbound message, or a September product update going to one segment. Resend ships a hosted MCP server and a REST API that cover almost the same ground, built by the same team, backed by the same authorization server. The usual MCP-versus-API tiebreakers do not apply cleanly here, which is exactly why the choice is confusing. Here is what actually separates them.
Both surfaces reach the same Resend platform. The difference is what sits between your agent and api.resend.com, and what shape the tool contract arrives in.
Resend hosts its official MCP server at mcp.resend.com/mcp over Streamable HTTP. There is nothing to install and no local process to run. Connecting a client opens a browser window to log in to Resend and approve access over OAuth.
For clients that cannot run a browser login, such as a server, CI job, or headless agent, Resend documents passing a re_ API key as a Bearer token instead. The same open-source server also runs locally through npx -y resend-mcp in either stdio or HTTP mode.
The tool surface is organised into groups covering emails, received emails, templates, contacts, broadcasts, automations, events, domains, segments, suppressions, topics, contact properties, API keys, webhooks, logs, and the dashboard editor. Full details are in Resend's MCP server documentation.
The REST API is served from https://api.resend.com and authenticates with Authorization: Bearer re_xxxxxxxxx. It covers emails, batch sends, received mail, broadcasts, automations, events, templates, contacts, contact properties and imports, segments, topics, domains, suppressions, webhooks, logs, and OAuth grant management.
Two operational details matter for agents before you write a line of code. Every request must carry a User-Agent header; requests without one are rejected with a 403 and error code 1010. And there is no versioning system in place today, with calendar-based headers noted as a future plan. The full endpoint list lives in Resend's API reference.
The four dimensions below are the ones that change your architecture. Capability coverage, the auth path, what you own in production, and where each surface wins.
Coverage overlaps heavily because the MCP server is a first-party wrapper over the same API. The divergences are small, specific, and worth knowing before you commit.
The editor tools are the real MCP-only capability. get-tiptap-json-content reads a broadcast or template's current document, compose-broadcast and compose-template write structured content back, and the result is editable by a human in the Resend dashboard. There is no REST endpoint for this.
Going the other way, Stop Automation and segment metrics exist as REST endpoints with no matching MCP tool. If your agent's job is to halt a misfiring drip campaign or report contact counts per segment, that gap is a blocker rather than an inconvenience.
The MCP server is written for a model to read. manage-events collapses create, list, get, update, and remove behind a single action parameter. Several tools accept a Resend dashboard URL wherever an ID is expected. Destructive tools carry instructions in their descriptions telling the model to confirm with the user first.
The REST surface is written for a program to call. One endpoint, one operation, one predictable response shape, no model-facing prose to drift. For a deterministic pipeline that is an advantage. For a chat agent it is work you now have to do in your own prompt.
This is where Resend breaks the pattern that holds for most tools in this series. There is no MCP-means-OAuth, API-means-keys split.
Resend implements OAuth 2.0 and 2.1 with PKCE required on every authorization code exchange. A client_id comes from pre-registration, a Client ID Metadata Document (CIMD), or Dynamic Client Registration (RFC 7591) at POST /oauth/register. Resend recommends CIMD over DCR, because one document gives a client a single identity across every install. Two scopes exist: emails:send for send-only routes and full_access for everything else. Omitting scope grants both, so pass it explicitly.
The hosted MCP server is an OAuth-protected resource sitting in front of that same authorization server, and it also accepts a re_ API key as a Bearer token. The REST API accepts either an OAuth access token or an API key. Whichever surface you pick, the credential your infrastructure has to store, rotate, and revoke is the same object.
One caveat worth knowing before you design around it: Resend does not support RFC 8707 resource indicators yet. A resource parameter is accepted and ignored, so you cannot audience-bind a token to one surface.
Resend OAuth access tokens are JWTs with a 900-second lifetime. Refresh tokens are opaque, rotate on every refresh, and carry a 60-day lifetime that resets on each use.
The failure mode is reuse detection. Replaying an old refresh token fails with invalid_grant and revokes the entire grant unless the rotation happened within the last minute. Two background workers refreshing the same tenant's grant concurrently is enough to disconnect that tenant. Resend's guidance: serialize refreshes per grant, and persist the new refresh token atomically with the rest of the response.
Access tokens are JWTs and cannot be revoked individually; revoking the refresh token revokes the grant. If your compromise story needs faster than 15 minutes, plan around that ceiling. More in handling token refresh for AI agents.
Resend API keys are created with either full_access or sending_access permission, and a sending_access key can be pinned to a single verified domain. The token value is displayed exactly once at creation.
That makes a key per tenant a reasonable posture: least privilege by permission level, domain pinning where it applies, and clean revocation when a customer offboards. What it does not buy you is throughput. Resend's rate limit is 10 requests per second per team, applied across every API key on that team, so a noisy tenant still degrades a quiet one.
On the MCP path, Resend owns hosting, transport, and the tool schemas. You own the credential per tenant, the retry policy, and the fact that the tool surface can change under you when Resend ships. Scalekit's Resend MCP connector lists 94 tools; the upstream open-source server registers 103 at the time of writing. That drift is normal, and it is yours to absorb.
On the REST path you own the schema mapping, pagination, and error handling as well. What you do not gain, unlike most tools in this series, is a pinned contract. Resend has no versioning today, so the REST surface is stable by convention rather than by guarantee.
Every response carries ratelimit-limit, ratelimit-remaining, ratelimit-reset, and retry-after. Quota headers x-resend-daily-quota and x-resend-monthly-quota track sending volume, and exceeding either returns a 429 with daily_quota_exceeded or monthly_quota_exceeded.
Retries are safe on exactly two routes. Idempotency keys are supported on POST /emails and POST /emails/batch, held for 24 hours, and capped at 256 characters. The MCP send-email and send-batch-emails tools accept an idempotencyKey too, so this is not an MCP gap. Everything else, including broadcast sends and domain mutations, is not idempotent. An agent that retries a broadcast send on a timeout will send it twice.
Both paths are viable for most Resend agents. These are the cases where the choice is not a coin flip.
Use Resend MCP when:
Use the Resend REST API when:
Both paths hand your agent a credential and stop there. Neither gives you a vault, rotation logic, revocation flow, or per-tenant isolation. That work is identical whichever surface you picked.
One full_access key in an environment variable works on day one. It also means every tenant's agent run shares one identity. Resend's request logs record endpoint, method, response status, user agent, and the request and response bodies; they do not carry your application's end-user identity, because the key is the identity.
So when a customer asks who sent the broadcast that went to the wrong segment, the answer from Resend's side is "your API key." The mapping back to a specific tenant and a specific agent run has to exist somewhere in your own infrastructure.
In a multi-tenant B2B agent, which is the norm rather than the exception, each customer brings their own Resend account, their own verified sending domain, and their own key or OAuth grant. Forty tenants means forty credentials to store encrypted, refresh before a 900-second access token expires, and revoke on offboarding.
Miss the revocation and a key issued eight months ago still sends mail from a customer you no longer serve. The agent does not decide to keep using it. It just does. Our breakdown of access control for multi-tenant AI agents walks through the isolation boundaries this requires.
Scalekit's Resend connector and Resend MCP connector both take a Bearer token, hold it in an AES-256 token vault, and resolve the right credential per connected account on every call. Credentials never enter the agent runtime or the model context.
The connected account is the unit of isolation. One connection defined once per environment, one connected account per tenant, and identifier selects which credential a tool call runs with. That model is the same on both connectors, which is the point: the MCP versus API decision stops being an auth decision.
The two paths differ only by which connection you point at. Everything below the connection name is shared.
Create a Resend API key at the permission level your agent needs, then add it in the Scalekit dashboard under AgentKit, Connections, Create Connection. The connection name you choose is what you pass in code, and it must match the dashboard string exactly. This is the single most common integration error.
Before the agent sees a single tool, it loads the surface that this connected account is authorized for. This is not a flat catalogue of everything the Resend connector can do; it is the subset bound to acct_northwind. list_scoped_tools returns the raw schemas if you are writing your own adapter, and actions.langchain.get_tools returns the same scoped list as LangChain StructuredTool objects.
With the scoped tools bound to the model, the loop is ordinary LangChain. The credential resolution happens inside each tool invocation, keyed on the identifier you passed at discovery time. For a deeper look at how LangChain tool calling works under the hood, see our dedicated guide.
For the pipeline case, skip the model. execute_tool runs one named tool with one input payload and returns the result plus an execution_id you can correlate against your own logs. Note the idempotency_key, which makes this call safe to retry inside Resend's 24-hour window.
Renew before Friday to keep your workspace active.
", "idempotency_key": "trial-expiry/northwind-2026-09-08", }, identifier="acct_northwind", ) print(result.execution_id, result.data)Switching to Resend's MCP server changes the connection name and the tool prefix, nothing else. Tool names become resendmcp_send_email, resendmcp_list_broadcasts, and so on. Mastra has native MCP support, so the cleanest route in TypeScript is a Scalekit-generated MCP URL minted per tenant on your backend.
Each URL is pre-authenticated for a single tenant. A process-wide URL is safe only in a single-user demo; sharing it runs every request as that one account.
Resend is a wide connector. Handing all of it to every agent role is both a security problem and a cost problem, and virtual MCP servers exist to solve exactly that. As we explored in our post on why MCP is up to 32× more expensive than CLI, token overhead from wide tool surfaces is a real production cost.
Scalekit's Resend connector lists 101 tools. Using the roughly 200-tokens-per-tool figure in Scalekit's own virtual MCP documentation, that is on the order of 20,000 tokens of tool definitions loaded before your agent does any work.
A drip-campaign agent needs perhaps six of those tools. A support-reply agent needs four. Scoping a server to the tools one agent role actually calls cuts that overhead sharply and removes the possibility of the model reaching for resend_domain_delete because it was in scope.
You define the virtual server once per agent role: which connections it draws from and which tools from each. That yields a static mcp_server_url. At runtime you mint a short-lived session token bound to one tenant and pass both to the agent as bearer auth.
For a multi-tenant email agent this collapses a lot of plumbing. One definition serves every customer, each customer connects once, and every run resolves to that customer's own Resend credential. Blast radius from a misbehaving run stays inside one tenant. Rate limiting virtual MCP servers is worth reading alongside this, given Resend's team-wide 10-requests-per-second ceiling.
Every call through Scalekit is logged with full attribution: who authorized it, which agent ran it, and what came back. Failures are separated by source, so a Resend 429 is distinguishable from an expired credential, and logs export to your SIEM.
That is the layer Resend's own request logs cannot provide, because from Resend's side the credential is the identity. When a customer asks why a broadcast went out at 3am, you want the log row that names the tenant, the agent, and the execution_id. More on the shape of that trail in our post on agent tool observability.
If your agent produces content a human will review, particularly broadcasts and templates, build against Resend MCP. The editor tools are a capability the REST API does not have, and the workflow hints in the tool descriptions are work you would otherwise write yourself.
If your agent is a deterministic sender, or it needs Stop Automation or segment metrics, build against the REST API. Fixed schemas and explicit control over batching beat model ergonomics in a pipeline that runs unattended.
Most production Resend agents will run both; the marketing assistant and the billing dunning job are not one system. The credential layer does not change across that split: one credential per tenant, resolved at call time, revocable, attributable. Build that once. Understanding the credential ownership patterns across agent tool-calling architectures will help you design this layer correctly from the start.
Start with the Resend connector on Scalekit, or browse the full connector catalogue if your agent touches more than email. Related patterns are already scaffolded in the outbound prospecting agent, the support ticket automation agent, and the email to calendar agent templates. AgentKit tool calling and audit are free to start; see pricing for the details.
Building something with Resend and want another pair of eyes on the auth design? Join the Scalekit Slack community, or talk to us if you need an answer today.