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.
@@ -14,4 +14,4 @@
14
14
 
15
15
  """AWS Application Signals MCP Server."""
16
16
 
17
- __version__ = '0.1.9'
17
+ __version__ = '0.1.10'
@@ -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': trace_summaries,
457
- 'TraceCount': len(trace_summaries),
458
- 'Message': f'Retrieved {len(trace_summaries)} traces (limited to prevent size issues)',
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)} traces'
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.9
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=cPlKPRqNSL5d4RkWGdDJ_7jay1qZs4ppnntzxDdr4nw,681
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=F-vanuK8preiRHyI-EbZoOcxTueycDk-rRRPtjmKg5E,28990
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.9.dist-info/METADATA,sha256=WQuVsqGbrqcKZp0SA4cPBIGA0fSRRc_UNJ1ueUcjW78,27162
14
- awslabs_cloudwatch_appsignals_mcp_server-0.1.9.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
15
- awslabs_cloudwatch_appsignals_mcp_server-0.1.9.dist-info/entry_points.txt,sha256=iGwIMLU6AsBawl2Fhqi9GoeWdMGIVtg86-McaaNQqAQ,114
16
- awslabs_cloudwatch_appsignals_mcp_server-0.1.9.dist-info/licenses/LICENSE,sha256=zE1N4JILDTkSIDtdmqdnKKxKEQh_VdqeoAV2230eNOI,10141
17
- awslabs_cloudwatch_appsignals_mcp_server-0.1.9.dist-info/licenses/NOTICE,sha256=Pfbul2Ga0IJU2RMZFHC8QwDvNk72WO2XMn9l3390VYs,108
18
- awslabs_cloudwatch_appsignals_mcp_server-0.1.9.dist-info/RECORD,,
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,,