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.
- amazon_ads_mcp/__init__.py +11 -0
- amazon_ads_mcp/auth/__init__.py +33 -0
- amazon_ads_mcp/auth/base.py +211 -0
- amazon_ads_mcp/auth/hooks.py +172 -0
- amazon_ads_mcp/auth/manager.py +791 -0
- amazon_ads_mcp/auth/oauth_state_store.py +277 -0
- amazon_ads_mcp/auth/providers/__init__.py +14 -0
- amazon_ads_mcp/auth/providers/direct.py +393 -0
- amazon_ads_mcp/auth/providers/example_auth0.py.example +216 -0
- amazon_ads_mcp/auth/providers/openbridge.py +512 -0
- amazon_ads_mcp/auth/registry.py +146 -0
- amazon_ads_mcp/auth/secure_token_store.py +297 -0
- amazon_ads_mcp/auth/token_store.py +723 -0
- amazon_ads_mcp/config/__init__.py +5 -0
- amazon_ads_mcp/config/sampling.py +111 -0
- amazon_ads_mcp/config/settings.py +366 -0
- amazon_ads_mcp/exceptions.py +314 -0
- amazon_ads_mcp/middleware/__init__.py +11 -0
- amazon_ads_mcp/middleware/authentication.py +1474 -0
- amazon_ads_mcp/middleware/caching.py +177 -0
- amazon_ads_mcp/middleware/oauth.py +175 -0
- amazon_ads_mcp/middleware/sampling.py +112 -0
- amazon_ads_mcp/models/__init__.py +320 -0
- amazon_ads_mcp/models/amc_models.py +837 -0
- amazon_ads_mcp/models/api_responses.py +847 -0
- amazon_ads_mcp/models/base_models.py +215 -0
- amazon_ads_mcp/models/builtin_responses.py +496 -0
- amazon_ads_mcp/models/dsp_models.py +556 -0
- amazon_ads_mcp/models/stores_brands.py +610 -0
- amazon_ads_mcp/server/__init__.py +6 -0
- amazon_ads_mcp/server/__main__.py +6 -0
- amazon_ads_mcp/server/builtin_prompts.py +269 -0
- amazon_ads_mcp/server/builtin_tools.py +962 -0
- amazon_ads_mcp/server/file_routes.py +547 -0
- amazon_ads_mcp/server/html_templates.py +149 -0
- amazon_ads_mcp/server/mcp_server.py +327 -0
- amazon_ads_mcp/server/openapi_utils.py +158 -0
- amazon_ads_mcp/server/sampling_handler.py +251 -0
- amazon_ads_mcp/server/server_builder.py +751 -0
- amazon_ads_mcp/server/sidecar_loader.py +178 -0
- amazon_ads_mcp/server/transform_executor.py +827 -0
- amazon_ads_mcp/tools/__init__.py +22 -0
- amazon_ads_mcp/tools/cache_management.py +105 -0
- amazon_ads_mcp/tools/download_tools.py +267 -0
- amazon_ads_mcp/tools/identity.py +236 -0
- amazon_ads_mcp/tools/oauth.py +598 -0
- amazon_ads_mcp/tools/profile.py +150 -0
- amazon_ads_mcp/tools/profile_listing.py +285 -0
- amazon_ads_mcp/tools/region.py +320 -0
- amazon_ads_mcp/tools/region_identity.py +175 -0
- amazon_ads_mcp/utils/__init__.py +6 -0
- amazon_ads_mcp/utils/async_compat.py +215 -0
- amazon_ads_mcp/utils/errors.py +452 -0
- amazon_ads_mcp/utils/export_content_type_resolver.py +249 -0
- amazon_ads_mcp/utils/export_download_handler.py +579 -0
- amazon_ads_mcp/utils/header_resolver.py +81 -0
- amazon_ads_mcp/utils/http/__init__.py +56 -0
- amazon_ads_mcp/utils/http/circuit_breaker.py +127 -0
- amazon_ads_mcp/utils/http/client_manager.py +329 -0
- amazon_ads_mcp/utils/http/request.py +207 -0
- amazon_ads_mcp/utils/http/resilience.py +512 -0
- amazon_ads_mcp/utils/http/resilient_client.py +195 -0
- amazon_ads_mcp/utils/http/retry.py +76 -0
- amazon_ads_mcp/utils/http_client.py +873 -0
- amazon_ads_mcp/utils/media/__init__.py +21 -0
- amazon_ads_mcp/utils/media/negotiator.py +243 -0
- amazon_ads_mcp/utils/media/types.py +199 -0
- amazon_ads_mcp/utils/openapi/__init__.py +16 -0
- amazon_ads_mcp/utils/openapi/json.py +55 -0
- amazon_ads_mcp/utils/openapi/loader.py +263 -0
- amazon_ads_mcp/utils/openapi/refs.py +46 -0
- amazon_ads_mcp/utils/region_config.py +200 -0
- amazon_ads_mcp/utils/response_wrapper.py +171 -0
- amazon_ads_mcp/utils/sampling_helpers.py +156 -0
- amazon_ads_mcp/utils/sampling_wrapper.py +173 -0
- amazon_ads_mcp/utils/security.py +630 -0
- amazon_ads_mcp/utils/tool_naming.py +137 -0
- amazon_ads_mcp-0.2.7.dist-info/METADATA +664 -0
- amazon_ads_mcp-0.2.7.dist-info/RECORD +82 -0
- amazon_ads_mcp-0.2.7.dist-info/WHEEL +4 -0
- amazon_ads_mcp-0.2.7.dist-info/entry_points.txt +3 -0
- amazon_ads_mcp-0.2.7.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
"""Structured exception classes for Amazon Ads MCP."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from typing import Any, Dict, Optional
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class AmazonAdsMCPError(Exception):
|
|
8
|
+
"""Base exception for all Amazon Ads MCP errors.
|
|
9
|
+
|
|
10
|
+
This exception serves as the parent class for all Amazon Ads MCP
|
|
11
|
+
specific exceptions, providing a consistent interface for error
|
|
12
|
+
handling across the application.
|
|
13
|
+
|
|
14
|
+
:param message: Human-readable error message
|
|
15
|
+
:param code: Optional error code for programmatic handling
|
|
16
|
+
:param details: Optional dictionary containing additional error context
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
def __init__(
|
|
20
|
+
self,
|
|
21
|
+
message: str,
|
|
22
|
+
code: Optional[str] = None,
|
|
23
|
+
details: Optional[Dict[str, Any]] = None,
|
|
24
|
+
):
|
|
25
|
+
"""Initialize the exception with message, code, and details."""
|
|
26
|
+
super().__init__(message)
|
|
27
|
+
self.message = message
|
|
28
|
+
self.code = code or self.__class__.__name__
|
|
29
|
+
self.details = details or {}
|
|
30
|
+
|
|
31
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
32
|
+
"""Convert exception to dictionary format.
|
|
33
|
+
|
|
34
|
+
:return: Dictionary containing error code, message, and details
|
|
35
|
+
"""
|
|
36
|
+
return {
|
|
37
|
+
"error": self.code,
|
|
38
|
+
"message": self.message,
|
|
39
|
+
"details": self.details,
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
def to_json(self) -> str:
|
|
43
|
+
"""Convert exception to JSON string.
|
|
44
|
+
|
|
45
|
+
:return: JSON-encoded string representation of the exception
|
|
46
|
+
"""
|
|
47
|
+
return json.dumps(self.to_dict())
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class AuthenticationError(AmazonAdsMCPError):
|
|
51
|
+
"""Raised when authentication fails.
|
|
52
|
+
|
|
53
|
+
This exception is raised when authentication operations fail,
|
|
54
|
+
including token validation, credential verification, and
|
|
55
|
+
provider initialization errors.
|
|
56
|
+
|
|
57
|
+
:param message: Description of the authentication failure
|
|
58
|
+
:param details: Optional additional context about the failure
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
def __init__(self, message: str, details: Optional[Dict[str, Any]] = None):
|
|
62
|
+
"""Initialize authentication error with message and optional details."""
|
|
63
|
+
super().__init__(message=message, code="AUTHENTICATION_ERROR", details=details)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class OAuthError(AuthenticationError):
|
|
67
|
+
"""Raised for OAuth-specific errors.
|
|
68
|
+
|
|
69
|
+
This exception is raised when OAuth-related operations fail,
|
|
70
|
+
such as authorization code exchange, token refresh, or
|
|
71
|
+
OAuth flow validation.
|
|
72
|
+
|
|
73
|
+
:param message: Description of the OAuth error
|
|
74
|
+
:param error_code: Optional OAuth error code from the provider
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
def __init__(self, message: str, error_code: Optional[str] = None):
|
|
78
|
+
"""Initialize OAuth error with message and optional error code."""
|
|
79
|
+
details = {}
|
|
80
|
+
if error_code:
|
|
81
|
+
details["oauth_error"] = error_code
|
|
82
|
+
super().__init__(message=message, details=details)
|
|
83
|
+
self.code = "OAUTH_ERROR"
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class OAuthStateError(OAuthError):
|
|
87
|
+
"""Raised when OAuth state validation fails.
|
|
88
|
+
|
|
89
|
+
This exception is raised when the OAuth state parameter
|
|
90
|
+
validation fails during the authorization flow, indicating
|
|
91
|
+
a potential security issue or tampering.
|
|
92
|
+
|
|
93
|
+
:param message: Description of the state validation failure
|
|
94
|
+
"""
|
|
95
|
+
|
|
96
|
+
def __init__(self, message: str):
|
|
97
|
+
"""Initialize OAuth state error with message."""
|
|
98
|
+
super().__init__(message)
|
|
99
|
+
self.code = "OAUTH_STATE_ERROR"
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class TokenError(AuthenticationError):
|
|
103
|
+
"""Raised for token-related errors.
|
|
104
|
+
|
|
105
|
+
This exception is raised when token operations fail,
|
|
106
|
+
including token validation, refresh, or parsing errors.
|
|
107
|
+
|
|
108
|
+
:param message: Description of the token error
|
|
109
|
+
:param token_type: Optional type of token that caused the error
|
|
110
|
+
"""
|
|
111
|
+
|
|
112
|
+
def __init__(self, message: str, token_type: Optional[str] = None):
|
|
113
|
+
"""Initialize token error with message and optional token type."""
|
|
114
|
+
details = {}
|
|
115
|
+
if token_type:
|
|
116
|
+
details["token_type"] = token_type
|
|
117
|
+
super().__init__(message=message, details=details)
|
|
118
|
+
self.code = "TOKEN_ERROR"
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class APIError(AmazonAdsMCPError):
|
|
122
|
+
"""Raised for API-related errors.
|
|
123
|
+
|
|
124
|
+
This exception is raised when Amazon Ads API operations fail,
|
|
125
|
+
including HTTP errors, invalid responses, and API-specific
|
|
126
|
+
error conditions.
|
|
127
|
+
|
|
128
|
+
:param message: Description of the API error
|
|
129
|
+
:param status_code: Optional HTTP status code from the API response
|
|
130
|
+
:param response_body: Optional response body from the failed request
|
|
131
|
+
"""
|
|
132
|
+
|
|
133
|
+
def __init__(
|
|
134
|
+
self,
|
|
135
|
+
message: str,
|
|
136
|
+
status_code: Optional[int] = None,
|
|
137
|
+
response_body: Optional[str] = None,
|
|
138
|
+
):
|
|
139
|
+
"""Initialize API error with message and optional response details."""
|
|
140
|
+
details: Dict[str, Any] = {}
|
|
141
|
+
if status_code:
|
|
142
|
+
details["status_code"] = status_code
|
|
143
|
+
if response_body:
|
|
144
|
+
details["response_body"] = response_body
|
|
145
|
+
super().__init__(message=message, code="API_ERROR", details=details)
|
|
146
|
+
self.status_code = status_code
|
|
147
|
+
self.response_body = response_body
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
class TimeoutError(APIError):
|
|
151
|
+
"""Raised when an API request times out.
|
|
152
|
+
|
|
153
|
+
This exception is raised when an API request exceeds the
|
|
154
|
+
configured timeout duration, indicating network or server
|
|
155
|
+
performance issues.
|
|
156
|
+
|
|
157
|
+
:param message: Description of the timeout error
|
|
158
|
+
:param operation: Optional name of the operation that timed out
|
|
159
|
+
"""
|
|
160
|
+
|
|
161
|
+
def __init__(self, message: str, operation: Optional[str] = None):
|
|
162
|
+
"""Initialize timeout error with message and optional operation."""
|
|
163
|
+
details = {}
|
|
164
|
+
if operation:
|
|
165
|
+
details["operation"] = operation
|
|
166
|
+
super().__init__(message=message, status_code=None, response_body=None)
|
|
167
|
+
self.code = "TIMEOUT_ERROR"
|
|
168
|
+
self.details.update(details)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
class RateLimitError(APIError):
|
|
172
|
+
"""Raised when API rate limits are exceeded.
|
|
173
|
+
|
|
174
|
+
This exception is raised when API requests exceed the
|
|
175
|
+
configured rate limits, requiring backoff or retry logic.
|
|
176
|
+
|
|
177
|
+
:param message: Description of the rate limit error
|
|
178
|
+
:param retry_after: Optional seconds to wait before retrying
|
|
179
|
+
:param limit: Optional rate limit that was exceeded
|
|
180
|
+
"""
|
|
181
|
+
|
|
182
|
+
def __init__(
|
|
183
|
+
self,
|
|
184
|
+
message: str,
|
|
185
|
+
retry_after: Optional[int] = None,
|
|
186
|
+
limit: Optional[int] = None,
|
|
187
|
+
):
|
|
188
|
+
"""Initialize rate limit error with message and optional limits."""
|
|
189
|
+
details = {}
|
|
190
|
+
if retry_after:
|
|
191
|
+
details["retry_after"] = retry_after
|
|
192
|
+
if limit:
|
|
193
|
+
details["limit"] = limit
|
|
194
|
+
super().__init__(message=message, status_code=429, response_body=None)
|
|
195
|
+
self.code = "RATE_LIMIT_ERROR"
|
|
196
|
+
self.details.update(details)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
class ConfigurationError(AmazonAdsMCPError):
|
|
200
|
+
"""Raised for configuration-related errors.
|
|
201
|
+
|
|
202
|
+
This exception is raised when configuration validation fails
|
|
203
|
+
or when required configuration settings are missing or invalid.
|
|
204
|
+
|
|
205
|
+
:param message: Description of the configuration error
|
|
206
|
+
:param setting: Optional name of the problematic setting
|
|
207
|
+
"""
|
|
208
|
+
|
|
209
|
+
def __init__(self, message: str, setting: Optional[str] = None):
|
|
210
|
+
"""Initialize configuration error with message and optional setting."""
|
|
211
|
+
details = {}
|
|
212
|
+
if setting:
|
|
213
|
+
details["setting"] = setting
|
|
214
|
+
super().__init__(message=message, code="CONFIGURATION_ERROR", details=details)
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
class ToolExecutionError(AmazonAdsMCPError):
|
|
218
|
+
"""Raised when tool execution fails.
|
|
219
|
+
|
|
220
|
+
This exception is raised when MCP tool execution fails,
|
|
221
|
+
wrapping the original error with additional context.
|
|
222
|
+
|
|
223
|
+
:param message: Description of the tool execution error
|
|
224
|
+
:param tool_name: Optional name of the tool that failed
|
|
225
|
+
:param original_error: Optional original exception that caused the failure
|
|
226
|
+
"""
|
|
227
|
+
|
|
228
|
+
def __init__(
|
|
229
|
+
self,
|
|
230
|
+
message: str,
|
|
231
|
+
tool_name: Optional[str] = None,
|
|
232
|
+
original_error: Optional[Exception] = None,
|
|
233
|
+
):
|
|
234
|
+
"""Initialize tool execution error with message and optional context."""
|
|
235
|
+
details = {}
|
|
236
|
+
if tool_name:
|
|
237
|
+
details["tool"] = tool_name
|
|
238
|
+
if original_error:
|
|
239
|
+
details["original_error"] = str(original_error)
|
|
240
|
+
details["error_type"] = type(original_error).__name__
|
|
241
|
+
super().__init__(message=message, code="TOOL_EXECUTION_ERROR", details=details)
|
|
242
|
+
self.tool_name = tool_name
|
|
243
|
+
self.original_error = original_error
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
class SamplingError(AmazonAdsMCPError):
|
|
247
|
+
"""Raised when sampling operations fail.
|
|
248
|
+
|
|
249
|
+
This exception is raised when data sampling operations fail,
|
|
250
|
+
such as when sampling configuration is invalid or when
|
|
251
|
+
sampling cannot be performed on the requested data.
|
|
252
|
+
|
|
253
|
+
:param message: Description of the sampling error
|
|
254
|
+
:param fallback_available: Whether a fallback sampling method is available
|
|
255
|
+
"""
|
|
256
|
+
|
|
257
|
+
def __init__(self, message: str, fallback_available: bool = False):
|
|
258
|
+
"""Initialize sampling error with message and fallback availability."""
|
|
259
|
+
details = {"fallback_available": fallback_available}
|
|
260
|
+
super().__init__(message=message, code="SAMPLING_ERROR", details=details)
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
class TransformError(AmazonAdsMCPError):
|
|
264
|
+
"""Raised when data transformation fails.
|
|
265
|
+
|
|
266
|
+
This exception is raised when data transformation operations
|
|
267
|
+
fail, such as when transforming API responses or converting
|
|
268
|
+
data between different formats.
|
|
269
|
+
|
|
270
|
+
:param message: Description of the transformation error
|
|
271
|
+
:param transform_type: Optional type of transformation that failed
|
|
272
|
+
:param data_path: Optional path to the data that caused the error
|
|
273
|
+
"""
|
|
274
|
+
|
|
275
|
+
def __init__(
|
|
276
|
+
self,
|
|
277
|
+
message: str,
|
|
278
|
+
transform_type: Optional[str] = None,
|
|
279
|
+
data_path: Optional[str] = None,
|
|
280
|
+
):
|
|
281
|
+
"""Initialize transform error with message and optional context."""
|
|
282
|
+
details = {}
|
|
283
|
+
if transform_type:
|
|
284
|
+
details["transform_type"] = transform_type
|
|
285
|
+
if data_path:
|
|
286
|
+
details["data_path"] = data_path
|
|
287
|
+
super().__init__(message=message, code="TRANSFORM_ERROR", details=details)
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
class ValidationError(AmazonAdsMCPError):
|
|
291
|
+
"""Raised when validation fails.
|
|
292
|
+
|
|
293
|
+
This exception is raised when data validation fails,
|
|
294
|
+
such as when input parameters don't meet required
|
|
295
|
+
constraints or when data format validation fails.
|
|
296
|
+
|
|
297
|
+
:param message: Description of the validation error
|
|
298
|
+
:param field: Optional name of the field that failed validation
|
|
299
|
+
:param value: Optional value that caused the validation failure
|
|
300
|
+
"""
|
|
301
|
+
|
|
302
|
+
def __init__(
|
|
303
|
+
self,
|
|
304
|
+
message: str,
|
|
305
|
+
field: Optional[str] = None,
|
|
306
|
+
value: Optional[Any] = None,
|
|
307
|
+
):
|
|
308
|
+
"""Initialize validation error with message and optional field/value."""
|
|
309
|
+
details = {}
|
|
310
|
+
if field:
|
|
311
|
+
details["field"] = field
|
|
312
|
+
if value is not None:
|
|
313
|
+
details["value"] = str(value)
|
|
314
|
+
super().__init__(message=message, code="VALIDATION_ERROR", details=details)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"""Middleware module for Amazon Ads MCP.
|
|
2
|
+
|
|
3
|
+
This module provides middleware components for the Amazon Ads MCP
|
|
4
|
+
server, including authentication middleware and request/response
|
|
5
|
+
processing.
|
|
6
|
+
|
|
7
|
+
The module provides:
|
|
8
|
+
- Authentication middleware for request processing
|
|
9
|
+
- Request/response transformation
|
|
10
|
+
- Error handling and validation
|
|
11
|
+
"""
|