MCPcopy Create free account
hub / github.com/adcontextprotocol/adcp / handleListCreatives

Function handleListCreatives

server/src/training-agent/task-handlers.ts:2153–2238  ·  view source on GitHub ↗
(args: ToolArgs, ctx: TrainingContext)

Source from the content-addressed store, hash-verified

2151}
2152
2153export async function handleListCreatives(args: ToolArgs, ctx: TrainingContext) {
2154 const req = args as unknown as ListCreativesRequest & ToolArgs & { creative_ids?: string[]; include_pricing?: boolean; include_snapshot?: boolean };
2155 const session = await getSession(sessionKeyFromArgs(req, ctx.mode, ctx.userId, ctx.moduleId));
2156 const filterIds = req.creative_ids || req.filters?.creative_ids;
2157
2158 let creatives = Array.from(session.creatives.values());
2159 if (filterIds?.length) {
2160 creatives = creatives.filter(c => filterIds.includes(c.creativeId));
2161 } else if (creatives.length === 0) {
2162 // Empty session falls back to compliance fixtures so storyboards that
2163 // reference stable IDs (e.g., campaign_hero_video in creative_ad_server)
2164 // resolve without the SDK's controller_seeding auto-fire. Sessions that
2165 // have synced their own creatives return only those — no mixing.
2166 creatives = getComplianceCreatives();
2167 }
2168
2169 const totalMatching = creatives.length;
2170 // Schema declares max_results min=1, max=100, default=50. Honor the cap;
2171 // do not silently lift sub-1 values — those should surface as schema
2172 // violations through the SDK's request validator, not be quietly corrected.
2173 const requestedMax = req.pagination?.max_results;
2174 const maxResults = Math.min(typeof requestedMax === 'number' ? requestedMax : 50, 100);
2175 const offset = decodeCreativeCursor(req.pagination?.cursor);
2176 if (offset === null) {
2177 return {
2178 errors: [{ code: 'INVALID_REQUEST', message: 'pagination.cursor is malformed' }] as TaskError[],
2179 };
2180 }
2181 const pageEnd = Math.min(offset + maxResults, totalMatching);
2182 const pageCreatives = creatives.slice(offset, pageEnd);
2183 const hasMore = pageEnd < totalMatching;
2184
2185 // Ad-server-capable sellers (creative.has_creative_library) quote per-
2186 // creative pricing whenever an account is present, independent of the
2187 // buyer setting include_pricing. Explicit `include_pricing: false` still
2188 // suppresses — matches the spec wording while letting callers that omit
2189 // the flag (e.g., SDK request builders that drop it) still receive pricing.
2190 // Spec today says "When false or omitted, pricing is not computed"; the
2191 // emission-on-omit behaviour here is deliberate per the has_creative_library
2192 // gate in #2847 and tracks the spec-side clarification referenced there.
2193 const emitPricing = Boolean(req.account) && req.include_pricing !== false;
2194 const agentUrl = getAgentUrl();
2195
2196 return {
2197 query_summary: {
2198 total_matching: totalMatching,
2199 returned: pageCreatives.length,
2200 },
2201 pagination: {
2202 has_more: hasMore,
2203 total_count: totalMatching,
2204 // Cursor MUST be present iff has_more is true — see
2205 // static/schemas/source/core/pagination-response.json. Carrying a stale
2206 // cursor on a terminal page invites callers to follow it past the end
2207 // (caught by universal/pagination-integrity.yaml).
2208 ...(hasMore && { cursor: encodeCreativeCursor(pageEnd) }),
2209 },
2210 creatives: pageCreatives.map(c => {

Callers

nothing calls this directly

Calls 7

getSessionFunction · 0.85
sessionKeyFromArgsFunction · 0.85
getComplianceCreativesFunction · 0.85
decodeCreativeCursorFunction · 0.85
getAgentUrlFunction · 0.85
encodeCreativeCursorFunction · 0.85
getCreativePricingFunction · 0.85

Tested by

no test coverage detected