Connect MCP
Connect Claude, Claude Code, Codex, Cursor, or any MCP client to the AdGreetz Creative MCP endpoint.
AdGreetz exposes a Model Context Protocol (MCP) endpoint that lets an AI agent generate video, carousel, static, and rich media ads on your behalf.
https://app.adgreetz.com/api/mcp
The endpoint speaks streamable HTTP MCP and is stateless — every request is authenticated independently, so there's no session handshake to manage.
1. Connect with your URL (no API key needed)
This is the recommended way to connect. Point any OAuth-capable MCP client at https://app.adgreetz.com/api/mcp with no credentials — the client discovers the authorization server automatically, opens your browser to sign in, and you pick the team the connection may act on.
You can also find one-click setup instructions for each client in the app under Settings → API Keys → Connect MCP.
Claude (claude.ai / Claude Desktop)
- Open Settings → Connectors and choose Add custom connector.
- Set the URL to
https://app.adgreetz.com/api/mcpand save. - Claude opens a browser window — sign in, pick your team, and click Authorize.
Claude Code
claude mcp add --transport http adgreetz https://app.adgreetz.com/api/mcp
Then run /mcp inside Claude Code and choose Authenticate next to adgreetz to complete the browser sign-in.
Codex
Add to ~/.codex/config.toml:
[mcp_servers.adgreetz] url = "https://app.adgreetz.com/api/mcp"
Codex prompts you to authenticate the server in the browser on first use.
Cursor
Add a .cursor/mcp.json file (project or global) with:
{
"mcpServers": {
"adgreetz": {
"url": "https://app.adgreetz.com/api/mcp"
}
}
}
Cursor detects the server needs authentication and offers a Login button that opens the browser flow.
What happens when you authorize
- Sign in: Your browser opens and you log in to your AdGreetz account (including via your organization's SSO if configured).
- Team selection: Choose the team this connection may act on. The connection is bound to that team and cannot access other teams.
- Permission review: Review the requested access scopes and click Authorize. The authorization prompt expires after a couple of minutes — complete it promptly.
- Automatic attribution: Your username is recorded on every generation, and credits draw from the chosen team's balance.
- Connection management: View or revoke connections anytime under Settings → API Keys → Connected apps. Revocation takes effect immediately. If a team manager revokes your connection on your behalf, MCP access is cut off immediately (the underlying grant is deleted) — but you may still need to remove the app from your MCP client to fully clear the upstream OAuth session on your end.
- Multi-team access: One connection binds one team. To use another team, revoke this connection and connect again — you'll be re-prompted to pick a different team.
2. Connect with an API key (headless / server-to-server)
Use an API key when there's no browser available — CI/CD, server-to-server, or platform-on-platform integrations. Account keys support an optional external_actor_id for user attribution without OAuth.
Create an API key
Go to Settings → API Keys for the team account you want your agent to act on.
- Creating an account key requires the
settings.managepermission on that account. - The full secret is shown exactly once, at creation time — copy it immediately. AdGreetz only ever stores a hash of the key, never the raw secret, so it cannot be recovered later if you lose it.
- Revoking a key takes effect immediately — the next request with that key is rejected.
- Each key's row shows when it was last used, so you can spot stale or unused keys before revoking them.
See Personal access tokens below if you don't have settings.manage on the account.
Configure your client
Send the key as a bearer token:
POST https://app.adgreetz.com/api/mcp Authorization: Bearer agz_live_...
For example, in Claude Code:
claude mcp add --transport http adgreetz https://app.adgreetz.com/api/mcp --header "Authorization: Bearer <your-api-key>"
Or in Cursor's .cursor/mcp.json:
{
"mcpServers": {
"adgreetz": {
"url": "https://app.adgreetz.com/api/mcp",
"headers": {
"Authorization": "Bearer <your-api-key>"
}
}
}
}
Any MCP client that supports streamable HTTP transport with a bearer token works the same way.
3. Available tools
| Tool | Scope | Purpose |
|---|---|---|
list_brands | creative:read | List brands on the account |
get_brand | creative:read | Fetch a single brand's details |
get_credit_balance | creative:read | Check remaining credits |
create_static_ad | creative:generate | Generate a static image ad |
create_carousel_ad | creative:generate | Generate a carousel ad |
create_rich_media_ad | creative:generate | Generate a rich media (HTML5) ad |
create_video_ad | creative:generate | Generate a video ad |
get_generation_status | creative:read | Poll a generation's status |
get_generation_result | creative:read | Fetch finished assets |
list_generations | creative:read | List past generations across all four pipelines |
Typical session flow: call list_brands (or get_brand) to find or confirm a brand, optionally get_credit_balance to check you have enough credits, call one of the four create_* tools, then poll get_generation_status until the generation reaches a terminal state and call get_generation_result to fetch the assets. Use list_generations to look back over past work. All of this works the same whether you're authenticated with OAuth or an API key.
Every create_* tool takes a brand reference: pass either brand_id (from list_brands), or brand_name + website together to find-or-create a brand — never both. Each create_* call returns immediately with a generation ref and a required_credits cost; generation itself runs asynchronously, so you always follow up with get_generation_status / get_generation_result.
Retries & idempotency
All four create_* tools accept an optional idempotency_key (string, max 128 chars). Pass a unique value per logical request — if a network error or timeout leaves you unsure whether a create call went through, retry it with the same idempotency_key and you'll get the original result back instead of creating a duplicate generation. Keys are held for roughly 24 hours — do not reuse a key for a logically different request within that window, and don't rely on dedup beyond it.
If you retry with the same idempotency_key while the original call is still in flight (rather than genuinely finished), the retry gets back a REQUEST_IN_FLIGHT error instead of a result — wait a few seconds (see retry_after_seconds) and try again with the same key rather than switching to a new one.
Attributing generations to your users
If you're integrating on behalf of your own end users (e.g. a platform building on top of AdGreetz), all four create_* tools accept an optional external_actor_id (string, max 128 chars) — an opaque id you choose to identify your end user. It's never interpreted or used for authorization or credits; it's stored for attribution and echoed back verbatim on get_generation_status, get_generation_result, and list_generations payloads. You can also filter list_generations by external_actor_id to see everything generated on behalf of one of your users.
4. Polling & results
A generation moves through these statuses: queued → scraping → generating → rendering → completed (or partial / failed).
get_generation_status returns a poll_after_seconds hint while a generation is in flight:
- 15 seconds for image-based generations (static ads, carousels)
- 60 seconds for video and rich media generations
Once a generation reaches completed or partial, call get_generation_result to fetch the assets. Image and rich-media bundle URLs are signed and expire — if a URL has gone stale, call get_generation_result again to get a fresh one (video URLs are stable public URLs and don't expire).
Status and result payloads also include:
app_url— the in-app page where the creative can be viewed and edited. For carousels, whose slides are rendered in-app rather than exported as image files,app_urlis the primary deliverable.credits_used(result only) — the credits attributed to the generation in the usage log (versusrequired_credits, the estimate quoted at create time).
If a generation reaches failed, it's terminal — get_generation_result returns GENERATION_FAILED instead of assets, with no further polling hint.
5. Personal access tokens
If you don't have the settings.manage permission on a team account, you can still create your own key from the Personal access tokens section on the same Settings → API Keys page. A personal key:
- Acts on that team's account, scoped to your own permissions.
- Is visible and revocable only by you (or the account's managers) — other members can't see or manage it.
- Stops working automatically if you leave the team.
6. Error codes
| Code | Meaning | Details payload |
|---|---|---|
UNAUTHORIZED | Missing, invalid, or revoked credentials | — |
INVALID_SCOPE | The connection doesn't have the required scope for this tool | required_scope |
RATE_LIMITED | Too many requests for this connection | retry_after_seconds |
INSUFFICIENT_CREDITS | Not enough credits to run this generation | required_credits, balance |
BRAND_NOT_FOUND | The referenced brand_id doesn't exist on this account | — |
GENERATION_NOT_FOUND | The referenced generation doesn't exist on this account | — |
GENERATION_NOT_READY | Generation hasn't reached a terminal state yet | status, poll_after_seconds |
GENERATION_FAILED | Generation reached a terminal failure — no further polling | status, error_message (when available) |
VALIDATION_ERROR | Input failed validation (e.g. bad brand_id/brand_name combination) | field-specific details |
REQUEST_IN_FLIGHT | A create_* call with this idempotency_key is already running | retry_after_seconds |
INTERNAL_ERROR | Unexpected server error | correlation id for support |
Retry guidance: retry RATE_LIMITED after retry_after_seconds; retry REQUEST_IN_FLIGHT after retry_after_seconds using the same idempotency_key (not a new one); retry INTERNAL_ERROR with backoff (include the correlation id if you contact support); treat UNAUTHORIZED, INVALID_SCOPE, VALIDATION_ERROR, BRAND_NOT_FOUND, and GENERATION_FAILED as non-retryable without changing the request.
Limits
The rate limit is 60 requests per minute, per API key — not shared across keys on the same account. If you're running multiple agents or high-throughput automation against one account, mint separate keys per workload rather than sharing one.