amazon-ads-mcp 0.2.7__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.
Files changed (82) hide show
  1. amazon_ads_mcp/__init__.py +11 -0
  2. amazon_ads_mcp/auth/__init__.py +33 -0
  3. amazon_ads_mcp/auth/base.py +211 -0
  4. amazon_ads_mcp/auth/hooks.py +172 -0
  5. amazon_ads_mcp/auth/manager.py +791 -0
  6. amazon_ads_mcp/auth/oauth_state_store.py +277 -0
  7. amazon_ads_mcp/auth/providers/__init__.py +14 -0
  8. amazon_ads_mcp/auth/providers/direct.py +393 -0
  9. amazon_ads_mcp/auth/providers/example_auth0.py.example +216 -0
  10. amazon_ads_mcp/auth/providers/openbridge.py +512 -0
  11. amazon_ads_mcp/auth/registry.py +146 -0
  12. amazon_ads_mcp/auth/secure_token_store.py +297 -0
  13. amazon_ads_mcp/auth/token_store.py +723 -0
  14. amazon_ads_mcp/config/__init__.py +5 -0
  15. amazon_ads_mcp/config/sampling.py +111 -0
  16. amazon_ads_mcp/config/settings.py +366 -0
  17. amazon_ads_mcp/exceptions.py +314 -0
  18. amazon_ads_mcp/middleware/__init__.py +11 -0
  19. amazon_ads_mcp/middleware/authentication.py +1474 -0
  20. amazon_ads_mcp/middleware/caching.py +177 -0
  21. amazon_ads_mcp/middleware/oauth.py +175 -0
  22. amazon_ads_mcp/middleware/sampling.py +112 -0
  23. amazon_ads_mcp/models/__init__.py +320 -0
  24. amazon_ads_mcp/models/amc_models.py +837 -0
  25. amazon_ads_mcp/models/api_responses.py +847 -0
  26. amazon_ads_mcp/models/base_models.py +215 -0
  27. amazon_ads_mcp/models/builtin_responses.py +496 -0
  28. amazon_ads_mcp/models/dsp_models.py +556 -0
  29. amazon_ads_mcp/models/stores_brands.py +610 -0
  30. amazon_ads_mcp/server/__init__.py +6 -0
  31. amazon_ads_mcp/server/__main__.py +6 -0
  32. amazon_ads_mcp/server/builtin_prompts.py +269 -0
  33. amazon_ads_mcp/server/builtin_tools.py +962 -0
  34. amazon_ads_mcp/server/file_routes.py +547 -0
  35. amazon_ads_mcp/server/html_templates.py +149 -0
  36. amazon_ads_mcp/server/mcp_server.py +327 -0
  37. amazon_ads_mcp/server/openapi_utils.py +158 -0
  38. amazon_ads_mcp/server/sampling_handler.py +251 -0
  39. amazon_ads_mcp/server/server_builder.py +751 -0
  40. amazon_ads_mcp/server/sidecar_loader.py +178 -0
  41. amazon_ads_mcp/server/transform_executor.py +827 -0
  42. amazon_ads_mcp/tools/__init__.py +22 -0
  43. amazon_ads_mcp/tools/cache_management.py +105 -0
  44. amazon_ads_mcp/tools/download_tools.py +267 -0
  45. amazon_ads_mcp/tools/identity.py +236 -0
  46. amazon_ads_mcp/tools/oauth.py +598 -0
  47. amazon_ads_mcp/tools/profile.py +150 -0
  48. amazon_ads_mcp/tools/profile_listing.py +285 -0
  49. amazon_ads_mcp/tools/region.py +320 -0
  50. amazon_ads_mcp/tools/region_identity.py +175 -0
  51. amazon_ads_mcp/utils/__init__.py +6 -0
  52. amazon_ads_mcp/utils/async_compat.py +215 -0
  53. amazon_ads_mcp/utils/errors.py +452 -0
  54. amazon_ads_mcp/utils/export_content_type_resolver.py +249 -0
  55. amazon_ads_mcp/utils/export_download_handler.py +579 -0
  56. amazon_ads_mcp/utils/header_resolver.py +81 -0
  57. amazon_ads_mcp/utils/http/__init__.py +56 -0
  58. amazon_ads_mcp/utils/http/circuit_breaker.py +127 -0
  59. amazon_ads_mcp/utils/http/client_manager.py +329 -0
  60. amazon_ads_mcp/utils/http/request.py +207 -0
  61. amazon_ads_mcp/utils/http/resilience.py +512 -0
  62. amazon_ads_mcp/utils/http/resilient_client.py +195 -0
  63. amazon_ads_mcp/utils/http/retry.py +76 -0
  64. amazon_ads_mcp/utils/http_client.py +873 -0
  65. amazon_ads_mcp/utils/media/__init__.py +21 -0
  66. amazon_ads_mcp/utils/media/negotiator.py +243 -0
  67. amazon_ads_mcp/utils/media/types.py +199 -0
  68. amazon_ads_mcp/utils/openapi/__init__.py +16 -0
  69. amazon_ads_mcp/utils/openapi/json.py +55 -0
  70. amazon_ads_mcp/utils/openapi/loader.py +263 -0
  71. amazon_ads_mcp/utils/openapi/refs.py +46 -0
  72. amazon_ads_mcp/utils/region_config.py +200 -0
  73. amazon_ads_mcp/utils/response_wrapper.py +171 -0
  74. amazon_ads_mcp/utils/sampling_helpers.py +156 -0
  75. amazon_ads_mcp/utils/sampling_wrapper.py +173 -0
  76. amazon_ads_mcp/utils/security.py +630 -0
  77. amazon_ads_mcp/utils/tool_naming.py +137 -0
  78. amazon_ads_mcp-0.2.7.dist-info/METADATA +664 -0
  79. amazon_ads_mcp-0.2.7.dist-info/RECORD +82 -0
  80. amazon_ads_mcp-0.2.7.dist-info/WHEEL +4 -0
  81. amazon_ads_mcp-0.2.7.dist-info/entry_points.txt +3 -0
  82. amazon_ads_mcp-0.2.7.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,269 @@
