Skip to main content
Glama
PlatAid

Naver Search Ad MCP

by PlatAid
README.md
# Naver Search Ad MCP

An [MCP](https://modelcontextprotocol.io) server for the **Naver Search Ad**
(네이버 검색광고) API — read/analytics focused. Query campaigns, ad groups,
keywords, stats, keyword research, and bid estimates through any MCP client.

- **Read-only** by default (safe): all tools are annotated `readOnlyHint`.
- **Multi-account**: one credential per user auto-discovers every advertiser
  account it can access (agency-delegated + own) via `/ad-accounts` +
  `child-ad-accounts`, addressed by `account_id` (= Naver `customerId`).
- **Two transports**: local `stdio` for a single account, or hosted
  `streamable-http` (Google Workspace OAuth) for a team — see [DEPLOY.md](DEPLOY.md).

## Quick start (local, stdio)

Get your credentials at **searchad.naver.com → 관리 → 도구 → API 사용 관리**
(CUSTOMER_ID, access license, secret key).

```bash
uv venv --python 3.13
uv pip install -e .

export NAVER_API_KEY=...        # access license
export NAVER_SECRET_KEY=...     # secret key
export NAVER_CUSTOMER_ID=...    # customer id (integer)
naver-searchad-mcp             # stdio MCP server
```

Register with an MCP client (e.g. Claude Desktop):

```json
{
  "mcpServers": {
    "naver-searchad": {
      "command": "/path/to/.venv/bin/naver-searchad-mcp",
      "env": {
        "NAVER_API_KEY": "...",
        "NAVER_SECRET_KEY": "...",
        "NAVER_CUSTOMER_ID": "..."
      }
    }
  }
}
```

## Tools

**Accounts**
| Tool | Description |
|------|-------------|
| `list_accounts()` | All accessible ad accounts (`/ad-accounts` ∪ `child-ad-accounts`, deduped). Each `account_id` = customerId |
| `get_accounts_overview(...)` | Per-account campaign count + period performance summary |
| `whoami()` | Diagnostic: authenticated caller + linked credential (hosted mode) |

**Entities**
| Tool | Description |
|------|-------------|
| `list_campaigns(account_id, campaign_type?)` | Campaigns |
| `get_campaign(account_id, campaign_id)` | Campaign detail |
| `list_adgroups(account_id, campaign_id)` | Ad groups |
| `get_adgroup(account_id, adgroup_id)` | Ad group detail |
| `list_keywords(account_id, adgroup_id)` | Keywords |
| `list_ads(account_id, adgroup_id)` | Ads (creatives) |
| `list_business_channels(account_id)` | Business channels |

**Performance & analytics**
| Tool | Description |
|------|-------------|
| `get_stats(account_id, ids[], fields[], since/until\|date_preset, ...)` | Low-level `/stats` (≤92-day window, single entity level) |
| `get_campaign_performance(account_id, dates, fields?)` | All campaigns + names |
| `get_keyword_performance(account_id, adgroup_id, dates)` | Keyword performance + text |
| `get_related_keywords(account_id, hint_keywords[])` | Related keywords, search volume, competition (`/keywordstool`) |
| `get_performance_report(account_id, level, since, until, daily?, ...)` | Named report; auto-chunks >92 days; aggregate (ratios recomputed) or daily |
| `create_stat_report(account_id, report_tp, stat_dt)` | Async bulk StatReport job (1 job = 1 day) |
| `download_stat_report(account_id, download_url, max_rows?)` | Download StatReport TSV (raw, columns not interpreted) |

**Bid estimates**
| Tool | Description |
|------|-------------|
| `estimate_keyword_bid(account_id, keywords[], estimate_type, device, position)` | Target-position / min-exposure bid |
| `estimate_keyword_performance(account_id, keyword, bids[], device)` | Predicted impressions/clicks/cost per bid |

Metric field names are terse and sometimes misleading (`salesAmt` = **cost**,
`ror` = **ROAS %**); the server attaches clear aliases (`cost`, `roas_pct`, …)
and exposes a `naver://metric-glossary` resource.

## Hosted deployment (team, Google OAuth)

See [DEPLOY.md](DEPLOY.md) — Cloud Run + Secret Manager + Google Workspace
OAuth, per-email credential model, and a self-service admin console at `/admin`.

## Development

```bash
uv pip install -e ".[dev]"
pytest
```

## Notes

- This server covers **Search Ad** only. Naver GFA (성과형 디스플레이광고) is a
  separate API (partner-only OAuth) and is out of scope.
- Signing rule: `base64(HMAC_SHA256(secret, "{timestamp}.{METHOD}.{path}"))` —
  path only, query excluded, timestamp in ms.

## License

MIT — see [LICENSE](LICENSE).

TDQS

A3.8/5.0

Scored across 19 tools

Disambiguation5/5

Each tool has a clear, distinct purpose. For example, create_stat_report and download_stat_report are sequential steps, and get_stats and get_performance_report serve different use cases (sync vs. named reports). No overlap or ambiguity.

Naming Consistency5/5

All tools follow a consistent verb_noun snake_case pattern (create_, download_, estimate_, get_, list_). The only outlier is whoami, which is conventional for diagnostics. No mixing of styles.

Tool Count5/5

19 tools cover account overview, campaign/adgroup/keyword details, performance reports, keyword estimation, and diagnostic tools. The number feels appropriate for the apparent scope of a search advertising management API.

Completeness2/5

The tool set is heavily read-oriented with only create_stat_report for report generation. There are no tools to create, update, or delete campaigns, adgroups, or keywords, which are critical for full management. This leaves significant gaps.

Maintenance

ActivityStale
ResponsivenessNo issues