awslabs.cloudwatch-applicationsignals-mcp-server 0.1.21__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 (36) hide show
  1. awslabs/__init__.py +17 -0
  2. awslabs/cloudwatch_applicationsignals_mcp_server/__init__.py +17 -0
  3. awslabs/cloudwatch_applicationsignals_mcp_server/audit_presentation_utils.py +288 -0
  4. awslabs/cloudwatch_applicationsignals_mcp_server/audit_utils.py +912 -0
  5. awslabs/cloudwatch_applicationsignals_mcp_server/aws_clients.py +120 -0
  6. awslabs/cloudwatch_applicationsignals_mcp_server/canary_utils.py +910 -0
  7. awslabs/cloudwatch_applicationsignals_mcp_server/enablement_guides/templates/ec2/ec2-dotnet-enablement.md +435 -0
  8. awslabs/cloudwatch_applicationsignals_mcp_server/enablement_guides/templates/ec2/ec2-java-enablement.md +321 -0
  9. awslabs/cloudwatch_applicationsignals_mcp_server/enablement_guides/templates/ec2/ec2-nodejs-enablement.md +420 -0
  10. awslabs/cloudwatch_applicationsignals_mcp_server/enablement_guides/templates/ec2/ec2-python-enablement.md +598 -0
  11. awslabs/cloudwatch_applicationsignals_mcp_server/enablement_guides/templates/ecs/ecs-dotnet-enablement.md +264 -0
  12. awslabs/cloudwatch_applicationsignals_mcp_server/enablement_guides/templates/ecs/ecs-java-enablement.md +193 -0
  13. awslabs/cloudwatch_applicationsignals_mcp_server/enablement_guides/templates/ecs/ecs-nodejs-enablement.md +198 -0
  14. awslabs/cloudwatch_applicationsignals_mcp_server/enablement_guides/templates/ecs/ecs-python-enablement.md +236 -0
  15. awslabs/cloudwatch_applicationsignals_mcp_server/enablement_guides/templates/eks/eks-dotnet-enablement.md +166 -0
  16. awslabs/cloudwatch_applicationsignals_mcp_server/enablement_guides/templates/eks/eks-java-enablement.md +166 -0
  17. awslabs/cloudwatch_applicationsignals_mcp_server/enablement_guides/templates/eks/eks-nodejs-enablement.md +166 -0
  18. awslabs/cloudwatch_applicationsignals_mcp_server/enablement_guides/templates/eks/eks-python-enablement.md +169 -0
  19. awslabs/cloudwatch_applicationsignals_mcp_server/enablement_guides/templates/lambda/lambda-dotnet-enablement.md +336 -0
  20. awslabs/cloudwatch_applicationsignals_mcp_server/enablement_guides/templates/lambda/lambda-java-enablement.md +336 -0
  21. awslabs/cloudwatch_applicationsignals_mcp_server/enablement_guides/templates/lambda/lambda-nodejs-enablement.md +336 -0
  22. awslabs/cloudwatch_applicationsignals_mcp_server/enablement_guides/templates/lambda/lambda-python-enablement.md +336 -0
  23. awslabs/cloudwatch_applicationsignals_mcp_server/enablement_tools.py +147 -0
  24. awslabs/cloudwatch_applicationsignals_mcp_server/server.py +1505 -0
  25. awslabs/cloudwatch_applicationsignals_mcp_server/service_audit_utils.py +231 -0
  26. awslabs/cloudwatch_applicationsignals_mcp_server/service_tools.py +659 -0
  27. awslabs/cloudwatch_applicationsignals_mcp_server/sli_report_client.py +333 -0
  28. awslabs/cloudwatch_applicationsignals_mcp_server/slo_tools.py +386 -0
  29. awslabs/cloudwatch_applicationsignals_mcp_server/trace_tools.py +784 -0
  30. awslabs/cloudwatch_applicationsignals_mcp_server/utils.py +172 -0
  31. awslabs_cloudwatch_applicationsignals_mcp_server-0.1.21.dist-info/METADATA +808 -0
  32. awslabs_cloudwatch_applicationsignals_mcp_server-0.1.21.dist-info/RECORD +36 -0
  33. awslabs_cloudwatch_applicationsignals_mcp_server-0.1.21.dist-info/WHEEL +4 -0
  34. awslabs_cloudwatch_applicationsignals_mcp_server-0.1.21.dist-info/entry_points.txt +2 -0
  35. awslabs_cloudwatch_applicationsignals_mcp_server-0.1.21.dist-info/licenses/LICENSE +174 -0
  36. awslabs_cloudwatch_applicationsignals_mcp_server-0.1.21.dist-info/licenses/NOTICE +2 -0
