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,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
|