跳到正文
MCP ThesaurusMCP Thesaurus

Build Creative Agent

社区Good78/100认领

Apache-2.0updated 7d ago

A creative agent manages the creative lifecycle: accepts assets from buyers, stores them in a library, builds serving tags, and renders previews. Unlike a generative seller (which also sells inventory), a creative agent is a standalone creative platform — it manages creatives but doesn't sell media.

源码官网文档18

Build Creative Agent 能做什么?


name: build-creative-agent description: Use when building an AdCP creative agent — an ad server, creative management platform, or any system that accepts, stores, transforms, and serves ad creatives.

Build a Creative Agent

Overview

A creative agent manages the creative lifecycle: accepts assets from buyers, stores them in a library, builds serving tags, and renders previews. Unlike a generative seller (which also sells inventory), a creative agent is a standalone creative platform — it manages creatives but doesn't sell media.

When to Use

  • User wants to build an ad server, creative management platform, or creative rendering service
  • User mentions build_creative, preview_creative, sync_creatives, or list_creatives
  • User references creative formats, VAST tags, serving tags, or creative libraries

Not this skill:

  • Selling inventory + generating creatives → skills/build-generative-seller-agent/
  • Selling inventory (no creative management) → skills/build-seller-agent/
  • Serving audience segments → skills/build-signals-agent/

Before Writing Code

Determine these things. Ask the user — don't guess.

1. What kind of creative platform?

  • Ad server (Innovid, Flashtalking, CM360) — stateful library, builds serving tags (VAST, display tags), tracks delivery
  • Creative management platform (Celtra) — format transformation, template rendering, asset management
  • Publisher creative service — accepts buyer assets, validates against publisher specs, renders previews

2. What formats?

Get specific formats the platform supports. Common ones:

  • Display: display_300x250, display_728x90, display_160x600
  • Video: video_30s, vast_30s, video_15s
  • Native: native_content (image + headline + description)
  • Rich media: html5_300x250 (interactive HTML)

Each format needs: dimensions, accepted asset types (image, video, html, text), mime types.

3. What operations?

  • Sync — accept and store creatives from buyers (always needed)
  • List — query the creative library with filtering (recommended)
  • Preview — render a visual preview of a creative (recommended)
  • Build — produce serving tags (VAST, display tags, etc.) from stored creatives (recommended)

4. Review pipeline?

What happens when a creative is synced:

  • Instant accept — creative passes validation, immediately available
  • Pending review — human or automated review before going live
  • Rejection — creative fails validation (wrong dimensions, prohibited content)

Tools and Required Response Shapes

get_adcp_capabilities — register first, empty {} schema

capabilitiesResponse({
  adcp: { major_versions: [3] },
  supported_protocols: ['creative'],
})

list_creative_formatsListCreativeFormatsRequestSchema.shape

listCreativeFormatsResponse({
  formats: [{
    format_id: { agent_url: string, id: string },  // required
    name: string,                                    // required
    description: string,
    renders: [{ width: number, height: number }],    // output dimensions
    assets: [{                                       // what the format accepts
      item_type: 'individual',
      asset_id: string,
      asset_type: 'image' | 'video' | 'html' | 'text',
      required: boolean,
      accepted_media_types: string[],                // e.g., ['image/png', 'image/jpeg']
    }],
  }],
})

sync_creativesSyncCreativesRequestSchema.shape

Store creatives in the library. Echo back creative_id and action.

syncCreativesResponse({
  creatives: [{
    creative_id: string,              // required — echo from request
    action: 'created' | 'updated',    // required (also: 'unchanged' | 'failed' | 'deleted')
  }],
})

list_creativesListCreativesRequestSchema.shape

Return creatives from the library. Support filtering by format_id.

listCreativesResponse({
  query_summary: { total_matching: number, returned: number, filters_applied: [] },
  creatives: [{
    creative_id: string,
    name: string,
    format_id: { agent_url: string, id: string },
    status: 'processing' | 'pending_review' | 'approved' | 'rejected' | 'archived',
    created_date: string,            // required — ISO timestamp
    updated_date: string,            // required — ISO timestamp
  }],
  pagination: { has_more: boolean, cursor?: string, total_count?: number },
})

The handler should check args.filters?.format_ids — if present, return only creatives matching those formats.

preview_creativePreviewCreativeSingleRequestSchema.shape

Note: PreviewCreativeRequestSchema is a union (single/batch/variant) and can't use .shape. Use PreviewCreativeSingleRequestSchema for single preview support.

Render a preview from the creative_manifest in the request. No library lookup needed — the manifest is provided. Each preview has a renders array with output_format discriminator.

previewCreativeResponse({
  response_type: 'single',
  previews: [{
    preview_id: string,
    input: { name: string },
    renders: [{
      render_id: string,
      output_format: 'url',         // discriminator: 'url' or 'html'
      preview_url: string,          // URL to rendered preview (for output_format: 'url')
      role: 'primary',
      dimensions: { width: number, height: number },
    }],
  }],
  expires_at: string,              // ISO timestamp
})

