@channel47/tiktok-ads-mcp
v0.1.0
Published
TikTok Ads MCP Server - Query and mutate TikTok for Business ads data via the Business API
Maintainers
Readme
@channel47/tiktok-ads-mcp
MCP server for TikTok Ads using the TikTok for Business API (v1.3).
This server exposes four tools expected by channel47 TikTok workflows:
list_accountsqueryreportmutate
Installation
Standalone
npx @channel47/tiktok-ads-mcp@latestClaude Code
claude mcp add tiktok-ads --env TIKTOK_ADS_ACCESS_TOKEN=<token> -- npx @channel47/tiktok-ads-mcp@latestOr as JSON config:
{
"mcpServers": {
"tiktok-ads": {
"command": "npx",
"args": ["@channel47/tiktok-ads-mcp@latest"],
"env": {
"TIKTOK_ADS_ACCESS_TOKEN": "<token>",
"TIKTOK_ADS_ADVERTISER_ID": "<advertiser id>"
}
}
}
}Monorepo Development
cd mcps
npm install
npm run testGetting Credentials
- Create a developer app at TikTok for Business Developers (Marketing API).
- Authorize the app against your advertiser account(s) via the app's authorization URL.
- Exchange the returned
auth_codefor a long-lived access token atPOST /open_api/v1.3/oauth2/access_token/. - Use that token as
TIKTOK_ADS_ACCESS_TOKEN. The token is sent as theAccess-Tokenrequest header (notAuthorization: Bearer).
Configuration
Required
| Variable | Description |
|----------|-------------|
| TIKTOK_ADS_ACCESS_TOKEN | TikTok Business API long-lived access token |
Optional
| Variable | Description |
|----------|-------------|
| TIKTOK_ADS_ADVERTISER_ID | Default advertiser ID used when advertiser_id is omitted |
| TIKTOK_ADS_APP_ID | Developer app ID — only needed so list_accounts can discover authorized advertisers via /oauth2/advertiser/get/ |
| TIKTOK_ADS_APP_SECRET | Developer app secret (pairs with TIKTOK_ADS_APP_ID) |
| TIKTOK_ADS_READ_ONLY | Set to true to disable live mutations |
| TIKTOK_ADS_REQUEST_TIMEOUT_MS | HTTP request timeout in milliseconds (default 30000) |
Tool Reference
list_accounts
List accessible TikTok ad accounts (advertisers).
Params:
advertiser_ids(optional): explicit advertiser ids to look up
Notes:
- With
TIKTOK_ADS_APP_ID+TIKTOK_ADS_APP_SECRETset, ids are discovered viaGET /oauth2/advertiser/get/ - Without app credentials, pass
advertiser_idsor setTIKTOK_ADS_ADVERTISER_ID - Details (name, status, currency, timezone, company, country) come from
GET /advertiser/info/(batched 100 ids per request)
query
Structured query wrapper for TikTok Business API entities:
campaigns—GET /campaign/get/adgroups—GET /adgroup/get/ads—GET /ad/get/
Params:
entity(required)advertiser_id(optional ifTIKTOK_ADS_ADVERTISER_IDexists)fields: array or comma-separated string (entity-specific defaults)filtering: TikTok filtering object, e.g.{ "campaign_ids": ["123"], "primary_status": "STATUS_DELIVERY_OK" }limit: max rows (default100, max1000); pagination viapage/page_sizeis handled automatically
report
Synchronous integrated reporting via GET /report/integrated/get/.
Params:
advertiser_id(optional ifTIKTOK_ADS_ADVERTISER_IDexists)report_type:BASIC(default) orAUDIENCEdata_level:AUCTION_ADVERTISER,AUCTION_CAMPAIGN(default),AUCTION_ADGROUP,AUCTION_ADdimensions: defaults to the data_level id dimension plusstat_time_daymetrics: defaults tospend, impressions, clicks, ctr, cpc, cpm, conversion, cost_per_conversion, conversion_ratestart_date/end_date(YYYY-MM-DD, default trailing 7 days UTC) orlifetime: truefiltering: array of{ field_name, filter_type, filter_value }clausesorder_field/order_type(ASC/DESC)limit: max rows (default100, max1000)
Rows are returned with dimensions and metrics flattened into a single object per row.
mutate
Mutation tool with dry-run safety by default.
Operation format:
{
"entity": "campaign",
"action": "update",
"id": "1781234567890",
"params": {
"budget": 500
}
}Supported entities: campaign, adgroup, ad
Supported actions:
create—POST /<entity>/create/; campaign and adgroup creates defaultoperation_statustoDISABLE(paused) — pass explicitoperation_statusto overrideupdate—POST /<entity>/update/;idmaps tocampaign_id/adgroup_id. Ad updates take the full/ad/update/body inparams(ads are identified viacreatives[].ad_id), soidis optionalpause/enable/delete—POST /<entity>/status/update/withoperation_statusDISABLE/ENABLE/DELETE
Top-level params:
operations(required)advertiser_id(optional ifTIKTOK_ADS_ADVERTISER_IDexists)dry_run(defaulttrue)partial_failure(defaulttrue)
Safety notes:
- TikTok has no server-side validate-only mode.
dry_run: truevalidates operations locally and returns a preview of the exact requests (method, path, body) without calling the API. deleteis permanent and unrecoverable — preferpause.- Set
TIKTOK_ADS_READ_ONLY=trueto remove the mutate tool entirely.
Behavior Notes
- Auth is sent via the
Access-Tokenrequest header - TikTok returns HTTP
200with an envelope{ code, message, request_id, data }; any non-zerocodeis surfaced as an error including the API code and message - Complex GET params (
fields,filtering,dimensions,metrics,advertiser_ids) are JSON-encoded into the query string automatically - API retries once on HTTP
429or envelope error code40100(rate limit), honoringRetry-Afterwhen present (fallback60s) - Requests are aborted on timeout (default
30000ms, configurable viaTIKTOK_ADS_REQUEST_TIMEOUT_MS) - List endpoints paginate with
page/page_size(data.page_info.total_page)
Development Commands
cd tiktok-ads
npm test
node server/index.jsLicense
MIT
