Announcing CIMD support for MCP Client registration
Learn more

Brevo MCP vs Brevo API for AI Agents (2026)

Nishant Choudhary
Tech Evangelist

TL;DR

  • Brevo's MCP tools have been auto-generated from its OpenAPI specification since March 2026, so capability parity with the REST API is unusually high. Contacts, campaigns, CRM, loyalty, and transactional sends exist on both paths.
  • Brevo MCP auth is a static bearer token, not OAuth. Headless agents become trivial; least privilege becomes impossible. The MCP token grants full read and write access to the whole account, with no scopes.
  • The REST API accepts two credentials: an api-key header secret, and OAuth 2.0 with 32 documented scopes, one-hour access tokens, and 30-day refresh tokens.
  • Brevo OAuth apps are private only today, authorizable solely by users inside your own Brevo organisation. Multi-tenant B2B agents therefore hold a static, unexpiring secret per tenant on either path.
  • Scalekit's Brevo connector keeps that credential in a token vault outside the agent runtime, scopes the tool surface per user through Virtual MCP servers, and gives you queryable auth logs.

Your agent needs to send campaigns, sync contacts, and read deal pipelines in Brevo. Brevo ships a hosted MCP server at mcp.brevo.com and a REST API at api.brevo.com/v3. Most MCP-versus-API decisions turn on capability gaps. This one does not. Brevo generates its MCP tools from the same OpenAPI specification that documents the REST API, so the two surfaces track each other closely. The decision is almost entirely about the credential your agent ends up holding.

What Brevo MCP and Brevo API actually are

Both paths are first-party and both are hosted by Brevo. They differ in transport, in the shape of the contract, and most of all in what credential they accept.

Brevo MCP

Brevo shipped its MCP server in early access in October 2025. It is hosted and remote; there is no local install. The main endpoint is https://mcp.brevo.com/v1/brevo/mcp, which Brevo describes as all features combined across 27 modules.

Brevo also publishes 27 individual server endpoints, one per module, such as /v1/brevo_contacts/mcp and /v1/brevo_deals/mcp.

How the MCP server authenticates

Authentication is a bearer MCP token generated from Account > SMTP & API > API Keys with the MCP option enabled. Brevo's March 2026 changelog entry moved that token out of the URL path into the Authorization header, and switched the 193 tools it shipped at the time to automatic generation from the OpenAPI specification.

Official documentation: Brevo MCP Server overview and Tool configuration.

Brevo API

The REST API is versioned at https://api.brevo.com/v3 and covers contacts, lists, segments, attributes, email and SMS and WhatsApp campaigns, transactional messaging, CRM objects, ecommerce, loyalty, events, conversations, custom objects, and webhook subscription management.

It accepts two credential types. An API key goes in the api-key header and is generated once from the same SMTP and API settings page. OAuth 2.0 runs an authorization code flow against https://oauth.brevo.com/realms/partner/oauth/authorize, returning a signed JWT access token valid for one hour and a refresh token valid for 30 days.

The API also carries everything that cannot be expressed as a tool call: SMTP relay sending, inbound webhook deliveries, the JavaScript tracker, and documented rate limit headers.

Official documentation: Brevo API getting started and Authentication schemes.

Comparing them where it matters for agents

Four dimensions decide this for an agent builder: what the agent can do, what credential it holds, what you operate in production, and which use cases each path actually fits.

What your agent can actually do

Start with what Brevo genuinely got right here. Because the MCP tools are generated from the OpenAPI specification rather than hand-written, the usual MCP problem of a thin, lagging tool surface mostly does not apply. Brevo's own changelog frames auto-generation as eliminating discrepancies between the API and the MCP server, and the catalog reflects that.

At the time of writing, Scalekit's Brevo MCP connector lists 282 tools across 38 module prefixes, including 50 loyalty tools, 22 account and sub-account tools, 18 transactional tools, and 12 email campaign tools. Transactional email, transactional SMS, and async SMS all have send tools. That is a wide surface, and the width itself becomes a problem later in this article.

Where the surfaces diverge

The gaps that remain are structural rather than incidental. They are the things MCP is not shaped to carry, plus the things that only exist as request-level controls.