1
+ """Built-in prompts for Amazon Ads MCP Server.
2
+
3
+ These prompts provide structured templates for common Amazon Ads API workflows,
4
+ helping LLMs generate correct sequences of tool calls and handle typical tasks.
5
+ """
6
+
7
+ from typing import TYPE_CHECKING
8
+
9
+ if TYPE_CHECKING:
10
+ from fastmcp import FastMCP
11
+
12
+
13
+ async def register_all_builtin_prompts(server: "FastMCP") -> None:
14
+ """Register all built-in prompts with the server.
15
+
16
+ Args:
17
+ server: The FastMCP server instance to register prompts with
18
+ """
19
+
20
+ # Authentication and Profile Setup
21
+ @server.prompt(
22
+ name="auth_profile_setup",
23
+ description="Complete authentication and profile setup for Amazon Ads API",
24
+ tags={"auth", "profile", "setup"},
25
+ meta={"version": "0.1", "owner": "ads-platform"},
26
+ )
27
+ def auth_profile_setup_prompt(region: str = "na") -> str:
28
+ """Guide authentication, region selection, and profile setup."""
29
+ return (
30
+ "Goal: Set up Amazon Ads API authentication and select an active profile.\n"
31
+ "Steps for the model:\n"
32
+ "1) Start OAuth flow if needed:\n"
33
+ " - Tool: start_oauth_flow\n"
34
+ " - Monitor with: check_oauth_status\n"
35
+ "2) Set the region:\n"
36
+ f" - Tool: set_active_region (use '{region}')\n"
37
+ "3) Discover available profiles safely:\n"
38
+ " - Tool: summarize_profiles\n"
39
+ " - Optional: search_profiles or page_profiles to locate a specific profile\n"
40
+ " - Note: acprof:GET /v2/profiles can return very large payloads\n"
41
+ "4) Set the active profile:\n"
42
+ " - Tool: set_active_profile\n"
43
+ " - Use the profileId from the previous step\n"
44
+ "5) Verify setup:\n"
45
+ " - Tool: get_routing_state\n"
46
+ " - Tool: get_active_profile\n"
47
+ " - Tool: check_oauth_status\n"
48
+ "Return: Summary of authentication status, active region, and selected profile."
49
+ )
50
+
51
+ # Export and Download Workflow
52
+ @server.prompt(
53
+ name="export_entity_download",
54
+ description="Request entity export, poll status, and download when ready",
55
+ tags={"exports", "download", "reports"},
56
+ meta={"version": "0.1", "owner": "ads-platform"},
57
+ )
58
+ def export_entity_download_prompt(
59
+ entity: str,
60
+ profile_id: str | None = None,
61
+ date_range: str = "last_30_days",
62
+ state_filter: str | None = None,
63
+ ) -> str:
64
+ """Export Amazon Ads entities and download the results."""
65
+ profile_note = (
66
+ f" (use profileId: {profile_id})"
67
+ if profile_id
68
+ else " (use current active profile)"
69
+ )
70
+ filter_note = f", stateFilter: '{state_filter}'" if state_filter else ""
71
+
72
+ return (
73
+ f"Goal: Export and download Amazon Ads {entity} data.\n"
74
+ "Steps for the model:\n"
75
+ "1) Verify region and profile:\n"
76
+ " - Tool: get_routing_state\n"
77
+ " - Tool: get_active_profile\n"
78
+ "2) Create export request:\n"
79
+ f" - Tool: export:POST /{entity}/export\n"
80
+ f" - Body: {{profileId{profile_note}, dateRange: '{date_range}'{filter_note}}}\n"
81
+ "3) Extract exportId from response and poll status:\n"
82
+ " - Tool: export:GET /exports/{{exportId}}\n"
83
+ " - Repeat every 5-10 seconds until status is COMPLETED or FAILED\n"
84
+ " - Check for 'downloadLocation' in response\n"
85
+ "4) When COMPLETED with downloadLocation:\n"
86
+ " - Tool: download_export\n"
87
+ " - Parameters: exportId and export_url from step 3\n"
88
+ "5) Return the local file_path and summary of exported data.\n"
89
+ "Error handling: If 401/403, check authentication and profile access rights."
90
+ )
91
+
92
+ # Campaign Creation
93
+ @server.prompt(
94
+ name="create_campaign",
95
+ description="Create a new advertising campaign with proper validation",
96
+ tags={"campaign", "creation", "sponsored"},
97
+ meta={"version": "0.1", "owner": "ads-platform"},
98
+ )
99
+ def create_campaign_prompt(
100
+ campaign_type: str = "sponsoredProducts",
101
+ objective: str = "SALES",
102
+ name: str = "New Campaign",
103
+ budget: float = 100.0,
104
+ marketplace_id: str | None = None,
105
+ ) -> str:
106
+ """Create a new campaign with specified parameters."""
107
+ mp_note = f", marketplaceId: '{marketplace_id}'" if marketplace_id else ""
108
+
109
+ return (
110
+ f"Goal: Create a new {campaign_type} campaign.\n"
111
+ "Steps for the model:\n"
112
+ "1) Verify authentication and profile:\n"
113
+ " - Tool: get_active_profile\n"
114
+ " - Tool: check_oauth_status\n"
115
+ "2) Create the campaign:\n"
116
+ " - Tool: cm:POST /adsApi/v1/create/campaigns\n"
117
+ " - Body structure:\n"
118
+ " {{\n"
119
+ f" channel: '{campaign_type}',\n"
120
+ f" objective: '{objective}',\n"
121
+ f" name: '{name}',\n"
122
+ f" budget: {budget},\n"
123
+ " budgetType: 'DAILY',\n"
124
+ " state: 'ENABLED',\n"
125
+ " startDate: <today's date in YYYYMMDD format>,\n"
126
+ f" targetingType: 'MANUAL'{mp_note}\n"
127
+ " }}\n"
128
+ "3) Verify campaign creation:\n"
129
+ " - Tool: cm:POST /adsApi/v1/query/campaigns\n"
130
+ " - Body: {{filters: {{campaignNameFilter: {{name: '{name}'}}}}}}\n"
131
+ "4) Return the campaign ID and confirmation details.\n"
132
+ "Note: Ensure all required fields are included based on campaign type."
133
+ )
134
+
135
+ # Error Recovery
136
+ @server.prompt(
137
+ name="troubleshoot_api_error",
138
+ description="Diagnose and recover from common API errors",
139
+ tags={"error", "troubleshooting", "recovery"},
140
+ meta={"version": "0.1", "owner": "ads-platform"},
141
+ )
142
+ def troubleshoot_api_error_prompt(
143
+ error_code: int,
144
+ error_message: str | None = None,
145
+ last_operation: str | None = None,
146
+ ) -> str:
147
+ """Guide error diagnosis and recovery steps."""
148
+ context = f" during '{last_operation}'" if last_operation else ""
149
+ msg_note = f": {error_message}" if error_message else ""
150
+
151
+ recovery_steps = {
152
+ 401: (
153
+ "Authentication issue detected. Steps:\n"
154
+ "1) Check token status: check_oauth_status\n"
155
+ "2) If expired, refresh: refresh_oauth_token\n"
156
+ "3) If refresh fails, restart: start_oauth_flow\n"
157
+ "4) Retry the original operation"
158
+ ),
159
+ 403: (
160
+ "Access denied. Steps:\n"
161
+ "1) Verify active profile: get_active_profile\n"
162
+ "2) Check profile permissions: acprof:GET /v2/profiles\n"
163
+ "3) Verify region/marketplace: get_routing_state\n"
164
+ "4) Switch profile if needed: set_active_profile\n"
165
+ "5) Retry with correct profile"
166
+ ),
167
+ 404: (
168
+ "Resource not found. Steps:\n"
169
+ "1) Verify the resource ID is correct\n"
170
+ "2) Check if using correct region: get_routing_state\n"
171
+ "3) List available resources to confirm existence\n"
172
+ "4) Update parameters and retry"
173
+ ),
174
+ 429: (
175
+ "Rate limit exceeded. Steps:\n"
176
+ "1) Wait 60 seconds before retrying\n"
177
+ "2) Implement exponential backoff for subsequent retries\n"
178
+ "3) Consider reducing request frequency"
179
+ ),
180
+ }
181
+
182
+ steps = recovery_steps.get(
183
+ error_code,
184
+ (
185
+ "Unknown error. Generic steps:\n"
186
+ "1) Check authentication: check_oauth_status\n"
187
+ "2) Verify routing: get_routing_state\n"
188
+ "3) Review request parameters\n"
189
+ "4) Check API documentation for requirements"
190
+ ),
191
+ )
192
+
193
+ return (
194
+ f"Goal: Diagnose and recover from error {error_code}{msg_note}{context}.\n"
195
+ f"{steps}\n"
196
+ "Additional diagnostics:\n"
197
+ "- Review the full error response for details\n"
198
+ "- Check if the API endpoint requires specific scopes\n"
199
+ "- Verify request body format and required fields\n"
200
+ "Return: Root cause analysis and whether the issue was resolved."
201
+ )
202
+
203
+ # Async Report Generation
204
+ @server.prompt(
205
+ name="generate_async_report",
206
+ description="Create and retrieve an async report with polling",
207
+ tags={"reports", "async", "analytics"},
208
+ meta={"version": "0.1", "owner": "ads-platform"},
209
+ )
210
+ def generate_async_report_prompt(
211
+ report_type: str = "campaigns",
212
+ metrics: str = "impressions,clicks,spend,sales",
213
+ time_period: str = "LAST_30_DAYS",
214
+ group_by: str | None = None,
215
+ ) -> str:
216
+ """Generate async report and retrieve results."""
217
+ grouping = f", groupBy: ['{group_by}']" if group_by else ""
218
+
219
+ return (
220
+ f"Goal: Generate and retrieve a {report_type} performance report.\n"
221
+ "Steps for the model:\n"
222
+ "1) Create report request:\n"
223
+ " - Tool: rpasyn:POST /reporting/reports\n"
224
+ " - Body structure:\n"
225
+ " {{\n"
226
+ f" reportType: '{report_type.upper()}',\n"
227
+ " metrics: ["
228
+ + ", ".join(f'"{m}"' for m in metrics.split(","))
229
+ + "],\n"
230
+ f" timeUnit: 'DAILY',\n"
231
+ f" timePeriod: '{time_period}'{grouping}\n"
232
+ " }}\n"
233
+ "2) Extract reportId and poll status:\n"
234
+ " - Tool: rpasyn:GET /reporting/reports/{{reportId}}\n"
235
+ " - Check 'status' field (PENDING → IN_PROGRESS → SUCCESS/FAILURE)\n"
236
+ " - Poll every 5-10 seconds\n"
237
+ "3) When SUCCESS, extract download URL:\n"
238
+ " - Look for 'url' or 'location' in response\n"
239
+ " - Tool: download_export with the URL\n"
240
+ "4) Return the downloaded file path and report metadata.\n"
241
+ "Note: Large reports may take several minutes to generate."
242
+ )
243
+
244
+ # Region Setup
245
+ @server.prompt(
246
+ name="setup_region",
247
+ description="Configure region for API routing",
248
+ tags={"region", "routing"},
249
+ meta={"version": "0.2", "owner": "ads-platform"},
250
+ )
251
+ def setup_region_prompt(
252
+ target_region: str,
253
+ ) -> str:
254
+ """Set up region configuration."""
255
+ return (
256
+ f"Goal: Configure API routing for region '{target_region}'.\n"
257
+ "Steps for the model:\n"
258
+ f"1) Set the target region:\n"
259
+ f" - Tool: set_active_region\n"
260
+ f" - Parameter: region = '{target_region}'\n"
261
+ f" - Valid regions: na, eu, fe\n"
262
+ f"2) Verify configuration:\n"
263
+ " - Tool: get_routing_state\n"
264
+ " - Confirm region is correctly set\n"
265
+ f"3) Test with a simple API call:\n"
266
+ " - Tool: acprof:GET /v2/profiles\n"
267
+ " - Verify profiles are from the correct region\n"
268
+ "Return: Current routing configuration and validation results."
269
+ )