Meta Ad Library MCP
by netty-linux
README.md
# Meta Ad Library MCP
Servidor [MCP](https://modelcontextprotocol.io/) de produção para consultar a **Meta Ad Library API oficial** (`/ads_archive`) — sem scraping.
Construído com **FastMCP**, **httpx**, **Pydantic v2** e cache **SQLite** com TTL (preparado para migrar para Redis).
## Ferramentas (v1)
| Ferramenta | Descrição |
|---|---|
| `search_meta_ads` | Busca anúncios por palavras-chave + país |
| `get_ads_from_page` | Lista anúncios de uma página (`page_id`) |
| `health_check` | Verifica token e saúde do servidor |
## Limitações reais da API (2026)
A Meta Ad Library API é **oficial**, mas tem restrições importantes:
1. **UE e Reino Unido** — A API retorna a maior parte dos anúncios comerciais entregues nessas regiões, incluindo dados de transparência (alcance, targeting, beneficiários, etc.).
2. **Fora da UE/UK (ex.: EUA, Brasil)** — A cobertura de **anúncios comerciais** é **muito limitada**. Em geral, a API retorna principalmente:
- Anúncios de **temas sociais, eleições e política** (`POLITICAL_AND_ISSUE_ADS`)
- Anúncios que **atingiram audiência na UE**, mesmo que a campanha seja global
3. **Sem tradução automática** — `search_terms` devem estar no **idioma dos anúncios** que você busca.
4. **Campos condicionais** — `spend`, `impressions`, `demographic_distribution` e similares só aparecem em categorias/regiões específicas (principalmente política e UE).
5. **Rate limits** — A Graph API aplica limites; o cliente faz retry automático em erros 429/5xx.
6. **Não é substituto do site** — O site [facebook.com/ads/library](https://www.facebook.com/ads/library) pode exibir mais anúncios do que a API em alguns cenários fora da UE.
> **Resumo para agentes de IA:** Para pesquisa competitiva comercial no Brasil ou EUA, espere resultados parciais. Para compliance/transparência na UE/UK ou ads políticos globais, a API é confiável.
## Pré-requisitos
- Python **3.12+**
- Conta [Meta for Developers](https://developers.facebook.com/)
- **User Access Token** com permissão `ads_read`
## Como obter o User Access Token
1. Acesse [developers.facebook.com](https://developers.facebook.com/) e crie um app (tipo **Business** ou **Other**).
2. No app, vá em **Tools → Graph API Explorer**.
3. Selecione seu app e adicione a permissão **`ads_read`**.
4. Gere um **User Access Token** (não Page Token).
5. Para produção, prefira um **token de longa duração** via [Access Token Debugger](https://developers.facebook.com/tools/debug/accesstoken/) → *Extend Access Token*.
6. Copie o token para `META_ACCESS_TOKEN`.
Documentação oficial: [Ad Library API](https://www.facebook.com/ads/library/api/)
## Setup local
```bash
cd meta-ad-library-mcp
python -m venv .venv
# Windows
.venv\Scripts\activate
# macOS/Linux
source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env
# Edite .env e defina META_ACCESS_TOKEN
```
### Executar
```bash
python server.py
```
Por padrão usa transporte **stdio** (ideal para Claude Desktop, Cursor, etc.).
### Modo HTTP (remoto / Railway)
```bash
# .env
MCP_TRANSPORT=http
MCP_PORT=8000
```
```bash
python server.py
# Endpoint MCP: http://localhost:8000/mcp
```
## Conectar clientes MCP
### Cursor
Em **Settings → MCP**, adicione:
```json
{
"mcpServers": {
"meta-ad-library": {
"command": "python",
"args": ["D:/caminho/absoluto/para/meta-ad-library-mcp/server.py"],
"env": {
"META_ACCESS_TOKEN": "seu_token_aqui"
}
}
}
}
```
> Use o caminho absoluto do `server.py` e o Python do seu venv se preferir.
### Claude Desktop
Em `claude_desktop_config.json`:
```json
{
"mcpServers": {
"meta-ad-library": {
"command": "python",
"args": ["/caminho/absoluto/para/meta-ad-library-mcp/server.py"],
"env": {
"META_ACCESS_TOKEN": "seu_token_aqui"
}
}
}
}
```
### Cliente HTTP (Ollama, scripts, etc.)
Com `MCP_TRANSPORT=http`:
```python
import asyncio
from fastmcp import Client
async def main():
async with Client("http://localhost:8000/mcp") as client:
result = await client.call_tool(
"search_meta_ads",
{"search_terms": "fitness", "country": "GB", "limit": 10},
)
print(result)
asyncio.run(main())
```
## Deploy no Railway
### 1. Preparar o repositório
Faça push desta pasta para um repositório Git (GitHub, GitLab, etc.).
### 2. Criar projeto no Railway
1. [railway.app](https://railway.app/) → **New Project** → **Deploy from GitHub repo**
2. Selecione o repositório
### 3. Variáveis de ambiente
| Variável | Valor |
|---|---|
| `META_ACCESS_TOKEN` | Seu token Meta |
| `MCP_TRANSPORT` | `http` |
| `MCP_HOST` | `0.0.0.0` |
| `MCP_PORT` | `${{PORT}}` (Railway injeta a porta) |
| `CACHE_DB_PATH` | `/data/cache.db` |
### 4. Volume persistente (cache SQLite)
1. No serviço Railway → **Volumes** → **Add Volume**
2. Mount path: `/data`
3. Garanta `CACHE_DB_PATH=/data/cache.db`
Sem volume, o cache é perdido a cada redeploy.
### 5. Dockerfile
O projeto já inclui um `Dockerfile` otimizado. Railway detecta e usa automaticamente.
### 6. Verificar deploy
```bash
curl https://seu-app.up.railway.app/mcp
```
Use a URL pública no cliente MCP com transporte HTTP.
## Variáveis de ambiente
| Variável | Padrão | Descrição |
|---|---|---|
| `META_ACCESS_TOKEN` | — | **Obrigatório.** Token com `ads_read` |
| `META_API_VERSION` | `v25.0` | Versão da Graph API |
| `CACHE_TTL_SECONDS` | `3600` | TTL do cache em segundos |
| `CACHE_DB_PATH` | `./data/cache.db` | Caminho do SQLite |
| `MCP_TRANSPORT` | `stdio` | `stdio` ou `http` |
| `MCP_HOST` | `0.0.0.0` | Host HTTP |
| `MCP_PORT` | `8000` | Porta HTTP |
| `LOG_LEVEL` | `INFO` | Nível de log |
| `REQUEST_TIMEOUT_SECONDS` | `30` | Timeout httpx |
| `MAX_RETRIES` | `3` | Retries em 429/5xx |
## Estrutura do projeto
```
meta-ad-library-mcp/
├── server.py # FastMCP server + tools
├── config.py # Settings via env vars
├── clients/
│ └── meta_api_client.py # httpx client + pagination/errors
├── models/
│ └── ad_models.py # Pydantic v2 models
├── cache/
│ ├── base.py # CacheBackend protocol (Redis-ready)
│ └── sqlite_cache.py # SQLite implementation
├── data/ # SQLite cache (gitignored)
├── requirements.txt
├── Dockerfile
└── README.md
```
## Migrar cache para Redis
Implemente `CacheBackend` em `cache/redis_cache.py` com os mesmos métodos de `SqliteCache`, injete no `MetaApiClient` em `server.py`, e troque a instância — nenhuma tool precisa mudar.
## Exemplos de uso (tools)
**Busca por keyword (Reino Unido — boa cobertura comercial):**
```json
{
"search_terms": "protein powder",
"country": "GB",
"limit": 25
}
```
**Anúncios de uma página:**
```json
{
"page_id": "123456789012345",
"country": "US",
"ad_active_status": "ALL",
"limit": 50
}
```
**Paginação:**
Passe `after` com o valor de `paging.next_cursor` da resposta anterior.
## Licença
MIT — use livremente em projetos pessoais e comerciais.This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues