adcp 2.7.0__py3-none-any.whl → 2.9.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- adcp/__init__.py +7 -4
- adcp/__main__.py +31 -3
- adcp/client.py +200 -0
- adcp/protocols/a2a.py +12 -0
- adcp/protocols/base.py +15 -0
- adcp/protocols/mcp.py +12 -0
- adcp/types/__init__.py +461 -31
- adcp/types/_generated.py +37 -38
- adcp/types/aliases.py +251 -46
- adcp/types/generated_poc/activate_signal_request.py +3 -3
- adcp/types/generated_poc/activate_signal_response.py +2 -2
- adcp/types/generated_poc/asset_content_type.py +23 -0
- adcp/types/generated_poc/brand_manifest.py +8 -8
- adcp/types/generated_poc/create_media_buy_response.py +16 -21
- adcp/types/generated_poc/deployment.py +6 -6
- adcp/types/generated_poc/destination.py +4 -4
- adcp/types/generated_poc/format.py +5 -30
- adcp/types/generated_poc/format_category.py +17 -0
- adcp/types/generated_poc/get_signals_request.py +4 -4
- adcp/types/generated_poc/get_signals_response.py +2 -2
- adcp/types/generated_poc/list_creative_formats_request.py +4 -22
- adcp/types/generated_poc/update_media_buy_response.py +15 -22
- adcp/types/stable.py +268 -7
- {adcp-2.7.0.dist-info → adcp-2.9.0.dist-info}/METADATA +172 -1
- {adcp-2.7.0.dist-info → adcp-2.9.0.dist-info}/RECORD +29 -28
- adcp/types/generated_poc/asset_type.py +0 -100
- {adcp-2.7.0.dist-info → adcp-2.9.0.dist-info}/WHEEL +0 -0
- {adcp-2.7.0.dist-info → adcp-2.9.0.dist-info}/entry_points.txt +0 -0
- {adcp-2.7.0.dist-info → adcp-2.9.0.dist-info}/licenses/LICENSE +0 -0
- {adcp-2.7.0.dist-info → adcp-2.9.0.dist-info}/top_level.txt +0 -0
adcp/__init__.py
CHANGED
|
@@ -65,7 +65,6 @@ from adcp.types.aliases import (
|
|
|
65
65
|
BothPreviewRender,
|
|
66
66
|
BuildCreativeErrorResponse,
|
|
67
67
|
BuildCreativeSuccessResponse,
|
|
68
|
-
CreatedPackageReference,
|
|
69
68
|
CreateMediaBuyErrorResponse,
|
|
70
69
|
CreateMediaBuySuccessResponse,
|
|
71
70
|
HtmlPreviewRender,
|
|
@@ -109,6 +108,8 @@ from adcp.types.stable import (
|
|
|
109
108
|
# Audience & Targeting
|
|
110
109
|
ActivateSignalRequest,
|
|
111
110
|
ActivateSignalResponse,
|
|
111
|
+
# Type enums from PR #222
|
|
112
|
+
AssetContentType,
|
|
112
113
|
# Core domain types
|
|
113
114
|
BrandManifest,
|
|
114
115
|
# Creative Operations
|
|
@@ -132,6 +133,7 @@ from adcp.types.stable import (
|
|
|
132
133
|
Error,
|
|
133
134
|
FlatRatePricingOption,
|
|
134
135
|
Format,
|
|
136
|
+
FormatCategory,
|
|
135
137
|
FormatId,
|
|
136
138
|
GetMediaBuyDeliveryRequest,
|
|
137
139
|
GetMediaBuyDeliveryResponse,
|
|
@@ -177,7 +179,7 @@ from adcp.validation import (
|
|
|
177
179
|
validate_publisher_properties_item,
|
|
178
180
|
)
|
|
179
181
|
|
|
180
|
-
__version__ = "2.
|
|
182
|
+
__version__ = "2.9.0"
|
|
181
183
|
|
|
182
184
|
__all__ = [
|
|
183
185
|
# Client classes
|
|
@@ -219,6 +221,9 @@ __all__ = [
|
|
|
219
221
|
"Error",
|
|
220
222
|
"Format",
|
|
221
223
|
"FormatId",
|
|
224
|
+
# New type enums from PR #222
|
|
225
|
+
"AssetContentType",
|
|
226
|
+
"FormatCategory",
|
|
222
227
|
"Product",
|
|
223
228
|
"Property",
|
|
224
229
|
# Core domain types (from stable API)
|
|
@@ -228,8 +233,6 @@ __all__ = [
|
|
|
228
233
|
"MediaBuy",
|
|
229
234
|
"Package",
|
|
230
235
|
"PackageRequest",
|
|
231
|
-
# Package type aliases
|
|
232
|
-
"CreatedPackageReference",
|
|
233
236
|
# Status enums (for control flow)
|
|
234
237
|
"CreativeStatus",
|
|
235
238
|
"MediaBuyStatus",
|
adcp/__main__.py
CHANGED
|
@@ -83,11 +83,17 @@ async def execute_tool(
|
|
|
83
83
|
|
|
84
84
|
# Tool dispatch mapping - single source of truth for ADCP methods
|
|
85
85
|
# Types are filled at runtime to avoid circular imports
|
|
86
|
+
# Special case: list_tools takes no parameters (None means no request type)
|
|
86
87
|
TOOL_DISPATCH: dict[str, tuple[str, type | None]] = {
|
|
88
|
+
"list_tools": ("list_tools", None), # Protocol introspection - no request type
|
|
87
89
|
"get_products": ("get_products", None),
|
|
88
90
|
"list_creative_formats": ("list_creative_formats", None),
|
|
91
|
+
"preview_creative": ("preview_creative", None),
|
|
92
|
+
"build_creative": ("build_creative", None),
|
|
89
93
|
"sync_creatives": ("sync_creatives", None),
|
|
90
94
|
"list_creatives": ("list_creatives", None),
|
|
95
|
+
"create_media_buy": ("create_media_buy", None),
|
|
96
|
+
"update_media_buy": ("update_media_buy", None),
|
|
91
97
|
"get_media_buy_delivery": ("get_media_buy_delivery", None),
|
|
92
98
|
"list_authorized_properties": ("list_authorized_properties", None),
|
|
93
99
|
"get_signals": ("get_signals", None),
|
|
@@ -122,8 +128,12 @@ async def _dispatch_tool(client: ADCPClient, tool_name: str, payload: dict[str,
|
|
|
122
128
|
"list_creative_formats",
|
|
123
129
|
gen.ListCreativeFormatsRequest,
|
|
124
130
|
)
|
|
131
|
+
TOOL_DISPATCH["preview_creative"] = ("preview_creative", gen.PreviewCreativeRequest)
|
|
132
|
+
TOOL_DISPATCH["build_creative"] = ("build_creative", gen.BuildCreativeRequest)
|
|
125
133
|
TOOL_DISPATCH["sync_creatives"] = ("sync_creatives", gen.SyncCreativesRequest)
|
|
126
134
|
TOOL_DISPATCH["list_creatives"] = ("list_creatives", gen.ListCreativesRequest)
|
|
135
|
+
TOOL_DISPATCH["create_media_buy"] = ("create_media_buy", gen.CreateMediaBuyRequest)
|
|
136
|
+
TOOL_DISPATCH["update_media_buy"] = ("update_media_buy", gen.UpdateMediaBuyRequest)
|
|
127
137
|
TOOL_DISPATCH["get_media_buy_delivery"] = (
|
|
128
138
|
"get_media_buy_delivery",
|
|
129
139
|
gen.GetMediaBuyDeliveryRequest,
|
|
@@ -144,21 +154,38 @@ async def _dispatch_tool(client: ADCPClient, tool_name: str, payload: dict[str,
|
|
|
144
154
|
available = ", ".join(sorted(TOOL_DISPATCH.keys()))
|
|
145
155
|
return TaskResult(
|
|
146
156
|
status=TaskStatus.FAILED,
|
|
157
|
+
success=False,
|
|
147
158
|
error=f"Unknown tool: {tool_name}. Available tools: {available}",
|
|
148
159
|
)
|
|
149
160
|
|
|
150
161
|
# Get method and request type
|
|
151
162
|
method_name, request_type = TOOL_DISPATCH[tool_name]
|
|
163
|
+
method = getattr(client, method_name)
|
|
152
164
|
|
|
153
|
-
#
|
|
165
|
+
# Special case: list_tools takes no parameters and returns list[str], not TaskResult
|
|
166
|
+
if tool_name == "list_tools":
|
|
167
|
+
try:
|
|
168
|
+
tools = await method()
|
|
169
|
+
return TaskResult(
|
|
170
|
+
status=TaskStatus.COMPLETED,
|
|
171
|
+
data={"tools": tools},
|
|
172
|
+
success=True,
|
|
173
|
+
)
|
|
174
|
+
except Exception as e:
|
|
175
|
+
return TaskResult(
|
|
176
|
+
status=TaskStatus.FAILED,
|
|
177
|
+
success=False,
|
|
178
|
+
error=f"Failed to list tools: {e}",
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
# Type guard - request_type should be initialized by this point for non-list_tools
|
|
154
182
|
if request_type is None:
|
|
155
183
|
return TaskResult(
|
|
156
184
|
status=TaskStatus.FAILED,
|
|
185
|
+
success=False,
|
|
157
186
|
error=f"Internal error: {tool_name} request type not initialized",
|
|
158
187
|
)
|
|
159
188
|
|
|
160
|
-
method = getattr(client, method_name)
|
|
161
|
-
|
|
162
189
|
# Validate and invoke
|
|
163
190
|
try:
|
|
164
191
|
request = request_type(**payload)
|
|
@@ -173,6 +200,7 @@ async def _dispatch_tool(client: ADCPClient, tool_name: str, payload: dict[str,
|
|
|
173
200
|
|
|
174
201
|
return TaskResult(
|
|
175
202
|
status=TaskStatus.FAILED,
|
|
203
|
+
success=False,
|
|
176
204
|
error=f"Invalid request payload for {tool_name}:\n" + "\n".join(error_details),
|
|
177
205
|
)
|
|
178
206
|
|
adcp/client.py
CHANGED
|
@@ -28,6 +28,10 @@ from adcp.types.core import (
|
|
|
28
28
|
from adcp.types.stable import (
|
|
29
29
|
ActivateSignalRequest,
|
|
30
30
|
ActivateSignalResponse,
|
|
31
|
+
BuildCreativeRequest,
|
|
32
|
+
BuildCreativeResponse,
|
|
33
|
+
CreateMediaBuyRequest,
|
|
34
|
+
CreateMediaBuyResponse,
|
|
31
35
|
GetMediaBuyDeliveryRequest,
|
|
32
36
|
GetMediaBuyDeliveryResponse,
|
|
33
37
|
GetProductsRequest,
|
|
@@ -46,6 +50,8 @@ from adcp.types.stable import (
|
|
|
46
50
|
ProvidePerformanceFeedbackResponse,
|
|
47
51
|
SyncCreativesRequest,
|
|
48
52
|
SyncCreativesResponse,
|
|
53
|
+
UpdateMediaBuyRequest,
|
|
54
|
+
UpdateMediaBuyResponse,
|
|
49
55
|
WebhookPayload,
|
|
50
56
|
)
|
|
51
57
|
from adcp.types.stable import (
|
|
@@ -574,6 +580,200 @@ class ADCPClient:
|
|
|
574
580
|
|
|
575
581
|
return self.adapter._parse_response(raw_result, ProvidePerformanceFeedbackResponse)
|
|
576
582
|
|
|
583
|
+
async def create_media_buy(
|
|
584
|
+
self,
|
|
585
|
+
request: CreateMediaBuyRequest,
|
|
586
|
+
) -> TaskResult[CreateMediaBuyResponse]:
|
|
587
|
+
"""
|
|
588
|
+
Create a new media buy reservation.
|
|
589
|
+
|
|
590
|
+
Requests the agent to reserve inventory for a campaign. The agent returns a
|
|
591
|
+
media_buy_id that tracks this reservation and can be used for updates.
|
|
592
|
+
|
|
593
|
+
Args:
|
|
594
|
+
request: Media buy creation parameters including:
|
|
595
|
+
- brand_manifest: Advertiser brand information and creative assets
|
|
596
|
+
- packages: List of package requests specifying desired inventory
|
|
597
|
+
- publisher_properties: Target properties for ad placement
|
|
598
|
+
- budget: Optional budget constraints
|
|
599
|
+
- start_date/end_date: Campaign flight dates
|
|
600
|
+
|
|
601
|
+
Returns:
|
|
602
|
+
TaskResult containing CreateMediaBuyResponse with:
|
|
603
|
+
- media_buy_id: Unique identifier for this reservation
|
|
604
|
+
- status: Current state of the media buy
|
|
605
|
+
- packages: Confirmed package details
|
|
606
|
+
- Additional platform-specific metadata
|
|
607
|
+
|
|
608
|
+
Example:
|
|
609
|
+
>>> from adcp import ADCPClient, CreateMediaBuyRequest
|
|
610
|
+
>>> client = ADCPClient(agent_config)
|
|
611
|
+
>>> request = CreateMediaBuyRequest(
|
|
612
|
+
... brand_manifest=brand,
|
|
613
|
+
... packages=[package_request],
|
|
614
|
+
... publisher_properties=properties
|
|
615
|
+
... )
|
|
616
|
+
>>> result = await client.create_media_buy(request)
|
|
617
|
+
>>> if result.success:
|
|
618
|
+
... media_buy_id = result.data.media_buy_id
|
|
619
|
+
"""
|
|
620
|
+
operation_id = create_operation_id()
|
|
621
|
+
params = request.model_dump(exclude_none=True)
|
|
622
|
+
|
|
623
|
+
self._emit_activity(
|
|
624
|
+
Activity(
|
|
625
|
+
type=ActivityType.PROTOCOL_REQUEST,
|
|
626
|
+
operation_id=operation_id,
|
|
627
|
+
agent_id=self.agent_config.id,
|
|
628
|
+
task_type="create_media_buy",
|
|
629
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
630
|
+
)
|
|
631
|
+
)
|
|
632
|
+
|
|
633
|
+
raw_result = await self.adapter.create_media_buy(params)
|
|
634
|
+
|
|
635
|
+
self._emit_activity(
|
|
636
|
+
Activity(
|
|
637
|
+
type=ActivityType.PROTOCOL_RESPONSE,
|
|
638
|
+
operation_id=operation_id,
|
|
639
|
+
agent_id=self.agent_config.id,
|
|
640
|
+
task_type="create_media_buy",
|
|
641
|
+
status=raw_result.status,
|
|
642
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
643
|
+
)
|
|
644
|
+
)
|
|
645
|
+
|
|
646
|
+
return self.adapter._parse_response(raw_result, CreateMediaBuyResponse)
|
|
647
|
+
|
|
648
|
+
async def update_media_buy(
|
|
649
|
+
self,
|
|
650
|
+
request: UpdateMediaBuyRequest,
|
|
651
|
+
) -> TaskResult[UpdateMediaBuyResponse]:
|
|
652
|
+
"""
|
|
653
|
+
Update an existing media buy reservation.
|
|
654
|
+
|
|
655
|
+
Modifies a previously created media buy by updating packages or publisher
|
|
656
|
+
properties. The update operation uses discriminated unions to specify what
|
|
657
|
+
to change - either package details or targeting properties.
|
|
658
|
+
|
|
659
|
+
Args:
|
|
660
|
+
request: Media buy update parameters including:
|
|
661
|
+
- media_buy_id: Identifier from create_media_buy response
|
|
662
|
+
- updates: Discriminated union specifying update type:
|
|
663
|
+
* UpdateMediaBuyPackagesRequest: Modify package selections
|
|
664
|
+
* UpdateMediaBuyPropertiesRequest: Change targeting properties
|
|
665
|
+
|
|
666
|
+
Returns:
|
|
667
|
+
TaskResult containing UpdateMediaBuyResponse with:
|
|
668
|
+
- media_buy_id: The updated media buy identifier
|
|
669
|
+
- status: Updated state of the media buy
|
|
670
|
+
- packages: Updated package configurations
|
|
671
|
+
- Additional platform-specific metadata
|
|
672
|
+
|
|
673
|
+
Example:
|
|
674
|
+
>>> from adcp import ADCPClient, UpdateMediaBuyPackagesRequest
|
|
675
|
+
>>> client = ADCPClient(agent_config)
|
|
676
|
+
>>> request = UpdateMediaBuyPackagesRequest(
|
|
677
|
+
... media_buy_id="mb_123",
|
|
678
|
+
... packages=[updated_package]
|
|
679
|
+
... )
|
|
680
|
+
>>> result = await client.update_media_buy(request)
|
|
681
|
+
>>> if result.success:
|
|
682
|
+
... updated_packages = result.data.packages
|
|
683
|
+
"""
|
|
684
|
+
operation_id = create_operation_id()
|
|
685
|
+
params = request.model_dump(exclude_none=True)
|
|
686
|
+
|
|
687
|
+
self._emit_activity(
|
|
688
|
+
Activity(
|
|
689
|
+
type=ActivityType.PROTOCOL_REQUEST,
|
|
690
|
+
operation_id=operation_id,
|
|
691
|
+
agent_id=self.agent_config.id,
|
|
692
|
+
task_type="update_media_buy",
|
|
693
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
694
|
+
)
|
|
695
|
+
)
|
|
696
|
+
|
|
697
|
+
raw_result = await self.adapter.update_media_buy(params)
|
|
698
|
+
|
|
699
|
+
self._emit_activity(
|
|
700
|
+
Activity(
|
|
701
|
+
type=ActivityType.PROTOCOL_RESPONSE,
|
|
702
|
+
operation_id=operation_id,
|
|
703
|
+
agent_id=self.agent_config.id,
|
|
704
|
+
task_type="update_media_buy",
|
|
705
|
+
status=raw_result.status,
|
|
706
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
707
|
+
)
|
|
708
|
+
)
|
|
709
|
+
|
|
710
|
+
return self.adapter._parse_response(raw_result, UpdateMediaBuyResponse)
|
|
711
|
+
|
|
712
|
+
async def build_creative(
|
|
713
|
+
self,
|
|
714
|
+
request: BuildCreativeRequest,
|
|
715
|
+
) -> TaskResult[BuildCreativeResponse]:
|
|
716
|
+
"""
|
|
717
|
+
Generate production-ready creative assets.
|
|
718
|
+
|
|
719
|
+
Requests the creative agent to build final deliverable assets in the target
|
|
720
|
+
format (e.g., VAST, DAAST, HTML5). This is typically called after previewing
|
|
721
|
+
and approving a creative manifest.
|
|
722
|
+
|
|
723
|
+
Args:
|
|
724
|
+
request: Creative build parameters including:
|
|
725
|
+
- manifest: Creative manifest with brand info and content
|
|
726
|
+
- target_format_id: Desired output format identifier
|
|
727
|
+
- inputs: Optional user-provided inputs for template variables
|
|
728
|
+
- deployment: Platform or agent deployment configuration
|
|
729
|
+
|
|
730
|
+
Returns:
|
|
731
|
+
TaskResult containing BuildCreativeResponse with:
|
|
732
|
+
- assets: Production-ready creative files (URLs or inline content)
|
|
733
|
+
- format_id: The generated format identifier
|
|
734
|
+
- manifest: The creative manifest used for generation
|
|
735
|
+
- metadata: Additional platform-specific details
|
|
736
|
+
|
|
737
|
+
Example:
|
|
738
|
+
>>> from adcp import ADCPClient, BuildCreativeRequest
|
|
739
|
+
>>> client = ADCPClient(agent_config)
|
|
740
|
+
>>> request = BuildCreativeRequest(
|
|
741
|
+
... manifest=creative_manifest,
|
|
742
|
+
... target_format_id="vast_2.0",
|
|
743
|
+
... inputs={"duration": 30}
|
|
744
|
+
... )
|
|
745
|
+
>>> result = await client.build_creative(request)
|
|
746
|
+
>>> if result.success:
|
|
747
|
+
... vast_url = result.data.assets[0].url
|
|
748
|
+
"""
|
|
749
|
+
operation_id = create_operation_id()
|
|
750
|
+
params = request.model_dump(exclude_none=True)
|
|
751
|
+
|
|
752
|
+
self._emit_activity(
|
|
753
|
+
Activity(
|
|
754
|
+
type=ActivityType.PROTOCOL_REQUEST,
|
|
755
|
+
operation_id=operation_id,
|
|
756
|
+
agent_id=self.agent_config.id,
|
|
757
|
+
task_type="build_creative",
|
|
758
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
759
|
+
)
|
|
760
|
+
)
|
|
761
|
+
|
|
762
|
+
raw_result = await self.adapter.build_creative(params)
|
|
763
|
+
|
|
764
|
+
self._emit_activity(
|
|
765
|
+
Activity(
|
|
766
|
+
type=ActivityType.PROTOCOL_RESPONSE,
|
|
767
|
+
operation_id=operation_id,
|
|
768
|
+
agent_id=self.agent_config.id,
|
|
769
|
+
task_type="build_creative",
|
|
770
|
+
status=raw_result.status,
|
|
771
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
772
|
+
)
|
|
773
|
+
)
|
|
774
|
+
|
|
775
|
+
return self.adapter._parse_response(raw_result, BuildCreativeResponse)
|
|
776
|
+
|
|
577
777
|
async def list_tools(self) -> list[str]:
|
|
578
778
|
"""
|
|
579
779
|
List available tools from the agent.
|
adcp/protocols/a2a.py
CHANGED
|
@@ -248,6 +248,18 @@ class A2AAdapter(ProtocolAdapter):
|
|
|
248
248
|
"""Generate preview URLs for a creative manifest."""
|
|
249
249
|
return await self._call_a2a_tool("preview_creative", params)
|
|
250
250
|
|
|
251
|
+
async def create_media_buy(self, params: dict[str, Any]) -> TaskResult[Any]:
|
|
252
|
+
"""Create media buy."""
|
|
253
|
+
return await self._call_a2a_tool("create_media_buy", params)
|
|
254
|
+
|
|
255
|
+
async def update_media_buy(self, params: dict[str, Any]) -> TaskResult[Any]:
|
|
256
|
+
"""Update media buy."""
|
|
257
|
+
return await self._call_a2a_tool("update_media_buy", params)
|
|
258
|
+
|
|
259
|
+
async def build_creative(self, params: dict[str, Any]) -> TaskResult[Any]:
|
|
260
|
+
"""Build creative."""
|
|
261
|
+
return await self._call_a2a_tool("build_creative", params)
|
|
262
|
+
|
|
251
263
|
async def list_tools(self) -> list[str]:
|
|
252
264
|
"""
|
|
253
265
|
List available tools from A2A agent.
|
adcp/protocols/base.py
CHANGED
|
@@ -136,6 +136,21 @@ class ProtocolAdapter(ABC):
|
|
|
136
136
|
"""Provide performance feedback."""
|
|
137
137
|
pass
|
|
138
138
|
|
|
139
|
+
@abstractmethod
|
|
140
|
+
async def create_media_buy(self, params: dict[str, Any]) -> TaskResult[Any]:
|
|
141
|
+
"""Create media buy."""
|
|
142
|
+
pass
|
|
143
|
+
|
|
144
|
+
@abstractmethod
|
|
145
|
+
async def update_media_buy(self, params: dict[str, Any]) -> TaskResult[Any]:
|
|
146
|
+
"""Update media buy."""
|
|
147
|
+
pass
|
|
148
|
+
|
|
149
|
+
@abstractmethod
|
|
150
|
+
async def build_creative(self, params: dict[str, Any]) -> TaskResult[Any]:
|
|
151
|
+
"""Build creative."""
|
|
152
|
+
pass
|
|
153
|
+
|
|
139
154
|
@abstractmethod
|
|
140
155
|
async def list_tools(self) -> list[str]:
|
|
141
156
|
"""
|
adcp/protocols/mcp.py
CHANGED
|
@@ -373,6 +373,18 @@ class MCPAdapter(ProtocolAdapter):
|
|
|
373
373
|
"""Generate preview URLs for a creative manifest."""
|
|
374
374
|
return await self._call_mcp_tool("preview_creative", params)
|
|
375
375
|
|
|
376
|
+
async def create_media_buy(self, params: dict[str, Any]) -> TaskResult[Any]:
|
|
377
|
+
"""Create media buy."""
|
|
378
|
+
return await self._call_mcp_tool("create_media_buy", params)
|
|
379
|
+
|
|
380
|
+
async def update_media_buy(self, params: dict[str, Any]) -> TaskResult[Any]:
|
|
381
|
+
"""Update media buy."""
|
|
382
|
+
return await self._call_mcp_tool("update_media_buy", params)
|
|
383
|
+
|
|
384
|
+
async def build_creative(self, params: dict[str, Any]) -> TaskResult[Any]:
|
|
385
|
+
"""Build creative."""
|
|
386
|
+
return await self._call_mcp_tool("build_creative", params)
|
|
387
|
+
|
|
376
388
|
async def list_tools(self) -> list[str]:
|
|
377
389
|
"""List available tools from MCP agent."""
|
|
378
390
|
session = await self._get_session()
|