Metadata-Version: 2.4
Name: flin-gmp-mcp
Version: 0.1.3
Summary: Google Marketing Platform MCP: campaign reads, DV360 reports, CM360 and SA360.
Project-URL: Homepage, https://github.com/flin-agency/flin-gmp-mcp
Project-URL: Repository, https://github.com/flin-agency/flin-gmp-mcp
Project-URL: Issues, https://github.com/flin-agency/flin-gmp-mcp/issues
Author-email: flin GmbH <flin@flin.agency>
License-Expression: MIT
License-File: LICENSE
Keywords: cm360,dv360,google-marketing-platform,mcp,sa360
Requires-Python: >=3.10
Requires-Dist: google-auth-oauthlib<2,>=1.5.0
Requires-Dist: google-auth<3,>=2.40.0
Requires-Dist: mcp<2,>=1.6.0
Requires-Dist: requests<3,>=2.32.3
Provides-Extra: dev
Requires-Dist: build>=1.2.2; extra == 'dev'
Requires-Dist: jsonschema<5,>=4.23; extra == 'dev'
Requires-Dist: pytest-asyncio<2,>=0.24; extra == 'dev'
Requires-Dist: pytest<9,>=8; extra == 'dev'
Requires-Dist: ruff<1,>=0.11; extra == 'dev'
Requires-Dist: tomli>=2; (python_version < '3.11') and extra == 'dev'
Requires-Dist: twine<7,>=6; extra == 'dev'
Description-Content-Type: text/markdown

# flin-gmp-mcp