Capability
Brevo MCP
Brevo API
Contact create, read, update, delete
Yes
Yes
Bulk contact import and export
Yes
Yes
Email, SMS and WhatsApp campaign management
Yes
Yes
Transactional email, SMS and WhatsApp sends
Yes
Yes
CRM deals, companies, tasks, notes, pipelines
Yes
Yes
Loyalty programs, balances, tiers, rewards
Yes
Yes
Ecommerce orders, products, categories, coupons
Yes
Yes
Webhook subscription management
Yes
Yes
Receiving webhook event deliveries
No, there is no inbound event transport
Yes
SMTP relay sending
No
Yes, over SMTP rather than REST
JavaScript tracker and page-level events
No
Yes
Scoped credentials for least privilege
No, one account-wide token
Yes, 32 OAuth scopes
Documented rate limit headers on responses
Not surfaced to the caller
Yes
Version pinning of the contract
No, tools regenerate from the spec
Yes, /v3 with a dated changelog

Why the capability axis is the wrong axis here

If you are used to the Notion or Slack version of this comparison, recalibrate. The Brevo MCP server is not a retrieval-focused subset of a richer API. It is close to a full mirror.

That means the usual tie-breaker is gone. You cannot pick the API because MCP lacks the tools you need, because in most cases it does not. You have to pick on auth, and Brevo's two paths diverge sharply there.

The auth path each one puts you on

This is the section that decides the article. Brevo inverts the pattern the rest of this series has established, and the inversion cuts both ways.

MCP: a static token with no scopes

The Brevo MCP server accepts one credential: a bearer MCP token in the Authorization header. There is no OAuth flow, no consent screen, no PKCE, and no scope parameter. Brevo's own tool configuration guide states plainly that the token grants full read and write access to the account.

The upside is real. A background agent on a nightly schedule connects to mcp.brevo.com with a static header and works. No browser, no redirect, no user in the loop. Compared with an OAuth-only MCP server, headless execution is the easy case, not the blocked case.

Why "no scopes" is the expensive part

The downside is that the MCP token is the opposite of least privilege. An agent whose only job is to read campaign statistics holds a credential that can delete contacts, revoke admin users, generate sub-account API keys, and mint 15-day SSO tokens into sub-accounts.

Brevo's individual server endpoints reduce which tools the assistant sees, but the token itself is unchanged. Point the same token at /v1/brevo/mcp instead of /v1/brevo_contacts/mcp and the full surface is back. Module selection is a context-window control, not an authorization boundary.

API: two credentials, one of which can be scoped

The REST API accepts the same class of static secret through the api-key header, and it also supports OAuth 2.0 with a real scope model. Scopes follow a {resource}[.{sub-resource}]:{action} convention, and Brevo publishes 32 of them across account, campaigns, contacts and CRM, conversations, custom objects, ecommerce, events, loyalty, and transactional.

Two details matter for agent design. First, :write does not imply :read, so a sync agent needs both contacts:read and contacts:write declared explicitly. Second, every issued access token is a signed JWT with a scope claim, and Brevo exposes an RFC 7662 introspection endpoint, so you can verify at runtime what a credential is actually permitted to do.

The constraint that decides multi-tenant B2B

Brevo's OAuth documentation states that OAuth apps are currently private only. A private app can be authorized only by users within your own Brevo organisation. It cannot be distributed to external users or listed in a marketplace, and Brevo describes public app support as planned for a future release.

Read that against a B2B agent product. If your customers each have their own Brevo account, delegated OAuth is not available to you today. Every tenant credential is a static, account-wide secret with no expiry: an MCP token or an API key.

What that means in practice

You do not get to choose the good credential model. You get to choose which static secret you hold, and then you have to build the isolation, rotation, and revocation that the credential itself does not provide.

The structural point holds on both paths. MCP gives you a token per tenant. The direct API gives you a credential per tenant. In neither case does the path itself solve storage, rotation, or revocation. Those are infrastructure problems regardless of which path you choose, and on Brevo they are harder than usual because the credentials never expire on their own.

What you own in production

