awslabs.cloudwatch-mcp-server 0.0.6__tar.gz → 0.0.8__tar.gz

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 (37) hide show
  1. {awslabs_cloudwatch_mcp_server-0.0.6 → awslabs_cloudwatch_mcp_server-0.0.8}/PKG-INFO +2 -2
  2. {awslabs_cloudwatch_mcp_server-0.0.6 → awslabs_cloudwatch_mcp_server-0.0.8}/README.md +1 -1
  3. {awslabs_cloudwatch_mcp_server-0.0.6 → awslabs_cloudwatch_mcp_server-0.0.8}/awslabs/cloudwatch_mcp_server/cloudwatch_logs/tools.py +2 -0
  4. {awslabs_cloudwatch_mcp_server-0.0.6 → awslabs_cloudwatch_mcp_server-0.0.8}/pyproject.toml +1 -1
  5. {awslabs_cloudwatch_mcp_server-0.0.6 → awslabs_cloudwatch_mcp_server-0.0.8}/tests/cloudwatch_logs/test_logs_error_handling.py +148 -0
  6. {awslabs_cloudwatch_mcp_server-0.0.6 → awslabs_cloudwatch_mcp_server-0.0.8}/tests/cloudwatch_logs/test_logs_server.py +60 -0
  7. {awslabs_cloudwatch_mcp_server-0.0.6 → awslabs_cloudwatch_mcp_server-0.0.8}/.gitignore +0 -0
  8. {awslabs_cloudwatch_mcp_server-0.0.6 → awslabs_cloudwatch_mcp_server-0.0.8}/.python-version +0 -0
  9. {awslabs_cloudwatch_mcp_server-0.0.6 → awslabs_cloudwatch_mcp_server-0.0.8}/CHANGELOG.md +0 -0
  10. {awslabs_cloudwatch_mcp_server-0.0.6 → awslabs_cloudwatch_mcp_server-0.0.8}/Dockerfile +0 -0
  11. {awslabs_cloudwatch_mcp_server-0.0.6 → awslabs_cloudwatch_mcp_server-0.0.8}/LICENSE +0 -0
  12. {awslabs_cloudwatch_mcp_server-0.0.6 → awslabs_cloudwatch_mcp_server-0.0.8}/NOTICE +0 -0
  13. {awslabs_cloudwatch_mcp_server-0.0.6 → awslabs_cloudwatch_mcp_server-0.0.8}/awslabs/__init__.py +0 -0
  14. {awslabs_cloudwatch_mcp_server-0.0.6 → awslabs_cloudwatch_mcp_server-0.0.8}/awslabs/cloudwatch_mcp_server/__init__.py +0 -0
  15. {awslabs_cloudwatch_mcp_server-0.0.6 → awslabs_cloudwatch_mcp_server-0.0.8}/awslabs/cloudwatch_mcp_server/cloudwatch_alarms/models.py +0 -0
  16. {awslabs_cloudwatch_mcp_server-0.0.6 → awslabs_cloudwatch_mcp_server-0.0.8}/awslabs/cloudwatch_mcp_server/cloudwatch_alarms/tools.py +0 -0
  17. {awslabs_cloudwatch_mcp_server-0.0.6 → awslabs_cloudwatch_mcp_server-0.0.8}/awslabs/cloudwatch_mcp_server/cloudwatch_logs/models.py +0 -0
  18. {awslabs_cloudwatch_mcp_server-0.0.6 → awslabs_cloudwatch_mcp_server-0.0.8}/awslabs/cloudwatch_mcp_server/cloudwatch_metrics/data/metric_metadata.json +0 -0
  19. {awslabs_cloudwatch_mcp_server-0.0.6 → awslabs_cloudwatch_mcp_server-0.0.8}/awslabs/cloudwatch_mcp_server/cloudwatch_metrics/models.py +0 -0
  20. {awslabs_cloudwatch_mcp_server-0.0.6 → awslabs_cloudwatch_mcp_server-0.0.8}/awslabs/cloudwatch_mcp_server/cloudwatch_metrics/tools.py +0 -0
  21. {awslabs_cloudwatch_mcp_server-0.0.6 → awslabs_cloudwatch_mcp_server-0.0.8}/awslabs/cloudwatch_mcp_server/common.py +0 -0
  22. {awslabs_cloudwatch_mcp_server-0.0.6 → awslabs_cloudwatch_mcp_server-0.0.8}/awslabs/cloudwatch_mcp_server/server.py +0 -0
  23. {awslabs_cloudwatch_mcp_server-0.0.6 → awslabs_cloudwatch_mcp_server-0.0.8}/docker-healthcheck.sh +0 -0
  24. {awslabs_cloudwatch_mcp_server-0.0.6 → awslabs_cloudwatch_mcp_server-0.0.8}/tests/cloudwatch_alarms/test_active_alarms.py +0 -0
  25. {awslabs_cloudwatch_mcp_server-0.0.6 → awslabs_cloudwatch_mcp_server-0.0.8}/tests/cloudwatch_alarms/test_alarm_history.py +0 -0
  26. {awslabs_cloudwatch_mcp_server-0.0.6 → awslabs_cloudwatch_mcp_server-0.0.8}/tests/cloudwatch_alarms/test_alarm_history_integration.py +0 -0
  27. {awslabs_cloudwatch_mcp_server-0.0.6 → awslabs_cloudwatch_mcp_server-0.0.8}/tests/cloudwatch_alarms/test_alarms_error_handling.py +0 -0
  28. {awslabs_cloudwatch_mcp_server-0.0.6 → awslabs_cloudwatch_mcp_server-0.0.8}/tests/cloudwatch_logs/test_logs_models.py +0 -0
  29. {awslabs_cloudwatch_mcp_server-0.0.6 → awslabs_cloudwatch_mcp_server-0.0.8}/tests/cloudwatch_metrics/test_metrics_error_handling.py +0 -0
  30. {awslabs_cloudwatch_mcp_server-0.0.6 → awslabs_cloudwatch_mcp_server-0.0.8}/tests/cloudwatch_metrics/test_metrics_models.py +0 -0
  31. {awslabs_cloudwatch_mcp_server-0.0.6 → awslabs_cloudwatch_mcp_server-0.0.8}/tests/cloudwatch_metrics/test_metrics_server.py +0 -0
  32. {awslabs_cloudwatch_mcp_server-0.0.6 → awslabs_cloudwatch_mcp_server-0.0.8}/tests/cloudwatch_metrics/test_validation_error.py +0 -0
  33. {awslabs_cloudwatch_mcp_server-0.0.6 → awslabs_cloudwatch_mcp_server-0.0.8}/tests/test_common_and_server.py +0 -0
  34. {awslabs_cloudwatch_mcp_server-0.0.6 → awslabs_cloudwatch_mcp_server-0.0.8}/tests/test_init.py +0 -0
  35. {awslabs_cloudwatch_mcp_server-0.0.6 → awslabs_cloudwatch_mcp_server-0.0.8}/tests/test_main.py +0 -0
  36. {awslabs_cloudwatch_mcp_server-0.0.6 → awslabs_cloudwatch_mcp_server-0.0.8}/uv-requirements.txt +0 -0
  37. {awslabs_cloudwatch_mcp_server-0.0.6 → awslabs_cloudwatch_mcp_server-0.0.8}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: awslabs.cloudwatch-mcp-server