MCP server for **Google Marketing Platform** with campaign read access and DV360 report creation, built like the other
[flin MCPs](https://github.com/flin-agency): Python, FastMCP, `uv`, browser OAuth,
private local tokens, and stdio transport.

## Supported products

| Product | Tools and data | API |
| --- | --- | --- |
| GMP Admin | Organizations and linked Analytics accounts | v1alpha |
| Display & Video 360 | Partners, advertisers, campaigns, insertion orders, line items, creatives | v4 |
| DV360 reporting | Create report queries, start runs, read status and CSV values | Bid Manager v2 |
| Campaign Manager 360 | User profiles, advertisers, campaigns, creatives with sizes/assets, saved reports and existing file metadata/URLs | v5 |
| Search Ads 360 | Customer discovery, manager hierarchy, campaign performance, custom SELECT queries and field discovery | Reporting v0 |

GA4 reporting belongs in the separate `flin-ga4-mcp`. Google Ads, Search Console
and Google Tag Manager are outside this package's scope. GMP account links are
**Analytics account links**, not a universal cross-product account directory.

No campaign mutations, account linking or arbitrary HTTP requests are exposed.
DV360 reports can be created and run, and completed CSV results can be read.
CM360 reports still return existing metadata and URLs only. SA360 returns performance rows directly.
DV360 uses v4; v5 was still labelled beta in Google's documentation when this
implementation was verified on 2026-10-30.

## Quickstart from this repository

Requires Python 3.10+ and [uv](https://docs.astral.sh/uv/).

```bash
uv sync --locked --extra dev
```

Create a Google Cloud project and enable the APIs you will use:

- Google Marketing Platform Admin API (`marketingplatformadmin.googleapis.com`)
- Display & Video 360 API (`displayvideo.googleapis.com`)
- DoubleClick Bid Manager API (`doubleclickbidmanager.googleapis.com`)
- Campaign Manager 360 API (`dfareporting.googleapis.com`)
- Search Ads 360 Reporting API (`searchads360.googleapis.com`)

Configure the Google OAuth consent screen, add your account as a test user if
using Testing mode, and create an OAuth client of type **Desktop app**. The Google
account must already have access to the relevant products. OAuth consent alone
does not grant product access. CM360 also requires an API-enabled user profile.

Add this configuration to a stdio MCP client such as Claude Desktop, replacing
the checkout path and OAuth values:

```json
{
  "mcpServers": {
    "flin-gmp-mcp": {
      "command": "uv",
      "args": [
        "run", "--directory", "/absolute/path/to/flin-gmp-mcp",
        "--locked", "flin-gmp-mcp"
      ],
      "env": {
        "GOOGLE_CLIENT_ID": "your-desktop-client-id",
        "GOOGLE_CLIENT_SECRET": "your-desktop-client-secret"
      }
    }
  }
}
```

Restart your MCP client. Then ask it to:

1. Run `health_check`.
2. Run `authenticate`, finish Google sign-in in the browser, and grant the requested permissions.
3. Discover IDs using `list_organizations`, `list_dv360_partners`,
   `list_cm360_profiles`, or `list_sa360_customers`.
4. Use those IDs in the corresponding data tools.

`authenticate` waits up to 180 seconds; configure a longer tool timeout in your
client if necessary. It requires a browser on the computer running the server.
Data tools never launch a browser; they return `oauth_required` when sign-in is
needed. Access tokens refresh automatically. Use `authenticate(force=true)` to
replace a stale login or switch the selected account. No secrets are returned.

## Install from PyPI

```bash
uvx flin-gmp-mcp@0.1.3
```

In an MCP client, use `command: "uvx"` with `args: ["flin-gmp-mcp@0.1.3"]`
and the same Google environment variables shown above.

## macOS desktop installation

Download `flin-gmp-mcp-0.1.3.mcpb` from the
[v0.1.3 release](https://github.com/flin-agency/flin-gmp-mcp/releases/tag/v0.1.3)
and import it into Claude Desktop. The package includes the server and locked
dependency definitions; the first launch needs internet access. Enter your own
Google OAuth credentials in the extension settings.

See [macOS instructions](docs/desktop-extension.md), [privacy](PRIVACY.md) and
[support](SUPPORT.md). The bundle is unsigned and accompanied by a SHA-256 checksum.

## Configuration

| Variable | Required | Meaning |
| --- | --- | --- |
| `GOOGLE_CLIENT_ID` | Yes | Desktop OAuth client ID, same convention as flin Search Console |
| `GOOGLE_CLIENT_SECRET` | Yes | Desktop OAuth client secret |
| `GOOGLE_GMP_SERVICES` | No | Comma-separated subset of `admin,dv360,cm360,sa360`; defaults to all |
| `GOOGLE_GMP_TOKEN_DIR` | No | Absolute path to a dedicated private token directory |
| `GOOGLE_GMP_OAUTH_PORT` | No | Loopback port; `0` chooses an available port |
| `GOOGLE_GMP_QUOTA_PROJECT` | No | Optional quota project ID, sent as `x-goog-user-project` |

Environment variables are read from the process. `.env.example` is a reference;
`.env` files are **not automatically loaded**.

Only enabled products' scopes are requested. Disabled products return a
configuration error. After adding a product, run `authenticate` again to grant its
scopes. A token created by a different OAuth client is rejected.

### Multiple accounts and token storage

Pass `account="work"` to `authenticate` and subsequent calls to use a separate
Google login. Aliases use lower-case letters, digits, `_` and `-`, start with a
letter or digit, and have at most 64 characters. Omit `account` for the default
login; the name `default` is reserved.

Default directories:

- macOS: `~/Library/Application Support/flin-gmp-mcp/`
- Linux: `$XDG_CONFIG_HOME/flin-gmp-mcp/` or `~/.config/flin-gmp-mcp/`
- Windows: `%APPDATA%\flin-gmp-mcp\`

The default token is `default.json`; named accounts use `<account>.json`. Writes
are atomic and files use mode `0600` on POSIX. New directories use `0700`. Existing
directories must be owned by the user and not writable by others. Never commit
these files. To disconnect locally, stop the server and delete the corresponding
token file; revoke the app in your Google account to invalidate its access.

## OAuth scopes and campaign protection

| Product | Scope suffixes under `https://www.googleapis.com/auth/` |
| --- | --- |
| GMP Admin | `marketingplatformadmin.analytics.read` |
| DV360 | `display-video`, `doubleclickbidmanager` |
| CM360 | `dfatrafficking`, `dfareporting` |
| SA360 | `doubleclicksearch` |

Google's 360 APIs require scopes that can also permit writes. The MCP enforces
a fixed endpoint/method allowlist: GET requests, SA360 reporting/field-search POSTs,
and Bid Manager POSTs only to create queries and run reports. Campaigns, budgets,
bids, targeting, creatives and account links cannot be changed. Report creation
and execution are marked as non-read-only, non-idempotent tools; they create saved
Google report resources. No delete or update endpoints are exposed.

## Results and pagination

Data tools return `{ "ok": true, "service": "...", "account": "...", "data": {...} }`.
`data` preserves Google's native response, including field masks, currencies,
report statuses and `nextPageToken`. The list key varies by API (`organizations`,
`advertisers`, `items`, `results`, etc.). Empty responses are valid.

Each list/search call returns **one page**. If `data.nextPageToken` is present,
pass it as `page_token` with all other arguments unchanged. Do not report the
first page as the full account total. Limits: DV360 200, Bid Manager 100,
GMP Admin 1000, CM360 1000 (local cap), SA360 data search 10000. Responses over
10 MiB are rejected; reduce the page size or selected fields. Requests have a
10-second connection and 60-second read timeout, with no automatic quota retries.
Google requests and browser sign-in run in worker threads so a slow call does not
block the MCP event loop or unrelated tool calls. Cancelling a tool does not stop
an already running HTTP request; its transport timeout still applies.

SA360 IDs are bare digits without hyphens. `login_customer_id` selects the manager
through which access is granted. `list_sa360_customers` lists directly accessible
customers only; `get_sa360_customer_clients` discovers manager children.
`get_sa360_campaign_performance` uses inclusive account-timezone dates and returns
`costMicros` in millionths of `customer.currencyCode`.

## Development

```bash
uv sync --locked --extra dev
uv run ruff check .
uv run pytest
uv build
```

Tests use mocked Google responses, including transport/authentication failures,
request contracts and a real local MCP stdio handshake. No Google credentials
are required. Live product access must be verified separately with your account.

- [Tool reference and examples](docs/mcp-usage-guide.md)
- [Testing and live verification](docs/testing.md)
- [Release checklist](docs/release.md)

## References

Implementation conventions follow
[flin Search Console](https://github.com/flin-agency/flin-google-search-console-mcp)
and [flin Google Ads](https://github.com/flin-agency/flin-google-ads-mcp).

Verified against Google's REST references and live discovery documents:

- [GMP Admin API](https://developers.google.com/marketing-platform/devguides/api/admin/v1/rest)
- [DV360 v4](https://developers.google.com/display-video/api/reference/rest/v4/advertisers/list)
- [Bid Manager v2](https://developers.google.com/bid-manager/reference/rest/v2/queries.reports/list)
- [CM360 v5](https://developers.google.com/doubleclick-advertisers/rest/v5)
- [SA360 Reporting v0](https://developers.google.com/search-ads/reporting/api/reference/rest)
- [Desktop OAuth](https://developers.google.com/identity/protocols/oauth2/native-app)

MIT © flin GmbH.

### Desktop auto-updates

From bundle 0.1.2, the desktop launcher loads the latest stable 0.x server from PyPI
at each connector start. Install that bundle once, then restart the connector to
pick up future server releases. Cached and bundled fallbacks handle update failures.
`health_check.version` shows the running server version. See
[desktop update details](docs/desktop-extension.md#automatic-server-updates-from-012).

### DV360 performance without a manually prepared report

1. Discover the advertiser ID, then reuse a matching `list_dv360_report_queries` result
   or call `create_dv360_report_query(title, advertiser_id)`.
2. Call `run_dv360_report(query_id)`. It starts asynchronously and returns the report key.
3. Check `get_dv360_report(query_id, report_id)` with pauses until `DONE` or `FAILED`.
4. Read `read_dv360_report_rows(query_id, report_id)` and follow `next_row_offset`.

New definitions default to STANDARD CSV reports for yesterday in the advertiser's
timezone, with impressions and clicks by date and advertiser. Custom metrics and
dimensions use Bid Manager `METRIC_*` and `FILTER_*` names; Google checks their
compatibility. Supply both `start_date` and `end_date` for an explicit date range.
Creation saves a query but does not run it. There is no automatic daily schedule,
email notification or sharing on newly created queries. Running an existing query
honors its existing notification settings. Reuse saved definitions for later days.

CSV downloads are capped at 10 MiB and 1000 records per returned page. Values stay
strings to preserve precision; output includes headers, totals and footer records.
Use column labels for units and currencies and never add totals to detail rows.
Downloads only use HTTPS Google Storage URLs obtained from authenticated report
metadata, without forwarding Google OAuth credentials or following redirects.
After an uncertain create/run outcome, list queries/runs before retrying to avoid
duplicates. A completed report may still reflect Google's data processing delay.

DV360 report creation and CSV reading require server version 0.1.3 or newer.
