# oceanengine-mcp

[![CI](https://github.com/virgoC0der/go-mcp/actions/workflows/go.yml/badge.svg)](https://github.com/virgoC0der/go-mcp/actions/workflows/go.yml)

A [Model Context Protocol](https://modelcontextprotocol.io) (MCP) server for
**Ocean Engine (巨量引擎)** — ByteDance's domestic advertising platform (巨量广告 /
巨量千川 / 本地推 / 星图). It lets AI agents query advertiser accounts, campaigns,
ads and performance reports — and, when explicitly enabled, adjust campaign
status and budget — over the standard MCP interface.

> **Why this exists.** The "general-purpose Go MCP SDK" question is settled: the
> [official `modelcontextprotocol/go-sdk`](https://github.com/modelcontextprotocol/go-sdk)
> (maintained with Google) and [`mark3labs/mcp-go`](https://github.com/mark3labs/mcp-go)
> own that space. The open niche is **vertical** MCP servers. Google Ads and Meta
> Ads already have MCP servers (and TikTok Ads has several), but **Ocean Engine —
> the domestic Chinese platform — has none.** This project fills that gap, and is
> built *on top of* the official SDK rather than reimplementing the protocol.

## Status

Early but functional. The MCP layer is fully working (verified end-to-end via the
in-memory transport and a stdio smoke test); the Ocean Engine client implements
the documented Marketing API endpoints. Hitting the live API requires a valid
`access_token` from the [Ocean Engine open platform](https://open.oceanengine.com/).

## Install

```bash
go install github.com/virgoC0der/go-mcp/cmd/oceanengine-mcp@latest
```

Or build from source:

```bash
make build   # produces ./bin/oceanengine-mcp
```

## Configuration

The server is configured via environment variables.

**Authentication** — choose one of two modes:

*Static token* (you manage refresh yourself):

| Variable | Description |
|---|---|
| `OCEANENGINE_ACCESS_TOKEN` | OAuth access token from the Ocean Engine open platform |

*Auto-refresh* (recommended — access tokens last ~1 day): supply app credentials
and a refresh token and the server refreshes transparently before expiry. Ocean
Engine **rotates the refresh token on every refresh**, so the server tracks the
latest one in memory for its lifetime.

| Variable | Required | Description |
|---|---|---|
| `OCEANENGINE_APP_ID` | yes | developer app ID (numeric) |
| `OCEANENGINE_APP_SECRET` | yes | developer app secret |
| `OCEANENGINE_REFRESH_TOKEN` | yes | OAuth refresh token (valid ~30 days) |
| `OCEANENGINE_ACCESS_TOKEN` | no | current access token, if you have a fresh one |
| `OCEANENGINE_ACCESS_TOKEN_EXPIRES_IN` | no | remaining lifetime in seconds; omit to refresh on first use |

Auto-refresh mode activates when `OCEANENGINE_APP_ID`, `OCEANENGINE_APP_SECRET`
and `OCEANENGINE_REFRESH_TOKEN` are all set; otherwise the server falls back to
the static `OCEANENGINE_ACCESS_TOKEN`.

> Persisting the rotated refresh token across restarts: when embedding the
> package, pass `oceanengine.WithOnRefresh(...)` to `NewRefreshingTokenSource` to
> receive each new token pair and store it.

**Other options:**

| Variable | Required | Description |
|---|---|---|
| `OCEANENGINE_BASE_URL` | no | API host override (defaults to `https://api.oceanengine.com`) |
| `OCEANENGINE_ENABLE_WRITES` | no | set to `1`/`true` to register the mutating tools (off by default) |

### Use with an MCP client

```json
{
  "mcpServers": {
    "oceanengine": {
      "command": "oceanengine-mcp",
      "env": { "OCEANENGINE_ACCESS_TOKEN": "your-token" }
    }
  }
}
```

## Tools

Read tools (always available):

| Tool | Ocean Engine endpoint | Purpose |
|---|---|---|
| `oceanengine_get_advertiser_info` | `GET /2/advertiser/info/` | account info by advertiser ID |
| `oceanengine_list_campaigns` | `GET /2/campaign/get/` | list campaigns (广告组), paginated |
| `oceanengine_list_ads` | `GET /2/ad/get/` | list ads (广告计划), paginated |
| `oceanengine_get_report` | `GET /2/report/ad/get/` | performance report by date range/dimensions |

Write tools (only when `OCEANENGINE_ENABLE_WRITES` is set — they mutate the live
account):

| Tool | Ocean Engine endpoint | Purpose |
|---|---|---|
| `oceanengine_update_campaign_status` | `POST /2/campaign/update/status/` | enable / disable / delete campaigns |
| `oceanengine_update_campaign_budget` | `POST /2/campaign/update/budget/` | set a campaign budget |

## Architecture

```
cmd/oceanengine-mcp     entrypoint: reads env, runs MCP over stdio
internal/mcpserver      registers tools on the official go-sdk; no protocol code
internal/oceanengine    thin Marketing API client (auth, envelope, endpoints)
```

The Ocean Engine client is deliberately thin and dependency-light. To broaden
endpoint coverage later, its methods can be backed by the much larger community
SDK [`bububa/oceanengine`](https://github.com/bububa/oceanengine) without touching
the MCP tool layer.

## Roadmap

- ~~OAuth token refresh~~ ✅ done (auto-refresh token source)
- 千川 (Qianchuan) e-commerce ad endpoints
- Broader report dimensions/metrics and async report export
- Optional `bububa/oceanengine` backend for full endpoint coverage

## Note on the repository name

This project currently lives in the `go-mcp` repository for historical reasons.
The intended home is a dedicated `oceanengine-mcp` repository — renaming the repo
(which preserves stars and history) updates the import path accordingly.

## Development

```bash
make test    # go test ./...
make vet     # go vet ./...
make build   # build the binary
```

## License

MIT — see [LICENSE](./LICENSE).