build_creativeBuildCreativeRequestSchema.shape

Produce a serving tag. The request may include target_format_id (format to build for) and/or message (brief). Look up a matching creative from the library by format, then build the output.

The handler should:

  1. Check args.target_format_id — find a synced creative matching that format
  2. Fall back to args.creative_id if provided (direct lookup)
  3. Build a serving tag from the matched creative's assets
buildCreativeResponse({
  creative_manifest: {
    format_id: { agent_url: string, id: string },
    assets: {},              // built output assets (serving tag, VAST XML, etc.)
  },
  sandbox: true,
})

Asset values use type-specific shapes, not a generic asset_type discriminator:

  • Image: { url: string, width: number, height: number, format: string }
  • Video: { url: string, duration_ms: number, format: string }
  • HTML: { content: string } (not { html: string })
  • Text: { text: string }

SDK Quick Reference

SDK piece Usage
serve(createAgent) Start HTTP server on :3001/mcp
createTaskCapableServer(name, version, { taskStore }) Create MCP server with task support
server.tool(name, Schema.shape, handler) Register tool — .shape unwraps Zod
capabilitiesResponse(data) Build get_adcp_capabilities response
listCreativeFormatsResponse(data) Build list_creative_formats response
syncCreativesResponse(data) Build sync_creatives response
listCreativesResponse(data) Build list_creatives response
previewCreativeResponse(data) Build preview_creative response
buildCreativeResponse(data) Build build_creative response
buildCreativeMultiResponse(data) Build multi-format build_creative response
taskToolResponse(data, summary) Build generic tool response (for tools without a dedicated builder)
adcpError(code, { message }) Structured error

Schemas: ListCreativeFormatsRequestSchema, SyncCreativesRequestSchema, ListCreativesRequestSchema, PreviewCreativeSingleRequestSchema, BuildCreativeRequestSchema.

Import everything from @adcp/sdk. Types from @adcp/sdk with import type.

Setup

npm init -y
npm install @adcp/sdk
npm install -D typescript @types/node

Minimal tsconfig.json:

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "Node16",
    "moduleResolution": "Node16",
    "strict": true,
    "skipLibCheck": true,
    "outDir": "dist"
  }
}

skipLibCheck: true avoids false-positive errors from transitive .d.ts files (e.g., @opentelemetry/api).

Implementation

  1. Single .ts file — all tools in one file
  2. Always register get_adcp_capabilities as the first tool with empty {} schema
  3. Use Schema.shape (not Schema) when registering tools
  4. Use an in-memory Map to store synced creatives (the creative library)
  5. Set sandbox: true on all mock/demo responses
  6. Use ServeContext pattern: function createAgent({ taskStore }: ServeContext)

The skill contains everything you need. Do not read additional docs before writing code.

Key implementation detail: creative library

Use a Map<string, Creative> to store synced creatives. Declare the Map outside the createAgent factoryserve() creates a new server per request (stateless HTTP), so state inside the factory is lost between calls.

The sync_creatives handler adds/updates entries. The list_creatives handler queries the map (include created_date and updated_date in each creative). The preview_creative handler previews the creative_manifest sent in the request (no library lookup needed). The build_creative handler finds a synced creative by target_format_id (matching the format), then builds a serving tag from it.

Validation

After writing the agent, validate it. Fix failures. Repeat.

Full validation (if you can bind ports):

npx tsx agent.ts &
npx @adcp/sdk@latest storyboard run http://localhost:3001/mcp creative_lifecycle --json

Sandbox validation (if ports are blocked):

npx tsc --noEmit agent.ts

Keep iterating until all steps pass.

Common Mistakes

Mistake Fix
Skip get_adcp_capabilities Must be the first tool registered
Pass Schema instead of Schema.shape MCP SDK needs unwrapped Zod fields
Use PreviewCreativeRequestSchema.shape It's a union — use PreviewCreativeSingleRequestSchema.shape instead
list_creatives ignores format filter Check args.filters?.format_ids and filter results
preview_creative returns wrong response_type Must be 'single' for single creative previews
preview_creative looks up by creative_id Preview the creative_manifest from the request — no library lookup needed
build_creative looks up by args.creative_id only Storyboard sends target_format_id — find a synced creative matching that format
build_creative missing creative_manifest Required field — contains the built output
creative_manifest includes name field CreativeManifest has no name — only format_id and assets
HTML asset uses { html: '...' } Use { content: '...' } — the schema field is content, not html
No in-memory store for synced creatives list_creatives and build_creative need to find previously synced creatives

Storyboards

Storyboard Tests
creative_lifecycle Full lifecycle: format discovery → sync → list → preview → build
creative_template Stateless template rendering (build + preview only)
creative_sales_agent Sales agent that accepts pushed assets
creative_ad_server Ad server with pre-loaded library

Reference

  • storyboards/creative_lifecycle.yaml — full creative lifecycle storyboard
  • docs/guides/BUILD-AN-AGENT.md — SDK patterns
  • docs/TYPE-SUMMARY.md — curated type signatures
  • docs/llms.txt — full protocol reference