Skip to main content
Glama
Wayy-Research

flour-ads

README.md
# flour-ads

CLI + MCP server for managing ad campaigns across Google Ads, Meta, and more.

Deploy campaigns, check performance, and manage budgets — from the terminal or through any MCP-compatible AI assistant (Claude Code, Cursor, etc.).

## Install

```bash
git clone https://github.com/Wayy-Research/flour-ads.git
cd flour-ads
uv venv && source .venv/bin/activate
uv pip install -e ".[dev]"
```

## Quick Start

### CLI

```bash
# List available platforms
flour-ads platforms

# Authenticate (uses env vars or stored credentials)
flour-ads auth login --platform google_ads --account-id 123-456-7890

# Deploy a campaign from YAML config
flour-ads campaign create \
  --platform google_ads \
  --account-id 123-456-7890 \
  --config examples/ringgold_campaign.yaml

# List campaigns
flour-ads campaign list --platform google_ads --account-id 123-456-7890

# Check performance
flour-ads campaign performance \
  --platform google_ads \
  --account-id 123-456-7890 \
  --campaign-id 12345678 \
  --range LAST_7_DAYS

# Pause/resume
flour-ads campaign pause --platform google_ads --account-id ID --campaign-id CID
flour-ads campaign resume --platform google_ads --account-id ID --campaign-id CID

# Update budget
flour-ads budget update \
  --platform google_ads \
  --campaign-id 12345678 \
  --account-id 123-456-7890 \
  --daily-budget 45.00
```

### MCP Server

```bash
# Start the MCP server (stdio transport)
flour-ads serve
```

Add to your Claude Code settings (`.claude/settings.json`):

```json
{
  "mcpServers": {
    "flour-ads": {
      "command": "flour-ads",
      "args": ["serve"]
    }
  }
}
```

**MCP Tools:**

| Tool | Description |
|------|-------------|
| `list_platforms` | List available ad platforms |
| `authenticate` | Authenticate with a platform |
| `create_campaign` | Create a campaign from config file or inline params |
| `pause_campaign` | Pause an active campaign |
| `resume_campaign` | Resume a paused campaign |
| `list_campaigns` | List campaigns for an account |
| `update_budget` | Update daily budget |
| `get_performance` | Get performance metrics with daily breakdown |

## Campaign Config (YAML)

Define campaigns as YAML files for reproducible, version-controlled deployments:

```yaml
name: "My Search Campaign"
platform: google_ads
campaign_type: SEARCH
status: PAUSED  # deploy paused, review, then enable

budget:
  daily_amount: 50.00

bidding:
  strategy: MAXIMIZE_CONVERSIONS

targeting:
  locations: ["10001", "10002", "10003"]
  languages: ["en"]
  networks:
    search: true
    display: false

ad_groups:
  - name: "Core Keywords"
    keywords:
      - text: "plumber NYC"
        match_type: PHRASE
    ads:
      - headlines:
          - "NYC Plumber — Fast Service"
          - "Licensed & Insured"
          - "Free Estimates Today"
        descriptions:
          - "Trusted plumber serving NYC. Same-day service. Call now."
          - "20+ years experience. No hourly rates. Upfront pricing."
        final_url: "https://example.com"

negative_keywords:
  - "DIY"
  - "jobs"
  - "hiring"
```

See [examples/](examples/) for a complete real-world campaign config.

## Credentials

flour-ads looks for credentials in this order:

1. **OS Keyring** (macOS Keychain, Linux Secret Service, Windows Credential Locker)
2. **JSON file** at `~/.flour-ads/credentials.json`
3. **Environment variables**

### Google Ads

```bash
export GOOGLE_ADS_DEVELOPER_TOKEN="..."
export GOOGLE_ADS_CLIENT_ID="..."
export GOOGLE_ADS_CLIENT_SECRET="..."
export GOOGLE_ADS_REFRESH_TOKEN="..."
export GOOGLE_ADS_CUSTOMER_ID="1234567890"
```

See [docs/google-ads-setup.md](docs/google-ads-setup.md) for the full setup guide.

## Adding a Platform

flour-ads uses a plugin architecture. To add a new platform:

1. Create `src/flour_ads/platforms/yourplatform/adapter.py`
2. Inherit from `AdPlatform` and implement all abstract methods:

```python
from flour_ads.platforms.base import AdPlatform

class YourPlatformAdapter(AdPlatform):
    platform_id = "yourplatform"
    platform_name = "Your Platform"

    async def authenticate(self, account_id, credentials): ...
    async def create_campaign(self, account_id, config): ...
    async def pause_campaign(self, account_id, campaign_id): ...
    async def resume_campaign(self, account_id, campaign_id): ...
    async def get_performance(self, account_id, campaign_id, date_range): ...
    async def list_campaigns(self, account_id, status=None): ...
    async def update_budget(self, account_id, campaign_id, daily_budget): ...
```

3. Register via entry point in `pyproject.toml`:

```toml
[project.entry-points."flour_ads.platforms"]
yourplatform = "flour_ads.platforms.yourplatform.adapter:YourPlatformAdapter"
```

## Platforms

| Platform | Status | Notes |
|----------|--------|-------|
| Google Ads | **Ready** | Search campaigns, RSA ads, keyword targeting |
| Meta (Facebook/Instagram) | Stub | Adapter skeleton in place |
| TikTok | Planned | |
| LinkedIn | Planned | |
| Microsoft Ads | Planned | |

## Development

```bash
uv pip install -e ".[dev]"
pytest tests/ -v
black . && ruff check .
mypy src/
```

## License

MIT — see [LICENSE](LICENSE).

---

Built by [Wayy Research](https://github.com/Wayy-Research) — Buffalo, NY