3
- Version: 0.0.6
3
+ Version: 0.0.8
4
4
  Summary: An AWS Labs Model Context Protocol (MCP) server for cloudwatch
5
5
  Project-URL: homepage, https://awslabs.github.io/mcp/
6
6
  Project-URL: docs, https://awslabs.github.io/mcp/servers/cloudwatch-mcp-server/
@@ -95,7 +95,7 @@ Alarm Recommendations - Suggests recommended alarm configurations for CloudWatch
95
95
 
96
96
  | Cursor | VS Code |
97
97
  |:------:|:-------:|
98
- | [![Install MCP Server](https://cursor.com/deeplink/mcp-install-light.svg)](https://cursor.com/install-mcp?name=awslabs.cloudwatch-mcp-server&config=ewogICAgImF1dG9BcHByb3ZlIjogW10sCiAgICAiZGlzYWJsZWQiOiBmYWxzZSwKICAgICJjb21tYW5kIjogInV2eCBhd3NsYWJzLmNsb3Vkd2F0Y2gtbWNwLXNlcnZlckBsYXRlc3QiLAogICAgImVudiI6IHsKICAgICAgIkFXU19QUk9GSUxFIjogIltUaGUgQVdTIFByb2ZpbGUgTmFtZSB0byB1c2UgZm9yIEFXUyBhY2Nlc3NdIiwKICAgICAgIkZBU1RNQ1BfTE9HX0xFVkVMIjogIkVSUk9SIgogICAgfSwKICAgICJ0cmFuc3BvcnRUeXBlIjogInN0ZGlvIgp9) | [![Install on VS Code](https://img.shields.io/badge/Install_on-VS_Code-FF9900?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=CloudWatch%20MCP%20Server&config=%7B%22autoApprove%22%3A%5B%5D%2C%22disabled%22%3Afalse%2C%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22awslabs.cloudwatch-mcp-server%40latest%22%5D%2C%22env%22%3A%7B%22AWS_PROFILE%22%3A%22%5BThe%20AWS%20Profile%20Name%20to%20use%20for%20AWS%20access%5D%22%2C%22FASTMCP_LOG_LEVEL%22%3A%22ERROR%22%7D%2C%22transportType%22%3A%22stdio%22%7D) |
98
+ | [![Install MCP Server](https://cursor.com/deeplink/mcp-install-light.svg)](https://cursor.com/en/install-mcp?name=awslabs.cloudwatch-mcp-server&config=ewogICAgImF1dG9BcHByb3ZlIjogW10sCiAgICAiZGlzYWJsZWQiOiBmYWxzZSwKICAgICJjb21tYW5kIjogInV2eCBhd3NsYWJzLmNsb3Vkd2F0Y2gtbWNwLXNlcnZlckBsYXRlc3QiLAogICAgImVudiI6IHsKICAgICAgIkFXU19QUk9GSUxFIjogIltUaGUgQVdTIFByb2ZpbGUgTmFtZSB0byB1c2UgZm9yIEFXUyBhY2Nlc3NdIiwKICAgICAgIkZBU1RNQ1BfTE9HX0xFVkVMIjogIkVSUk9SIgogICAgfSwKICAgICJ0cmFuc3BvcnRUeXBlIjogInN0ZGlvIgp9) | [![Install on VS Code](https://img.shields.io/badge/Install_on-VS_Code-FF9900?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=CloudWatch%20MCP%20Server&config=%7B%22autoApprove%22%3A%5B%5D%2C%22disabled%22%3Afalse%2C%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22awslabs.cloudwatch-mcp-server%40latest%22%5D%2C%22env%22%3A%7B%22AWS_PROFILE%22%3A%22%5BThe%20AWS%20Profile%20Name%20to%20use%20for%20AWS%20access%5D%22%2C%22FASTMCP_LOG_LEVEL%22%3A%22ERROR%22%7D%2C%22transportType%22%3A%22stdio%22%7D) |
99
99
 
100
100
  #### MCP Config (Q CLI, Cline)
101
101
  * For Q CLI, update MCP Config Amazon Q Developer CLI (~/.aws/amazonq/mcp.json)
@@ -66,7 +66,7 @@ Alarm Recommendations - Suggests recommended alarm configurations for CloudWatch
66
66
 
67
67
  | Cursor | VS Code |
68
68
  |:------:|:-------:|
69
- | [![Install MCP Server](https://cursor.com/deeplink/mcp-install-light.svg)](https://cursor.com/install-mcp?name=awslabs.cloudwatch-mcp-server&config=ewogICAgImF1dG9BcHByb3ZlIjogW10sCiAgICAiZGlzYWJsZWQiOiBmYWxzZSwKICAgICJjb21tYW5kIjogInV2eCBhd3NsYWJzLmNsb3Vkd2F0Y2gtbWNwLXNlcnZlckBsYXRlc3QiLAogICAgImVudiI6IHsKICAgICAgIkFXU19QUk9GSUxFIjogIltUaGUgQVdTIFByb2ZpbGUgTmFtZSB0byB1c2UgZm9yIEFXUyBhY2Nlc3NdIiwKICAgICAgIkZBU1RNQ1BfTE9HX0xFVkVMIjogIkVSUk9SIgogICAgfSwKICAgICJ0cmFuc3BvcnRUeXBlIjogInN0ZGlvIgp9) | [![Install on VS Code](https://img.shields.io/badge/Install_on-VS_Code-FF9900?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=CloudWatch%20MCP%20Server&config=%7B%22autoApprove%22%3A%5B%5D%2C%22disabled%22%3Afalse%2C%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22awslabs.cloudwatch-mcp-server%40latest%22%5D%2C%22env%22%3A%7B%22AWS_PROFILE%22%3A%22%5BThe%20AWS%20Profile%20Name%20to%20use%20for%20AWS%20access%5D%22%2C%22FASTMCP_LOG_LEVEL%22%3A%22ERROR%22%7D%2C%22transportType%22%3A%22stdio%22%7D) |
69
+ | [![Install MCP Server](https://cursor.com/deeplink/mcp-install-light.svg)](https://cursor.com/en/install-mcp?name=awslabs.cloudwatch-mcp-server&config=ewogICAgImF1dG9BcHByb3ZlIjogW10sCiAgICAiZGlzYWJsZWQiOiBmYWxzZSwKICAgICJjb21tYW5kIjogInV2eCBhd3NsYWJzLmNsb3Vkd2F0Y2gtbWNwLXNlcnZlckBsYXRlc3QiLAogICAgImVudiI6IHsKICAgICAgIkFXU19QUk9GSUxFIjogIltUaGUgQVdTIFByb2ZpbGUgTmFtZSB0byB1c2UgZm9yIEFXUyBhY2Nlc3NdIiwKICAgICAgIkZBU1RNQ1BfTE9HX0xFVkVMIjogIkVSUk9SIgogICAgfSwKICAgICJ0cmFuc3BvcnRUeXBlIjogInN0ZGlvIgp9) | [![Install on VS Code](https://img.shields.io/badge/Install_on-VS_Code-FF9900?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=CloudWatch%20MCP%20Server&config=%7B%22autoApprove%22%3A%5B%5D%2C%22disabled%22%3Afalse%2C%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22awslabs.cloudwatch-mcp-server%40latest%22%5D%2C%22env%22%3A%7B%22AWS_PROFILE%22%3A%22%5BThe%20AWS%20Profile%20Name%20to%20use%20for%20AWS%20access%5D%22%2C%22FASTMCP_LOG_LEVEL%22%3A%22ERROR%22%7D%2C%22transportType%22%3A%22stdio%22%7D) |
70
70
 
71
71
  #### MCP Config (Q CLI, Cline)
72
72
  * For Q CLI, update MCP Config Amazon Q Developer CLI (~/.aws/amazonq/mcp.json)
@@ -451,6 +451,7 @@ class CloudWatchLogsTools:
451
451
  query_string='pattern @message | sort @sampleCount desc | limit 5',
452
452
  limit=5,
453
453
  max_timeout=30,
454
+ region=region,
454
455
  ),
455
456
  self.execute_log_insights_query(
456
457
  ctx,
@@ -461,6 +462,7 @@ class CloudWatchLogsTools:
461
462
  query_string='fields @timestamp, @message | filter @message like /(?i)(error|exception|fail|timeout|fatal)/ | pattern @message | limit 5',
462
463
  limit=5,
463
464
  max_timeout=30,
465
+ region=region,
464
466
  ),
465
467
  )
466
468
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "awslabs.cloudwatch-mcp-server"
3
- version = "0.0.6"
3
+ version = "0.0.8"
4
4
  description = "An AWS Labs Model Context Protocol (MCP) server for cloudwatch"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -386,3 +386,151 @@ class TestEdgeCases:
386
386
  assert params['logGroupNames'] is None
387
387
  assert params['logGroupIdentifiers'] == ['arn:test']
388
388
  assert params['limit'] is None
389
+
390
+
391
+ class TestRegionHandling:
392
+ """Test region parameter handling across tools."""
393
+
394
+ def test_get_logs_client_region_parameter(self):
395
+ """Test that _get_logs_client creates client with correct region."""
396
+ with patch(
397
+ 'awslabs.cloudwatch_mcp_server.cloudwatch_logs.tools.boto3.Session'
398
+ ) as mock_session:
399
+ mock_client = Mock()
400
+ mock_session.return_value.client.return_value = mock_client
401
+
402
+ tools = CloudWatchLogsTools()
403
+ result = tools._get_logs_client('ap-northeast-1')
404
+
405
+ # Verify session was created with correct region
406
+ mock_session.assert_called_with(region_name='ap-northeast-1')
407
+ mock_session.return_value.client.assert_called_with(
408
+ 'logs', config=mock_session.return_value.client.call_args[1]['config']
409
+ )
410
+ assert result == mock_client
411
+
412
+ def test_get_logs_client_with_aws_profile(self):
413
+ """Test _get_logs_client with AWS_PROFILE environment variable."""
414
+ with patch.dict('os.environ', {'AWS_PROFILE': 'test-profile'}):
415
+ with patch(
416
+ 'awslabs.cloudwatch_mcp_server.cloudwatch_logs.tools.boto3.Session'
417
+ ) as mock_session:
418
+ mock_client = Mock()
419
+ mock_session.return_value.client.return_value = mock_client
420
+
421
+ tools = CloudWatchLogsTools()
422
+ result = tools._get_logs_client('ca-central-1')
423
+
424
+ # Verify session was created with profile and region
425
+ mock_session.assert_called_with(
426
+ profile_name='test-profile', region_name='ca-central-1'
427
+ )
428
+ assert result == mock_client
429
+
430
+ @pytest.mark.asyncio
431
+ async def test_execute_log_insights_query_region_parameter(self, mock_context):
432
+ """Test that execute_log_insights_query uses correct region for client creation."""
433
+ with patch(
434
+ 'awslabs.cloudwatch_mcp_server.cloudwatch_logs.tools.boto3.Session'
435
+ ) as mock_session:
436
+ mock_client = Mock()
437
+ mock_client.start_query.return_value = {'queryId': 'test-query-id'}
438
+ mock_client.get_query_results.return_value = {
439
+ 'status': 'Complete',
440
+ 'results': [],
441
+ 'statistics': {},
442
+ }
443
+ mock_session.return_value.client.return_value = mock_client
444
+
445
+ tools = CloudWatchLogsTools()
446
+
447
+ # Mock _get_logs_client to capture the region parameter
448
+ with patch.object(
449
+ tools, '_get_logs_client', return_value=mock_client
450
+ ) as mock_get_client:
451
+ await tools.execute_log_insights_query(
452
+ mock_context,
453
+ log_group_names=['test-group'],
454
+ log_group_identifiers=None,
455
+ start_time='2023-01-01T00:00:00+00:00',
456
+ end_time='2023-01-01T01:00:00+00:00',
457
+ query_string='fields @message',
458
+ region='ap-southeast-2',
459
+ )
460
+
461
+ # Verify _get_logs_client was called with correct region
462
+ mock_get_client.assert_called_once_with('ap-southeast-2')
463
+
464
+ @pytest.mark.asyncio
465
+ async def test_get_logs_insight_query_results_region_parameter(self, mock_context):
466
+ """Test that get_logs_insight_query_results uses correct region for client creation."""
467
+ with patch(
468
+ 'awslabs.cloudwatch_mcp_server.cloudwatch_logs.tools.boto3.Session'
469
+ ) as mock_session:
470
+ mock_client = Mock()
471
+ mock_client.get_query_results.return_value = {
472
+ 'status': 'Complete',
473
+ 'results': [],
474
+ 'statistics': {},
475
+ }
476
+ mock_session.return_value.client.return_value = mock_client
477
+
478
+ tools = CloudWatchLogsTools()
479
+
480
+ # Mock _get_logs_client to capture the region parameter
481
+ with patch.object(
482
+ tools, '_get_logs_client', return_value=mock_client
483
+ ) as mock_get_client:
484
+ await tools.get_logs_insight_query_results(
485
+ mock_context, query_id='test-query-id', region='eu-central-1'
486
+ )
487
+
488
+ # Verify _get_logs_client was called with correct region
489
+ mock_get_client.assert_called_once_with('eu-central-1')
490
+
491
+ @pytest.mark.asyncio
492
+ async def test_cancel_logs_insight_query_region_parameter(self, mock_context):
493
+ """Test that cancel_logs_insight_query uses correct region for client creation."""
494
+ with patch(
495
+ 'awslabs.cloudwatch_mcp_server.cloudwatch_logs.tools.boto3.Session'
496
+ ) as mock_session:
497
+ mock_client = Mock()
498
+ mock_client.stop_query.return_value = {'success': True}
499
+ mock_session.return_value.client.return_value = mock_client
500
+
501
+ tools = CloudWatchLogsTools()
502
+
503
+ # Mock _get_logs_client to capture the region parameter
504
+ with patch.object(
505
+ tools, '_get_logs_client', return_value=mock_client
506
+ ) as mock_get_client:
507
+ await tools.cancel_logs_insight_query(
508
+ mock_context, query_id='test-query-id', region='sa-east-1'
509
+ )
510
+
511
+ # Verify _get_logs_client was called with correct region
512
+ mock_get_client.assert_called_once_with('sa-east-1')
513
+
514
+ @pytest.mark.asyncio
515
+ async def test_describe_log_groups_region_parameter(self, mock_context):
516
+ """Test that describe_log_groups uses correct region for client creation."""
517
+ with patch(
518
+ 'awslabs.cloudwatch_mcp_server.cloudwatch_logs.tools.boto3.Session'
519
+ ) as mock_session:
520
+ mock_client = Mock()
521
+ mock_paginator = Mock()
522
+ mock_paginator.paginate.return_value = [{'logGroups': []}]
523
+ mock_client.get_paginator.return_value = mock_paginator
524
+ mock_client.describe_query_definitions.return_value = {'queryDefinitions': []}
525
+ mock_session.return_value.client.return_value = mock_client
526
+
527
+ tools = CloudWatchLogsTools()
528
+
529
+ # Mock _get_logs_client to capture the region parameter
530
+ with patch.object(
531
+ tools, '_get_logs_client', return_value=mock_client
532
+ ) as mock_get_client:
533
+ await tools.describe_log_groups(mock_context, region='us-west-1')
534
+
535
+ # Verify _get_logs_client was called with correct region
536
+ mock_get_client.assert_called_once_with('us-west-1')
@@ -392,3 +392,63 @@ class TestAnalyzeLogGroup:
392
392
  assert result.log_anomaly_results.anomaly_detectors[0].detectorName == 'test-detector'
393
393
  assert 'results' in result.top_patterns
394
394
  assert 'results' in result.top_patterns_containing_errors
395
+
396
+ async def test_analyze_log_group_region_parameter(self, ctx, cloudwatch_tools):
397
+ """Test that analyze_log_group passes region parameter to execute_log_insights_query calls."""
398
+ log_group_arn = 'arn:aws:logs:eu-west-1:123456789012:log-group:/aws/test/group1'
399
+
400
+ # Mock anomaly detection
401
+ cloudwatch_tools.logs_client.get_paginator = MagicMock()
402
+
403
+ # Mock list_log_anomaly_detectors paginator
404
+ anomaly_paginator = MagicMock()
405
+ anomaly_paginator.paginate.return_value = [{'anomalyDetectors': []}]
406
+
407
+ # Mock list_anomalies paginator
408
+ anomalies_paginator = MagicMock()
409
+ anomalies_paginator.paginate.return_value = [{'anomalies': []}]
410
+
411
+ def get_paginator_side_effect(operation_name):
412
+ if operation_name == 'list_log_anomaly_detectors':
413
+ return anomaly_paginator
414
+ elif operation_name == 'list_anomalies':
415
+ return anomalies_paginator
416
+ else:
417
+ return MagicMock()
418
+
419
+ cloudwatch_tools.logs_client.get_paginator.side_effect = get_paginator_side_effect
420
+
421
+ # Mock execute_log_insights_query to capture the region parameter
422
+ executed_queries = []
423
+
424
+ async def mock_execute_query(*args, **kwargs):
425
+ executed_queries.append(kwargs)
426
+ return {
427
+ 'queryId': 'test-query-id',
428
+ 'status': 'Complete',
429
+ 'results': [{'@message': 'Test pattern', '@sampleCount': '10'}],
430
+ }
431
+
432
+ # Patch the execute_log_insights_query method
433
+ with patch.object(
434
+ cloudwatch_tools, 'execute_log_insights_query', side_effect=mock_execute_query
435
+ ):
436
+ # Call analyze_log_group with specific region
437
+ await cloudwatch_tools.analyze_log_group(
438
+ ctx,
439
+ log_group_arn=log_group_arn,
440
+ start_time='2023-01-01T00:00:00+00:00',
441
+ end_time='2023-01-01T01:00:00+00:00',
442
+ region='eu-west-1',
443
+ )
444
+
445
+ # Verify that both execute_log_insights_query calls received the correct region
446
+ assert len(executed_queries) == 2
447
+ assert executed_queries[0]['region'] == 'eu-west-1'
448
+ assert executed_queries[1]['region'] == 'eu-west-1'
449
+
450
+ # Verify other parameters are passed correctly
451
+ for query in executed_queries:
452
+ assert query['log_group_identifiers'] == [log_group_arn]
453
+ assert query['start_time'] == '2023-01-01T00:00:00+00:00'
454
+ assert query['end_time'] == '2023-01-01T01:00:00+00:00'