Go SDK for the Ad Context Protocol (AdCP). Build advertising agents that sell inventory, serve audience data, manage creatives, and pass storyboard compliance validation.
go get github.com/adcontextprotocol/adcp-go/adcppackage main
import (
"context"
"log"
"time"
"github.com/adcontextprotocol/adcp-go/adcp"
"github.com/modelcontextprotocol/go-sdk/mcp"
)
func main() {
server := mcp.NewServer(&mcp.Implementation{Name: "my-agent", Version: "1.0.0"}, nil)
adcp.Register(server, adcp.Config{
IdempotencyReplayTTL: 24 * time.Hour,
Capabilities: &adcp.CapabilitiesData{
SupportedProtocols: []string{"media_buy"},
MediaBuy: &adcp.MediaBuyCapabilities{
SupportedPricingModels: []string{"cpm"},
},
},
GetProducts: func(ctx context.Context, acct any, req *adcp.GetProductsRequest) (*adcp.ProductsData, error) {
return &adcp.ProductsData{Products: []adcp.Product{}}, nil
},
})
log.Fatal(adcp.Serve(func() *mcp.Server { return server }))
}Validate with the storyboard runner:
go run main.go &
npx @adcp/client storyboard run http://localhost:3001/mcp media_buy_seller --jsonUse skill files to build complete agents with coding assistants (Claude, Codex). Each skill is self-contained — a coding agent reads one file and produces a passing agent.
| Skill | Agent type | Storyboard | Status |
|---|---|---|---|
build-seller-agent |
Publisher, SSP | media_buy_seller |
9/9 validated |
build-signals-agent |
CDP, data provider | signal_owned |
4/4 validated |
build-creative-agent |
Ad server, CMP | creative_lifecycle |
6/6 validated |
build-generative-seller-agent |
AI ad network | media_buy_generative_seller |
9/9 validated |
build-retail-media-agent |
Retail media | media_buy_catalog_creative |
9/9 validated |
adcp.AddTool(server, "get_products", "Available advertising products",
func(ctx context.Context, req *mcp.CallToolRequest, input adcp.GetProductsRequest) (*mcp.CallToolResult, any, error) {
return adcp.ProductsResponse(&adcp.ProductsData{Products: []adcp.Product{}})
})AddTool generates a JSON schema from the Go input struct while allowing additional protocol fields. Use it instead of mcp.AddTool (which rejects extra fields).
Prefer adcp.Register for seller agents when possible. It wires common tools,
fills required idempotency and capability fields, and handles AdCP 3.0/3.1
capability negotiation. See docs/adcp-version-compatibility.md
for the version compatibility contract.
| Builder | Tool |
|---|---|
adcp.CapabilitiesResponse(data) |
get_adcp_capabilities |
adcp.ProductsResponse(data) |
get_products |
adcp.MediaBuyResponse(*CreateMediaBuySuccess|*CreateMediaBuyError|*CreateMediaBuySubmitted) |
create_media_buy |
adcp.CreateMediaBuySuccessResponse(data) |
synchronous create_media_buy |
adcp.CreateMediaBuyErrorResponse(data) |
schema error branch for create_media_buy |
adcp.CreateMediaBuySubmittedResponse(taskID, message) |
async create_media_buy |
adcp.MediaBuysResponse(buys, sandbox) |
get_media_buys |
adcp.MediaBuysDataResponse(data) |
get_media_buys with pagination/errors |
adcp.DeliveryResponse(data) |
get_media_buy_delivery |
adcp.SyncAccountsResponse(accounts, sandbox) |
sync_accounts |
adcp.GovernanceResponse(accounts) |
sync_governance |
adcp.SyncCreativesResponse(creatives, sandbox) |
sync_creatives |
adcp.CreativeFormatsResponse(formats, sandbox) |
list_creative_formats |
adcp.ListCreativesResponse(items) |
list_creatives |
adcp.PreviewCreativeResponse(id, name, url, w, h) |
preview_creative |
adcp.BuildCreativeResponse(manifest, sandbox) |
build_creative |
adcp.SignalsResponse(signals, sandbox) |
get_signals |
adcp.ActivateSignalResponse(deployments, sandbox) |
activate_signal |
adcp.SyncCatalogsResponse(catalogs, sandbox) |
sync_catalogs |
adcp.SyncEventSourcesResponse(sources, sandbox) |
sync_event_sources |
adcp.LogEventResponse(received, processed, matchQuality, sandbox) |
log_event |
adcp.PerformanceFeedbackResponse(sandbox) |
provide_performance_feedback |
adcp.Errorf(code, opts) |
Error response |
| Function | Usage |
|---|---|
adcp.Serve(createAgent) |
HTTP server on :3001/mcp with timeouts |
adcp.RegisterTestController(server, store) |
Compliance test controller (sandbox only) |
adcp/types.go— Hand-written SDK types (Product, MediaBuyData, Signal, etc.)adcp/inputs.go— Typed input structs for all tool handlersadcp/types_gen.go— types generated from AdCP schemas 3.1.0-rc.3adcp/governance_types.go— hand-writtenPlanand related governance types (inline in sync_plans)adcp/plan_validate.go— client-side enforcement of the budgetoneOfand Annex IIIif/theninvariants
Media-buy seller helpers use the schema variants directly:
*CreateMediaBuySuccess, *CreateMediaBuyError, or *CreateMediaBuySubmitted
for create_media_buy, and MediaBuyData for items returned by
get_media_buys. MediaBuyData.Packages is []PackageStatus; create success
packages remain []Package.
Use adcp.Bool(true) for optional boolean updates and adcp.Float64(0) when a
creative assignment weight of zero is intentional. CreativeAssignment.Extra
preserves seller-specific assignment fields allowed by the schema.
Generated enum aliases decode unknown wire values for forward compatibility.
When handler logic needs strict current-schema validation, use the generated
helpers: KnownMediaBuyStatusValues(), IsKnownMediaBuyStatus(status), and
ParseMediaBuyStatus(raw).
For typed structs whose schema-required fields cannot be represented by Go's
zero values, use the SDK validators before request submission or handler-side
acceptance. Validation is opt-in and intentionally narrower than full JSON
Schema validation: it catches required fields and schema invariants the Go type
cannot express, but keeps unknown enum and oneOf variant values
forward-compatible unless adcp.WithStrictEnums() is supplied.
Flattened oneOf types are validated by active branch: event-only fields such as
attribution_window are checked on event goals and ignored on metric goals.
For value-based event targets such as per_ad_spend and maximize_value, the
validator also requires at least one event source value_field; that is an SDK
invariant derived from the schema descriptions, not a general-purpose JSON
Schema validation pass.
goal := adcp.OptimizationGoal{
Kind: "event",
Target: adcp.OptimizationGoalCostPerTarget{Value: 10},
EventSources: []adcp.OptimizationGoalEventSource{{
EventSourceID: "pixel-1",
EventType: "purchase",
}},
}
if issues := goal.Validate(); len(issues) > 0 {
// Map issue.Code and issue.Field to your request error handling.
}adcp/signing implements the AdCP RFC 9421 request-signing profile — optional in 3.0, required for spend-committing operations in 4.0. The package is self-validating against the spec's conformance vectors: all 8 positive + 20 negative vectors pass, and signed Ed25519 signatures match the committed positive-vector bytes.
As an agent that signs requests:
import "github.com/adcontextprotocol/adcp-go/adcp/signing"
pemBytes, _ := os.ReadFile("signing.pem")
priv, _, _ := signing.LoadPrivateKey(pemBytes)
signer, _ := signing.NewSigner(signing.SignerOptions{
KeyID: "buyer-ed25519-2026",
PrivateKey: priv,
})
client := &http.Client{Transport: signer.RoundTripper(nil, true /* cover content-digest */)}
resp, err := client.Post("https://seller.example.com/adcp/create_media_buy", "application/json", body)As a verifier (seller):
mw := signing.Middleware(signing.MiddlewareOptions{
Resolver: signing.NewHTTPJWKSResolver(agents), // SSRF-safe fetcher
Replay: signing.NewMemoryReplayStore(0),
Revocation: signing.NewStaticRevocationList(nil),
OperationResolver: signing.DefaultOperationResolver, // /adcp/<op>
RequiredFor: []string{"create_media_buy"},
ContentDigestPolicy: signing.DigestRequired,
})
http.ListenAndServe(":8080", mw(yourHandler))Generate a signing keypair:
go run github.com/adcontextprotocol/adcp-go/adcp/cmd/adcp-signing-keygen -alg ed25519 -kid my-agent-2026 -out signing.pemEmits a PEM-encoded private key plus the public JWK (with adcp_use: "request-signing") ready to paste into your agent's JWKS document at jwks_uri.
| Package | Description |
|---|---|
adcp/ |
MCP server helpers — AddTool, response builders, test controller, Serve() |
adcp/signing/ |
RFC 9421 request signing — signer, verifier, middleware, conformance tests |
skills/ |
SKILL.md files for coding agent generation |
tmproto/ |
TMP message types, provider interfaces, JSON codec |
targeting/ |
Targeting engine — property bitmaps, freq caps, audiences, intent |
router/ |
TMP Router — fan-out, merge, privacy enforcement, Ed25519 signing |
registry/ |
AgenticAdvertising.org registry sync client |
tmpclient/ |
Publisher-side TMP client library |
Benchmarked on Apple M4 Pro:
| Operation | ns/op | QPS (single core) |
|---|---|---|
| Full TMP pipeline | 960 ns | 1.04M |
| OpenRTB equivalent | 2,340 ns | 427K |
TMP is 1.8x faster than OpenRTB with 37% smaller payloads.
| Document | Description |
|---|---|
AGENTS.md |
Agent guidelines — hardening, architecture, key files |
docs/network-surface.md |
Port map, data flow, TEE pinhole spec |
docs/embedding.md |
Embedding the router in host systems (e.g., Prebid Server) |
Contributions welcome! All contributors must agree to the AgenticAdvertising.Org IPR Policy — the bot prompts new contributors on their first PR and a single signature covers all AAO repositories.
Apache 2.0