Brevo operates the MCP server and the REST API. Everything between your agent and that boundary is yours.

On the MCP path

Brevo owns hosting, tool schema generation, and keeping the generated tools aligned with the OpenAPI specification. You own the token: where it is stored, who can read it, and what happens when a customer rotates it in their Brevo dashboard.

You also own the consequences of auto-generation. Tools regenerate when Brevo updates its specification, and there is no version header on the MCP endpoint to pin against. A generated tool name or parameter can change under a running agent. Brevo's April 2026 API specification overhaul is a concrete example of the kind of upstream change that propagates.

On the API path

You own endpoint selection, request construction, pagination, retries, and the token lifecycle. If you use OAuth, you also own proactive refresh against the one-hour access token expiry and re-authorization when the 30-day refresh token lapses.

What you get in return is a versioned contract. The API is pinned at /v3, breaking changes are announced with dates in the changelog, and responses carry rate limit headers you can act on. For a deterministic pipeline where an unexpected schema change is an incident, that predictability is the argument. Handling token refresh for AI agents is a problem you take on here, but you get predictability in return.

Rate limits are a hard planning constraint

Brevo's general rate limit tier is generous where you would expect and tight where agents actually live. Transactional email sends get 1,000 requests per second. Contact endpoints get 36,000 requests per hour. Everything else, including /emailCampaigns, /crm/deals, /companies and /smsCampaigns, gets 100 requests per hour.

That last number is the one to design around. An agentic workflow that lists campaigns, fetches a campaign, checks deals, and updates a company issues four calls per user action against a 100 per hour ceiling. Advanced and Extended tiers raise it to 200 and 600 respectively, but the shape does not change: CRM and campaign work is the scarce budget, not sending.

Rate limits and the MCP server

Brevo added request limits to the MCP server in March 2026 but does not publish an MCP-specific limit table. Plan against the documented REST tiers, monitor 429 responses from day one, and treat the campaign and CRM ceiling as your real throughput budget on either path.

When to use MCP, when to use the API

Both are legitimate. The split is cleaner on Brevo than on most tools because capability is not the deciding variable.

Use Brevo MCP when

  • Your agent is a marketing or CRM assistant operating inside a single Brevo account that your own team controls, where an account-wide token is an accepted risk
  • You are running a background or scheduled agent and want to skip an interactive flow entirely, since the static bearer token works headlessly with no user present
  • You want the widest first-party tool surface without writing schemas, and you can constrain which tools reach the model at the agent layer
  • You are prototyping a Brevo agent and want a working tool call in minutes rather than an OAuth app registration first

Use the Brevo API directly when

  • You need least privilege, and a credential scoped to campaigns.email:read rather than full account access is a requirement rather than a preference
  • Your agent must react to Brevo events such as contact updates, hard bounces, or deal stage changes, which requires receiving webhook deliveries
  • You send through the SMTP relay or depend on request-level behaviour that is not expressed as a tool parameter
  • You are building a deterministic pipeline where you pin /v3 and migrate on your own schedule rather than absorbing regenerated tool schemas
  • You operate inside one Brevo organisation and can therefore use a private OAuth app for genuine per-user delegation

The credential problem that exists on both paths

Both paths hand you a secret per tenant. Neither hands you a vault, a rotation policy, or a revocation flow.

The N-credential problem, without an expiry to save you

Take a B2B agent serving 60 customers, each with their own Brevo account. That is 60 MCP tokens or 60 API keys to store encrypted, isolate per tenant, and invalidate when a customer churns or an employee leaves.

Because Brevo API keys and MCP tokens do not expire on a schedule, nothing forces the issue. A token generated during onboarding eleven months ago is still valid. The agent does not decide to keep using it. It just does. This is exactly the kind of scenario explored in secure token management for AI agents at scale.

Why the blast radius is unusually wide

On most connectors, a leaked credential is bounded by the scopes it was granted. On the Brevo MCP path there are no scopes, so the boundary is the account. The same secret that reads campaign statistics can delete contacts and provision sub-account API keys.

