awslabs.cloudwatch-appsignals-mcp-server 0.1.9__py3-none-any.whl → 0.1.10__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.
- awslabs/cloudwatch_appsignals_mcp_server/__init__.py +1 -1
- awslabs/cloudwatch_appsignals_mcp_server/trace_tools.py +71 -13
- {awslabs_cloudwatch_appsignals_mcp_server-0.1.9.dist-info → awslabs_cloudwatch_appsignals_mcp_server-0.1.10.dist-info}/METADATA +1 -1
- {awslabs_cloudwatch_appsignals_mcp_server-0.1.9.dist-info → awslabs_cloudwatch_appsignals_mcp_server-0.1.10.dist-info}/RECORD +8 -8
- {awslabs_cloudwatch_appsignals_mcp_server-0.1.9.dist-info → awslabs_cloudwatch_appsignals_mcp_server-0.1.10.dist-info}/WHEEL +0 -0
- {awslabs_cloudwatch_appsignals_mcp_server-0.1.9.dist-info → awslabs_cloudwatch_appsignals_mcp_server-0.1.10.dist-info}/entry_points.txt +0 -0
- {awslabs_cloudwatch_appsignals_mcp_server-0.1.9.dist-info → awslabs_cloudwatch_appsignals_mcp_server-0.1.10.dist-info}/licenses/LICENSE +0 -0
- {awslabs_cloudwatch_appsignals_mcp_server-0.1.9.dist-info → awslabs_cloudwatch_appsignals_mcp_server-0.1.10.dist-info}/licenses/NOTICE +0 -0
|
@@ -402,6 +402,26 @@ async def query_sampled_traces(
|
|
|
402
402
|
return obj.isoformat()
|
|
403
403
|
return obj
|
|
404
404
|
|
|
405
|
+
# Helper function to extract fault message from root causes for deduplication
|
|
406
|
+
def get_fault_message(trace_data):
|
|
407
|
+
"""Extract fault message from a trace for deduplication.
|
|
408
|
+
|
|
409
|
+
Only checks FaultRootCauses (5xx server errors) since this is the primary
|
|
410
|
+
use case for root cause investigation. Traces without fault messages are
|
|
411
|
+
not deduplicated.
|
|
412
|
+
"""
|
|
413
|
+
# Only check FaultRootCauses for deduplication
|
|
414
|
+
root_causes = trace_data.get('FaultRootCauses', [])
|
|
415
|
+
if root_causes:
|
|
416
|
+
for cause in root_causes:
|
|
417
|
+
services = cause.get('Services', [])
|
|
418
|
+
for service in services:
|
|
419
|
+
exceptions = service.get('Exceptions', [])
|
|
420
|
+
if exceptions and exceptions[0].get('Message'):
|
|
421
|
+
return exceptions[0].get('Message')
|
|
422
|
+
return None
|
|
423
|
+
|
|
424
|
+
# Build trace summaries (original format)
|
|
405
425
|
trace_summaries = []
|
|
406
426
|
for trace in traces:
|
|
407
427
|
# Create a simplified trace data structure to reduce size
|
|
@@ -417,17 +437,11 @@ async def query_sampled_traces(
|
|
|
417
437
|
|
|
418
438
|
# Only include root causes if they exist (to save space)
|
|
419
439
|
if trace.get('ErrorRootCauses'):
|
|
420
|
-
trace_data['ErrorRootCauses'] = trace.get('ErrorRootCauses', [])[
|
|
421
|
-
:3
|
|
422
|
-
] # Limit to first 3
|
|
440
|
+
trace_data['ErrorRootCauses'] = trace.get('ErrorRootCauses', [])[:3]
|
|
423
441
|
if trace.get('FaultRootCauses'):
|
|
424
|
-
trace_data['FaultRootCauses'] = trace.get('FaultRootCauses', [])[
|
|
425
|
-
:3
|
|
426
|
-
] # Limit to first 3
|
|
442
|
+
trace_data['FaultRootCauses'] = trace.get('FaultRootCauses', [])[:3]
|
|
427
443
|
if trace.get('ResponseTimeRootCauses'):
|
|
428
|
-
trace_data['ResponseTimeRootCauses'] = trace.get('ResponseTimeRootCauses', [])[
|
|
429
|
-
:3
|
|
430
|
-
] # Limit to first 3
|
|
444
|
+
trace_data['ResponseTimeRootCauses'] = trace.get('ResponseTimeRootCauses', [])[:3]
|
|
431
445
|
|
|
432
446
|
# Include limited annotations for key operations
|
|
433
447
|
annotations = trace.get('Annotations', {})
|
|
@@ -447,15 +461,50 @@ async def query_sampled_traces(
|
|
|
447
461
|
# Convert any datetime objects to ISO format strings
|
|
448
462
|
for key, value in trace_data.items():
|
|
449
463
|
trace_data[key] = convert_datetime(value)
|
|
464
|
+
|
|
450
465
|
trace_summaries.append(trace_data)
|
|
451
466
|
|
|
467
|
+
# Deduplicate trace summaries by fault message
|
|
468
|
+
seen_faults = {}
|
|
469
|
+
deduped_trace_summaries = []
|
|
470
|
+
|
|
471
|
+
for trace_summary in trace_summaries:
|
|
472
|
+
# Check if this trace has an error
|
|
473
|
+
has_issues = (
|
|
474
|
+
trace_summary.get('HasError')
|
|
475
|
+
or trace_summary.get('HasFault')
|
|
476
|
+
or trace_summary.get('HasThrottle')
|
|
477
|
+
)
|
|
478
|
+
|
|
479
|
+
if not has_issues:
|
|
480
|
+
# Always include healthy traces
|
|
481
|
+
deduped_trace_summaries.append(trace_summary)
|
|
482
|
+
continue
|
|
483
|
+
|
|
484
|
+
# Extract fault message for deduplication (only checks FaultRootCauses)
|
|
485
|
+
fault_msg = get_fault_message(trace_summary)
|
|
486
|
+
|
|
487
|
+
if fault_msg and fault_msg in seen_faults:
|
|
488
|
+
# Skip this trace - we already have one with the same fault message
|
|
489
|
+
seen_faults[fault_msg]['count'] += 1
|
|
490
|
+
logger.debug(
|
|
491
|
+
f'Skipping duplicate trace {trace_summary.get("Id")} - fault message already seen: {fault_msg[:100]}...'
|
|
492
|
+
)
|
|
493
|
+
continue
|
|
494
|
+
else:
|
|
495
|
+
# First time seeing this fault (or no fault message) - include it
|
|
496
|
+
deduped_trace_summaries.append(trace_summary)
|
|
497
|
+
if fault_msg:
|
|
498
|
+
seen_faults[fault_msg] = {'count': 1}
|
|
499
|
+
|
|
452
500
|
# Check transaction search status
|
|
453
501
|
is_tx_search_enabled, tx_destination, tx_status = check_transaction_search_enabled(region)
|
|
454
502
|
|
|
503
|
+
# Build response with original format but deduplicated traces
|
|
455
504
|
result_data = {
|
|
456
|
-
'TraceSummaries':
|
|
457
|
-
'TraceCount': len(
|
|
458
|
-
'Message': f'Retrieved {len(
|
|
505
|
+
'TraceSummaries': deduped_trace_summaries,
|
|
506
|
+
'TraceCount': len(deduped_trace_summaries),
|
|
507
|
+
'Message': f'Retrieved {len(deduped_trace_summaries)} unique traces from {len(trace_summaries)} total (deduplicated by fault message)',
|
|
459
508
|
'SamplingNote': "⚠️ This data is from X-Ray's 5% sampling. Results may not show all errors or issues.",
|
|
460
509
|
'TransactionSearchStatus': {
|
|
461
510
|
'enabled': is_tx_search_enabled,
|
|
@@ -467,9 +516,18 @@ async def query_sampled_traces(
|
|
|
467
516
|
},
|
|
468
517
|
}
|
|
469
518
|
|
|
519
|
+
# Add dedup stats if we actually deduped anything
|
|
520
|
+
if len(deduped_trace_summaries) < len(trace_summaries):
|
|
521
|
+
duplicates_removed = len(trace_summaries) - len(deduped_trace_summaries)
|
|
522
|
+
result_data['DeduplicationStats'] = {
|
|
523
|
+
'OriginalTraceCount': len(trace_summaries),
|
|
524
|
+
'DuplicatesRemoved': duplicates_removed,
|
|
525
|
+
'UniqueFaultMessages': len(seen_faults),
|
|
526
|
+
}
|
|
527
|
+
|
|
470
528
|
elapsed_time = timer() - start_time_perf
|
|
471
529
|
logger.info(
|
|
472
|
-
f'query_sampled_traces completed in {elapsed_time:.3f}s - retrieved {len(trace_summaries)}
|
|
530
|
+
f'query_sampled_traces completed in {elapsed_time:.3f}s - retrieved {len(deduped_trace_summaries)} unique traces from {len(trace_summaries)} total'
|
|
473
531
|
)
|
|
474
532
|
return json.dumps(result_data, indent=2)
|
|
475
533
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: awslabs.cloudwatch-appsignals-mcp-server
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.10
|
|
4
4
|
Summary: An AWS Labs Model Context Protocol (MCP) server for AWS Application Signals
|
|
5
5
|
Project-URL: Homepage, https://awslabs.github.io/mcp/
|
|
6
6
|
Project-URL: Documentation, https://awslabs.github.io/mcp/servers/cloudwatch-appsignals-mcp-server/
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
awslabs/__init__.py,sha256=WuqxdDgUZylWNmVoPKiK7qGsTB_G4UmuXIrJ-VBwDew,731
|
|
2
|
-
awslabs/cloudwatch_appsignals_mcp_server/__init__.py,sha256=
|
|
2
|
+
awslabs/cloudwatch_appsignals_mcp_server/__init__.py,sha256=zmAQBvB227-Fwnes1CNk2nNM9eZwfTvbfkycgYypGKk,682
|
|
3
3
|
awslabs/cloudwatch_appsignals_mcp_server/audit_presentation_utils.py,sha256=xYJz0I-wdigYKxAaVLjyoMUh2UQpwlZM7sFxfL2pPmw,8923
|
|
4
4
|
awslabs/cloudwatch_appsignals_mcp_server/audit_utils.py,sha256=Mqa8q3MUMpDKRFJQgUoKYikknGO4sBIe2_-0e2BWlCA,30765
|
|
5
5
|
awslabs/cloudwatch_appsignals_mcp_server/aws_clients.py,sha256=I-amnrnVLGv-gAPkEYo-AxvmqktBjpdEuB1pjeTO1Fs,3542
|
|
@@ -8,11 +8,11 @@ awslabs/cloudwatch_appsignals_mcp_server/service_audit_utils.py,sha256=i-6emomFi
|
|
|
8
8
|
awslabs/cloudwatch_appsignals_mcp_server/service_tools.py,sha256=iJnkROnR0FdxEgF0LJb5zYNcD-CCSa9LVXwUqxU1_tI,29093
|
|
9
9
|
awslabs/cloudwatch_appsignals_mcp_server/sli_report_client.py,sha256=LGs7tDLVVa3mbT_maTefwGEA3cl3fNVft9brh3lVTzM,12374
|
|
10
10
|
awslabs/cloudwatch_appsignals_mcp_server/slo_tools.py,sha256=dMLGqeZYHu2adk9uquBGIZkMZStb-puzlI0xtKhxYNI,17824
|
|
11
|
-
awslabs/cloudwatch_appsignals_mcp_server/trace_tools.py,sha256=
|
|
11
|
+
awslabs/cloudwatch_appsignals_mcp_server/trace_tools.py,sha256=SMIaxStaJNZOU4GaAFkUiNXrb978bPTlF7MRBRJVEP8,31785
|
|
12
12
|
awslabs/cloudwatch_appsignals_mcp_server/utils.py,sha256=nZBqiCBAUewQft26FVf4IGL4P1b152VAcG9Y7Mh0gZY,5782
|
|
13
|
-
awslabs_cloudwatch_appsignals_mcp_server-0.1.
|
|
14
|
-
awslabs_cloudwatch_appsignals_mcp_server-0.1.
|
|
15
|
-
awslabs_cloudwatch_appsignals_mcp_server-0.1.
|
|
16
|
-
awslabs_cloudwatch_appsignals_mcp_server-0.1.
|
|
17
|
-
awslabs_cloudwatch_appsignals_mcp_server-0.1.
|
|
18
|
-
awslabs_cloudwatch_appsignals_mcp_server-0.1.
|
|
13
|
+
awslabs_cloudwatch_appsignals_mcp_server-0.1.10.dist-info/METADATA,sha256=JxgaSJRwabngeigjaRlEx3uFMOq-ATyMEZxxN4cQtxQ,27163
|
|
14
|
+
awslabs_cloudwatch_appsignals_mcp_server-0.1.10.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
15
|
+
awslabs_cloudwatch_appsignals_mcp_server-0.1.10.dist-info/entry_points.txt,sha256=iGwIMLU6AsBawl2Fhqi9GoeWdMGIVtg86-McaaNQqAQ,114
|
|
16
|
+
awslabs_cloudwatch_appsignals_mcp_server-0.1.10.dist-info/licenses/LICENSE,sha256=zE1N4JILDTkSIDtdmqdnKKxKEQh_VdqeoAV2230eNOI,10141
|
|
17
|
+
awslabs_cloudwatch_appsignals_mcp_server-0.1.10.dist-info/licenses/NOTICE,sha256=Pfbul2Ga0IJU2RMZFHC8QwDvNk72WO2XMn9l3390VYs,108
|
|
18
|
+
awslabs_cloudwatch_appsignals_mcp_server-0.1.10.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|