mcp-meta-ads
Provides tools for interacting with Meta's Marketing API, enabling management of ad accounts, campaigns, ad sets, and ads, including reading performance insights and updating statuses and budgets.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mcp-meta-adsList my campaigns with their current status and budget for the last 7 days."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
mcp-1nort-meta
Servidor MCP que expõe a Meta Marketing API ao Claude: relatórios de desempenho de anúncios e ajustes operacionais (pausar/reativar, alterar orçamento), para as contas dos clientes da 1nort.
Roda local, por stdio, em TypeScript sobre Node 20+.
O token configurado é de produção. Ele é de um usuário de sistema do Business Manager e alcança as contas de todos os clientes da agência. A allowlist de contas é o que restringe este servidor a um subconjunto — leia docs/seguranca-mutacoes.md antes de liberar escrita.
Começando
npm ci
cp .env.example .env # e preencha
npm run check # typecheck + testes
npm run buildO .env precisa ter META_AD_ACCOUNT_ALLOWLIST preenchida. Sem ela o servidor não inicia — de
propósito: vazio nunca significa "liberar todas as contas".
Rodar e inspecionar
npm run inspector # abre o MCP Inspector apontando para o servidor
npm run dev # roda direto do TypeScript, sem build
npm start # roda o build de dist/Registrar no Claude Code
O .mcp.json na raiz já registra dois servidores (só caminhos, nenhum segredo):
meta-ads— respeita o.env.meta-ads-somente-leitura— forçaMETA_READ_ONLY=true. Como o ambiente do processo tem precedência sobre o--env-file, este é somente-leitura por construção, independente do que o.envdiga. Use este como padrão e deixe o outro para sessões deliberadas de alteração.
Ou pela linha de comando:
claude mcp add --scope project meta-ads -- node --env-file=.env dist/index.jsNo Claude Desktop, o claude_desktop_config.json precisa de caminhos absolutos (Desktop não tem
raiz de projeto).
Related MCP server: Marketing MCP
Ferramentas
Leitura (sempre disponíveis)
Ferramenta | O que faz |
| Guard-rails em vigor: contas permitidas, modo, limites. Zero chamadas à Meta. Consulte antes de propor qualquer alteração. |
| As contas da allowlist, com moeda, fuso e orçamento mínimo. |
| Métricas por conta/campanha/conjunto/anúncio, uma linha por dia por padrão. |
| Campanhas com status, objetivo e orçamento. |
| Conjuntos, opcionalmente de uma campanha específica. |
| Anúncios com miniatura em 512px; |
Banco (só com DB_FERRAMENTAS_MCP=true)
Leem o banco da 1nort com um usuário SELECT-only. Histórico já coletado, sem consumir cota da Meta.
Ferramenta | O que faz |
| Quantas contas o escopo alcança e até que dia o banco tem dado. |
| Nome e segmento do cliente de cada conta — traduz "cliente X" em id de conta. |
| Série diária de uma conta a partir do histórico coletado. |
| Se a coleta de uma conta está bloqueada e até onde chegou. |
| Ranking de anúncios do período. |
Nenhuma delas aceita SQL, e nenhuma aceita e-mail. SQL livre não tem como ser seguro aqui: o
usuário somente-leitura enxerga tb_credenciais (com token_kommo, token_ghl, pixel_token) e a
própria tb_meta_ads tem pixel_token; um agente que lê nome de campanha escrito por cliente é superfície
de injeção. Filtrar SQL na aplicação não resolve (CTE, subquery, pg_catalog, ::regclass), e a
restrição correta — REVOKE no Postgres — depende de um direito que não temos. E como nenhuma
ferramenta aceita e-mail, o modelo não consegue trocar o próprio escopo: isso é ação do humano
na tela.
Escrita (só com META_READ_ONLY=false)
Ferramenta | O que faz |
| Pausa ou reativa campanha, conjunto ou anúncio. |
| Altera orçamento diário ou total de campanha ou conjunto. |
| Cria campanha. Nasce pausada. |
| Cria conjunto numa campanha existente. Nasce pausado. |
| Cria anúncio a partir de publicação, criativo salvo ou URL de imagem. |
| Cria público personalizado (Instagram, página, site ou formulário). |
E três de leitura que existem para o modelo não inventar id: meta_list_creatives,
meta_list_publications e meta_list_audiences.
Tudo nasce pausado, e isso não é parâmetro. Nenhuma ferramenta de criação aceita status: um
objeto pausado não gasta, então errar custa zero, e ativar continua sendo meta_update_status —
auditado e com confirmação do host.
special_ad_categories é constante [], fora do schema. A 1nort declara que não anuncia
crédito, emprego, moradia nem tema social. Se isso mudar — financiamento solar seria CREDIT —, o
valor está em SEM_CATEGORIA_ESPECIAL, num lugar só, e alterá-lo é decisão de um humano. Declarar
categoria especial errada é violação de política da Meta, não erro de campanha.
Não existe exclusão nem arquivamento. DELETED e ARCHIVED não estão no schema, então não há
caminho de código que chegue a eles — objeto criado por engano se apaga à mão no Gerenciador.
Duas regras de negócio que não podem ser afrouxadas
1. Leads de formulário e de mensagem nunca se somam.
leads_form ← onsite_conversion.lead_grouped
leads_message ← onsite_conversion.messaging_conversation_started_7dO action type genérico lead é ignorado — conta formulário por outro critério e diverge de
lead_grouped por ordem de grandeza. Ausência devolve null, nunca 0: "não medido" e "medido e
deu zero" são fatos diferentes. Regra portada de ExtratorAcoesMeta.java, do projeto Citrino, para
que os relatórios dos dois sistemas não divirjam para o mesmo cliente no mesmo dia.
2. Orçamento é informado na unidade MAIOR da moeda.
amount: 250.50 significa R$ 250,50. A Meta armazena em unidade menor (25050) e a conversão é do
servidor. Mandar centavos aqui definiria um orçamento cem vezes maior — por isso a resposta sempre
mostra as duas unidades lado a lado, para o erro saltar aos olhos antes da confirmação.
Segurança
Resumo; o contrato completo está em docs/seguranca-mutacoes.md.
Allowlist de contas, com comparação exata e tipo branded que o compilador cobra.
Vínculo objeto → conta antes de toda escrita:
POST /{id}não menciona conta nenhuma, então sem essa releitura a allowlist não valeria nada na escrita.Duas chaves para aplicar:
META_WRITE_DRY_RUN=falseeconfirm: true. Prévia e aplicação percorrem o mesmo código; muda só ovalidate_only, que é validado pela própria Meta.Limites de orçamento com falha fechada; moeda fora da tabela é recusada, nunca chutada.
Auditoria de toda tentativa, inclusive recusas, em
stderr.Token só no header
Authorization;appsecret_proofem toda chamada.
Variáveis de ambiente
Ver .env.example. As que mais importam:
Variável | Padrão | Efeito |
| (nenhum) | Obrigatória. Sem ela o servidor não inicia. |
|
| Ferramentas de escrita nem são registradas. |
|
| Toda escrita vira |
|
| Variação máxima num ajuste. |
|
| Teto diário, unidade maior. |
|
|
|
| (nenhum) | Ausentes = recurso de banco desligado. |
|
| Registra as cinco ferramentas |
Interface local
npm run ui # constrói tudo e sobe em http://127.0.0.1:8787Ou, do Claude Code: /painel — ou /painel email@do-usuario para abrir já escopado.
O painel lê do banco: uma consulta traz o histórico de todas as contas do escopo. Um gestor com 67 contas carrega em menos de 2 s com zero chamadas à Meta. O que só a Graph sabe — teto de gastos, status da conta, moeda, fuso, campanhas ativas — chega ao expandir uma linha, uma conta por vez. Antes eram quatro chamadas por conta na carga da tela, o que a 67 contas seriam 268 chamadas contra um limite de ~15/min.
O chat responde interpretando os números, com as duas famílias de ferramenta. A conversa é
gravada em .conversas/ (fora do git): sobrevive a trocar de aba, a F5, a fechar o navegador e a
reiniciar o servidor. Uma resposta cortada no meio volta marcada como interrompida — e nunca é
retomada sozinha, o que recobraria tokens e poderia reexecutar consultas.
Escopo por usuário
Ativar um e-mail resolve users → tb_usuarios_clientes → tb_clientes → tb_meta_ads e constrói uma
Allowlist nova com essas contas. ROLE_ADMINo usuário somente-leitura enxerga todos os clientes ativos, porque a
plataforma não enumera vínculo de administrador. Contas sem cliente vinculado não entram no escopo
de ninguém — conta sem dono não é de todo mundo —, mas a contagem aparece no aviso.
Ativar é ação de operador, pelo controle da tela ou por ?ativar=. Não é um padrão que o sistema
reconheça dentro de uma mensagem: o agente lê texto escrito por cliente, e uma campanha chamada
[ativar:alguem@1nort...] viraria escalonamento de escopo por um campo que o cliente controla. O
atalho de digitação existe, mas é tratado só no navegador e removido antes do envio.
De onde vem cada número
Dado | Fonte |
gasto, impressões, cliques, leads, série diária | banco ( |
cliente, segmento, saúde da coleta | banco |
teto de gastos, status da conta, moeda, fuso | Meta, sob demanda |
campanhas ativas, dados de hoje | Meta, sob demanda |
A escolha da tabela foi medida, não suposta (npm run diag:comparar). Em julho/2026, contra a
Graph: tb_dados_trafego perdia 67 leads de mensagem numa conta, 54 de formulário noutra, e não
tinha linha nenhuma para uma terceira que gastou R$ 4.850 no mês. tb_meta_anuncios_metricas bateu
nas três, dentro de 0,2%, e ainda preserva NULL para "não medido" — coisa que o agregado legado
não faz (13.264 linhas, 8.875 zeros onde deveria haver nulo).
Período pedido além da cobertura é recortado e avisado, nunca completado em silêncio: somar um dia do banco com um dia da Graph produz um total que não reconcilia com fonte nenhuma.
Desenvolvimento
npm test # 325 testes
npm run typecheck
npm run fmt
npm run diag:banco # sonda o banco: cobertura, semântica de nulo, escopo de um e-mail
npm run diag:comparar -- act_123 2026-07-01 2026-07-31 # banco × Graph, mesma conta e períodoTestes injetam fetch em vez de mockar o cliente Graph, então exercitam o que de fato quebra:
montagem de URL, a string fields, encoding do time_range, cursor de paginação e parsing de
número-string. test/invariantes.test.ts varre todas as URLs emitidas atrás do token, confere que
ele está no Authorization de toda chamada, e falha se alguma coisa escrever em stdout.
Pendências conhecidas
Conferir os números contra o Gerenciador de Anúncios antes de confiar neles. A Meta interpreta datas no fuso da conta, e a janela de atribuição padrão molda a contagem de leads. Toda resposta de
meta_get_insightstrazaccount_timezonee o período resolvido justamente para permitir essa conferência. Pode ser necessário fixaraction_attribution_windowsexplicitamente.Criar uma campanha sacrificial antes do primeiro teste de escrita real — campanha nova, pausada, orçamento mínimo, sem anúncios. Senão a primeira escrita cai num cliente pagante.
Ligar Require App Secret nas configurações do app Meta. O
appsecret_proofjá é enviado em toda chamada, mas o benefício (token roubado deixa de servir sozinho) só vale depois de ativar a exigência do lado da Meta.Token com escopo menor. A allowlist é controle de aplicação sobre uma credencial sem limite técnico. A correção estrutural é um segundo usuário de sistema do BM com acesso só às contas permitidas.
v21.0expira em 2027-01-21. Agendar o bump, de preferência junto com o Citrino, para o conhecimento compartilhado de erros e action types continuar valendo.Rate limit (~15 req/min por conta). Há teto de páginas e de linhas, e o resultado sempre informa
truncated. Falta decidir se vale acrescentar pausa entre páginas.node_modules/edist/dentro do OneDrive sofrem varredura de sincronização contínua. Recomendo excluir os dois do sync, ou mover o projeto para fora do OneDrive.O agregado
tb_dados_trafegoestá errado ondetb_meta_anuncios_metricasestá certo. Vale investigar o coletor ou aposentar a tabela — hoje ela só alimentavw_desempenho_conta_diario, que também expõe umtotal_leadssomado e deveria sair de cena junto. Ver docs/proposta-tabelas.sql..conversas/dentro do OneDrive significa transcript com dado de cliente (gasto, nome de campanha, id de conta) sincronizando para uma nuvem pessoal. Mesmo problema do item 7, com conteúdo mais sensível.Postgres de produção sem TLS na internet pública. A senha e todas as linhas viajam em texto claro. Não é bug deste projeto, mas vale levar a quem cuida do
db02.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- Alicense-qualityDmaintenanceAn MCP server for programmatic management of Meta (Facebook/Instagram) advertising campaigns through AI assistants. It enables campaign creation, ad set management, creative upload, analytics, audience management, and conversion tracking.Last updated1694MIT
- Alicense-qualityBmaintenanceA unified MCP server for marketing analytics and management across Google Ads, Meta Ads, GA4, and keyword research, supporting multi-client rollups and platform-conditional credential requirements.Last updatedMIT
- Alicense-qualityDmaintenanceMCP server for Meta/Facebook Marketing API allowing you to view and manage ad accounts, campaigns, ad sets, ads, and creatives, as well as fetch insights and upload ad images.Last updatedMIT
- Alicense-qualityDmaintenanceRead-only MCP server for Meta Ads that lists and reads ad accounts, campaigns, ad sets, ads, ad images, creatives, and fetches insights at various levels.Last updatedMIT
Related MCP Connectors
Managed LinkedIn MCP server for AI agents: search, connect, message and enrich on accounts you own.
Hosted Amazon Seller Central and Amazon Ads MCP server for Claude, ChatGPT, Cursor, and agents.
A paid remote MCP for CLI tool MCP, built to return verdicts, receipts, usage logs, and audit-ready
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/wallacymenezes/mcp-meta-ads'
If you have feedback or need assistance with the MCP directory API, please join our Discord server