That is the argument for keeping the credential out of the agent runtime entirely, and for reducing what the agent can reach with it at the tool layer rather than trusting the credential to constrain anything. For a deeper look at how credential ownership works across agent tool-calling patterns, the structural tradeoffs apply directly here.

Where Scalekit fits

Scalekit's Brevo MCP connector handles the authorization flow, stores the credential in a token vault outside your agent runtime and outside LLM context, and resolves the right connected account on every tool call. Your agent calls execute_tool with a user identifier; it never sees a Brevo token.

The same infrastructure works whether you route through the MCP connector or proxy raw REST calls through a connected account. The path decision does not change what you need at the credential layer.

Building a Brevo agent with Scalekit

Scalekit ships one first-party Brevo connector today, brevomcp, which fronts Brevo's hosted MCP server. Anything the MCP surface does not cover is reachable through the API Proxy on the same connected account, so you get one credential model across both paths.

Set up the connection

Create the connection once in the Scalekit Dashboard under AgentKit > Connections, then install an SDK. The connection name you configure in the dashboard is the string you pass in code, and a mismatch here is the single most common integration error.

# Python pip install scalekit-sdk-python anthropic # TypeScript npm install @scalekit-sdk/node @anthropic-ai/sdk

Add your environment credentials from Developers > API Credentials.

SCALEKIT_ENV_URL=<your-environment-url> SCALEKIT_CLIENT_ID=<your-client-id> SCALEKIT_CLIENT_SECRET=<your-client-secret>

Authorize a user

Each user authorizes Brevo once. Scalekit creates a connected account, stores the credential, and marks the account ACTIVE. Check the status before every run rather than discovering a dead credential mid-task.

import os from scalekit import ScalekitClient scalekit_client = ScalekitClient( env_url=os.environ["SCALEKIT_ENV_URL"], client_id=os.environ["SCALEKIT_CLIENT_ID"], client_secret=os.environ["SCALEKIT_CLIENT_SECRET"], ) actions = scalekit_client.actions # Must match the connection name configured in the Scalekit Dashboard CONNECTION_NAME = "brevomcp" IDENTIFIER = "user_123" response = actions.get_or_create_connected_account( connection_name=CONNECTION_NAME, identifier=IDENTIFIER, ) if response.connected_account.status != "ACTIVE": link = actions.get_authorization_link( connection_name=CONNECTION_NAME, identifier=IDENTIFIER, ) print("Authorize Brevo:", link.link)

Retrieve the authorized tool surface

Before executing anything, retrieve the tools this specific user's connected account is authorized to call. This is the list you pass to the model, and it is not the same as a connector catalog.

from google.protobuf.json_format import MessageToDict scoped_response, _ = actions.tools.list_scoped_tools( identifier=IDENTIFIER, filter={"connection_names": [CONNECTION_NAME]}, page_size=100, ) llm_tools = [ { "name": MessageToDict(t.tool).get("definition", {}).get("name"), "description": MessageToDict(t.tool).get("definition", {}).get("description", ""), "input_schema": MessageToDict(t.tool).get("definition", {}).get("input_schema", {}), } for t in scoped_response.tools ]

Why scoping matters more on Brevo than on most connectors

The Brevo MCP connector catalog currently carries 282 tools. At roughly 200 tokens per tool definition, handing the model the whole surface costs around 56,000 tokens before the agent does any work, and it forces the model to choose from a decision space it was never designed to handle at that scale.

Wrong tool selection follows. Hallucinated parameters follow. Surface reduction is the lever. Model upgrades help; they are not the lever.

Run the agent loop with the Claude SDK

The loop below is the full execution path: construct messages, pass the scoped tools, check stop_reason, execute each tool call, and append the result. Scalekit injects the Brevo credential at execution time.

import anthropic client = anthropic.Anthropic() messages = [{ "role": "user", "content": "Summarize transactional email performance for the last 7 days, " "then list the 5 most recent email campaigns.", }] while True: response = client.messages.create( model="claude-sonnet-4-6", max_tokens=1024, tools=llm_tools, messages=messages, ) if response.stop_reason == "end_turn": print(response.content[0].text) break tool_results = [] for block in response.content: if block.type == "tool_use": result = actions.execute_tool( tool_name=block.name, identifier=IDENTIFIER, connection_name=CONNECTION_NAME, tool_input=block.input, ) tool_results.append({ "type": "tool_result", "tool_use_id": block.id, "content": str(result.data), }) messages.append({"role": "assistant", "content": response.content}) messages.append({"role": "user", "content": tool_results})

