Skip to content
MCP

M2M Authentication

Obtain a Teads MCP access token with OAuth2 client credentials on the public API token route.

Use M2M when the caller is a service: an in-house agent, a scheduled job, or a partner platform. There is no browser. You mint an access token on the API using the OAuth 2.0 Client Credentials grant, then send it as Authorization: Bearer on MCP.

Your agent or service
  → POST https://public-api.teads.tv/token   (client_id + client_secret)
  → access_token
  → POST https://public-api.teads.tv/mcp/v1/agency
       Authorization: Bearer <access_token>

1. Client id and secret

Teads doesn't provide a self-served way to create a client id and secret for MCP yet. You need to contact your Teads representative to create one.

2. Request an access token

Token URL:

POST https://public-api.teads.tv/token

Send application/x-www-form-urlencoded (not JSON):

FieldValue
grant_typeclient_credentials
client_idYour M2M client id
client_secretYour M2M client secret
scopemcp:agency
POST /token HTTP/1.1
Host: public-api.teads.tv
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials&client_id=CLIENT_ID&client_secret=CLIENT_SECRET&scope=mcp:agency
curl -sS -X POST 'https://public-api.teads.tv/token' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'grant_type=client_credentials' \
  -d 'client_id=CLIENT_ID' \
  -d 'client_secret=CLIENT_SECRET' \
  -d 'scope=mcp:agency'

Successful response (200):

{
  "access_token": "<jwt>",
  "expires_in": 3600,
  "token_type": "Bearer"
}

access_token is a JSON Web Token (JWT). There is no refresh_token. When expires_in elapses, repeat this POST with the same client id and secret.

Wrong credentials return 401.

3. Call MCP with the token

MCP URL:

POST https://public-api.teads.tv/mcp/v1/agency

Every MCP request (initialize, tools/list, tool call, resource read) must send:

Authorization: Bearer <access_token>
Accept: application/json, text/event-stream
Content-Type: application/json
HeaderRequiredValue
AuthorizationYesBearer plus the access_token from step 2
AcceptYesapplication/json, text/event-stream (both media types)
Content-TypeYesapplication/json

Optional if your client uses them: Mcp-Session-Id, MCP-Protocol-Version.

TOKEN='<access_token>'

curl -sS -X POST 'https://public-api.teads.tv/mcp/v1/agency' \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Accept: application/json, text/event-stream' \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

Expected: HTTP 200 and a JSON-RPC result listing tools.

4. Keep the token fresh

  1. Cache access_token and expires_in.
  2. Request a new token before expiry (same client_credentials POST).
  3. Replace Authorization on subsequent MCP calls.

MCP clients that accept headers

If the client supports custom headers on a remote Streamable HTTP server, pass the current Bearer token (refresh it as in step 4). These interactive setups are useful for local testing; production agents should mint and rotate tokens in code rather than paste them into a config file.

Pick your client:

Create .cursor/mcp.json in your project (or ~/.cursor/mcp.json globally):

{
  "mcpServers": {
    "teads-agency": {
      "url": "https://public-api.teads.tv/mcp/v1/agency",
      "headers": {
        "Authorization": "Bearer <access_token>"
      }
    }
  }
}

Or reference an environment variable:

{
  "mcpServers": {
    "teads-agency": {
      "url": "https://public-api.teads.tv/mcp/v1/agency",
      "headers": {
        "Authorization": "Bearer ${env:TEADS_MCP_TOKEN}"
      }
    }
  }
}

Replace <access_token> / refresh TEADS_MCP_TOKEN when you mint a new token. Cursor does not refresh client-credentials tokens for you.

Errors

HTTP statusTypical cause
401 on /tokenWrong client_id or client_secret
403 on /mcpMissing Authorization, expired token, scope is not mcp:agency, or the client is not enabled for Teads MCP
401 / 403 on /oauth2/token with client_credentialsWrong endpoint — use /token