Servidor MCP
Conectar agentes de IA à Asender pelo Model Context Protocol: endereço, autenticação e ferramentas.
Servidor MCP
A Asender tem um servidor MCP (Model Context Protocol) remoto. Com ele, um agente de IA (Claude, ChatGPT, Cursor, VS Code e outros clientes MCP) consulta os dados da sua conta: leads, formulários, campanhas, relatórios, conversas e mais. Com chave de API e o escopo certo, o agente também escreve: envia um e-mail e cria ou atualiza leads (veja Ferramentas de escrita). Token OAuth continua somente leitura.
- URL:
https://api.asender.net/mcp - Transporte: Streamable HTTP stateless (um
POSTpor mensagem JSON-RPC; sem SSE e sem sessão) - Versões do protocolo aceitas:
2025-11-25,2025-06-18e2025-03-26 - Autenticação: chave de API
sk_*ou token OAuth de um app, no headerAuthorization: Bearer - Ferramentas: 32 (veja o catálogo): 27 de leitura que servem a chave e o token OAuth, 2 de leitura de DNS e 3 de escrita, estas 5 só para chave
sk_*
Status
| Forma de conectar | Situação |
|---|---|
Chave de API sk_* no header Authorization: Bearer | Funciona em qualquer cliente que permita configurar headers (Claude Code, Cursor, VS Code, MCP Inspector). É a alternativa quando o cliente não faz OAuth. |
| OAuth com registro automático do cliente (CIMD / DCR) | Clientes MCP com OAuth (Claude, ChatGPT, Cursor, VS Code, MCP Inspector) se registram sozinhos no servidor de autorização, e o usuário autoriza na tela de consentimento. O cliente aparece com o selo Não verificado até a equipe Asender verificá-lo, e só recebe escopos de leitura. Disponível após a implantação em cada ambiente. |
OAuth com app cadastrado (client_id informado manualmente) | Para clientes que aceitam client_id (e client_secret, se o app for confidencial) digitados à mão, como as configurações avançadas do conector personalizado do Claude. Veja Aplicativos. |
O registro automático está descrito em Aplicativos. O que ainda não existe está em Limites e o que vem a seguir.
Conectar um cliente
A configuração exata muda de cliente para cliente e de versão para versão. Em todos os casos você informa a URL https://api.asender.net/mcp. Clientes com OAuth se registram sozinhos e abrem a tela de consentimento da Asender; nos demais, informe o header Authorization: Bearer sk_live_.... Crie a chave em Chaves de API com só os escopos de leitura de que o agente precisa.
Claude Code
claude mcp add --transport http asender https://api.asender.net/mcp \
--header "Authorization: Bearer sk_live_..."
Claude (claude.ai e Claude Desktop)
Em Configurações > Conectores, adicione um conector personalizado (Custom connectors) e informe a URL https://api.asender.net/mcp. O cliente se registra sozinho e você autoriza na tela de consentimento da Asender (selo Não verificado até a equipe verificar o cliente). Se preferir, abra as configurações avançadas do conector e informe o client_id de um app cadastrado (e o segredo, se for um app confidencial). Esse caminho não oferece um campo para o header com a chave sk_*; para usar a chave, conecte pelo Claude Code.
ChatGPT
Ative o modo desenvolvedor e adicione um conector (app) MCP remoto com a URL https://api.asender.net/mcp. A autenticação é por OAuth: o ChatGPT se registra sozinho (CIMD ou DCR) e você autoriza na tela de consentimento da Asender; se a sua versão permitir, também dá para informar o client_id de um app cadastrado.
Cursor
No mcp.json do Cursor, declare um servidor com url e headers:
{
"mcpServers": {
"asender": {
"url": "https://api.asender.net/mcp",
"headers": { "Authorization": "Bearer ${env:ASENDER_API_KEY}" }
}
}
}
VS Code
No mcp.json do VS Code, declare um servidor do tipo http:
{
"servers": {
"asender": {
"type": "http",
"url": "https://api.asender.net/mcp",
"headers": { "Authorization": "Bearer ${input:asender-key}" }
}
},
"inputs": [
{ "type": "promptString", "id": "asender-key", "description": "Chave de API da Asender", "password": true }
]
}
MCP Inspector
npx @modelcontextprotocol/inspector
Escolha o transporte Streamable HTTP, informe a URL https://api.asender.net/mcp e adicione o header Authorization: Bearer sk_live_... (ou use o fluxo OAuth do Inspector, que se registra sozinho). O Inspector, que roda em http://localhost:6274, passa pela verificação de Origin.
Qualquer outro cliente
Adicione um servidor MCP remoto HTTP (Streamable HTTP) com a URL https://api.asender.net/mcp e o header Authorization: Bearer <chave sk_*>. O servidor não usa SSE: um cliente que só fale SSE não conecta.
Autenticação
O servidor é um resource server OAuth 2.1 e também aceita chave de API.
Chave de API
Envie Authorization: Bearer sk_live_.... Valem os escopos da chave: a ferramenta só aparece e só roda se a chave tem o escopo dela. Uma chave sem escopo de leitura enxerga no máximo asender_account_get.
OAuth (app)
- Descoberta. Uma chamada sem credencial recebe
401comWWW-Authenticate: Bearer resource_metadata="https://api.asender.net/.well-known/oauth-protected-resource/mcp". - O cliente lê esse documento (RFC 9728), que lista em
authorization_serverso servidor de autorizaçãohttps://auth.asender.net, osscopes_supportede o link desta documentação. - Em
https://auth.asender.net/.well-known/oauth-authorization-server(RFC 8414) estão os endpoints de autorização, de token e de revogação, além doregistration_endpoint(https://auth.asender.net/register, DCR) e declient_id_metadata_document_supported: true(CIMD). - Registro. O cliente que ainda não tem
client_idse registra: publica um documento de metadados e usa a URL dele comoclient_id(CIMD) ou fazPOST /register(DCR, RFC 7591). O cliente nasce público (PKCE, sem segredo), Não verificado e só com escopos de leitura. Os formatos estão em Aplicativos. - O cliente abre
/authorizecom PKCES256(obrigatório) e o parâmetroresource=https://api.asender.net/mcp(RFC 8707). Oresourcefaz o token nascer comauddo MCP. Umresourcefora da lista permitida é recusado cominvalid_target. - O usuário entra, escolhe a conta e aprova os escopos na tela de consentimento, que mostra o selo Não verificado e o domínio do cliente até a equipe Asender verificá-lo. Um token vale para um usuário e uma conta. Para trocar de conta, autorize de novo.
- O cliente troca o
codeem/tokene chama/mcpcom o token. O token de acesso dura 15 minutos e é renovado com refresh token.
Clientes públicos (sem segredo, como apps de desktop) usam PKCE sem client_secret e podem usar redirect de loopback (http://127.0.0.1 ou http://[::1], com porta qualquer), conforme a RFC 8252.
Escopos
O token OAuth só exerce leitura; as ferramentas de escrita (email:send, leads:write) nunca aparecem para ele, mesmo que o token traga o escopo. Escopos disponíveis: account:read, leads:read, conversions:read, forms:read, analytics:read, campaigns:read, email:read, messaging:read, conversations:read, journeys:read, logs:read e openid (identidade do usuário que autorizou). Escopo de envio nunca vale para token OAuth. Para chave, valem os escopos da própria chave, descritos em Chaves de API.
Token do MCP e a API REST
Um token com aud só https://api.asender.net/mcp não vale na API REST (/v1): recebe 401. O inverso funciona: um token emitido sem resource, com aud https://api.asender.net, também é aceito no /mcp.
Catálogo de ferramentas
As de leitura anunciam readOnlyHint: true; as 3 de escrita estão em Ferramentas de escrita (readOnlyHint: false). Ferramenta cujo escopo a credencial não tem não aparece em tools/list, e chamá-la diretamente devolve erro. Além do escopo, a conta precisa ter o produto correspondente: sem ele a chamada falha como a REST falharia.
| Ferramenta | O que faz | Escopo | Produto exigido | Argumentos principais |
|---|---|---|---|---|
asender_account_get | Conta a que a credencial pertence | account:read (OAuth); qualquer chave válida | nenhum | nenhum |
asender_me_get | Quem autorizou o app, a conta e os escopos concedidos | openid (só token OAuth) | nenhum | nenhum |
asender_leads_list | Lista leads do CRM (mais antigo atualizado primeiro) | leads:read | CRM | limit, cursor, updated_after, created_after |
asender_leads_get | Um lead pelo id | leads:read | CRM | lead_id (obrigatório) |
asender_forms_list | Lista formulários de captura | forms:read | Pages | limit, cursor, updated_after, created_after |
asender_forms_submissions_list | Envios recebidos por um formulário | forms:read | Pages | form_id (obrigatório), limit, cursor, updated_after, created_after |
asender_conversions_list | Conversões enviadas às plataformas de anúncio | conversions:read | CRM | limit, cursor, updated_after, created_after |
asender_campaigns_list | Campanhas de e-mail marketing | campaigns:read | E-mail marketing | limit, cursor, updated_after |
asender_campaigns_get | Uma campanha | campaigns:read | E-mail marketing | campaign_id (obrigatório) |
asender_campaigns_report | Totais de entrega e engajamento de uma campanha | campaigns:read | E-mail marketing | campaign_id (obrigatório) |
asender_email_reports_overview | Panorama de e-mail da conta nos últimos N dias | campaigns:read | E-mail marketing | days (1 a 365) |
asender_email_reports_timeseries | Envios, aberturas e cliques ao longo do tempo | campaigns:read | E-mail marketing | from, to, period, granularity (hour, day, week) |
asender_email_reports_top_emails | Melhores e piores e-mails da janela | campaigns:read | E-mail marketing | from, to, period, order (volume, open_rate, click_rate), limit, min_delivered |
asender_email_reports_domains | Resultados por provedor de caixa postal | campaigns:read | E-mail marketing | from, to, period |
asender_emails_list | E-mails transacionais enviados pela API | email:read | E-mail marketing | status, q, cursor, limit, created_after |
asender_emails_get | Um e-mail enviado e seu status de entrega | email:read | E-mail marketing | email_id (obrigatório) |
asender_messaging_messages_list | Mensagens de SMS, WhatsApp ou push | messaging:read | SMS, WhatsApp (Zapify) ou Push, conforme o canal | channel (obrigatório: sms, whatsapp, push), limit, cursor, created_after |
asender_messaging_overview | Panorama de entrega de um canal | messaging:read | SMS, WhatsApp (Zapify) ou Push, conforme o canal | channel (obrigatório), days |
asender_analytics_overview | Totais de analytics de site e páginas (padrão: últimos 30 dias) | analytics:read | Pages | from, to, page_id, form_id, source, medium, campaign, country, device |
asender_analytics_timeseries | Série diária de analytics | analytics:read | Pages | os mesmos filtros de asender_analytics_overview |
asender_analytics_breakdown | Analytics agrupado por dimensão | analytics:read | Pages | filtros acima, dimension (page, source, medium, campaign, country, device, form), limit |
asender_analytics_forms | Funil de formulários (visualizações, inícios, envios) | analytics:read | Pages | from, to, form_id (omitido = resumo de todos), limit |
asender_conversations_list | Conversas de atendimento | conversations:read | Atendimento | limit, cursor, updated_after |
asender_conversations_messages_list | Linha do tempo de uma conversa | conversations:read | Atendimento | conversation_id (obrigatório), limit, cursor, created_after |
asender_journeys_list | Jornadas de automação | journeys:read | CRM | limit, cursor, updated_after, created_after |
asender_journeys_get | Uma jornada | journeys:read | CRM | journey_id (obrigatório) |
asender_logs_list | Log de requisições da API pública da conta | logs:read | nenhum | limit, after, before, status_class, status, method, path, api_key_id, error_code, idempotency_key, message_id, mode, since, until |
asender_dns_zones_list | Zonas de DNS da conta (só chave) | dns:read | nenhum | nenhum |
asender_dns_records_list | Registros de DNS de uma zona (só chave) | dns:read | nenhum | zone_id (obrigatório), type, name, page, per_page |
asender_emails_send | Envia um e-mail transacional (só chave; escrita) | email:send | E-mail marketing | from, to (obrigatórios), subject, text/html, cc, bcc, reply_to, tags, idempotency_key |
asender_leads_create | Cria um lead (só chave; escrita) | leads:write | CRM | email e/ou phone, first_name, last_name, job_title, stage, tags, custom_fields, idempotency_key… |
asender_leads_update | Atualiza um lead (só chave; escrita) | leads:write | CRM | lead_id (obrigatório), os campos de asender_leads_create, idempotency_key |
Datas aceitam instante RFC 3339 (por exemplo 2026-10-01T00:00:00Z); nos relatórios e no analytics também YYYY-MM-DD. limit vai de 1 a 200 (padrão 50). A conta é sempre a da credencial: não há argumento de conta.
Ferramentas de escrita
São três e só aparecem em tools/list para uma chave sk_* que tenha o escopo (email:send para o e-mail, leads:write para os leads). Chamá-las sem o escopo, ou com token OAuth, devolve isError. Cada uma roda o mesmo handler da API REST (POST /v1/emails/send, POST /v1/leads, PATCH /v1/leads/{id}): mesmas validações, mesmo corpo fechado (argumento desconhecido é recusado), a conta é sempre a da chave.
| Ferramenta | destructiveHint | idempotentHint | openWorldHint | Observação |
|---|---|---|---|---|
asender_emails_send | false | true | true | O e-mail vai para pessoas reais e não volta. O remetente (from) precisa ser de um domínio verificado da conta; senão 422 RemetenteNaoVerificado. Fora de produção nada é entregue de verdade. |
asender_leads_create | false | true | false | Precisa de email ou phone; outro lead da conta com o mesmo e-mail ou telefone dá 409. |
asender_leads_update | true | true | false | Só os campos enviados mudam; tags substitui a lista e "" limpa os textos opcionais, por isso é anunciada como destrutiva. |
Todas têm readOnlyHint: false. As anotações são dicas ao cliente (por exemplo, para pedir confirmação ao usuário), não uma garantia de segurança: quem protege é o escopo da chave.
Idempotência. Toda escrita leva um Idempotency-Key:
- Se você passa o argumento
idempotency_key(1 a 128 caracteres de[A-Za-z0-9._:-]), ele é a chave. Repetir a chamada com a mesma chave e os mesmos argumentos devolve o mesmo resultado sem escrever de novo; a mesma chave com argumentos diferentes é recusada (422 IdempotencyKeyReused). - Se omite, o servidor deriva a chave dos argumentos (
mcp:+ hash do nome da ferramenta, da conta e dos argumentos, sem importar a ordem). Assim, um agente que repete a mesma chamada (timeout, retry do cliente, modelo que insiste) não envia dois e-mails nem cria dois leads. Para reenviar de propósito a mesma coisa, passe umidempotency_keydiferente. A janela de deduplicação é a do dono do dado (24 h nos leads).
Exemplo (enviar um e-mail):
curl -s https://api.asender.net/mcp \
-H "Authorization: Bearer $ASENDER_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"asender_emails_send","arguments":{"from":"contato@exemplo.com","to":["cliente@exemplo.org"],"subject":"Seu pedido","text":"Obrigado pela compra.","idempotency_key":"pedido-1042-aviso"}}}'
Formato da resposta
Uma chamada com sucesso devolve o mesmo JSON da API REST em duas formas: em content (um bloco text com o JSON) e em structuredContent (o objeto). Uma resposta acima de 1 MiB é recusada com a orientação de reduzir limit, usar cursor ou estreitar a janela de tempo.
Erros
- Erro de negócio (argumento inválido, escopo ou produto ausente,
404,429,5xxda rota) não é erro JSON-RPC: volta como resultado comisError: truee um texto comoHTTP 404 Not Found: ..., para o modelo se corrigir. - Erro de protocolo usa os códigos JSON-RPC:
-32700(JSON inválido),-32600(pedido inválido),-32601(método inexistente) e-32602(parâmetros inválidos ou ferramenta desconhecida). - Erro de transporte:
401sem credencial válida;403paraOriginnão permitido;400paraMCP-Protocol-Versiondesconhecida, lote JSON-RPC ou JSON inválido;413acima de 1 MiB;405paraGETeDELETE.
Paginação
As listas devolvem next_cursor quando há mais itens. Para a próxima página, repita a chamada passando esse valor em cursor (valor opaco: não o monte nem o interprete). asender_logs_list pagina por after/before, com ids de log.
Exemplos com curl
Defina a chave em uma variável de ambiente:
export ASENDER_API_KEY='sk_live_...'
initialize
curl -s https://api.asender.net/mcp \
-H "Authorization: Bearer $ASENDER_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"curl","version":"1"}}}'
A resposta traz protocolVersion, capabilities (tools), serverInfo e as instructions do servidor. Depois do initialize, um cliente completo envia a notificação notifications/initialized (resposta 202 sem corpo); com curl isso é opcional, porque o servidor não guarda sessão.
tools/list
curl -s https://api.asender.net/mcp \
-H "Authorization: Bearer $ASENDER_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'
Só aparecem as ferramentas que a chave pode usar.
tools/call
curl -s https://api.asender.net/mcp \
-H "Authorization: Bearer $ASENDER_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"asender_leads_list","arguments":{"limit":10}}}'
Para a página seguinte, repita com "arguments":{"limit":10,"cursor":"<next_cursor>"}.
Segurança
- Origin. Chamadas de navegador de um site que não seja da Asender recebem
403. Clientes de servidor e de linha de comando não enviamOrigine passam; loopback (localhost, como o MCP Inspector) é aceito. - CORS. Liberado para qualquer origem sem credenciais (
Access-Control-Allow-Origin: *), o que deixa um cliente web ler oWWW-Authenticatedo401. A autenticação é só pelo headerAuthorization, nunca por cookie. - Limite de taxa. O
/mcptem limite de taxa; ao exceder, a ferramenta devolveisErrorcomHTTP 429. Reduza a frequência das chamadas. - Acesso por conta. Além do escopo, a Asender confere a cada chamada que o usuário do token ainda tem acesso àquela conta e àquele produto. Quem perde o acesso à conta perde o acesso do app em até 60 segundos.
- Revogação. O usuário revoga o acesso de um app na tela Apps conectados do login da Asender; a chave de API é revogada no painel, em Chaves de API.
- Token só do MCP. O
auddo token o amarra ao recurso: um token do/mcpnão funciona na REST. - Prompt injection. O conteúdo que o agente lê, como nome, e-mail, mensagem de lead, resposta de formulário ou texto de conversa, vem de terceiros e deve ser tratado como dado não confiável. Um texto de lead que diga "ignore as instruções anteriores" não é uma ordem para o modelo. Com as ferramentas de escrita (e-mail e leads) o risco é real: um lead ou uma conversa podem tentar induzir o agente a enviar e-mail ou alterar dados. Por isso o token OAuth não escreve, a escrita exige chave com escopo próprio e, no cliente, vale exigir confirmação humana antes de
asender_emails_send(ele anunciaopenWorldHint: true). - Menor privilégio. Para o agente, crie uma chave só com os escopos de que ele precisa (de preferência só leitura;
email:sendeleads:writeapenas se o agente realmente escreve) e use uma chave por integração, para revogar sem derrubar o resto.
Limites e o que vem a seguir
- Escrita só com chave e só em 3 ferramentas. Há e-mail transacional e criar/atualizar lead. Não há ferramenta para SMS, WhatsApp ou push, apagar lead, nem escrita por token OAuth (
leads:writesegue não concedível a apps). - Só
tools. O servidor não expõeresourcesnempromptsainda, e não envia notificações (listChangedé falso). - Sem stream. Não há SSE nem sessão (
Mcp-Session-Id);GET /mcpresponde405. Não há lote JSON-RPC. - Clientes registrados automaticamente são "Não verificados". Recebem só escopos de leitura e exibem o aviso na tela de consentimento até a equipe Asender verificá-los; a equipe também pode suspender um cliente ou bloquear um domínio.
- Uma conta por conexão. Para consultar outra conta, conecte de novo escolhendo a outra conta (ou use outra chave).