Real tool names from the catalog for this workflow are brevomcp_campaign_analytics_get_aggregated_smtp_report and brevomcp_email_campaign_management_get_email_campaigns. Full parameter schemas live on the connector docs page.

The LangChain variant

If you are already on LangChain, Scalekit returns native StructuredTool objects, so no schema reshaping is required. This fits naturally into the patterns covered in LangChain tool calling.

from langchain_openai import ChatOpenAI from langchain_core.messages import HumanMessage, ToolMessage tools = actions.langchain.get_tools( identifier=IDENTIFIER, connection_names=[CONNECTION_NAME], page_size=100, ) tool_map = {t.name: t for t in tools} llm = ChatOpenAI(model="gpt-4o").bind_tools(tools) messages = [HumanMessage("Add jane@example.com to the Newsletter list in Brevo")] while True: response = llm.invoke(messages) messages.append(response) if not response.tool_calls: print(response.content) break for tc in response.tool_calls: result = tool_map[tc["name"]].invoke(tc["args"]) messages.append(ToolMessage(content=str(result), tool_call_id=tc["id"]))

The TypeScript variant

The Node.js SDK exposes the same two calls with camel-cased parameters. Note that executeTool takes connector where Python takes connection_name.

import { ScalekitClient } from '@scalekit-sdk/node'; import 'dotenv/config'; const scalekit = new ScalekitClient( process.env.SCALEKIT_ENV_URL!, process.env.SCALEKIT_CLIENT_ID!, process.env.SCALEKIT_CLIENT_SECRET!, ); // Must match the connection name configured in the Scalekit Dashboard const CONNECTOR = 'brevomcp'; const IDENTIFIER = 'user_123'; const { tools } = await scalekit.tools.listScopedTools(IDENTIFIER, { filter: { connectionNames: [CONNECTOR] }, pageSize: 100, }); const result = await scalekit.actions.executeTool({ toolName: 'brevomcp_contacts_get_contacts', identifier: IDENTIFIER, connector: CONNECTOR, toolInput: { limit: 25 }, }); console.log(result.data);

Reaching the REST-only surface

When you need something the MCP tools do not cover, proxy the raw endpoint through the same connected account with actions.request. Scalekit resolves the base URL and injects the credential; you supply the path.

def brevo_get_webhooks(identifier: str): response = actions.request( connection_name=CONNECTION_NAME, identifier=identifier, method="GET", path="/v3/webhooks", query_params={"type": "transactional"}, ) return {"webhooks": response.json().get("webhooks", [])}

If you would rather model Brevo's REST API as a first-class connector with its own auth pattern, create a custom connector with API_KEY auth, proxy_url set to https://api.brevo.com, and auth_header_key_override set to api-key, because Brevo does not use the standard Authorization header for API keys.

Multi-tenant Brevo agents with Virtual MCP servers

The 282-tool surface and the unscoped credential are the same problem viewed from two angles. Virtual MCP servers address both.

Declare the tools once per agent role

A Virtual MCP server is a scoped endpoint that declares which connections and which tools are exposed. You create it once per agent role, not once per user, and you get a static mcp_server_url.

import os from datetime import timedelta from scalekit import ScalekitClient from scalekit.actions.models.mcp_config import McpConfigConnectionToolMapping scalekit_client = ScalekitClient( env_url=os.environ["SCALEKIT_ENV_URL"], client_id=os.environ["SCALEKIT_CLIENT_ID"], client_secret=os.environ["SCALEKIT_CLIENT_SECRET"], ) vmcp = scalekit_client.actions.mcp.create_config( name="brevo-campaign-reporter", connection_tool_mappings=[ McpConfigConnectionToolMapping( connection_name="brevomcp", tools=[ "brevomcp_campaign_analytics_get_aggregated_smtp_report", "brevomcp_campaign_analytics_get_smtp_report", "brevomcp_email_campaign_management_get_email_campaigns", ], ), ], ) config_id = vmcp.config.id mcp_server_url = vmcp.config.mcp_server_url

