Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 48 additions & 17 deletions .env.template
Original file line number Diff line number Diff line change
@@ -1,45 +1,76 @@
# AdCP Sales Agent - Environment Configuration
# =============================================
# Copy this file to .env: cp .env.template .env
# Then edit .env with your actual values.
#
# SETUP PATHS:
# Path 1 (Mock/Testing): Set [REQUIRED] variables only
# Path 2 (GAM Local): Set [REQUIRED] + [GAM-OAUTH] variables
# Path 3 (Production): See docs/deployment.md
#
# Copy this file to .env: cp .env.template .env
# Docker Compose automatically reads .env - just run: docker-compose up -d

# ============================================
# REQUIRED - App will not start without these
# [REQUIRED] Essential Configuration
# ============================================

# Gemini API Key (get free key at https://aistudio.google.com/apikey)
# Gemini API Key - Get free key at https://aistudio.google.com/apikey
GEMINI_API_KEY=

# Your email address (grants super admin access)
# Super Admin Email - Your email address for admin access
SUPER_ADMIN_EMAILS=your-email@example.com

# ============================================
# REQUIRED FOR ADMIN UI LOGIN
# [REQUIRED] Admin UI Authentication
# ============================================
# Create OAuth credentials at: https://console.cloud.google.com/apis/credentials
# Add authorized redirect URI: http://localhost:8001/auth/google/callback
# Test Mode is enabled by default for quick start.
# Switch to Google OAuth for production use.

# Test Mode (default - for quick testing)
# Enables pre-configured test accounts: test_super_admin@example.com / test123
# DO NOT USE IN PRODUCTION - set to false and configure OAuth below
ADCP_AUTH_TEST_MODE=true

# Google OAuth (for production use)
# 1. Set ADCP_AUTH_TEST_MODE=false above
# 2. Create OAuth client at: https://console.cloud.google.com/apis/credentials
# 3. Add redirect URI: http://localhost:8001/auth/google/callback
# 4. Enter credentials below:
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=

# ============================================
# OPTIONAL - Defaults work for local development
# [GAM-OAUTH] Google Ad Manager - Path 2 Only
# ============================================
# Required ONLY if using GAM adapter with OAuth authentication
#
# IMPORTANT: These are DIFFERENT from Admin UI credentials above!
# 1. Create separate OAuth client at: https://console.cloud.google.com/apis/credentials
# 2. Add redirect URI: http://localhost:8001/tenant/callback/gam
# 3. Enter credentials below:
# 4. Restart services: docker-compose restart
#
# NOTE: Service Account authentication (recommended for production) can be
# configured via Admin UI and does NOT require these OAuth credentials.
#
GAM_OAUTH_CLIENT_ID=
GAM_OAUTH_CLIENT_SECRET=

# ============================================
# [OPTIONAL] Port Configuration
# ============================================
# Change these if you have port conflicts

# Ports (change if you have conflicts)
POSTGRES_PORT=5432
ADCP_SALES_PORT=8080
ADMIN_UI_PORT=8001
A2A_PORT=8091

# Google Ad Manager integration (only if using GAM adapter)
# GAM_OAUTH_CLIENT_ID=
# GAM_OAUTH_CLIENT_SECRET=

# Allowed admin domains (optional - users from these domains get access)
# SUPER_ADMIN_DOMAINS=example.com
# ============================================
# [OPTIONAL] Advanced Settings
# ============================================

# Environment: development (strict validation) or production (lenient)
# Environment mode: development (strict validation) or production (lenient)
ENVIRONMENT=development

# Allowed admin domains (optional - grant access to all users from these domains)
# SUPER_ADMIN_DOMAINS=example.com
102 changes: 79 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,45 +11,97 @@ The AdCP Sales Agent is a server that:
- **Provides an admin interface** for managing inventory and monitoring campaigns
- **Handles the full campaign lifecycle** from discovery to reporting

## Quick Start
## Quick Start - Choose Your Setup Path

### Docker Setup (Recommended)
### Path 1: Mock Adapter (5 min) - Recommended First Step

**Perfect for:** Learning AdCP, testing integrations, development

