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,137 @@
1
+ """
2
+ Tool naming utilities for MCP servers.
3
+
4
+ This module provides utilities for managing tool names within the
5
+ constraints of the MCP protocol, including name shortening and
6
+ prefix management.
7
+ """
8
+
9
+ import inspect
10
+ import logging
11
+ import re
12
+ from typing import Dict
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+ # MCP tool name constraints
17
+ MAX_TOOL_NAME = 64
18
+ DEFAULT_MAX_PREFIX = 8
19
+
20
+
21
+ def shorten_prefix(namespace: str, max_len: int = DEFAULT_MAX_PREFIX) -> str:
22
+ """
23
+ Shorten a namespace to create a tool prefix.
24
+
25
+ Creates an acronym from CamelCase words or truncates the namespace.
26
+
27
+ :param namespace: The namespace to shorten
28
+ :type namespace: str
29
+ :param max_len: Maximum length for the prefix
30
+ :type max_len: int
31
+ :return: Shortened prefix string
32
+ :rtype: str
33
+ """
34
+ # Extract capital letters for acronym (e.g., "AccountBudgets" -> "AB")
35
+ parts = re.findall(r"[A-Z][a-z0-9]*", namespace) or [namespace]
36
+ acronym = "".join(p[0] for p in parts if p)
37
+
38
+ # Use acronym if available, otherwise truncate namespace
39
+ candidate = (acronym or namespace).lower()[:max_len]
40
+
41
+ return candidate or namespace[:max_len].lower()
42
+
43
+
44
+ async def get_tools(server) -> Dict[str, object]:
45
+ """
46
+ Get tools from a FastMCP server.
47
+
48
+ Handles both sync and async get_tools methods.
49
+
50
+ :param server: FastMCP server instance
51
+ :type server: object
52
+ :return: Dictionary of tools
53
+ :rtype: Dict[str, object]
54
+ """
55
+ res = server.get_tools()
56
+ return await res if inspect.isawaitable(res) else res
57
+
58
+
59
+ async def enforce_tool_name_limit(
60
+ server, prefix: str, limit: int = MAX_TOOL_NAME
61
+ ) -> None:
62
+ """
63
+ Enforce MCP tool name length limits by renaming if necessary.
64
+
65
+ MCP has a maximum tool name length. This function renames tools
66
+ that would exceed the limit when combined with their prefix.
67
+
68
+ :param server: FastMCP server instance
69
+ :type server: object
70
+ :param prefix: The prefix that will be prepended to tool names
71
+ :type prefix: str
72
+ :param limit: Maximum total name length (default: 64)
73
+ :type limit: int
74
+ :return: None
75
+ :rtype: None
76
+ """
77
+ tools = await get_tools(server)
78
+ rename = getattr(server, "rename_tool", None)
79
+
80
+ if not callable(rename):
81
+ logger.info(
82
+ "Tool renaming not supported; prefix '%s', tools=%d",
83
+ prefix,
84
+ len(tools),
85
+ )
86
+ return
87
+
88
+ renamed_count = 0
89
+
90
+ for local_name in list(tools.keys()):
91
+ # Calculate final name length: prefix + "_" + local_name
92
+ final_len = len(prefix) + 1 + len(local_name)
93
+
94
+ if final_len > limit:
95
+ # Calculate how much of the local name we can keep
96
+ keep = max(1, limit - len(prefix) - 1)
97
+ short_local = local_name[:keep]
98
+
99
+ if short_local != local_name:
100
+ try:
101
+ rename(local_name, short_local)
102
+ renamed_count += 1
103
+ logger.debug(
104
+ "Renamed tool '%s' to '%s' (prefix: %s)",
105
+ local_name,
106
+ short_local,
107
+ prefix,
108
+ )
109
+ except Exception as e:
110
+ logger.warning("Failed to rename tool '%s': %s", local_name, e)
111
+
112
+ if renamed_count > 0:
113
+ logger.info(
114
+ "Renamed %d tools for prefix '%s' to fit %d char limit",
115
+ renamed_count,
116
+ prefix,
117
+ limit,
118
+ )
119
+
120
+
121
+ def validate_tool_name(name: str, prefix: str = "") -> bool:
122
+ """
123
+ Validate that a tool name fits within MCP constraints.
124
+
125
+ :param name: The tool name to validate
126
+ :type name: str
127
+ :param prefix: Optional prefix that will be added
128
+ :type prefix: str
129
+ :return: True if the name is valid, False otherwise
130
+ :rtype: bool
131
+ """
132
+ if prefix:
133
+ full_name = f"{prefix}_{name}"
134
+ else:
135
+ full_name = name
136
+
137
+ return len(full_name) <= MAX_TOOL_NAME