Mint a per-user token before each run

The server definition is shared. The identity is not. Before every run, confirm the user's connections are still active, then mint a short-lived session token bound to that user.

accounts = scalekit_client.actions.mcp.list_mcp_connected_accounts( config_id=config_id, identifier="user_123", include_auth_link=True, ) for account in accounts.connected_accounts: if account.connected_account_status != "ACTIVE": print(f"{account.connection_name} needs auth: {account.authentication_link}") token_response = scalekit_client.actions.mcp.create_session_token( mcp_config_id=config_id, identifier="user_123", expiry=timedelta(minutes=30), ) mcp_server = { "url": mcp_server_url, "headers": {"Authorization": f"Bearer {token_response.token}"}, }

What this changes for a Brevo agent specifically

A reporting agent now reaches three tools instead of 282. The Brevo credential that could delete contacts and mint sub-account SSO tokens is still in the vault, but nothing in the agent's reachable surface can invoke those operations.

The endpoint is static; the identity is not. One server definition serves every tenant, and each run gets a token scoped to that tenant's connected accounts. There is no per-user server configuration and no MCP server for you to deploy, host, or maintain.

Multi-tool agents get the same treatment

Brevo agents rarely run alone. A lifecycle marketing agent reads Brevo campaign statistics, checks deal stages in a CRM, and posts a digest to Slack. Declare all three connections on one Virtual MCP server with a handful of tools each, and the agent sees a coherent, minimal surface instead of three full catalogs.

Observability for Brevo agent auth

Capability comparisons rarely cover this, and it is where teams lose days in production.

What breaks silently

A Brevo credential can go bad without your agent noticing until a task fails. A customer rotates their API key. An admin revokes an invited user. A refresh token lapses on the OAuth path. The agent gets a 401 mid-run and, depending on your error handling, either retries into a wall or logs nothing useful.

What Scalekit gives you

Connected accounts carry an explicit status of ACTIVE, PENDING, EXPIRED, or REVOKED, and you can subscribe to the connected_account.status_updated webhook so a dead credential surfaces as an event rather than a failed task.

The Scalekit Dashboard Auth Logs view records authentication events with status, timestamp, user, and method, filterable by time range, user, status, and organization. Webhook delivery logs record request payloads, response codes, latency, and retry attempts. When a security reviewer asks which credential performed an action and whether it was valid at the time, you have an answer that does not require reading application logs. This kind of audit trail for agent auth is exactly what enterprise reviews demand.

Tracing the tool calls themselves

For the reasoning layer above the credential layer, Scalekit publishes a cookbook for tracing AgentKit tool calls in LangSmith. Pair that with Auth Logs and you can follow a single request from the user prompt, through tool selection, to the connected account that authorized the call. Agent tool observability closes the loop between what your agent decided and what it actually executed.

Which one to build against

If your Brevo agent runs inside one account your team owns, and you can constrain the tool surface at the agent layer, the hosted MCP server is the faster path. The tools are generated from Brevo's own specification, the bearer token works headlessly, and you are operational quickly.

If you need scoped credentials, webhook-driven reactions, SMTP relay sending, or a contract you can pin and migrate on your own schedule, go direct to the REST API. And if you are building multi-tenant, understand the real constraint first: Brevo OAuth apps are private only today, so every tenant credential is a static, unexpiring, account-wide secret on either path.

That is the part that needs production-grade infrastructure, and it is identical whichever path you pick.

Get help building Brevo agents

Browse the Scalekit Brevo MCP connector on the connector page or in the AgentKit docs, and see the full catalog under agent connectors.

Building something on Brevo and want a second pair of eyes on the credential model? Join the Scalekit Slack community or talk to an engineer for immediate help.

No items found.
Agent
Auth Quickstart
On this page
Share this article
Agent
Auth Quickstart

Acquire enterprise customers with
zero upfront cost.

Every feature unlocked. No hidden fees.