@@ -0,0 +1,172 @@
1
+ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """CloudWatch Application Signals MCP Server - Utility functions."""
16
+
17
+ from datetime import datetime, timedelta, timezone
18
+
19
+
20
+ def remove_null_values(data: dict) -> dict:
21
+ """Remove keys with None values from a dictionary.
22
+
23
+ Args:
24
+ data: Dictionary to clean
25
+
26
+ Returns:
27
+ Dictionary with None values removed
28
+ """
29
+ return {k: v for k, v in data.items() if v is not None}
30
+
31
+
32
+ def parse_timestamp(timestamp_str: str, default_hours: int = 24) -> datetime:
33
+ """Parse timestamp string into datetime object.
34
+
35
+ Args:
36
+ timestamp_str: Timestamp in unix seconds or 'YYYY-MM-DD HH:MM:SS' format
37
+ default_hours: Default hours to subtract from now if parsing fails
38
+
39
+ Returns:
40
+ datetime object in UTC timezone
41
+ """
42
+ try:
43
+ # Ensure we have a string
44
+ if not isinstance(timestamp_str, str):
45
+ timestamp_str = str(timestamp_str)
46
+
47
+ # Try parsing as unix timestamp first
48
+ if timestamp_str.isdigit():
49
+ return datetime.fromtimestamp(int(timestamp_str), tz=timezone.utc)
50
+
51
+ # Try parsing as ISO format
52
+ if 'T' in timestamp_str:
53
+ return datetime.fromisoformat(timestamp_str.replace('Z', '+00:00'))
54
+
55
+ # Try parsing as 'YYYY-MM-DD HH:MM:SS' format
56
+ return datetime.strptime(timestamp_str, '%Y-%m-%d %H:%M:%S').replace(tzinfo=timezone.utc)
57
+ except (ValueError, TypeError):
58
+ # Fallback to default
59
+ return datetime.now(timezone.utc) - timedelta(hours=default_hours)
60
+
61
+
62
+ def calculate_name_similarity(
63
+ target_name: str, candidate_name: str, name_type: str = 'service'
64
+ ) -> int:
65
+ """Calculate similarity score between target name and candidate name.
66
+
67
+ Args:
68
+ target_name: The name the user is looking for
69
+ candidate_name: A candidate name from the API
70
+ name_type: Type of name being matched ("service" or "slo")
71
+
72
+ Returns:
73
+ Similarity score (0-100, higher is better match)
74
+ """
75
+ target_lower = target_name.lower().strip()
76
+ candidate_lower = candidate_name.lower().strip()
77
+
78
+ # Handle empty strings
79
+ if not target_lower or not candidate_lower:
80
+ return 0
81
+
82
+ # Exact match (case insensitive)
83
+ if target_lower == candidate_lower:
84
+ return 100
85
+
86
+ # Normalize for special characters (treat -, _, . as equivalent)
87
+ target_normalized = target_lower.replace('_', '-').replace('.', '-')
88
+ candidate_normalized = candidate_lower.replace('_', '-').replace('.', '-')
89
+
90
+ if target_normalized == candidate_normalized:
91
+ return 95
92
+
93
+ score = 0
94
+
95
+ # Word-based matching (most important for fuzzy matching)
96
+ target_words = set(target_normalized.split())
97
+ candidate_words = set(candidate_normalized.split())
98
+
99
+ if target_words and candidate_words:
100
+ common_words = target_words.intersection(candidate_words)
101
+ if common_words:
102
+ # Calculate word match ratio
103
+ word_match_ratio = len(common_words) / len(target_words.union(candidate_words))
104
+ score += int(word_match_ratio * 60) # Up to 60 points for word matches
105
+
106
+ # Bonus for high word overlap
107
+ target_coverage = len(common_words) / len(target_words)
108
+
109
+ if target_coverage >= 0.8: # 80% of target words found
110
+ score += 20
111
+ elif target_coverage >= 0.6: # 60% of target words found
112
+ score += 10
113
+
114
+ # Substring matching (secondary)
115
+ if target_normalized in candidate_normalized:
116
+ # Target is contained in candidate
117
+ containment_ratio = len(target_normalized) / len(candidate_normalized)
118
+ score += int(containment_ratio * 30) # Up to 30 points
119
+ elif candidate_normalized in target_normalized:
120
+ # Candidate is contained in target
121
+ containment_ratio = len(candidate_normalized) / len(target_normalized)
122
+ score += int(containment_ratio * 25) # Up to 25 points
123
+
124
+ # Check for key domain terms that should boost relevance
125
+ if name_type == 'slo':
126
+ key_terms = [
127
+ 'availability',
128
+ 'latency',
129
+ 'error',
130
+ 'fault',
131
+ 'search',
132
+ 'owner',
133
+ 'response',
134
+ 'time',
135
+ 'success',
136
+ 'failure',
137
+ 'request',
138
+ 'operation',
139
+ ]
140
+ else: # service
141
+ key_terms = [
142
+ 'service',
143
+ 'api',
144
+ 'web',
145
+ 'app',
146
+ 'backend',
147
+ 'frontend',
148
+ 'database',
149
+ 'cache',
150
+ 'queue',
151
+ 'worker',
152
+ 'lambda',
153
+ 'function',
154
+ 'microservice',
155
+ ]
156
+
157
+ common_key_terms = 0
158
+ for term in key_terms:
159
+ if term in target_normalized and term in candidate_normalized:
160
+ common_key_terms += 1
161
+
162
+ if common_key_terms > 0:
163
+ score += common_key_terms * 8 # Up to 8 points per key term
164
+
165
+ # Penalize very different lengths (likely different concepts)
166
+ length_diff = abs(len(target_normalized) - len(candidate_normalized))
167
+ if length_diff > 20:
168
+ score = max(0, score - 15)
169
+ elif length_diff > 10:
170
+ score = max(0, score - 5)
171
+
172
+ return min(100, score)