adcp 2.1.0__tar.gz → 2.3.0__tar.gz
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-2.1.0/src/adcp.egg-info → adcp-2.3.0}/PKG-INFO +38 -2
- {adcp-2.1.0 → adcp-2.3.0}/README.md +36 -0
- {adcp-2.1.0 → adcp-2.3.0}/pyproject.toml +2 -2
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/__init__.py +29 -13
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/adagents.py +122 -0
- adcp-2.3.0/src/adcp/types/__init__.py +48 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/aliases.py +51 -11
- {adcp-2.1.0 → adcp-2.3.0/src/adcp.egg-info}/PKG-INFO +38 -2
- {adcp-2.1.0 → adcp-2.3.0}/tests/test_adagents.py +362 -0
- {adcp-2.1.0 → adcp-2.3.0}/tests/test_cli.py +22 -0
- {adcp-2.1.0 → adcp-2.3.0}/tests/test_discriminated_unions.py +260 -0
- {adcp-2.1.0 → adcp-2.3.0}/tests/test_type_aliases.py +108 -3
- adcp-2.1.0/src/adcp/types/__init__.py +0 -27
- {adcp-2.1.0 → adcp-2.3.0}/LICENSE +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/setup.cfg +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/__main__.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/client.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/config.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/exceptions.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/protocols/__init__.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/protocols/a2a.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/protocols/base.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/protocols/mcp.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/py.typed +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/simple.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/testing/__init__.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/testing/test_helpers.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/base.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/core.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/__init__.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/activate_signal_request.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/activate_signal_response.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/activation_key.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/adagents.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/asset_type.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/audio_asset.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/brand_manifest.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/brand_manifest_ref.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/build_creative_request.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/build_creative_response.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/channels.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/cpc_option.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/cpcv_option.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/cpm_auction_option.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/cpm_fixed_option.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/cpp_option.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/cpv_option.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/create_media_buy_request.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/create_media_buy_response.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/creative_asset.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/creative_assignment.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/creative_manifest.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/creative_policy.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/creative_status.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/css_asset.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/daast_asset.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/delivery_metrics.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/delivery_type.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/deployment.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/destination.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/error.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/flat_rate_option.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/format.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/format_id.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/frequency_cap.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/frequency_cap_scope.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/get_media_buy_delivery_request.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/get_media_buy_delivery_response.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/get_products_request.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/get_products_response.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/get_signals_request.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/get_signals_response.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/html_asset.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/identifier_types.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/image_asset.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/index.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/javascript_asset.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/list_authorized_properties_request.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/list_authorized_properties_response.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/list_creative_formats_request.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/list_creative_formats_response.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/list_creatives_request.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/list_creatives_response.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/markdown_asset.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/measurement.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/media_buy.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/media_buy_status.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/pacing.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/package.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/package_request.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/package_status.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/performance_feedback.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/placement.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/preview_creative_request.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/preview_creative_response.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/preview_render.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/pricing_model.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/pricing_option.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/product.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/promoted_offerings.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/promoted_products.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/property.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/protocol_envelope.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/provide_performance_feedback_request.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/provide_performance_feedback_response.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/publisher_identifier_types.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/push_notification_config.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/reporting_capabilities.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/response.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/standard_format_ids.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/start_timing.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/sub_asset.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/sync_creatives_request.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/sync_creatives_response.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/targeting.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/task_status.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/task_type.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/tasks_get_request.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/tasks_get_response.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/tasks_list_request.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/tasks_list_response.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/text_asset.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/update_media_buy_request.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/update_media_buy_response.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/url_asset.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/vast_asset.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/vcpm_auction_option.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/vcpm_fixed_option.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/video_asset.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/webhook_asset.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/types/generated_poc/webhook_payload.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/utils/__init__.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/utils/operation_id.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/utils/preview_cache.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/utils/response_parser.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp/validation.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp.egg-info/SOURCES.txt +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp.egg-info/dependency_links.txt +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp.egg-info/entry_points.txt +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp.egg-info/requires.txt +1 -1
- {adcp-2.1.0 → adcp-2.3.0}/src/adcp.egg-info/top_level.txt +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/tests/test_client.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/tests/test_code_generation.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/tests/test_format_id_validation.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/tests/test_helpers.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/tests/test_preview_html.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/tests/test_protocols.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/tests/test_response_parser.py +0 -0
- {adcp-2.1.0 → adcp-2.3.0}/tests/test_simple_api.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: adcp
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3.0
|
|
4
4
|
Summary: Official Python client for the Ad Context Protocol (AdCP)
|
|
5
5
|
Author-email: AdCP Community <maintainers@adcontextprotocol.org>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -26,6 +26,7 @@ Requires-Dist: pydantic>=2.0.0
|
|
|
26
26
|
Requires-Dist: typing-extensions>=4.5.0
|
|
27
27
|
Requires-Dist: a2a-sdk>=0.3.0
|
|
28
28
|
Requires-Dist: mcp>=0.9.0
|
|
29
|
+
Requires-Dist: email-validator>=2.0.0
|
|
29
30
|
Provides-Extra: dev
|
|
30
31
|
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
31
32
|
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
@@ -34,7 +35,6 @@ Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
|
34
35
|
Requires-Dist: black>=23.0.0; extra == "dev"
|
|
35
36
|
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
36
37
|
Requires-Dist: datamodel-code-generator[http]>=0.35.0; extra == "dev"
|
|
37
|
-
Requires-Dist: email-validator>=2.0.0; extra == "dev"
|
|
38
38
|
Dynamic: license-file
|
|
39
39
|
|
|
40
40
|
# adcp - Python Client for Ad Context Protocol
|
|
@@ -544,6 +544,42 @@ is_authorized = await verify_agent_for_property(
|
|
|
544
544
|
|
|
545
545
|
See `examples/adagents_validation.py` for complete examples.
|
|
546
546
|
|
|
547
|
+
### Authorization Discovery
|
|
548
|
+
|
|
549
|
+
Discover which publishers have authorized your agent using two approaches:
|
|
550
|
+
|
|
551
|
+
**1. "Push" Approach** - Ask the agent (recommended, fastest):
|
|
552
|
+
```python
|
|
553
|
+
from adcp import ADCPClient
|
|
554
|
+
|
|
555
|
+
async with ADCPClient(agent_config) as client:
|
|
556
|
+
# Single API call to agent
|
|
557
|
+
response = await client.simple.list_authorized_properties()
|
|
558
|
+
print(f"Authorized for: {response.publisher_domains}")
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
**2. "Pull" Approach** - Check publisher adagents.json files (when you need property details):
|
|
562
|
+
```python
|
|
563
|
+
from adcp import fetch_agent_authorizations
|
|
564
|
+
|
|
565
|
+
# Check specific publishers (fetches in parallel)
|
|
566
|
+
contexts = await fetch_agent_authorizations(
|
|
567
|
+
"https://our-sales-agent.com",
|
|
568
|
+
["nytimes.com", "wsj.com", "cnn.com"]
|
|
569
|
+
)
|
|
570
|
+
|
|
571
|
+
for domain, ctx in contexts.items():
|
|
572
|
+
print(f"{domain}:")
|
|
573
|
+
print(f" Property IDs: {ctx.property_ids}")
|
|
574
|
+
print(f" Tags: {ctx.property_tags}")
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
**When to use which:**
|
|
578
|
+
- **Push**: Quick discovery, portfolio overview, high-level authorization check
|
|
579
|
+
- **Pull**: Property-level details, specific publisher list, works offline
|
|
580
|
+
|
|
581
|
+
See `examples/fetch_agent_authorizations.py` for complete examples.
|
|
582
|
+
|
|
547
583
|
## CLI Tool
|
|
548
584
|
|
|
549
585
|
The `adcp` command-line tool provides easy interaction with AdCP agents without writing code.
|
|
@@ -505,6 +505,42 @@ is_authorized = await verify_agent_for_property(
|
|
|
505
505
|
|
|
506
506
|
See `examples/adagents_validation.py` for complete examples.
|
|
507
507
|
|
|
508
|
+
### Authorization Discovery
|
|
509
|
+
|
|
510
|
+
Discover which publishers have authorized your agent using two approaches:
|
|
511
|
+
|
|
512
|
+
**1. "Push" Approach** - Ask the agent (recommended, fastest):
|
|
513
|
+
```python
|
|
514
|
+
from adcp import ADCPClient
|
|
515
|
+
|
|
516
|
+
async with ADCPClient(agent_config) as client:
|
|
517
|
+
# Single API call to agent
|
|
518
|
+
response = await client.simple.list_authorized_properties()
|
|
519
|
+
print(f"Authorized for: {response.publisher_domains}")
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
**2. "Pull" Approach** - Check publisher adagents.json files (when you need property details):
|
|
523
|
+
```python
|
|
524
|
+
from adcp import fetch_agent_authorizations
|
|
525
|
+
|
|
526
|
+
# Check specific publishers (fetches in parallel)
|
|
527
|
+
contexts = await fetch_agent_authorizations(
|
|
528
|
+
"https://our-sales-agent.com",
|
|
529
|
+
["nytimes.com", "wsj.com", "cnn.com"]
|
|
530
|
+
)
|
|
531
|
+
|
|
532
|
+
for domain, ctx in contexts.items():
|
|
533
|
+
print(f"{domain}:")
|
|
534
|
+
print(f" Property IDs: {ctx.property_ids}")
|
|
535
|
+
print(f" Tags: {ctx.property_tags}")
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
**When to use which:**
|
|
539
|
+
- **Push**: Quick discovery, portfolio overview, high-level authorization check
|
|
540
|
+
- **Pull**: Property-level details, specific publisher list, works offline
|
|
541
|
+
|
|
542
|
+
See `examples/fetch_agent_authorizations.py` for complete examples.
|
|
543
|
+
|
|
508
544
|
## CLI Tool
|
|
509
545
|
|
|
510
546
|
The `adcp` command-line tool provides easy interaction with AdCP agents without writing code.
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "adcp"
|
|
7
|
-
version = "2.
|
|
7
|
+
version = "2.3.0"
|
|
8
8
|
description = "Official Python client for the Ad Context Protocol (AdCP)"
|
|
9
9
|
authors = [
|
|
10
10
|
{name = "AdCP Community", email = "maintainers@adcontextprotocol.org"}
|
|
@@ -31,6 +31,7 @@ dependencies = [
|
|
|
31
31
|
"typing-extensions>=4.5.0",
|
|
32
32
|
"a2a-sdk>=0.3.0",
|
|
33
33
|
"mcp>=0.9.0",
|
|
34
|
+
"email-validator>=2.0.0",
|
|
34
35
|
]
|
|
35
36
|
|
|
36
37
|
[project.scripts]
|
|
@@ -45,7 +46,6 @@ dev = [
|
|
|
45
46
|
"black>=23.0.0",
|
|
46
47
|
"ruff>=0.1.0",
|
|
47
48
|
"datamodel-code-generator[http]>=0.35.0",
|
|
48
|
-
"email-validator>=2.0.0",
|
|
49
49
|
]
|
|
50
50
|
|
|
51
51
|
[project.urls]
|
|
@@ -8,8 +8,10 @@ Supports both A2A and MCP protocols with full type safety.
|
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
from adcp.adagents import (
|
|
11
|
+
AuthorizationContext,
|
|
11
12
|
domain_matches,
|
|
12
13
|
fetch_adagents,
|
|
14
|
+
fetch_agent_authorizations,
|
|
13
15
|
get_all_properties,
|
|
14
16
|
get_all_tags,
|
|
15
17
|
get_properties_by_agent,
|
|
@@ -56,27 +58,33 @@ from adcp.types import aliases, generated
|
|
|
56
58
|
from adcp.types.aliases import (
|
|
57
59
|
ActivateSignalErrorResponse,
|
|
58
60
|
ActivateSignalSuccessResponse,
|
|
61
|
+
BothPreviewRender,
|
|
59
62
|
BuildCreativeErrorResponse,
|
|
60
63
|
BuildCreativeSuccessResponse,
|
|
61
64
|
CreateMediaBuyErrorResponse,
|
|
62
65
|
CreateMediaBuySuccessResponse,
|
|
66
|
+
HtmlPreviewRender,
|
|
67
|
+
InlineDaastAsset,
|
|
68
|
+
InlineVastAsset,
|
|
69
|
+
MediaSubAsset,
|
|
63
70
|
PreviewCreativeFormatRequest,
|
|
64
71
|
PreviewCreativeInteractiveResponse,
|
|
65
72
|
PreviewCreativeManifestRequest,
|
|
66
73
|
PreviewCreativeStaticResponse,
|
|
67
|
-
PreviewRenderHtml,
|
|
68
|
-
PreviewRenderIframe,
|
|
69
|
-
PreviewRenderImage,
|
|
70
74
|
PropertyIdActivationKey,
|
|
71
75
|
PropertyTagActivationKey,
|
|
72
76
|
ProvidePerformanceFeedbackErrorResponse,
|
|
73
77
|
ProvidePerformanceFeedbackSuccessResponse,
|
|
74
78
|
SyncCreativesErrorResponse,
|
|
75
79
|
SyncCreativesSuccessResponse,
|
|
80
|
+
TextSubAsset,
|
|
76
81
|
UpdateMediaBuyErrorResponse,
|
|
77
82
|
UpdateMediaBuyPackagesRequest,
|
|
78
83
|
UpdateMediaBuyPropertiesRequest,
|
|
79
84
|
UpdateMediaBuySuccessResponse,
|
|
85
|
+
UrlDaastAsset,
|
|
86
|
+
UrlPreviewRender,
|
|
87
|
+
UrlVastAsset,
|
|
80
88
|
)
|
|
81
89
|
from adcp.types.core import AgentConfig, Protocol, TaskResult, TaskStatus, WebhookMetadata
|
|
82
90
|
|
|
@@ -128,7 +136,7 @@ from adcp.validation import (
|
|
|
128
136
|
validate_publisher_properties_item,
|
|
129
137
|
)
|
|
130
138
|
|
|
131
|
-
__version__ = "2.
|
|
139
|
+
__version__ = "2.3.0"
|
|
132
140
|
|
|
133
141
|
__all__ = [
|
|
134
142
|
# Client classes
|
|
@@ -172,7 +180,9 @@ __all__ = [
|
|
|
172
180
|
"Product",
|
|
173
181
|
"Property",
|
|
174
182
|
# Adagents validation
|
|
183
|
+
"AuthorizationContext",
|
|
175
184
|
"fetch_adagents",
|
|
185
|
+
"fetch_agent_authorizations",
|
|
176
186
|
"verify_agent_authorization",
|
|
177
187
|
"verify_agent_for_property",
|
|
178
188
|
"domain_matches",
|
|
@@ -219,25 +229,31 @@ __all__ = [
|
|
|
219
229
|
# Semantic type aliases (for better API ergonomics)
|
|
220
230
|
"ActivateSignalSuccessResponse",
|
|
221
231
|
"ActivateSignalErrorResponse",
|
|
232
|
+
"BothPreviewRender",
|
|
222
233
|
"BuildCreativeSuccessResponse",
|
|
223
234
|
"BuildCreativeErrorResponse",
|
|
224
235
|
"CreateMediaBuySuccessResponse",
|
|
225
236
|
"CreateMediaBuyErrorResponse",
|
|
226
|
-
"
|
|
227
|
-
"
|
|
228
|
-
"
|
|
229
|
-
"
|
|
230
|
-
"UpdateMediaBuySuccessResponse",
|
|
231
|
-
"UpdateMediaBuyErrorResponse",
|
|
237
|
+
"HtmlPreviewRender",
|
|
238
|
+
"InlineDaastAsset",
|
|
239
|
+
"InlineVastAsset",
|
|
240
|
+
"MediaSubAsset",
|
|
232
241
|
"PreviewCreativeFormatRequest",
|
|
233
242
|
"PreviewCreativeManifestRequest",
|
|
234
243
|
"PreviewCreativeStaticResponse",
|
|
235
244
|
"PreviewCreativeInteractiveResponse",
|
|
236
|
-
"PreviewRenderImage",
|
|
237
|
-
"PreviewRenderHtml",
|
|
238
|
-
"PreviewRenderIframe",
|
|
239
245
|
"PropertyIdActivationKey",
|
|
240
246
|
"PropertyTagActivationKey",
|
|
247
|
+
"ProvidePerformanceFeedbackSuccessResponse",
|
|
248
|
+
"ProvidePerformanceFeedbackErrorResponse",
|
|
249
|
+
"SyncCreativesSuccessResponse",
|
|
250
|
+
"SyncCreativesErrorResponse",
|
|
251
|
+
"TextSubAsset",
|
|
252
|
+
"UpdateMediaBuySuccessResponse",
|
|
253
|
+
"UpdateMediaBuyErrorResponse",
|
|
241
254
|
"UpdateMediaBuyPackagesRequest",
|
|
242
255
|
"UpdateMediaBuyPropertiesRequest",
|
|
256
|
+
"UrlDaastAsset",
|
|
257
|
+
"UrlPreviewRender",
|
|
258
|
+
"UrlVastAsset",
|
|
243
259
|
]
|
|
@@ -518,3 +518,125 @@ def get_properties_by_agent(adagents_data: dict[str, Any], agent_url: str) -> li
|
|
|
518
518
|
return [p for p in properties if isinstance(p, dict)]
|
|
519
519
|
|
|
520
520
|
return []
|
|
521
|
+
|
|
522
|
+
|
|
523
|
+
class AuthorizationContext:
|
|
524
|
+
"""Authorization context for a publisher domain.
|
|
525
|
+
|
|
526
|
+
Attributes:
|
|
527
|
+
property_ids: List of property IDs the agent is authorized for
|
|
528
|
+
property_tags: List of property tags the agent is authorized for
|
|
529
|
+
raw_properties: Raw property data from adagents.json
|
|
530
|
+
"""
|
|
531
|
+
|
|
532
|
+
def __init__(self, properties: list[dict[str, Any]]):
|
|
533
|
+
"""Initialize from list of properties.
|
|
534
|
+
|
|
535
|
+
Args:
|
|
536
|
+
properties: List of property dictionaries from adagents.json
|
|
537
|
+
"""
|
|
538
|
+
self.property_ids: list[str] = []
|
|
539
|
+
self.property_tags: list[str] = []
|
|
540
|
+
self.raw_properties = properties
|
|
541
|
+
|
|
542
|
+
# Extract property IDs and tags
|
|
543
|
+
for prop in properties:
|
|
544
|
+
if not isinstance(prop, dict):
|
|
545
|
+
continue
|
|
546
|
+
|
|
547
|
+
# Extract property ID
|
|
548
|
+
prop_id = prop.get("id")
|
|
549
|
+
if prop_id and isinstance(prop_id, str):
|
|
550
|
+
self.property_ids.append(prop_id)
|
|
551
|
+
|
|
552
|
+
# Extract tags
|
|
553
|
+
tags = prop.get("tags", [])
|
|
554
|
+
if isinstance(tags, list):
|
|
555
|
+
for tag in tags:
|
|
556
|
+
if isinstance(tag, str) and tag not in self.property_tags:
|
|
557
|
+
self.property_tags.append(tag)
|
|
558
|
+
|
|
559
|
+
def __repr__(self) -> str:
|
|
560
|
+
return (
|
|
561
|
+
f"AuthorizationContext("
|
|
562
|
+
f"property_ids={self.property_ids}, "
|
|
563
|
+
f"property_tags={self.property_tags})"
|
|
564
|
+
)
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
async def fetch_agent_authorizations(
|
|
568
|
+
agent_url: str,
|
|
569
|
+
publisher_domains: list[str],
|
|
570
|
+
timeout: float = 10.0,
|
|
571
|
+
client: httpx.AsyncClient | None = None,
|
|
572
|
+
) -> dict[str, AuthorizationContext]:
|
|
573
|
+
"""Fetch authorization contexts by checking publisher adagents.json files.
|
|
574
|
+
|
|
575
|
+
This function discovers what publishers have authorized your agent by fetching
|
|
576
|
+
their adagents.json files from the .well-known directory and extracting the
|
|
577
|
+
properties your agent can access.
|
|
578
|
+
|
|
579
|
+
This is the "pull" approach - you query publishers to see if they've authorized you.
|
|
580
|
+
For the "push" approach where the agent tells you what it's authorized for,
|
|
581
|
+
use the agent's list_authorized_properties endpoint via ADCPClient.
|
|
582
|
+
|
|
583
|
+
Args:
|
|
584
|
+
agent_url: URL of your sales agent
|
|
585
|
+
publisher_domains: List of publisher domains to check (e.g., ["nytimes.com", "wsj.com"])
|
|
586
|
+
timeout: Request timeout in seconds for each fetch
|
|
587
|
+
client: Optional httpx.AsyncClient for connection pooling
|
|
588
|
+
|
|
589
|
+
Returns:
|
|
590
|
+
Dictionary mapping publisher domain to AuthorizationContext.
|
|
591
|
+
Only includes domains where the agent is authorized.
|
|
592
|
+
|
|
593
|
+
Example:
|
|
594
|
+
>>> # "Pull" approach - check what publishers have authorized you
|
|
595
|
+
>>> contexts = await fetch_agent_authorizations(
|
|
596
|
+
... "https://our-sales-agent.com",
|
|
597
|
+
... ["nytimes.com", "wsj.com", "cnn.com"]
|
|
598
|
+
... )
|
|
599
|
+
>>> for domain, ctx in contexts.items():
|
|
600
|
+
... print(f"{domain}:")
|
|
601
|
+
... print(f" Property IDs: {ctx.property_ids}")
|
|
602
|
+
... print(f" Tags: {ctx.property_tags}")
|
|
603
|
+
|
|
604
|
+
See Also:
|
|
605
|
+
ADCPClient.list_authorized_properties: "Push" approach using the agent's API
|
|
606
|
+
|
|
607
|
+
Notes:
|
|
608
|
+
- Silently skips domains where adagents.json is not found or invalid
|
|
609
|
+
- Only returns domains where the agent is explicitly authorized
|
|
610
|
+
- For production use with many domains, pass a shared httpx.AsyncClient
|
|
611
|
+
to enable connection pooling
|
|
612
|
+
"""
|
|
613
|
+
import asyncio
|
|
614
|
+
|
|
615
|
+
# Create tasks to fetch all adagents.json files in parallel
|
|
616
|
+
async def fetch_authorization_for_domain(
|
|
617
|
+
domain: str,
|
|
618
|
+
) -> tuple[str, AuthorizationContext | None]:
|
|
619
|
+
"""Fetch authorization context for a single domain."""
|
|
620
|
+
try:
|
|
621
|
+
adagents_data = await fetch_adagents(domain, timeout=timeout, client=client)
|
|
622
|
+
|
|
623
|
+
# Check if agent is authorized
|
|
624
|
+
if not verify_agent_authorization(adagents_data, agent_url):
|
|
625
|
+
return (domain, None)
|
|
626
|
+
|
|
627
|
+
# Get properties for this agent
|
|
628
|
+
properties = get_properties_by_agent(adagents_data, agent_url)
|
|
629
|
+
|
|
630
|
+
# Create authorization context
|
|
631
|
+
return (domain, AuthorizationContext(properties))
|
|
632
|
+
|
|
633
|
+
except (AdagentsNotFoundError, AdagentsValidationError, AdagentsTimeoutError):
|
|
634
|
+
# Silently skip domains with missing or invalid adagents.json
|
|
635
|
+
return (domain, None)
|
|
636
|
+
|
|
637
|
+
# Fetch all domains in parallel
|
|
638
|
+
tasks = [fetch_authorization_for_domain(domain) for domain in publisher_domains]
|
|
639
|
+
results = await asyncio.gather(*tasks)
|
|
640
|
+
|
|
641
|
+
# Build result dictionary, filtering out None values
|
|
642
|
+
return {domain: ctx for domain, ctx in results if ctx is not None}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
"""Type definitions for AdCP client."""
|
|
4
|
+
|
|
5
|
+
from adcp.types.aliases import (
|
|
6
|
+
BothPreviewRender,
|
|
7
|
+
HtmlPreviewRender,
|
|
8
|
+
InlineDaastAsset,
|
|
9
|
+
InlineVastAsset,
|
|
10
|
+
MediaSubAsset,
|
|
11
|
+
TextSubAsset,
|
|
12
|
+
UrlDaastAsset,
|
|
13
|
+
UrlPreviewRender,
|
|
14
|
+
UrlVastAsset,
|
|
15
|
+
)
|
|
16
|
+
from adcp.types.base import AdCPBaseModel
|
|
17
|
+
from adcp.types.core import (
|
|
18
|
+
Activity,
|
|
19
|
+
ActivityType,
|
|
20
|
+
AgentConfig,
|
|
21
|
+
DebugInfo,
|
|
22
|
+
Protocol,
|
|
23
|
+
TaskResult,
|
|
24
|
+
TaskStatus,
|
|
25
|
+
WebhookMetadata,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
__all__ = [
|
|
29
|
+
"AdCPBaseModel",
|
|
30
|
+
"AgentConfig",
|
|
31
|
+
"Protocol",
|
|
32
|
+
"TaskResult",
|
|
33
|
+
"TaskStatus",
|
|
34
|
+
"WebhookMetadata",
|
|
35
|
+
"Activity",
|
|
36
|
+
"ActivityType",
|
|
37
|
+
"DebugInfo",
|
|
38
|
+
# Semantic aliases for discriminated unions
|
|
39
|
+
"BothPreviewRender",
|
|
40
|
+
"HtmlPreviewRender",
|
|
41
|
+
"InlineDaastAsset",
|
|
42
|
+
"InlineVastAsset",
|
|
43
|
+
"MediaSubAsset",
|
|
44
|
+
"TextSubAsset",
|
|
45
|
+
"UrlDaastAsset",
|
|
46
|
+
"UrlPreviewRender",
|
|
47
|
+
"UrlVastAsset",
|
|
48
|
+
]
|
|
@@ -45,6 +45,9 @@ from adcp.types.generated import (
|
|
|
45
45
|
# Create media buy responses
|
|
46
46
|
CreateMediaBuyResponse1,
|
|
47
47
|
CreateMediaBuyResponse2,
|
|
48
|
+
# DAAST assets
|
|
49
|
+
DaastAsset1,
|
|
50
|
+
DaastAsset2,
|
|
48
51
|
# Preview creative requests
|
|
49
52
|
PreviewCreativeRequest1,
|
|
50
53
|
PreviewCreativeRequest2,
|
|
@@ -58,6 +61,9 @@ from adcp.types.generated import (
|
|
|
58
61
|
# Performance feedback responses
|
|
59
62
|
ProvidePerformanceFeedbackResponse1,
|
|
60
63
|
ProvidePerformanceFeedbackResponse2,
|
|
64
|
+
# SubAssets
|
|
65
|
+
SubAsset1,
|
|
66
|
+
SubAsset2,
|
|
61
67
|
# Sync creatives responses
|
|
62
68
|
SyncCreativesResponse1,
|
|
63
69
|
SyncCreativesResponse2,
|
|
@@ -67,6 +73,9 @@ from adcp.types.generated import (
|
|
|
67
73
|
# Update media buy responses
|
|
68
74
|
UpdateMediaBuyResponse1,
|
|
69
75
|
UpdateMediaBuyResponse2,
|
|
76
|
+
# VAST assets
|
|
77
|
+
VastAsset1,
|
|
78
|
+
VastAsset2,
|
|
70
79
|
)
|
|
71
80
|
|
|
72
81
|
# ============================================================================
|
|
@@ -157,15 +166,40 @@ PreviewCreativeStaticResponse = PreviewCreativeResponse1
|
|
|
157
166
|
PreviewCreativeInteractiveResponse = PreviewCreativeResponse2
|
|
158
167
|
"""Preview response with interactive renders (iframe embedding)."""
|
|
159
168
|
|
|
160
|
-
# Preview Render Variants
|
|
161
|
-
|
|
162
|
-
"""
|
|
169
|
+
# Preview Render Variants (discriminated by output_format)
|
|
170
|
+
UrlPreviewRender = PreviewRender1
|
|
171
|
+
"""Preview render with output_format='url' - provides preview_url for iframe embedding."""
|
|
163
172
|
|
|
164
|
-
|
|
165
|
-
"""
|
|
173
|
+
HtmlPreviewRender = PreviewRender2
|
|
174
|
+
"""Preview render with output_format='html' - provides preview_html for direct embedding."""
|
|
166
175
|
|
|
167
|
-
|
|
168
|
-
"""
|
|
176
|
+
BothPreviewRender = PreviewRender3
|
|
177
|
+
"""Preview render with output_format='both' - provides both preview_url and preview_html."""
|
|
178
|
+
|
|
179
|
+
# ============================================================================
|
|
180
|
+
# ASSET TYPE ALIASES - Delivery & Kind Discriminated Unions
|
|
181
|
+
# ============================================================================
|
|
182
|
+
|
|
183
|
+
# VAST Asset Variants (discriminated by delivery_type)
|
|
184
|
+
UrlVastAsset = VastAsset1
|
|
185
|
+
"""VAST asset delivered via URL endpoint - delivery_type='url'."""
|
|
186
|
+
|
|
187
|
+
InlineVastAsset = VastAsset2
|
|
188
|
+
"""VAST asset with inline XML content - delivery_type='inline'."""
|
|
189
|
+
|
|
190
|
+
# DAAST Asset Variants (discriminated by delivery_type)
|
|
191
|
+
UrlDaastAsset = DaastAsset1
|
|
192
|
+
"""DAAST asset delivered via URL endpoint - delivery_type='url'."""
|
|
193
|
+
|
|
194
|
+
InlineDaastAsset = DaastAsset2
|
|
195
|
+
"""DAAST asset with inline XML content - delivery_type='inline'."""
|
|
196
|
+
|
|
197
|
+
# SubAsset Variants (discriminated by asset_kind)
|
|
198
|
+
MediaSubAsset = SubAsset1
|
|
199
|
+
"""SubAsset for media content (images, videos) - asset_kind='media', provides content_uri."""
|
|
200
|
+
|
|
201
|
+
TextSubAsset = SubAsset2
|
|
202
|
+
"""SubAsset for text content (headlines, body text) - asset_kind='text', provides content."""
|
|
169
203
|
|
|
170
204
|
# ============================================================================
|
|
171
205
|
# EXPORTS
|
|
@@ -178,6 +212,16 @@ __all__ = [
|
|
|
178
212
|
# Activation keys
|
|
179
213
|
"PropertyIdActivationKey",
|
|
180
214
|
"PropertyTagActivationKey",
|
|
215
|
+
# Asset type aliases
|
|
216
|
+
"BothPreviewRender",
|
|
217
|
+
"HtmlPreviewRender",
|
|
218
|
+
"InlineDaastAsset",
|
|
219
|
+
"InlineVastAsset",
|
|
220
|
+
"MediaSubAsset",
|
|
221
|
+
"TextSubAsset",
|
|
222
|
+
"UrlDaastAsset",
|
|
223
|
+
"UrlPreviewRender",
|
|
224
|
+
"UrlVastAsset",
|
|
181
225
|
# Build creative responses
|
|
182
226
|
"BuildCreativeSuccessResponse",
|
|
183
227
|
"BuildCreativeErrorResponse",
|
|
@@ -193,10 +237,6 @@ __all__ = [
|
|
|
193
237
|
# Preview creative responses
|
|
194
238
|
"PreviewCreativeStaticResponse",
|
|
195
239
|
"PreviewCreativeInteractiveResponse",
|
|
196
|
-
# Preview renders
|
|
197
|
-
"PreviewRenderImage",
|
|
198
|
-
"PreviewRenderHtml",
|
|
199
|
-
"PreviewRenderIframe",
|
|
200
240
|
# Sync creatives responses
|
|
201
241
|
"SyncCreativesSuccessResponse",
|
|
202
242
|
"SyncCreativesErrorResponse",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: adcp
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3.0
|
|
4
4
|
Summary: Official Python client for the Ad Context Protocol (AdCP)
|
|
5
5
|
Author-email: AdCP Community <maintainers@adcontextprotocol.org>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -26,6 +26,7 @@ Requires-Dist: pydantic>=2.0.0
|
|
|
26
26
|
Requires-Dist: typing-extensions>=4.5.0
|
|
27
27
|
Requires-Dist: a2a-sdk>=0.3.0
|
|
28
28
|
Requires-Dist: mcp>=0.9.0
|
|
29
|
+
Requires-Dist: email-validator>=2.0.0
|
|
29
30
|
Provides-Extra: dev
|
|
30
31
|
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
31
32
|
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
@@ -34,7 +35,6 @@ Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
|
34
35
|
Requires-Dist: black>=23.0.0; extra == "dev"
|
|
35
36
|
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
36
37
|
Requires-Dist: datamodel-code-generator[http]>=0.35.0; extra == "dev"
|
|
37
|
-
Requires-Dist: email-validator>=2.0.0; extra == "dev"
|
|
38
38
|
Dynamic: license-file
|
|
39
39
|
|
|
40
40
|
# adcp - Python Client for Ad Context Protocol
|
|
@@ -544,6 +544,42 @@ is_authorized = await verify_agent_for_property(
|
|
|
544
544
|
|
|
545
545
|
See `examples/adagents_validation.py` for complete examples.
|
|
546
546
|
|
|
547
|
+
### Authorization Discovery
|
|
548
|
+
|
|
549
|
+
Discover which publishers have authorized your agent using two approaches:
|
|
550
|
+
|
|
551
|
+
**1. "Push" Approach** - Ask the agent (recommended, fastest):
|
|
552
|
+
```python
|
|
553
|
+
from adcp import ADCPClient
|
|
554
|
+
|
|
555
|
+
async with ADCPClient(agent_config) as client:
|
|
556
|
+
# Single API call to agent
|
|
557
|
+
response = await client.simple.list_authorized_properties()
|
|
558
|
+
print(f"Authorized for: {response.publisher_domains}")
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
**2. "Pull" Approach** - Check publisher adagents.json files (when you need property details):
|
|
562
|
+
```python
|
|
563
|
+
from adcp import fetch_agent_authorizations
|
|
564
|
+
|
|
565
|
+
# Check specific publishers (fetches in parallel)
|
|
566
|
+
contexts = await fetch_agent_authorizations(
|
|
567
|
+
"https://our-sales-agent.com",
|
|
568
|
+
["nytimes.com", "wsj.com", "cnn.com"]
|
|
569
|
+
)
|
|
570
|
+
|
|
571
|
+
for domain, ctx in contexts.items():
|
|
572
|
+
print(f"{domain}:")
|
|
573
|
+
print(f" Property IDs: {ctx.property_ids}")
|
|
574
|
+
print(f" Tags: {ctx.property_tags}")
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
**When to use which:**
|
|
578
|
+
- **Push**: Quick discovery, portfolio overview, high-level authorization check
|
|
579
|
+
- **Pull**: Property-level details, specific publisher list, works offline
|
|
580
|
+
|
|
581
|
+
See `examples/fetch_agent_authorizations.py` for complete examples.
|
|
582
|
+
|
|
547
583
|
## CLI Tool
|
|
548
584
|
|
|
549
585
|
The `adcp` command-line tool provides easy interaction with AdCP agents without writing code.
|