```bash
# 1. Clone and enter the repository
# 1. Clone and configure
git clone https://github.com/adcontextprotocol/salesagent.git
cd salesagent

# 2. Create your .env file
cp .env.template .env
# Edit .env with your values (instructions in the file)

# 2. Set your Gemini API key in .env:
# GEMINI_API_KEY=get-free-at-https://aistudio.google.com/apikey
# (Test mode is enabled by default - no OAuth setup needed)

# 3. Start services
docker-compose up -d

# 4. Access the Admin UI
# 4. Create test tenant (note the token output!)
docker-compose exec adcp-server python -m scripts.setup.setup_tenant "Test Publisher" \
--adapter mock \
--admin-email your-email@example.com

# 5. Test the MCP server with AdCP CLI (use token from step 4)
uvx adcp http://localhost:8080/mcp/ --auth YOUR_TOKEN list_tools

# 6. Access Admin UI
open http://localhost:8001
# Login with: test_super_admin@example.com / test123
```

**Required configuration in .env:**
- `GEMINI_API_KEY` - Get free at https://aistudio.google.com/apikey
- `SUPER_ADMIN_EMAILS` - Your email address
- `GOOGLE_CLIENT_ID` / `GOOGLE_CLIENT_SECRET` - From [Google Cloud Console](https://console.cloud.google.com/apis/credentials)
- Add redirect URI: `http://localhost:8001/auth/google/callback`
**Using with Claude Desktop:** Add to your Claude config (`~/Library/Application Support/Claude/claude_desktop_config.json`):
```json
{
"mcpServers": {
"adcp": {
"command": "uvx",
"args": ["mcp-remote", "http://localhost:8080/mcp/", "--header", "x-adcp-auth: YOUR_TOKEN"]
}
}
}
```

### Creating Your First Tenant
The mock adapter simulates a complete ad server - no external credentials needed.

```bash
# Create a test tenant with mock adapter (no ad server needed)
docker-compose exec adcp-server python -m scripts.setup.setup_tenant "My Publisher" \
--adapter mock \
--admin-email your-email@example.com
```
---

### Conductor Setup (for parallel workspaces)
### Path 2: Google Ad Manager with OAuth (30 min)

If using Conductor, see [docs/DEVELOPMENT.md](docs/DEVELOPMENT.md) for workspace setup.
Each workspace gets unique ports automatically.
**Perfect for:** Quick local testing against a real GAM network

**Note:** This uses OAuth refresh tokens. For production, use Service Account authentication instead (see Path 3).

**Prerequisites - complete BEFORE starting:**

1. **Create GAM OAuth Credentials:**
- Go to [Google Cloud Console](https://console.cloud.google.com/apis/credentials)
- Create OAuth 2.0 Client ID (Web application)
- Add redirect URI: `http://localhost:8001/tenant/callback/gam`
- Save Client ID and Client Secret

2. **Add to .env file:**
```bash
GAM_OAUTH_CLIENT_ID=your-client-id.apps.googleusercontent.com
GAM_OAUTH_CLIENT_SECRET=your-client-secret
```

3. **Start services and configure:**
```bash
docker-compose up -d
docker-compose exec adcp-server python -m scripts.setup.setup_tenant "My Publisher" \
--adapter google_ad_manager \
--gam-network-code YOUR_NETWORK_CODE \
--admin-email your-email@example.com
```

4. **Complete OAuth flow** in Admin UI at http://localhost:8001

---

### Path 3: Production Deployment

Use **Service Account** authentication (recommended over OAuth):
- Credentials never expire
- Better security and isolation
- No manual refresh required

See [docs/deployment.md](docs/deployment.md) for production setup.

---

### Troubleshooting

Expand All @@ -58,8 +110,12 @@ Each workspace gets unique ports automatically.
docker-compose logs admin-ui | head -50 # Check for missing env vars
```

**GAM OAuth error: "Could not determine client ID"?**
- Check that `GAM_OAUTH_CLIENT_ID` and `GAM_OAUTH_CLIENT_SECRET` are set in `.env`
- Run `docker-compose restart` after adding credentials

**OAuth callback 404?**
- Redirect URI must be exactly: `http://localhost:8001/auth/google/callback`
- Redirect URI must match exactly what's in Google Cloud Console

**More help:** See [Troubleshooting Guide](docs/TROUBLESHOOTING.md)

Expand Down
46 changes: 46 additions & 0 deletions docs/TROUBLESHOOTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,52 @@ See `docker-compose.override.example.yml` for complete configuration.

### GAM Integration Issues

#### "Could not determine client ID from request"

**Symptom**: Error when trying to save/test GAM configuration with OAuth authentication.

**Cause**: `GAM_OAUTH_CLIENT_ID` or `GAM_OAUTH_CLIENT_SECRET` environment variables not set.

**Solution**:

1. Check if environment variables are set:
```bash
docker-compose exec adcp-server env | grep GAM_OAUTH
```

2. If missing, add to your `.env` file:
```bash
GAM_OAUTH_CLIENT_ID=your-client-id.apps.googleusercontent.com
GAM_OAUTH_CLIENT_SECRET=your-client-secret
```

3. Create OAuth credentials at [Google Cloud Console](https://console.cloud.google.com/apis/credentials):
- Create OAuth 2.0 Client ID (Web application)
- Add redirect URI: `http://localhost:8001/tenant/callback/gam`

4. Restart services:
```bash
docker-compose restart
```

5. Verify configuration:
```bash
docker-compose exec adcp-server python scripts/gam_prerequisites_check.py
```

**Alternative**: Use Service Account authentication instead (no OAuth setup required). Configure via Admin UI in the "Service Account Integration" section.

#### GAM OAuth vs Service Account

| Feature | OAuth (Refresh Token) | Service Account |
|---------|----------------------|-----------------|
| Setup complexity | Higher (requires OAuth credentials) | Lower (just upload JSON key) |
| Token expiration | Tokens can expire | Never expires |
| Use case | Quick local testing | Production deployments |
| Security | Tied to user account | Isolated service identity |

**Recommendation**: Use Service Account for production; OAuth for quick testing only.

#### OAuth Token Invalid
```bash
# Refresh OAuth token
Expand Down
69 changes: 69 additions & 0 deletions scripts/gam_prerequisites_check.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#!/usr/bin/env python3
"""
Check if GAM prerequisites are configured.

Usage:
python scripts/gam_prerequisites_check.py

Returns:
Exit code 0 if all prerequisites met, 1 otherwise
"""
import os
import sys


def main():
"""Check GAM prerequisites and print status."""
print("Checking GAM Prerequisites...\n")

all_good = True

# Check OAuth credentials
client_id = os.environ.get("GAM_OAUTH_CLIENT_ID")
client_secret = os.environ.get("GAM_OAUTH_CLIENT_SECRET")

if client_id:
print(" GAM_OAUTH_CLIENT_ID is set")
else:
print(" GAM_OAUTH_CLIENT_ID is not set")
all_good = False

if client_secret:
print(" GAM_OAUTH_CLIENT_SECRET is set")
else:
print(" GAM_OAUTH_CLIENT_SECRET is not set")
all_good = False

# Check service account provisioning capability
gcp_project = os.environ.get("GCP_PROJECT_ID")
if gcp_project:
print(f" GCP_PROJECT_ID is set ({gcp_project})")
print(" Service account auto-provisioning available")
else:
print(" GCP_PROJECT_ID not set")
print(" Service account auto-provisioning unavailable")
print(" Manual service account upload still supported")

print()

if not all_good:
print("GAM OAuth prerequisites not fully configured\n")
print("To use GAM with OAuth authentication:")
print(" 1. Go to https://console.cloud.google.com/apis/credentials")
print(" 2. Create OAuth 2.0 Client ID (Web application)")
print(" 3. Add redirect URI: http://localhost:8001/tenant/callback/gam")
print(" 4. Set credentials in .env file:")
print(" GAM_OAUTH_CLIENT_ID=your-client-id")
print(" GAM_OAUTH_CLIENT_SECRET=your-client-secret")
print(" 5. Restart: docker-compose restart\n")
print("Alternative: Use Service Account authentication via Admin UI")
print("(No OAuth setup required)\n")
return 1
else:
print("All GAM OAuth prerequisites configured!")
print("You can now use OAuth authentication with GAM.\n")
return 0


if __name__ == "__main__":
sys.exit(main())
6 changes: 6 additions & 0 deletions src/admin/blueprints/tenants.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,11 @@ def tenant_settings(tenant_id, section=None):
if adapter_config_obj and adapter_config_obj.adapter_type == "google_ad_manager":
oauth_configured = bool(adapter_config_obj.gam_refresh_token)

# Check if GAM OAuth environment variables are configured
gam_oauth_configured = bool(
os.environ.get("GAM_OAUTH_CLIENT_ID") and os.environ.get("GAM_OAUTH_CLIENT_SECRET")
)

# Get advertiser data for the advertisers section
from src.core.database.models import GAMInventory, Principal

Expand Down Expand Up @@ -379,6 +384,7 @@ def tenant_settings(tenant_id, section=None):
active_adapter=active_adapter,
adapter_config=adapter_config_dict, # Use dict format
oauth_configured=oauth_configured,
gam_oauth_configured=gam_oauth_configured, # Environment check for GAM OAuth
last_sync_time=last_sync_time,
running_sync=running_sync, # Pass running sync info
principals=principals,
Expand Down
Loading
Loading