#
tokens: 73742/50000 1/2535 files (page 609/612)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 609 of 612. Use http://codebase.md/awslabs/mcp?lines=true&page={x} to view the full context.

# Directory Structure

```
├── .devcontainer
│   └── devcontainer.json
├── .github
│   ├── actions
│   │   ├── build-and-push-container-image
│   │   │   └── action.yml
│   │   └── clear-space-ubuntu-latest-agressively
│   │       └── action.yml
│   ├── codecov.yml
│   ├── CODEOWNERS
│   ├── dependabot.yml
│   ├── ISSUE_TEMPLATE
│   │   ├── bug_report.yml
│   │   ├── documentation.yml
│   │   ├── feature_request.yml
│   │   ├── rfc.yml
│   │   └── support_awslabs_mcp_servers.yml
│   ├── pull_request_template.md
│   ├── SECURITY
│   ├── SUPPORT
│   └── workflows
│       ├── aws-api-mcp-upgrade-version.yml
│       ├── bandit-requirements.txt
│       ├── bandit.yml
│       ├── cfn_nag.yml
│       ├── check-gh-pages-builds.yml
│       ├── check-license-header-hash.txt
│       ├── check-license-header.json
│       ├── check-license-header.yml
│       ├── checkov.yml
│       ├── codeql.yml
│       ├── dependency-review-action.yml
│       ├── detect-secrets-requirements.txt
│       ├── gh-pages.yml
│       ├── merge-prevention.yml
│       ├── powershell.yml
│       ├── pre-commit-requirements.txt
│       ├── pre-commit.yml
│       ├── pull-request-lint.yml
│       ├── python.yml
│       ├── RELEASE_INSTRUCTIONS.md
│       ├── release-initiate-branch.yml
│       ├── release-merge-tag.yml
│       ├── release.py
│       ├── release.yml
│       ├── scanners.yml
│       ├── scorecard-analysis.yml
│       ├── semgrep-requirements.txt
│       ├── semgrep.yml
│       ├── stale.yml
│       ├── trivy.yml
│       └── typescript.yml
├── .gitignore
├── .pre-commit-config.yaml
├── .python-version
├── .ruff.toml
├── .secrets.baseline
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── DESIGN_GUIDELINES.md
├── DEVELOPER_GUIDE.md
├── docs
│   └── images
│       └── root-readme
│           ├── cline-api-provider-filled.png
│           ├── cline-chat-interface.png
│           ├── cline-custom-instructions.png
│           ├── cline-select-aws-profile.png
│           ├── cline-select-bedrock.png
│           ├── configure-mcp-servers.png
│           ├── install-cline-extension.png
│           ├── mcp-servers-installed.png
│           └── select-mcp-servers.png
├── docusaurus
│   ├── .gitignore
│   ├── docs
│   │   ├── installation.md
│   │   ├── intro.md
│   │   ├── samples
│   │   │   ├── index.md
│   │   │   ├── mcp-integration-with-kb.md
│   │   │   ├── mcp-integration-with-nova-canvas.md
│   │   │   └── stepfunctions-tool-mcp-server.md
│   │   ├── servers
│   │   │   ├── amazon-bedrock-agentcore-mcp-server.md
│   │   │   ├── amazon-keyspaces-mcp-server.md
│   │   │   ├── amazon-mq-mcp-server.md
│   │   │   ├── amazon-neptune-mcp-server.md
│   │   │   ├── amazon-qbusiness-anonymous-mcp-server.md
│   │   │   ├── amazon-qindex-mcp-server.md
│   │   │   ├── amazon-sns-sqs-mcp-server.md
│   │   │   ├── aurora-dsql-mcp-server.md
│   │   │   ├── aws-api-mcp-server.md
│   │   │   ├── aws-appsync-mcp-server.md
│   │   │   ├── aws-bedrock-custom-model-import-mcp-server.md
│   │   │   ├── aws-bedrock-data-automation-mcp-server.md
│   │   │   ├── aws-dataprocessing-mcp-server.md
│   │   │   ├── aws-diagram-mcp-server.md
│   │   │   ├── aws-documentation-mcp-server.md
│   │   │   ├── aws-healthomics-mcp-server.md
│   │   │   ├── aws-iot-sitewise-mcp-server.md
│   │   │   ├── aws-knowledge-mcp-server.md
│   │   │   ├── aws-location-mcp-server.md
│   │   │   ├── aws-msk-mcp-server.md
│   │   │   ├── aws-pricing-mcp-server.md
│   │   │   ├── aws-serverless-mcp-server.md
│   │   │   ├── aws-support-mcp-server.md
│   │   │   ├── bedrock-kb-retrieval-mcp-server.md
│   │   │   ├── billing-cost-management-mcp-server.md
│   │   │   ├── ccapi-mcp-server.md
│   │   │   ├── cdk-mcp-server.md
│   │   │   ├── cfn-mcp-server.md
│   │   │   ├── cloudtrail-mcp-server.md
│   │   │   ├── cloudwatch-applicationsignals-mcp-server.md
│   │   │   ├── cloudwatch-mcp-server.md
│   │   │   ├── code-doc-gen-mcp-server.md
│   │   │   ├── core-mcp-server.md
│   │   │   ├── cost-explorer-mcp-server.md
│   │   │   ├── documentdb-mcp-server.md
│   │   │   ├── dynamodb-mcp-server.md
│   │   │   ├── ecs-mcp-server.md
│   │   │   ├── eks-mcp-server.md
│   │   │   ├── elasticache-mcp-server.md
│   │   │   ├── finch-mcp-server.md
│   │   │   ├── frontend-mcp-server.md
│   │   │   ├── git-repo-research-mcp-server.md
│   │   │   ├── healthlake-mcp-server.md
│   │   │   ├── iam-mcp-server.md
│   │   │   ├── kendra-index-mcp-server.md
│   │   │   ├── lambda-tool-mcp-server.md
│   │   │   ├── memcached-mcp-server.md
│   │   │   ├── mysql-mcp-server.md
│   │   │   ├── nova-canvas-mcp-server.md
│   │   │   ├── openapi-mcp-server.md
│   │   │   ├── postgres-mcp-server.md
│   │   │   ├── prometheus-mcp-server.md
│   │   │   ├── redshift-mcp-server.md
│   │   │   ├── s3-tables-mcp-server.md
│   │   │   ├── stepfunctions-tool-mcp-server.md
│   │   │   ├── syntheticdata-mcp-server.md
│   │   │   ├── terraform-mcp-server.md
│   │   │   ├── timestream-for-influxdb-mcp-server.md
│   │   │   ├── valkey-mcp-server.md
│   │   │   └── well-architected-security-mcp-server.mdx
│   │   └── vibe_coding.md
│   ├── docusaurus.config.ts
│   ├── package-lock.json
│   ├── package.json
│   ├── README.md
│   ├── sidebars.ts
│   ├── src
│   │   ├── components
│   │   │   ├── HomepageFeatures
│   │   │   │   └── styles.module.css
│   │   │   └── ServerCards
│   │   │       ├── index.tsx
│   │   │       └── styles.module.css
│   │   ├── css
│   │   │   ├── custom.css
│   │   │   └── doc-override.css
│   │   └── pages
│   │       ├── index.module.css
│   │       └── servers.tsx
│   ├── static
│   │   ├── .nojekyll
│   │   ├── assets
│   │   │   ├── icons
│   │   │   │   ├── activity.svg
│   │   │   │   ├── book-open.svg
│   │   │   │   ├── cpu.svg
│   │   │   │   ├── database.svg
│   │   │   │   ├── dollar-sign.svg
│   │   │   │   ├── help-circle.svg
│   │   │   │   ├── key.svg
│   │   │   │   ├── server.svg
│   │   │   │   ├── share-2.svg
│   │   │   │   ├── tool.svg
│   │   │   │   └── zap.svg
│   │   │   └── server-cards.json
│   │   └── img
│   │       ├── aws-logo.svg
│   │       └── logo.png
│   └── tsconfig.json
├── LICENSE
├── NOTICE
├── README.md
├── samples
│   ├── mcp-integration-with-kb
│   │   ├── .env.example
│   │   ├── .python-version
│   │   ├── assets
│   │   │   └── simplified-mcp-flow-diagram.png
│   │   ├── clients
│   │   │   └── client_server.py
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── user_interfaces
│   │   │   └── chat_bedrock_st.py
│   │   └── uv.lock
│   ├── mcp-integration-with-nova-canvas
│   │   ├── .env.example
│   │   ├── .python-version
│   │   ├── clients
│   │   │   └── client_server.py
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── user_interfaces
│   │   │   └── image_generator_st.py
│   │   └── uv.lock
│   ├── README.md
│   └── stepfunctions-tool-mcp-server
│       ├── README.md
│       └── sample_state_machines
│           ├── customer-create
│           │   └── app.py
│           ├── customer-id-from-email
│           │   └── app.py
│           ├── customer-info-from-id
│           │   └── app.py
│           └── template.yml
├── scripts
│   ├── README.md
│   └── verify_package_name.py
├── src
│   ├── amazon-bedrock-agentcore-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── amazon_bedrock_agentcore_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── config.py
│   │   │       ├── server.py
│   │   │       └── utils
│   │   │           ├── __init__.py
│   │   │           ├── cache.py
│   │   │           ├── doc_fetcher.py
│   │   │           ├── indexer.py
│   │   │           ├── text_processor.py
│   │   │           └── url_validator.py
│   │   ├── CHANGELOG.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── SECURITY.md
│   │   ├── tests
│   │   │   ├── __init__.py
│   │   │   ├── conftest.py
│   │   │   ├── test_cache.py
│   │   │   ├── test_config.py
│   │   │   ├── test_doc_fetcher.py
│   │   │   ├── test_indexer.py
│   │   │   ├── test_init.py
│   │   │   ├── test_main.py
│   │   │   ├── test_server.py
│   │   │   ├── test_text_processor.py
│   │   │   └── test_url_validator.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── amazon-kendra-index-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── amazon_kendra_index_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── server.py
│   │   │       └── util.py
│   │   ├── CHANGELOG.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── test_init.py
│   │   │   ├── test_main.py
│   │   │   └── test_server.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── amazon-keyspaces-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── amazon_keyspaces_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── client.py
│   │   │       ├── config.py
│   │   │       ├── consts.py
│   │   │       ├── llm_context.py
│   │   │       ├── models.py
│   │   │       ├── server.py
│   │   │       └── services.py
│   │   ├── CHANGELOG.md
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── run_tests.sh
│   │   ├── tests
│   │   │   ├── __init__.py
│   │   │   ├── test_client.py
│   │   │   ├── test_init.py
│   │   │   ├── test_main.py
│   │   │   ├── test_query_analysis_service.py
│   │   │   ├── test_server.py
│   │   │   └── test_services.py
│   │   └── uv.lock
│   ├── amazon-mq-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── amazon_mq_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── aws_service_mcp_generator.py
│   │   │       ├── consts.py
│   │   │       ├── rabbitmq
│   │   │       │   ├── __init__.py
│   │   │       │   ├── admin.py
│   │   │       │   ├── connection.py
│   │   │       │   ├── doc
│   │   │       │   │   ├── rabbitmq_broker_sizing_guide.md
│   │   │       │   │   ├── rabbitmq_performance_optimization_best_practice.md
│   │   │       │   │   ├── rabbitmq_production_deployment_guidelines.md
│   │   │       │   │   ├── rabbitmq_quorum_queue_migration_guide.md
│   │   │       │   │   └── rabbitmq_setup_best_practice.md
│   │   │       │   ├── handlers.py
│   │   │       │   └── module.py
│   │   │       └── server.py
│   │   ├── CHANGELOG.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── example
│   │   │   └── sample_mcp_q_cli.json
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── __init__.py
│   │   │   ├── .gitignore
│   │   │   ├── rabbitmq
│   │   │   │   ├── __init__.py
│   │   │   │   ├── conftest.py
│   │   │   │   ├── test_admin.py
│   │   │   │   ├── test_connection.py
│   │   │   │   ├── test_handlers.py
│   │   │   │   └── test_module.py
│   │   │   ├── test_aws_service_mcp_generator.py
│   │   │   └── test_server.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── amazon-neptune-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── amazon_neptune_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── exceptions.py
│   │   │       ├── graph_store
│   │   │       │   ├── __init__.py
│   │   │       │   ├── analytics.py
│   │   │       │   ├── base.py
│   │   │       │   └── database.py
│   │   │       ├── models.py
│   │   │       ├── neptune.py
│   │   │       └── server.py
│   │   ├── CHANGELOG.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── __init__.py
│   │   │   ├── conftest.py
│   │   │   ├── test_analytics.py
│   │   │   ├── test_database.py
│   │   │   ├── test_exceptions.py
│   │   │   ├── test_init.py
│   │   │   ├── test_main.py
│   │   │   ├── test_models.py
│   │   │   ├── test_neptune.py
│   │   │   └── test_server.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── amazon-qbusiness-anonymous-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── amazon_qbusiness_anonymous_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── clients.py
│   │   │       └── server.py
│   │   ├── CHANGELOG.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── __init__.py
│   │   │   ├── conftest.py
│   │   │   ├── test_init.py
│   │   │   ├── test_main.py
│   │   │   └── test_server.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── amazon-qindex-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── amazon_qindex_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── clients.py
│   │   │       └── server.py
│   │   ├── CHANGELOG.md
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── test_clients.py
│   │   │   ├── test_init.py
│   │   │   ├── test_main.py
│   │   │   └── test_server.py
│   │   └── uv.lock
│   ├── amazon-sns-sqs-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── amazon_sns_sqs_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── common.py
│   │   │       ├── consts.py
│   │   │       ├── generator.py
│   │   │       ├── server.py
│   │   │       ├── sns.py
│   │   │       └── sqs.py
│   │   ├── CHANGELOG.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── print_tools.py
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── run_tests.sh
│   │   ├── tests
│   │   │   ├── __init__.py
│   │   │   ├── .gitignore
│   │   │   ├── README.md
│   │   │   ├── test_common.py
│   │   │   ├── test_generator.py
│   │   │   ├── test_server.py
│   │   │   ├── test_sns.py
│   │   │   └── test_sqs.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── aurora-dsql-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── aurora_dsql_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── consts.py
│   │   │       ├── mutable_sql_detector.py
│   │   │       └── server.py
│   │   ├── CHANGELOG.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── test_connection_reuse.py
│   │   │   ├── test_init.py
│   │   │   ├── test_main.py
│   │   │   ├── test_profile_option.py
│   │   │   ├── test_readonly_enforcement.py
│   │   │   └── test_server.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── aws-api-mcp-server
│   │   ├── .gitattributes
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── aws_api_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── core
│   │   │       │   ├── __init__.py
│   │   │       │   ├── agent_scripts
│   │   │       │   │   ├── __init__.py
│   │   │       │   │   ├── manager.py
│   │   │       │   │   ├── models.py
│   │   │       │   │   └── registry
│   │   │       │   │       ├── __init__.py
│   │   │       │   │       ├── application-failure-troubleshooting.script.md
│   │   │       │   │       ├── cloudtral-mutli-region-setup.script.md
│   │   │       │   │       ├── create_amazon_aurora_db_cluster_with_instances.script.md
│   │   │       │   │       ├── lambda-timeout-debugging.script.md
│   │   │       │   │       ├── scripts_format.md
│   │   │       │   │       └── troubleshoot-permissions-with-cloudtrail-events.script.md
│   │   │       │   ├── aws
│   │   │       │   │   ├── __init__.py
│   │   │       │   │   ├── driver.py
│   │   │       │   │   ├── pagination.py
│   │   │       │   │   ├── regions.py
│   │   │       │   │   ├── service.py
│   │   │       │   │   └── services.py
│   │   │       │   ├── common
│   │   │       │   │   ├── __init__.py
│   │   │       │   │   ├── command_metadata.py
│   │   │       │   │   ├── command.py
│   │   │       │   │   ├── config.py
│   │   │       │   │   ├── errors.py
│   │   │       │   │   ├── file_operations.py
│   │   │       │   │   ├── file_system_controls.py
│   │   │       │   │   ├── helpers.py
│   │   │       │   │   ├── models.py
│   │   │       │   │   └── py.typed
│   │   │       │   ├── data
│   │   │       │   │   └── api_metadata.json
│   │   │       │   ├── metadata
│   │   │       │   │   ├── __init__.py
│   │   │       │   │   └── read_only_operations_list.py
│   │   │       │   ├── parser
│   │   │       │   │   ├── __init__.py
│   │   │       │   │   ├── custom_validators
│   │   │       │   │   │   ├── __init__.py
│   │   │       │   │   │   ├── botocore_param_validator.py
│   │   │       │   │   │   ├── ec2_validator.py
│   │   │       │   │   │   └── ssm_validator.py
│   │   │       │   │   ├── interpretation.py
│   │   │       │   │   ├── lexer.py
│   │   │       │   │   └── parser.py
│   │   │       │   ├── py.typed
│   │   │       │   └── security
│   │   │       │       ├── __init__.py
│   │   │       │       ├── aws_api_customization.json
│   │   │       │       └── policy.py
│   │   │       ├── middleware
│   │   │       │   ├── __init__.py
│   │   │       │   └── http_header_validation_middleware.py
│   │   │       └── server.py
│   │   ├── CHANGELOG.md
│   │   ├── CONTRIBUTING.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── __init__.py
│   │   │   ├── agent_scripts
│   │   │   │   ├── __init__.py
│   │   │   │   ├── test_manager.py
│   │   │   │   └── test_registry
│   │   │   │       ├── another_valid_script.script.md
│   │   │   │       ├── test_script.script.md
│   │   │   │       └── valid_script.script.md
│   │   │   ├── aws
│   │   │   │   ├── __init__.py
│   │   │   │   ├── test_driver.py
│   │   │   │   ├── test_pagination.py
│   │   │   │   ├── test_service.py
│   │   │   │   └── test_services.py
│   │   │   ├── common
│   │   │   │   ├── test_command.py
│   │   │   │   ├── test_config.py
│   │   │   │   ├── test_file_operations.py
│   │   │   │   ├── test_file_system_controls.py
│   │   │   │   ├── test_file_validation.py
│   │   │   │   └── test_helpers.py
│   │   │   ├── fixtures.py
│   │   │   ├── history_handler.py
│   │   │   ├── metadata
│   │   │   │   ├── __init__.py
│   │   │   │   └── test_read_only_operations_list.py
│   │   │   ├── middleware
│   │   │   │   └── test_http_header_validation_middleware.py
│   │   │   ├── parser
│   │   │   │   ├── __init__.py
│   │   │   │   ├── test_file_path_detection.py
│   │   │   │   ├── test_lexer.py
│   │   │   │   ├── test_parser_customizations.py
│   │   │   │   └── test_parser.py
│   │   │   ├── test_security_policy.py
│   │   │   └── test_server.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── aws-appsync-mcp-server
│   │   ├── .dockerignore
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── aws_appsync_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── decorators.py
│   │   │       ├── helpers.py
│   │   │       ├── operations
│   │   │       │   ├── __init__.py
│   │   │       │   ├── create_api_cache.py
│   │   │       │   ├── create_api_key.py
│   │   │       │   ├── create_api.py
│   │   │       │   ├── create_channel_namespace.py
│   │   │       │   ├── create_datasource.py
│   │   │       │   ├── create_domain_name.py
│   │   │       │   ├── create_function.py
│   │   │       │   ├── create_graphql_api.py
│   │   │       │   ├── create_resolver.py
│   │   │       │   └── create_schema.py
│   │   │       ├── server.py
│   │   │       ├── tools
│   │   │       │   ├── __init__.py
│   │   │       │   ├── create_api_cache.py
│   │   │       │   ├── create_api_key.py
│   │   │       │   ├── create_api.py
│   │   │       │   ├── create_channel_namespace.py
│   │   │       │   ├── create_datasource.py
│   │   │       │   ├── create_domain_name.py
│   │   │       │   ├── create_function.py
│   │   │       │   ├── create_graphql_api.py
│   │   │       │   ├── create_resolver.py
│   │   │       │   └── create_schema.py
│   │   │       └── validators.py
│   │   ├── CHANGELOG.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── __init__.py
│   │   │   ├── test_all_create_tools_write_protection.py
│   │   │   ├── test_create_api_cache.py
│   │   │   ├── test_create_api_key.py
│   │   │   ├── test_create_api.py
│   │   │   ├── test_create_channel_namespace.py
│   │   │   ├── test_create_datasource_tool.py
│   │   │   ├── test_create_datasource.py
│   │   │   ├── test_create_domain_name.py
│   │   │   ├── test_create_function.py
│   │   │   ├── test_create_graphql_api.py
│   │   │   ├── test_create_resolver.py
│   │   │   ├── test_create_schema_tool.py
│   │   │   ├── test_create_schema.py
│   │   │   ├── test_helpers.py
│   │   │   ├── test_server.py
│   │   │   ├── test_validators.py
│   │   │   └── test_write_operation.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── aws-bedrock-custom-model-import-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── aws_bedrock_custom_model_import_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── client.py
│   │   │       ├── llm_context.py
│   │   │       ├── models.py
│   │   │       ├── prompts.py
│   │   │       ├── server.py
│   │   │       ├── services
│   │   │       │   ├── __init__.py
│   │   │       │   ├── imported_model_service.py
│   │   │       │   └── model_import_service.py
│   │   │       ├── tools
│   │   │       │   ├── create_model_import_job.py
│   │   │       │   ├── delete_imported_model.py
│   │   │       │   ├── get_imported_model.py
│   │   │       │   ├── get_model_import_job.py
│   │   │       │   ├── list_imported_models.py
│   │   │       │   └── list_model_import_jobs.py
│   │   │       └── utils
│   │   │           ├── __init__.py
│   │   │           ├── aws.py
│   │   │           ├── config.py
│   │   │           ├── consts.py
│   │   │           └── matching.py
│   │   ├── CHANGELOG.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── services
│   │   │   │   ├── test_imported_model_service.py
│   │   │   │   └── test_model_import_service.py
│   │   │   ├── test_client.py
│   │   │   ├── test_init.py
│   │   │   ├── test_llm_context.py
│   │   │   ├── test_prompts.py
│   │   │   ├── test_server.py
│   │   │   ├── tools
│   │   │   │   ├── test_create_model_import_job.py
│   │   │   │   ├── test_delete_imported_model.py
│   │   │   │   ├── test_get_imported_model.py
│   │   │   │   ├── test_get_model_import_job.py
│   │   │   │   ├── test_list_imported_models.py
│   │   │   │   └── test_list_model_import_jobs.py
│   │   │   └── utils
│   │   │       ├── test_aws.py
│   │   │       ├── test_config.py
│   │   │       └── test_matching.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── aws-bedrock-data-automation-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── aws_bedrock_data_automation_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── helpers.py
│   │   │       └── server.py
│   │   ├── CHANGELOG.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── __init__.py
│   │   │   ├── test_helpers.py
│   │   │   ├── test_init.py
│   │   │   ├── test_main.py
│   │   │   └── test_server.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── aws-dataprocessing-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── aws_dataprocessing_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── core
│   │   │       │   ├── __init__.py
│   │   │       │   └── glue_data_catalog
│   │   │       │       ├── __init__.py
│   │   │       │       ├── data_catalog_database_manager.py
│   │   │       │       ├── data_catalog_handler.py
│   │   │       │       └── data_catalog_table_manager.py
│   │   │       ├── handlers
│   │   │       │   ├── __init__.py
│   │   │       │   ├── athena
│   │   │       │   │   ├── __init__.py
│   │   │       │   │   ├── athena_data_catalog_handler.py
│   │   │       │   │   ├── athena_query_handler.py
│   │   │       │   │   └── athena_workgroup_handler.py
│   │   │       │   ├── commons
│   │   │       │   │   ├── __init__.py
│   │   │       │   │   └── common_resource_handler.py
│   │   │       │   ├── emr
│   │   │       │   │   ├── emr_ec2_cluster_handler.py
│   │   │       │   │   ├── emr_ec2_instance_handler.py
│   │   │       │   │   └── emr_ec2_steps_handler.py
│   │   │       │   └── glue
│   │   │       │       ├── __init__.py
│   │   │       │       ├── crawler_handler.py
│   │   │       │       ├── data_catalog_handler.py
│   │   │       │       ├── glue_commons_handler.py
│   │   │       │       ├── glue_etl_handler.py
│   │   │       │       ├── interactive_sessions_handler.py
│   │   │       │       └── worklows_handler.py
│   │   │       ├── models
│   │   │       │   ├── __init__.py
│   │   │       │   ├── athena_models.py
│   │   │       │   ├── common_resource_models.py
│   │   │       │   ├── data_catalog_models.py
│   │   │       │   ├── emr_models.py
│   │   │       │   └── glue_models.py
│   │   │       ├── server.py
│   │   │       └── utils
│   │   │           ├── __init__.py
│   │   │           ├── aws_helper.py
│   │   │           ├── consts.py
│   │   │           ├── logging_helper.py
│   │   │           └── sql_analyzer.py
│   │   ├── CHANGELOG.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── __init__.py
│   │   │   ├── core
│   │   │   │   ├── __init__.py
│   │   │   │   └── glue_data_catalog
│   │   │   │       ├── __init__.py
│   │   │   │       ├── test_data_catalog_database_manager.py
│   │   │   │       ├── test_data_catalog_handler.py
│   │   │   │       └── test_data_catalog_table_manager.py
│   │   │   ├── handlers
│   │   │   │   ├── __init__.py
│   │   │   │   ├── athena
│   │   │   │   │   ├── __init__.py
│   │   │   │   │   ├── test_athena_data_catalog_handler.py
│   │   │   │   │   ├── test_athena_query_handler.py
│   │   │   │   │   ├── test_athena_workgroup_handler.py
│   │   │   │   │   └── test_custom_tags_athena.py
│   │   │   │   ├── commons
│   │   │   │   │   ├── __init__.py
│   │   │   │   │   └── test_common_resource_handler.py
│   │   │   │   ├── emr
│   │   │   │   │   ├── __init__.py
│   │   │   │   │   ├── test_custom_tags_emr.py
│   │   │   │   │   ├── test_emr_ec2_cluster_handler.py
│   │   │   │   │   ├── test_emr_ec2_instance_handler.py
│   │   │   │   │   └── test_emr_ec2_steps_handler.py
│   │   │   │   └── glue
│   │   │   │       ├── __init__.py
│   │   │   │       ├── test_crawler_handler.py
│   │   │   │       ├── test_custom_tags_glue.py
│   │   │   │       ├── test_data_catalog_handler.py
│   │   │   │       ├── test_glue_commons_handler.py
│   │   │   │       ├── test_glue_etl_handler.py
│   │   │   │       ├── test_glue_interactive_sessions_handler.py
│   │   │   │       └── test_glue_workflows_handler.py
│   │   │   ├── models
│   │   │   │   ├── __init__.py
│   │   │   │   ├── test_athena_models.py
│   │   │   │   ├── test_common_resource_models.py
│   │   │   │   ├── test_data_catalog_models.py
│   │   │   │   ├── test_emr_models.py
│   │   │   │   ├── test_glue_models.py
│   │   │   │   ├── test_interactive_sessions_models.py
│   │   │   │   └── test_workflows_models.py
│   │   │   ├── test_init.py
│   │   │   ├── test_server.py
│   │   │   └── utils
│   │   │       ├── __init__.py
│   │   │       ├── test_aws_helper.py
│   │   │       ├── test_custom_tags.py
│   │   │       ├── test_logging_helper.py
│   │   │       └── test_sql_analyzer.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── aws-diagram-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── aws_diagram_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── diagrams_tools.py
│   │   │       ├── models.py
│   │   │       ├── scanner.py
│   │   │       └── server.py
│   │   ├── CHANGELOG.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── __init__.py
│   │   │   ├── .gitignore
│   │   │   ├── conftest.py
│   │   │   ├── README.md
│   │   │   ├── resources
│   │   │   │   ├── __init__.py
│   │   │   │   └── example_diagrams
│   │   │   │       ├── __init__.py
│   │   │   │       ├── aws_example.py
│   │   │   │       ├── flow_example.py
│   │   │   │       └── sequence_example.py
│   │   │   ├── test_diagrams.py
│   │   │   ├── test_models.py
│   │   │   ├── test_sarif_fix.py
│   │   │   ├── test_scanner.py
│   │   │   └── test_server.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── aws-documentation-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── aws_documentation_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── models.py
│   │   │       ├── server_aws_cn.py
│   │   │       ├── server_aws.py
│   │   │       ├── server_utils.py
│   │   │       ├── server.py
│   │   │       └── util.py
│   │   ├── basic-usage.gif
│   │   ├── CHANGELOG.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── __init__.py
│   │   │   ├── conftest.py
│   │   │   ├── constants.py
│   │   │   ├── resources
│   │   │   │   └── lambda_sns_raw.html
│   │   │   ├── test_aws_cn_get_available_services_live.py
│   │   │   ├── test_aws_cn_read_documentation_live.py
│   │   │   ├── test_aws_read_documentation_live.py
│   │   │   ├── test_aws_recommend_live.py
│   │   │   ├── test_aws_search_live.py
│   │   │   ├── test_metadata_handling.py
│   │   │   ├── test_models.py
│   │   │   ├── test_server_aws_cn.py
│   │   │   ├── test_server_aws.py
│   │   │   ├── test_server_utils.py
│   │   │   ├── test_server.py
│   │   │   └── test_util.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── aws-healthomics-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── aws_healthomics_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── consts.py
│   │   │       ├── models.py
│   │   │       ├── server.py
│   │   │       ├── tools
│   │   │       │   ├── __init__.py
│   │   │       │   ├── helper_tools.py
│   │   │       │   ├── run_analysis.py
│   │   │       │   ├── troubleshooting.py
│   │   │       │   ├── workflow_analysis.py
│   │   │       │   ├── workflow_execution.py
│   │   │       │   ├── workflow_linting.py
│   │   │       │   └── workflow_management.py
│   │   │       └── utils
│   │   │           ├── __init__.py
│   │   │           ├── aws_utils.py
│   │   │           ├── s3_utils.py
│   │   │           └── validation_utils.py
│   │   ├── CHANGELOG.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── docs
│   │   │   └── workflow_linting.md
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── conftest.py
│   │   │   ├── test_aws_utils.py
│   │   │   ├── test_consts.py
│   │   │   ├── test_helper_tools.py
│   │   │   ├── test_init.py
│   │   │   ├── test_main.py
│   │   │   ├── test_models.py
│   │   │   ├── test_run_analysis.py
│   │   │   ├── test_s3_utils.py
│   │   │   ├── test_server.py
│   │   │   ├── test_troubleshooting.py
│   │   │   ├── test_workflow_analysis.py
│   │   │   ├── test_workflow_execution.py
│   │   │   ├── test_workflow_linting.py
│   │   │   ├── test_workflow_management.py
│   │   │   └── test_workflow_tools.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── aws-iot-sitewise-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── aws_iot_sitewise_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── client.py
│   │   │       ├── models
│   │   │       │   ├── computation_data_models.py
│   │   │       │   └── metadata_transfer_data_models.py
│   │   │       ├── prompts
│   │   │       │   ├── __init__.py
│   │   │       │   ├── anomaly_detection_workflow.py
│   │   │       │   ├── asset_hierarchy.py
│   │   │       │   ├── bulk_import_workflow.py
│   │   │       │   ├── data_exploration.py
│   │   │       │   └── data_ingestion.py
│   │   │       ├── server.py
│   │   │       ├── tool_metadata.py
│   │   │       ├── tools
│   │   │       │   ├── __init__.py
│   │   │       │   ├── sitewise_access.py
│   │   │       │   ├── sitewise_asset_models.py
│   │   │       │   ├── sitewise_assets.py
│   │   │       │   ├── sitewise_computation_models.py
│   │   │       │   ├── sitewise_data.py
│   │   │       │   ├── sitewise_executions.py
│   │   │       │   ├── sitewise_gateways.py
│   │   │       │   ├── sitewise_metadata_transfer.py
│   │   │       │   └── timestamp_tools.py
│   │   │       ├── validation_utils.py
│   │   │       └── validation.py
│   │   ├── CHANGELOG.md
│   │   ├── DEVELOPMENT.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── examples
│   │   │   └── wind_farm_example.py
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── run_server.py
│   │   ├── tests
│   │   │   ├── __init__.py
│   │   │   ├── conftest.py
│   │   │   ├── models
│   │   │   │   ├── test_computation_data_models.py
│   │   │   │   └── test_metadata_transfer_data_models.py
│   │   │   ├── test_client.py
│   │   │   ├── test_init.py
│   │   │   ├── test_main.py
│   │   │   ├── test_server.py
│   │   │   ├── test_validation_utils.py
│   │   │   ├── test_validation.py
│   │   │   └── tools
│   │   │       ├── test_sitewise_access.py
│   │   │       ├── test_sitewise_asset_models.py
│   │   │       ├── test_sitewise_assets.py
│   │   │       ├── test_sitewise_computation_models.py
│   │   │       ├── test_sitewise_data.py
│   │   │       ├── test_sitewise_executions.py
│   │   │       ├── test_sitewise_gateways.py
│   │   │       ├── test_sitewise_metadata_transfer.py
│   │   │       └── test_timestamp_tools.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── aws-knowledge-mcp-server
│   │   └── README.md
│   ├── aws-location-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── aws_location_server
│   │   │       ├── __init__.py
│   │   │       └── server.py
│   │   ├── CHANGELOG.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── __init__.py
│   │   │   ├── conftest.py
│   │   │   ├── test_server_integration.py
│   │   │   └── test_server.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── aws-msk-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── aws_msk_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── server.py
│   │   │       └── tools
│   │   │           ├── __init__.py
│   │   │           ├── common_functions
│   │   │           │   ├── __init__.py
│   │   │           │   ├── client_manager.py
│   │   │           │   └── common_functions.py
│   │   │           ├── logs_and_telemetry
│   │   │           │   ├── __init__.py
│   │   │           │   ├── cluster_metrics_tools.py
│   │   │           │   ├── list_customer_iam_access.py
│   │   │           │   └── metric_config.py
│   │   │           ├── mutate_cluster
│   │   │           │   ├── __init__.py
│   │   │           │   ├── batch_associate_scram_secret.py
│   │   │           │   ├── batch_disassociate_scram_secret.py
│   │   │           │   ├── create_cluster_v2.py
│   │   │           │   ├── put_cluster_policy.py
│   │   │           │   ├── reboot_broker.py
│   │   │           │   ├── update_broker_count.py
│   │   │           │   ├── update_broker_storage.py
│   │   │           │   ├── update_broker_type.py
│   │   │           │   ├── update_cluster_configuration.py
│   │   │           │   ├── update_monitoring.py
│   │   │           │   └── update_security.py
│   │   │           ├── mutate_config
│   │   │           │   ├── __init__.py
│   │   │           │   ├── create_configuration.py
│   │   │           │   ├── tag_resource.py
│   │   │           │   ├── untag_resource.py
│   │   │           │   └── update_configuration.py
│   │   │           ├── mutate_vpc
│   │   │           │   ├── __init__.py
│   │   │           │   ├── create_vpc_connection.py
│   │   │           │   ├── delete_vpc_connection.py
│   │   │           │   └── reject_client_vpc_connection.py
│   │   │           ├── read_cluster
│   │   │           │   ├── __init__.py
│   │   │           │   ├── describe_cluster_operation.py
│   │   │           │   ├── describe_cluster.py
│   │   │           │   ├── get_bootstrap_brokers.py
│   │   │           │   ├── get_cluster_policy.py
│   │   │           │   ├── get_compatible_kafka_versions.py
│   │   │           │   ├── list_client_vpc_connections.py
│   │   │           │   ├── list_cluster_operations.py
│   │   │           │   ├── list_nodes.py
│   │   │           │   └── list_scram_secrets.py
│   │   │           ├── read_config
│   │   │           │   ├── __init__.py
│   │   │           │   ├── describe_configuration_revision.py
│   │   │           │   ├── describe_configuration.py
│   │   │           │   ├── list_configuration_revisions.py
│   │   │           │   └── list_tags_for_resource.py
│   │   │           ├── read_global
│   │   │           │   ├── __init__.py
│   │   │           │   ├── list_clusters.py
│   │   │           │   ├── list_configurations.py
│   │   │           │   ├── list_kafka_versions.py
│   │   │           │   └── list_vpc_connections.py
│   │   │           ├── read_vpc
│   │   │           │   ├── __init__.py
│   │   │           │   └── describe_vpc_connection.py
│   │   │           └── static_tools
│   │   │               ├── __init__.py
│   │   │               └── cluster_best_practices.py
│   │   ├── CHANGELOG.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── test_client_manager.py
│   │   │   ├── test_cluster_metrics_tools.py
│   │   │   ├── test_common_functions.py
│   │   │   ├── test_create_cluster_v2.py
│   │   │   ├── test_create_configuration.py
│   │   │   ├── test_create_vpc_connection.py
│   │   │   ├── test_delete_vpc_connection.py
│   │   │   ├── test_describe_cluster_operation.py
│   │   │   ├── test_describe_cluster.py
│   │   │   ├── test_describe_configuration_revision.py
│   │   │   ├── test_describe_configuration.py
│   │   │   ├── test_describe_vpc_connection.py
│   │   │   ├── test_get_bootstrap_brokers.py
│   │   │   ├── test_get_cluster_policy.py
│   │   │   ├── test_get_compatible_kafka_versions.py
│   │   │   ├── test_init.py
│   │   │   ├── test_list_client_vpc_connections.py
│   │   │   ├── test_list_cluster_operations.py
│   │   │   ├── test_list_clusters.py
│   │   │   ├── test_list_configuration_revisions.py
│   │   │   ├── test_list_configurations.py
│   │   │   ├── test_list_customer_iam_access.py
│   │   │   ├── test_list_kafka_versions.py
│   │   │   ├── test_list_nodes.py
│   │   │   ├── test_list_scram_secrets.py
│   │   │   ├── test_list_tags_for_resource.py
│   │   │   ├── test_list_vpc_connections.py
│   │   │   ├── test_logs_and_telemetry.py
│   │   │   ├── test_main.py
│   │   │   ├── test_mutate_cluster_init.py
│   │   │   ├── test_mutate_cluster_success_cases.py
│   │   │   ├── test_mutate_cluster.py
│   │   │   ├── test_mutate_config_init.py
│   │   │   ├── test_mutate_vpc_init.py
│   │   │   ├── test_read_cluster_init_updated.py
│   │   │   ├── test_read_cluster_init.py
│   │   │   ├── test_read_config_init.py
│   │   │   ├── test_read_global_init.py
│   │   │   ├── test_read_vpc_init.py
│   │   │   ├── test_reject_client_vpc_connection.py
│   │   │   ├── test_server.py
│   │   │   ├── test_static_tools_init.py
│   │   │   ├── test_tag_resource.py
│   │   │   ├── test_tool_descriptions.py
│   │   │   ├── test_untag_resource.py
│   │   │   └── test_update_configuration.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── aws-pricing-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── aws_pricing_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── cdk_analyzer.py
│   │   │       ├── consts.py
│   │   │       ├── helpers.py
│   │   │       ├── models.py
│   │   │       ├── pricing_client.py
│   │   │       ├── pricing_transformer.py
│   │   │       ├── report_generator.py
│   │   │       ├── server.py
│   │   │       ├── static
│   │   │       │   ├── __init__.py
│   │   │       │   ├── COST_REPORT_TEMPLATE.md
│   │   │       │   └── patterns
│   │   │       │       ├── __init__.py
│   │   │       │       └── BEDROCK.md
│   │   │       └── terraform_analyzer.py
│   │   ├── CHANGELOG.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── __init__.py
│   │   │   ├── conftest.py
│   │   │   ├── test_cdk_analyzer.py
│   │   │   ├── test_helpers.py
│   │   │   ├── test_pricing_client.py
│   │   │   ├── test_pricing_transformer.py
│   │   │   ├── test_report_generator.py
│   │   │   ├── test_server.py
│   │   │   └── test_terraform_analyzer.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── aws-serverless-mcp-server
│   │   ├── .pre-commit.config.yaml
│   │   ├── .python-version
│   │   ├── .secrets.baseline
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── aws_serverless_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── models.py
│   │   │       ├── resources
│   │   │       │   ├── __init__.py
│   │   │       │   ├── deployment_details.py
│   │   │       │   ├── deployment_list.py
│   │   │       │   ├── template_details.py
│   │   │       │   └── template_list.py
│   │   │       ├── server.py
│   │   │       ├── template
│   │   │       │   ├── __init__.py
│   │   │       │   ├── registry.py
│   │   │       │   ├── renderer.py
│   │   │       │   └── templates
│   │   │       │       ├── backend.j2
│   │   │       │       ├── frontend.j2
│   │   │       │       ├── fullstack.j2
│   │   │       │       └── README.md
│   │   │       ├── templates
│   │   │       │   ├── __init__.py
│   │   │       │   └── iam_policies.py
│   │   │       ├── tools
│   │   │       │   ├── common
│   │   │       │   │   └── base_tool.py
│   │   │       │   ├── esm
│   │   │       │   │   ├── __init__.py
│   │   │       │   │   ├── esm_diagnosis.py
│   │   │       │   │   ├── esm_guidance.py
│   │   │       │   │   ├── esm_recommend.py
│   │   │       │   │   └── secure_esm_guidance.py
│   │   │       │   ├── guidance
│   │   │       │   │   ├── __init__.py
│   │   │       │   │   ├── deploy_serverless_app_help.py
│   │   │       │   │   ├── get_iac_guidance.py
│   │   │       │   │   ├── get_lambda_event_schemas.py
│   │   │       │   │   ├── get_lambda_guidance.py
│   │   │       │   │   └── get_serverless_templates.py
│   │   │       │   ├── poller
│   │   │       │   │   ├── __init__.py
│   │   │       │   │   ├── esm_diagnosis.py
│   │   │       │   │   ├── esm_guidance.py
│   │   │       │   │   └── esm_recommend.py
│   │   │       │   ├── sam
│   │   │       │   │   ├── __init__.py
│   │   │       │   │   ├── sam_build.py
│   │   │       │   │   ├── sam_deploy.py
│   │   │       │   │   ├── sam_init.py
│   │   │       │   │   ├── sam_local_invoke.py
│   │   │       │   │   └── sam_logs.py
│   │   │       │   ├── schemas
│   │   │       │   │   ├── __init__.py
│   │   │       │   │   ├── describe_schema.py
│   │   │       │   │   ├── list_registries.py
│   │   │       │   │   └── search_schema.py
│   │   │       │   └── webapps
│   │   │       │       ├── __init__.py
│   │   │       │       ├── configure_domain.py
│   │   │       │       ├── deploy_webapp.py
│   │   │       │       ├── get_metrics.py
│   │   │       │       ├── update_webapp_frontend.py
│   │   │       │       ├── utils
│   │   │       │       │   ├── deploy_service.py
│   │   │       │       │   ├── frontend_uploader.py
│   │   │       │       │   └── startup_script_generator.py
│   │   │       │       └── webapp_deployment_help.py
│   │   │       └── utils
│   │   │           ├── __init__.py
│   │   │           ├── aws_client_helper.py
│   │   │           ├── cloudformation.py
│   │   │           ├── const.py
│   │   │           ├── data_scrubber.py
│   │   │           ├── deployment_manager.py
│   │   │           ├── github.py
│   │   │           └── process.py
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── __init__.py
│   │   │   ├── conftest.py
│   │   │   ├── README.md
│   │   │   ├── test_cloudformation.py
│   │   │   ├── test_configure_domain.py
│   │   │   ├── test_data_scrubber.py
│   │   │   ├── test_deploy_serverless_app_help.py
│   │   │   ├── test_deploy_service.py
│   │   │   ├── test_deploy_webapp.py
│   │   │   ├── test_deployment_details.py
│   │   │   ├── test_deployment_help.py
│   │   │   ├── test_deployment_list.py
│   │   │   ├── test_deployment_manager.py
│   │   │   ├── test_esm_diagnosis.py
│   │   │   ├── test_esm_guidance.py
│   │   │   ├── test_esm_recommend.py
│   │   │   ├── test_frontend_uploader.py
│   │   │   ├── test_get_iac_guidance.py
│   │   │   ├── test_get_lambda_event_schemas.py
│   │   │   ├── test_get_lambda_guidance.py
│   │   │   ├── test_get_metrics.py
│   │   │   ├── test_get_serverless_templates.py
│   │   │   ├── test_github.py
│   │   │   ├── test_iam_policies.py
│   │   │   ├── test_models.py
│   │   │   ├── test_process.py
│   │   │   ├── test_sam_build.py
│   │   │   ├── test_sam_deploy.py
│   │   │   ├── test_sam_init.py
│   │   │   ├── test_sam_local_invoke.py
│   │   │   ├── test_sam_logs.py
│   │   │   ├── test_schemas.py
│   │   │   ├── test_secure_esm_guidance.py
│   │   │   ├── test_server.py
│   │   │   ├── test_startup_script_generator.py
│   │   │   ├── test_template_details.py
│   │   │   ├── test_template_list.py
│   │   │   ├── test_template_registry.py
│   │   │   ├── test_template_renderer.py
│   │   │   └── test_update_webapp_frontend.py
│   │   └── uv.lock
│   ├── aws-support-mcp-server
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── aws_support_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── client.py
│   │   │       ├── consts.py
│   │   │       ├── debug_helper.py
│   │   │       ├── errors.py
│   │   │       ├── formatters.py
│   │   │       ├── models.py
│   │   │       └── server.py
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── __init__.py
│   │   │   ├── conftests.py
│   │   │   ├── test_aws_support_mcp_server.py
│   │   │   └── test_models.py
│   │   └── uv.lock
│   ├── bedrock-kb-retrieval-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── bedrock_kb_retrieval_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── knowledgebases
│   │   │       │   ├── __init__.py
│   │   │       │   ├── clients.py
│   │   │       │   ├── discovery.py
│   │   │       │   └── retrieval.py
│   │   │       ├── models.py
│   │   │       └── server.py
│   │   ├── CHANGELOG.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── run_tests.sh
│   │   ├── tests
│   │   │   ├── __init__.py
│   │   │   ├── .gitignore
│   │   │   ├── conftest.py
│   │   │   ├── README.md
│   │   │   ├── test_clients.py
│   │   │   ├── test_discovery.py
│   │   │   ├── test_env_config.py
│   │   │   ├── test_models.py
│   │   │   ├── test_retrieval.py
│   │   │   └── test_server.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── billing-cost-management-mcp-server
│   │   ├── __init__.py
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── billing_cost_management_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── models.py
│   │   │       ├── prompts
│   │   │       │   ├── __init__.py
│   │   │       │   ├── decorator.py
│   │   │       │   ├── graviton_migration.py
│   │   │       │   ├── README.md
│   │   │       │   ├── savings_plans.py
│   │   │       │   └── types.py
│   │   │       ├── server.py
│   │   │       ├── templates
│   │   │       │   └── recommendation_templates
│   │   │       │       ├── ebs_volume.template
│   │   │       │       ├── ec2_asg.template
│   │   │       │       ├── ec2_instance.template
│   │   │       │       ├── ecs_service.template
│   │   │       │       ├── idle.template
│   │   │       │       ├── lambda_function.template
│   │   │       │       ├── rds_database.template
│   │   │       │       ├── reserved_instances.template
│   │   │       │       └── savings_plans.template
│   │   │       ├── tools
│   │   │       │   ├── __init__.py
│   │   │       │   ├── aws_pricing_operations.py
│   │   │       │   ├── aws_pricing_tools.py
│   │   │       │   ├── bcm_pricing_calculator_tools.py
│   │   │       │   ├── budget_tools.py
│   │   │       │   ├── compute_optimizer_tools.py
│   │   │       │   ├── cost_anomaly_tools.py
│   │   │       │   ├── cost_comparison_tools.py
│   │   │       │   ├── cost_explorer_operations.py
│   │   │       │   ├── cost_explorer_tools.py
│   │   │       │   ├── cost_optimization_hub_helpers.py
│   │   │       │   ├── cost_optimization_hub_tools.py
│   │   │       │   ├── free_tier_usage_tools.py
│   │   │       │   ├── recommendation_details_tools.py
│   │   │       │   ├── ri_performance_tools.py
│   │   │       │   ├── sp_performance_tools.py
│   │   │       │   ├── storage_lens_tools.py
│   │   │       │   └── unified_sql_tools.py
│   │   │       └── utilities
│   │   │           ├── __init__.py
│   │   │           ├── aws_service_base.py
│   │   │           ├── constants.py
│   │   │           ├── logging_utils.py
│   │   │           └── sql_utils.py
│   │   ├── CHANGELOG.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── requirements.txt
│   │   ├── tests
│   │   │   ├── __init__.py
│   │   │   ├── conftest.py
│   │   │   ├── prompts
│   │   │   │   ├── __init__.py
│   │   │   │   └── test_prompts.py
│   │   │   ├── README.md
│   │   │   ├── test_models.py
│   │   │   ├── test_server.py
│   │   │   ├── tools
│   │   │   │   ├── __init__.py
│   │   │   │   ├── fixtures.py
│   │   │   │   ├── test_aws_bcm_pricing_calculator_tools.py
│   │   │   │   ├── test_aws_pricing_tools.py
│   │   │   │   ├── test_budget_tools.py
│   │   │   │   ├── test_compute_optimizer_tools.py
│   │   │   │   ├── test_cost_anomaly_tools_enhanced.py
│   │   │   │   ├── test_cost_anomaly_tools.py
│   │   │   │   ├── test_cost_comparison_tools.py
│   │   │   │   ├── test_cost_explorer_operations.py
│   │   │   │   ├── test_cost_explorer_tools.py
│   │   │   │   ├── test_cost_optimization_hub_helpers.py
│   │   │   │   ├── test_cost_optimization_hub_tools.py
│   │   │   │   ├── test_free_tier_usage_tools_new.py
│   │   │   │   ├── test_recommendation_details_tools.py
│   │   │   │   ├── test_ri_performance_tools.py
│   │   │   │   ├── test_sp_performance_tools.py
│   │   │   │   ├── test_storage_lens_tools.py
│   │   │   │   └── test_unified_sql_tools.py
│   │   │   └── utilities
│   │   │       ├── test_aws_service_base.py
│   │   │       └── test_sql_utils.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── ccapi-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── ccapi_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── aws_client.py
│   │   │       ├── cloud_control_utils.py
│   │   │       ├── context.py
│   │   │       ├── errors.py
│   │   │       ├── iac_generator.py
│   │   │       ├── impl
│   │   │       │   ├── __init__.py
│   │   │       │   ├── tools
│   │   │       │   │   ├── __init__.py
│   │   │       │   │   ├── explanation.py
│   │   │       │   │   ├── infrastructure_generation.py
│   │   │       │   │   ├── resource_operations.py
│   │   │       │   │   ├── security_scanning.py
│   │   │       │   │   └── session_management.py
│   │   │       │   └── utils
│   │   │       │       ├── __init__.py
│   │   │       │       └── validation.py
│   │   │       ├── infrastructure_generator.py
│   │   │       ├── models
│   │   │       │   ├── __init__.py
│   │   │       │   └── models.py
│   │   │       ├── schema_manager.py
│   │   │       ├── server.py
│   │   │       └── static
│   │   │           └── __init__.py
│   │   ├── CHANGELOG.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── run_tests.sh
│   │   ├── tests
│   │   │   ├── __init__.py
│   │   │   ├── test_aws_client.py
│   │   │   ├── test_checkov_install.py
│   │   │   ├── test_cloud_control_utils.py
│   │   │   ├── test_context.py
│   │   │   ├── test_errors.py
│   │   │   ├── test_explanation.py
│   │   │   ├── test_iac_generator.py
│   │   │   ├── test_infrastructure_generation.py
│   │   │   ├── test_infrastructure_generator.py
│   │   │   ├── test_models.py
│   │   │   ├── test_resource_operations.py
│   │   │   ├── test_schema_manager.py
│   │   │   ├── test_security_scanning.py
│   │   │   ├── test_server.py
│   │   │   ├── test_session_management.py
│   │   │   └── test_validation.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── cdk-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── cdk_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── core
│   │   │       │   ├── __init__.py
│   │   │       │   ├── resources.py
│   │   │       │   ├── search_utils.py
│   │   │       │   ├── server.py
│   │   │       │   └── tools.py
│   │   │       ├── data
│   │   │       │   ├── __init__.py
│   │   │       │   ├── cdk_nag_parser.py
│   │   │       │   ├── construct_descriptions.py
│   │   │       │   ├── genai_cdk_loader.py
│   │   │       │   ├── lambda_layer_parser.py
│   │   │       │   ├── lambda_powertools_loader.py
│   │   │       │   ├── schema_generator.py
│   │   │       │   └── solutions_constructs_parser.py
│   │   │       ├── server.py
│   │   │       └── static
│   │   │           ├── __init__.py
│   │   │           ├── CDK_GENERAL_GUIDANCE.md
│   │   │           ├── CDK_NAG_GUIDANCE.md
│   │   │           └── lambda_powertools
│   │   │               ├── bedrock.md
│   │   │               ├── cdk.md
│   │   │               ├── dependencies.md
│   │   │               ├── index.md
│   │   │               ├── insights.md
│   │   │               ├── logging.md
│   │   │               ├── metrics.md
│   │   │               └── tracing.md
│   │   ├── CHANGELOG.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── __init__.py
│   │   │   ├── core
│   │   │   │   ├── test_resources_enhanced.py
│   │   │   │   ├── test_resources.py
│   │   │   │   ├── test_search_utils.py
│   │   │   │   ├── test_server.py
│   │   │   │   └── test_tools.py
│   │   │   └── data
│   │   │       ├── test_cdk_nag_parser.py
│   │   │       ├── test_genai_cdk_loader.py
│   │   │       ├── test_lambda_powertools_loader.py
│   │   │       ├── test_schema_generator.py
│   │   │       └── test_solutions_constructs_parser.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── cfn-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── cfn_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── aws_client.py
│   │   │       ├── cloud_control_utils.py
│   │   │       ├── context.py
│   │   │       ├── errors.py
│   │   │       ├── iac_generator.py
│   │   │       ├── schema_manager.py
│   │   │       └── server.py
│   │   ├── CHANGELOG.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── run_tests.sh
│   │   ├── tests
│   │   │   ├── __init__.py
│   │   │   ├── test_aws_client.py
│   │   │   ├── test_cloud_control_utils.py
│   │   │   ├── test_errors.py
│   │   │   ├── test_iac_generator.py
│   │   │   ├── test_init.py
│   │   │   ├── test_main.py
│   │   │   ├── test_schema_manager.py
│   │   │   └── test_server.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── cloudtrail-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── cloudtrail_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── common.py
│   │   │       ├── models.py
│   │   │       ├── server.py
│   │   │       └── tools.py
│   │   ├── CHANGELOG.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── __init__.py
│   │   │   ├── conftest.py
│   │   │   ├── test_init.py
│   │   │   ├── test_main.py
│   │   │   ├── test_models.py
│   │   │   ├── test_server.py
│   │   │   └── test_tools.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── cloudwatch-applicationsignals-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── cloudwatch_applicationsignals_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── audit_presentation_utils.py
│   │   │       ├── audit_utils.py
│   │   │       ├── aws_clients.py
│   │   │       ├── canary_utils.py
│   │   │       ├── server.py
│   │   │       ├── service_audit_utils.py
│   │   │       ├── service_tools.py
│   │   │       ├── sli_report_client.py
│   │   │       ├── slo_tools.py
│   │   │       ├── trace_tools.py
│   │   │       └── utils.py
│   │   ├── CHANGELOG.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── conftest.py
│   │   │   ├── test_audit_presentation_utils.py
│   │   │   ├── test_audit_utils.py
│   │   │   ├── test_aws_profile.py
│   │   │   ├── test_canary_utils.py
│   │   │   ├── test_initialization.py
│   │   │   ├── test_server_audit_functions.py
│   │   │   ├── test_server_audit_tools.py
│   │   │   ├── test_server.py
│   │   │   ├── test_service_audit_utils.py
│   │   │   ├── test_service_tools_operations.py
│   │   │   ├── test_sli_report_client.py
│   │   │   ├── test_slo_tools.py
│   │   │   └── test_utils.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── cloudwatch-appsignals-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── cloudwatch_appsignals_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── audit_presentation_utils.py
│   │   │       ├── audit_utils.py
│   │   │       ├── aws_clients.py
│   │   │       ├── canary_utils.py
│   │   │       ├── enablement_guides
│   │   │       │   └── templates
│   │   │       │       └── ec2
│   │   │       │           └── ec2-python-enablement.md
│   │   │       ├── enablement_tools.py
│   │   │       ├── server.py
│   │   │       ├── service_audit_utils.py
│   │   │       ├── service_tools.py
│   │   │       ├── sli_report_client.py
│   │   │       ├── slo_tools.py
│   │   │       ├── trace_tools.py
│   │   │       └── utils.py
│   │   ├── CHANGELOG.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── conftest.py
│   │   │   ├── test_audit_presentation_utils.py
│   │   │   ├── test_audit_utils.py
│   │   │   ├── test_aws_profile.py
│   │   │   ├── test_canary_utils.py
│   │   │   ├── test_enablement_tools.py
│   │   │   ├── test_initialization.py
│   │   │   ├── test_server_audit_functions.py
│   │   │   ├── test_server_audit_tools.py
│   │   │   ├── test_server.py
│   │   │   ├── test_service_audit_utils.py
│   │   │   ├── test_service_tools_operations.py
│   │   │   ├── test_sli_report_client.py
│   │   │   ├── test_slo_tools.py
│   │   │   └── test_utils.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── cloudwatch-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── cloudwatch_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── cloudwatch_alarms
│   │   │       │   ├── models.py
│   │   │       │   └── tools.py
│   │   │       ├── cloudwatch_logs
│   │   │       │   ├── models.py
│   │   │       │   └── tools.py
│   │   │       ├── cloudwatch_metrics
│   │   │       │   ├── cloudformation_template_generator.py
│   │   │       │   ├── constants.py
│   │   │       │   ├── data
│   │   │       │   │   └── metric_metadata.json
│   │   │       │   ├── metric_analyzer.py
│   │   │       │   ├── metric_data_decomposer.py
│   │   │       │   ├── models.py
│   │   │       │   └── tools.py
│   │   │       ├── common.py
│   │   │       └── server.py
│   │   ├── CHANGELOG.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── cloudwatch_alarms
│   │   │   │   ├── test_active_alarms.py
│   │   │   │   ├── test_alarm_history_integration.py
│   │   │   │   ├── test_alarm_history.py
│   │   │   │   └── test_alarms_error_handling.py
│   │   │   ├── cloudwatch_logs
│   │   │   │   ├── test_logs_error_handling.py
│   │   │   │   ├── test_logs_models.py
│   │   │   │   └── test_logs_server.py
│   │   │   ├── cloudwatch_metrics
│   │   │   │   ├── test_analyze_metric.py
│   │   │   │   ├── test_cloudformation_template_generator.py
│   │   │   │   ├── test_decomposer_trend.py
│   │   │   │   ├── test_metric_analyzer.py
│   │   │   │   ├── test_metrics_error_handling.py
│   │   │   │   ├── test_metrics_models.py
│   │   │   │   ├── test_metrics_server.py
│   │   │   │   ├── test_seasonal_detector.py
│   │   │   │   ├── test_seasonality_enum.py
│   │   │   │   ├── test_utils.py
│   │   │   │   └── test_validation_error.py
│   │   │   ├── test_common_and_server.py
│   │   │   ├── test_init.py
│   │   │   └── test_main.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── code-doc-gen-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── code_doc_gen_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── server.py
│   │   │       └── utils
│   │   │           ├── doc_generator.py
│   │   │           ├── models.py
│   │   │           ├── repomix_manager.py
│   │   │           └── templates.py
│   │   ├── CHANGELOG.md
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── test_doc_generator_edge_cases.py
│   │   │   ├── test_doc_generator.py
│   │   │   ├── test_init.py
│   │   │   ├── test_main.py
│   │   │   ├── test_repomix_manager_scenarios.py
│   │   │   ├── test_repomix_manager.py
│   │   │   ├── test_repomix_statistics.py
│   │   │   ├── test_server_extended.py
│   │   │   ├── test_server.py
│   │   │   └── test_templates.py
│   │   └── uv.lock
│   ├── core-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── core_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── server.py
│   │   │       └── static
│   │   │           ├── __init__.py
│   │   │           └── PROMPT_UNDERSTANDING.md
│   │   ├── CHANGELOG.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── __init__.py
│   │   │   ├── conftest.py
│   │   │   ├── README.md
│   │   │   ├── test_init.py
│   │   │   ├── test_main.py
│   │   │   ├── test_response_types.py
│   │   │   ├── test_server.py
│   │   │   └── test_static.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── cost-explorer-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── cost_explorer_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── comparison_handler.py
│   │   │       ├── constants.py
│   │   │       ├── cost_usage_handler.py
│   │   │       ├── forecasting_handler.py
│   │   │       ├── helpers.py
│   │   │       ├── metadata_handler.py
│   │   │       ├── models.py
│   │   │       ├── server.py
│   │   │       └── utility_handler.py
│   │   ├── CHANGELOG.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── __init__.py
│   │   │   ├── conftest.py
│   │   │   ├── test_comparison_handler.py
│   │   │   ├── test_cost_usage_handler.py
│   │   │   ├── test_forecasting_handler.py
│   │   │   ├── test_helpers.py
│   │   │   ├── test_metadata_handler.py
│   │   │   ├── test_models.py
│   │   │   ├── test_server.py
│   │   │   └── test_utility_handler.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── documentdb-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   └── documentdb_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── analytic_tools.py
│   │   │       ├── config.py
│   │   │       ├── connection_tools.py
│   │   │       ├── db_management_tools.py
│   │   │       ├── query_tools.py
│   │   │       ├── server.py
│   │   │       └── write_tools.py
│   │   ├── CHANGELOG.md
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── conftest.py
│   │   │   ├── test_analytic_tools.py
│   │   │   ├── test_connection_tools.py
│   │   │   ├── test_db_management_tools.py
│   │   │   ├── test_init.py
│   │   │   ├── test_main.py
│   │   │   ├── test_query_tools.py
│   │   │   └── test_write_tools.py
│   │   └── uv.lock
│   ├── dynamodb-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── dynamodb_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── common.py
│   │   │       ├── database_analysis_queries.py
│   │   │       ├── database_analyzers.py
│   │   │       ├── markdown_formatter.py
│   │   │       ├── prompts
│   │   │       │   └── dynamodb_architect.md
│   │   │       └── server.py
│   │   ├── CHANGELOG.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── __init__.py
│   │   │   ├── conftest.py
│   │   │   ├── evals
│   │   │   │   ├── dynamic_evaluators.py
│   │   │   │   ├── evaluation_registry.py
│   │   │   │   ├── logging_config.py
│   │   │   │   ├── multiturn_evaluator.py
│   │   │   │   ├── README.md
│   │   │   │   ├── scenarios.py
│   │   │   │   └── test_dspy_evals.py
│   │   │   ├── test_dynamodb_server.py
│   │   │   ├── test_markdown_formatter.py
│   │   │   └── test_source_db_integration.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── ecs-mcp-server
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── ecs_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── api
│   │   │       │   ├── __init__.py
│   │   │       │   ├── containerize.py
│   │   │       │   ├── delete.py
│   │   │       │   ├── ecs_troubleshooting.py
│   │   │       │   ├── infrastructure.py
│   │   │       │   ├── resource_management.py
│   │   │       │   ├── status.py
│   │   │       │   └── troubleshooting_tools
│   │   │       │       ├── __init__.py
│   │   │       │       ├── detect_image_pull_failures.py
│   │   │       │       ├── fetch_cloudformation_status.py
│   │   │       │       ├── fetch_network_configuration.py
│   │   │       │       ├── fetch_service_events.py
│   │   │       │       ├── fetch_task_failures.py
│   │   │       │       ├── fetch_task_logs.py
│   │   │       │       ├── get_ecs_troubleshooting_guidance.py
│   │   │       │       └── utils.py
│   │   │       ├── main.py
│   │   │       ├── modules
│   │   │       │   ├── __init__.py
│   │   │       │   ├── aws_knowledge_proxy.py
│   │   │       │   ├── containerize.py
│   │   │       │   ├── delete.py
│   │   │       │   ├── deployment_status.py
│   │   │       │   ├── infrastructure.py
│   │   │       │   ├── resource_management.py
│   │   │       │   └── troubleshooting.py
│   │   │       ├── templates
│   │   │       │   ├── ecr_infrastructure.json
│   │   │       │   └── ecs_infrastructure.json
│   │   │       └── utils
│   │   │           ├── arn_parser.py
│   │   │           ├── aws.py
│   │   │           ├── config.py
│   │   │           ├── docker.py
│   │   │           ├── security.py
│   │   │           ├── templates.py
│   │   │           └── time_utils.py
│   │   ├── DEVELOPMENT.md
│   │   ├── pyproject.toml
│   │   ├── pyrightconfig.json
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── __init__.py
│   │   │   ├── conftest.py
│   │   │   ├── integ
│   │   │   │   └── mcp-inspector
│   │   │   │       ├── .gitignore
│   │   │   │       ├── README.md
│   │   │   │       ├── run-tests.sh
│   │   │   │       └── scenarios
│   │   │   │           ├── 01_comprehensive_troubleshooting
│   │   │   │           │   ├── 01_create.sh
│   │   │   │           │   ├── 02_validate.sh
│   │   │   │           │   ├── 03_cleanup.sh
│   │   │   │           │   ├── description.txt
│   │   │   │           │   └── utils
│   │   │   │           │       ├── mcp_helpers.sh
│   │   │   │           │       └── validation_helpers.sh
│   │   │   │           └── 02_test_knowledge_proxy_tools
│   │   │   │               ├── 01_create.sh
│   │   │   │               ├── 02_validate.sh
│   │   │   │               ├── 03_cleanup.sh
│   │   │   │               ├── description.txt
│   │   │   │               └── utils
│   │   │   │                   ├── knowledge_validation_helpers.sh
│   │   │   │                   └── mcp_knowledge_helpers.sh
│   │   │   ├── llm_testing
│   │   │   │   ├── invalid_cfn_template.yaml
│   │   │   │   ├── README.md
│   │   │   │   ├── run_tests.sh
│   │   │   │   ├── scenarios
│   │   │   │   │   ├── 01_cloudformation_failure
│   │   │   │   │   │   ├── 01_create.sh
│   │   │   │   │   │   ├── 02_validate.sh
│   │   │   │   │   │   ├── 03_prompts.txt
│   │   │   │   │   │   ├── 04_evaluation.md
│   │   │   │   │   │   ├── 05_cleanup.sh
│   │   │   │   │   │   └── description.txt
│   │   │   │   │   ├── 02_service_failure
│   │   │   │   │   │   ├── 01_create.sh
│   │   │   │   │   │   ├── 02_validate.sh
│   │   │   │   │   │   ├── 03_prompts.txt
│   │   │   │   │   │   ├── 04_evaluation.md
│   │   │   │   │   │   ├── 05_cleanup.sh
│   │   │   │   │   │   └── description.txt
│   │   │   │   │   ├── 03_task_exit_failure
│   │   │   │   │   │   ├── 01_create.sh
│   │   │   │   │   │   ├── 02_validate.sh
│   │   │   │   │   │   ├── 03_prompts.txt
│   │   │   │   │   │   ├── 04_evaluation.md
│   │   │   │   │   │   ├── 05_cleanup.sh
│   │   │   │   │   │   └── description.txt
│   │   │   │   │   ├── 04_network_configuration_failure
│   │   │   │   │   │   ├── 01_create.sh
│   │   │   │   │   │   ├── 02_validate.sh
│   │   │   │   │   │   ├── 03_prompts.txt
│   │   │   │   │   │   ├── 05_cleanup.sh
│   │   │   │   │   │   └── description.txt
│   │   │   │   │   ├── 05_resource_constraint_failure
│   │   │   │   │   │   ├── 01_create.sh
│   │   │   │   │   │   ├── 02_validate.sh
│   │   │   │   │   │   ├── 03_prompts.txt
│   │   │   │   │   │   ├── 05_cleanup.sh
│   │   │   │   │   │   └── description.txt
│   │   │   │   │   └── 06_load_balancer_failure
│   │   │   │   │       ├── 01_create.sh
│   │   │   │   │       ├── 02_validate.sh
│   │   │   │   │       ├── 03_prompts.txt
│   │   │   │   │       ├── 05_cleanup.sh
│   │   │   │   │       └── description.txt
│   │   │   │   ├── SCRIPT_IMPROVEMENTS.md
│   │   │   │   └── utils
│   │   │   │       ├── aws_helpers.sh
│   │   │   │       └── evaluation_template.md
│   │   │   └── unit
│   │   │       ├── __init__.py
│   │   │       ├── api
│   │   │       │   ├── conftest.py
│   │   │       │   ├── test_delete_api.py
│   │   │       │   ├── test_ecs_troubleshooting.py
│   │   │       │   ├── test_resource_management_api.py
│   │   │       │   └── troubleshooting_tools
│   │   │       │       └── test_fetch_network_configuration.py
│   │   │       ├── conftest.py
│   │   │       ├── modules
│   │   │       │   ├── test_aws_knowledge_proxy.py
│   │   │       │   └── test_resource_management_module.py
│   │   │       ├── test_aws_role_utils.py
│   │   │       ├── test_aws_utils.py
│   │   │       ├── test_containerize.py
│   │   │       ├── test_delete.py
│   │   │       ├── test_docker_utils.py
│   │   │       ├── test_docker_with_role.py
│   │   │       ├── test_image_pull_failure_extended.py
│   │   │       ├── test_image_pull_failure.py
│   │   │       ├── test_infrastructure_role.py
│   │   │       ├── test_infrastructure.py
│   │   │       ├── test_integration.py
│   │   │       ├── test_main.py
│   │   │       ├── test_resource_management_api_operation.py
│   │   │       ├── test_resource_management_tool.py
│   │   │       ├── test_resource_management.py
│   │   │       ├── test_security_integration.py
│   │   │       ├── test_status_pytest.py
│   │   │       ├── test_status.py
│   │   │       ├── troubleshooting_tools
│   │   │       │   ├── __init__.py
│   │   │       │   ├── conftest.py
│   │   │       │   ├── test_detect_image_pull_failures.py
│   │   │       │   ├── test_fetch_cloudformation_status.py
│   │   │       │   ├── test_fetch_service_events.py
│   │   │       │   ├── test_fetch_task_failures.py
│   │   │       │   ├── test_fetch_task_logs.py
│   │   │       │   ├── test_get_ecs_troubleshooting_guidance.py
│   │   │       │   ├── test_is_ecr_image_security.py
│   │   │       │   └── test_utils.py
│   │   │       └── utils
│   │   │           ├── __init__.py
│   │   │           ├── async_test_utils.py
│   │   │           ├── test_arn_parser.py
│   │   │           ├── test_config.py
│   │   │           ├── test_docker.py
│   │   │           ├── test_response_sanitization.py
│   │   │           ├── test_security_extended.py
│   │   │           ├── test_security.py
│   │   │           ├── test_templates.py
│   │   │           └── test_time_utils.py
│   │   └── uv.lock
│   ├── eks-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── eks_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── aws_helper.py
│   │   │       ├── cloudwatch_handler.py
│   │   │       ├── cloudwatch_metrics_guidance_handler.py
│   │   │       ├── consts.py
│   │   │       ├── data
│   │   │       │   └── eks_cloudwatch_metrics_guidance.json
│   │   │       ├── eks_kb_handler.py
│   │   │       ├── eks_stack_handler.py
│   │   │       ├── iam_handler.py
│   │   │       ├── insights_handler.py
│   │   │       ├── k8s_apis.py
│   │   │       ├── k8s_client_cache.py
│   │   │       ├── k8s_handler.py
│   │   │       ├── logging_helper.py
│   │   │       ├── models.py
│   │   │       ├── scripts
│   │   │       │   └── update_eks_cloudwatch_metrics_guidance.py
│   │   │       ├── server.py
│   │   │       ├── templates
│   │   │       │   ├── eks-templates
│   │   │       │   │   └── eks-with-vpc.yaml
│   │   │       │   └── k8s-templates
│   │   │       │       ├── deployment.yaml
│   │   │       │       └── service.yaml
│   │   │       └── vpc_config_handler.py
│   │   ├── CHANGELOG.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── test_aws_helper.py
│   │   │   ├── test_cloudwatch_handler.py
│   │   │   ├── test_cloudwatch_metrics_guidance_handler.py
│   │   │   ├── test_eks_kb_handler.py
│   │   │   ├── test_eks_stack_handler.py
│   │   │   ├── test_iam_handler.py
│   │   │   ├── test_init.py
│   │   │   ├── test_insights_handler.py
│   │   │   ├── test_k8s_apis.py
│   │   │   ├── test_k8s_client_cache.py
│   │   │   ├── test_k8s_handler.py
│   │   │   ├── test_logging_helper.py
│   │   │   ├── test_main.py
│   │   │   ├── test_models.py
│   │   │   ├── test_server.py
│   │   │   └── test_vpc_config_handler.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── elasticache-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── elasticache_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── common
│   │   │       │   ├── __init__.py
│   │   │       │   ├── connection.py
│   │   │       │   ├── decorators.py
│   │   │       │   └── server.py
│   │   │       ├── context.py
│   │   │       ├── main.py
│   │   │       └── tools
│   │   │           ├── __init__.py
│   │   │           ├── cc
│   │   │           │   ├── __init__.py
│   │   │           │   ├── connect.py
│   │   │           │   ├── create.py
│   │   │           │   ├── delete.py
│   │   │           │   ├── describe.py
│   │   │           │   ├── modify.py
│   │   │           │   ├── parsers.py
│   │   │           │   └── processors.py
│   │   │           ├── ce
│   │   │           │   ├── __init__.py
│   │   │           │   └── get_cost_and_usage.py
│   │   │           ├── cw
│   │   │           │   ├── __init__.py
│   │   │           │   └── get_metric_statistics.py
│   │   │           ├── cwlogs
│   │   │           │   ├── __init__.py
│   │   │           │   ├── create_log_group.py
│   │   │           │   ├── describe_log_groups.py
│   │   │           │   ├── describe_log_streams.py
│   │   │           │   ├── filter_log_events.py
│   │   │           │   └── get_log_events.py
│   │   │           ├── firehose
│   │   │           │   ├── __init__.py
│   │   │           │   └── list_delivery_streams.py
│   │   │           ├── misc
│   │   │           │   ├── __init__.py
│   │   │           │   ├── batch_apply_update_action.py
│   │   │           │   ├── batch_stop_update_action.py
│   │   │           │   ├── describe_cache_engine_versions.py
│   │   │           │   ├── describe_engine_default_parameters.py
│   │   │           │   ├── describe_events.py
│   │   │           │   └── describe_service_updates.py
│   │   │           ├── rg
│   │   │           │   ├── __init__.py
│   │   │           │   ├── complete_migration.py
│   │   │           │   ├── connect.py
│   │   │           │   ├── create.py
│   │   │           │   ├── delete.py
│   │   │           │   ├── describe.py
│   │   │           │   ├── modify.py
│   │   │           │   ├── parsers.py
│   │   │           │   ├── processors.py
│   │   │           │   ├── start_migration.py
│   │   │           │   └── test_migration.py
│   │   │           └── serverless
│   │   │               ├── __init__.py
│   │   │               ├── connect.py
│   │   │               ├── create.py
│   │   │               ├── delete.py
│   │   │               ├── describe.py
│   │   │               ├── models.py
│   │   │               └── modify.py
│   │   ├── CHANGELOG.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── test_connection.py
│   │   │   ├── test_decorators.py
│   │   │   ├── test_init.py
│   │   │   ├── test_main.py
│   │   │   └── tools
│   │   │       ├── cc
│   │   │       │   ├── __init__.py
│   │   │       │   ├── test_connect_additional.py
│   │   │       │   ├── test_connect_coverage_additional.py
│   │   │       │   ├── test_connect_coverage.py
│   │   │       │   ├── test_connect.py
│   │   │       │   ├── test_create_additional.py
│   │   │       │   ├── test_create.py
│   │   │       │   ├── test_delete.py
│   │   │       │   ├── test_describe.py
│   │   │       │   ├── test_modify.py
│   │   │       │   ├── test_parsers.py
│   │   │       │   └── test_processors.py
│   │   │       ├── ce
│   │   │       │   ├── __init__.py
│   │   │       │   └── test_get_cost_and_usage.py
│   │   │       ├── cw
│   │   │       │   └── test_get_metric_statistics.py
│   │   │       ├── cwlogs
│   │   │       │   ├── __init__.py
│   │   │       │   ├── test_create_log_group.py
│   │   │       │   ├── test_describe_log_groups.py
│   │   │       │   ├── test_describe_log_streams.py
│   │   │       │   ├── test_filter_log_events.py
│   │   │       │   └── test_get_log_events.py
│   │   │       ├── firehose
│   │   │       │   └── test_list_delivery_streams.py
│   │   │       ├── misc
│   │   │       │   ├── __init__.py
│   │   │       │   ├── test_batch_apply_update_action.py
│   │   │       │   ├── test_batch_stop_update_action.py
│   │   │       │   ├── test_describe_cache_engine_versions.py
│   │   │       │   ├── test_describe_engine_default_parameters.py
│   │   │       │   ├── test_describe_events.py
│   │   │       │   └── test_describe_service_updates.py
│   │   │       ├── rg
│   │   │       │   ├── __init__.py
│   │   │       │   ├── test_complete_migration.py
│   │   │       │   ├── test_connect_additional.py
│   │   │       │   ├── test_connect_coverage_additional.py
│   │   │       │   ├── test_connect_optional_fields.py
│   │   │       │   ├── test_connect_partial_coverage.py
│   │   │       │   ├── test_connect.py
│   │   │       │   ├── test_create.py
│   │   │       │   ├── test_delete.py
│   │   │       │   ├── test_describe.py
│   │   │       │   ├── test_modify.py
│   │   │       │   ├── test_parsers.py
│   │   │       │   ├── test_processors.py
│   │   │       │   ├── test_start_migration.py
│   │   │       │   └── test_test_migration.py
│   │   │       └── serverless
│   │   │           ├── test_connect_additional.py
│   │   │           ├── test_connect_coverage_additional.py
│   │   │           ├── test_connect_optional_fields.py
│   │   │           ├── test_connect.py
│   │   │           ├── test_create.py
│   │   │           ├── test_delete.py
│   │   │           ├── test_describe.py
│   │   │           └── test_modify.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── finch-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── finch_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── consts.py
│   │   │       ├── models.py
│   │   │       ├── server.py
│   │   │       └── utils
│   │   │           ├── __init__.py
│   │   │           ├── build.py
│   │   │           ├── common.py
│   │   │           ├── ecr.py
│   │   │           ├── push.py
│   │   │           └── vm.py
│   │   ├── CHANGELOG.md
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── __init__.py
│   │   │   ├── test_cli_flags.py
│   │   │   ├── test_logging_configuration.py
│   │   │   ├── test_server.py
│   │   │   ├── test_utils_build.py
│   │   │   ├── test_utils_common.py
│   │   │   ├── test_utils_ecr.py
│   │   │   ├── test_utils_push.py
│   │   │   └── test_utils_vm.py
│   │   └── uv.lock
│   ├── frontend-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── frontend_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── server.py
│   │   │       ├── static
│   │   │       │   └── react
│   │   │       │       ├── essential-knowledge.md
│   │   │       │       └── troubleshooting.md
│   │   │       └── utils
│   │   │           ├── __init__.py
│   │   │           └── file_utils.py
│   │   ├── CHANGELOG.md
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── test_file_utils.py
│   │   │   ├── test_init.py
│   │   │   ├── test_main.py
│   │   │   └── test_server.py
│   │   └── uv.lock
│   ├── git-repo-research-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── git_repo_research_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── defaults.py
│   │   │       ├── embeddings.py
│   │   │       ├── github_search.py
│   │   │       ├── indexer.py
│   │   │       ├── models.py
│   │   │       ├── repository.py
│   │   │       ├── search.py
│   │   │       ├── server.py
│   │   │       └── utils.py
│   │   ├── CHANGELOG.md
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── run_tests.sh
│   │   ├── tests
│   │   │   ├── __init__.py
│   │   │   ├── conftest.py
│   │   │   ├── test_errors_repository.py
│   │   │   ├── test_github_search_edge_cases.py
│   │   │   ├── test_graphql_github_search.py
│   │   │   ├── test_local_repository.py
│   │   │   ├── test_repository_utils.py
│   │   │   ├── test_rest_github_search.py
│   │   │   ├── test_search.py
│   │   │   ├── test_server.py
│   │   │   └── test_url_repository.py
│   │   └── uv.lock
│   ├── healthlake-mcp-server
│   │   ├── .dockerignore
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── healthlake_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── fhir_operations.py
│   │   │       ├── main.py
│   │   │       ├── models.py
│   │   │       └── server.py
│   │   ├── CHANGELOG.md
│   │   ├── CONTRIBUTING.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── examples
│   │   │   ├── mcp_config.json
│   │   │   └── README.md
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── conftest.py
│   │   │   ├── test_fhir_client_comprehensive.py
│   │   │   ├── test_fhir_error_scenarios.py
│   │   │   ├── test_fhir_operations.py
│   │   │   ├── test_integration_mock_based.py
│   │   │   ├── test_main_edge_cases.py
│   │   │   ├── test_main.py
│   │   │   ├── test_mcp_integration_coverage.py
│   │   │   ├── test_models_edge_cases.py
│   │   │   ├── test_models.py
│   │   │   ├── test_readonly_mode.py
│   │   │   ├── test_server_core.py
│   │   │   ├── test_server_error_handling.py
│   │   │   ├── test_server_mcp_handlers.py
│   │   │   ├── test_server_toolhandler.py
│   │   │   └── test_server_validation.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── iam-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── iam_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── aws_client.py
│   │   │       ├── context.py
│   │   │       ├── errors.py
│   │   │       ├── models.py
│   │   │       └── server.py
│   │   ├── CHANGELOG.md
│   │   ├── DESIGN_COMPLIANCE.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── examples
│   │   │   ├── get_policy_document_example.py
│   │   │   └── inline_policy_demo.py
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── run_tests.sh
│   │   ├── tests
│   │   │   ├── test_context.py
│   │   │   ├── test_errors.py
│   │   │   ├── test_inline_policies.py
│   │   │   └── test_server.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── lambda-tool-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── lambda_tool_mcp_server
│   │   │       ├── __init__.py
│   │   │       └── server.py
│   │   ├── CHANGELOG.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── examples
│   │   │   ├── README.md
│   │   │   └── sample_functions
│   │   │       ├── customer-create
│   │   │       │   └── app.py
│   │   │       ├── customer-id-from-email
│   │   │       │   └── app.py
│   │   │       ├── customer-info-from-id
│   │   │       │   └── app.py
│   │   │       └── template.yml
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── __init__.py
│   │   │   ├── .gitignore
│   │   │   ├── conftest.py
│   │   │   ├── README.md
│   │   │   ├── test_format_lambda_response.py
│   │   │   ├── test_integration_coverage.py
│   │   │   ├── test_integration.py
│   │   │   ├── test_register_lambda_functions.py
│   │   │   ├── test_schema_integration.py
│   │   │   ├── test_server_coverage_additional.py
│   │   │   ├── test_server_coverage.py
│   │   │   └── test_server.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── mcp-lambda-handler
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   └── mcp_lambda_handler
│   │   │       ├── __init__.py
│   │   │       ├── mcp_lambda_handler.py
│   │   │       ├── session.py
│   │   │       └── types.py
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   └── test_lambda_handler.py
│   │   └── uv.lock
│   ├── memcached-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── memcached_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── common
│   │   │       │   ├── config.py
│   │   │       │   ├── connection.py
│   │   │       │   └── server.py
│   │   │       ├── context.py
│   │   │       ├── main.py
│   │   │       └── tools
│   │   │           └── cache.py
│   │   ├── CHANGELOG.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── ELASTICACHECONNECT.md
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── test_cache_readonly.py
│   │   │   ├── test_cache.py
│   │   │   ├── test_connection.py
│   │   │   ├── test_init.py
│   │   │   └── test_main.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── mysql-mcp-server
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── mysql_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── connection
│   │   │       │   ├── __init__.py
│   │   │       │   ├── abstract_db_connection.py
│   │   │       │   ├── asyncmy_pool_connection.py
│   │   │       │   ├── db_connection_singleton.py
│   │   │       │   └── rds_data_api_connection.py
│   │   │       ├── mutable_sql_detector.py
│   │   │       └── server.py
│   │   ├── CHANGELOG.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── conftest.py
│   │   │   ├── test_abstract_db_connection.py
│   │   │   ├── test_asyncmy_pool_connection.py
│   │   │   ├── test_db_connection_singleton.py
│   │   │   ├── test_rds_data_api_connection.py
│   │   │   └── test_server.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── nova-canvas-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── nova_canvas_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── consts.py
│   │   │       ├── models.py
│   │   │       ├── novacanvas.py
│   │   │       └── server.py
│   │   ├── CHANGELOG.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── __init__.py
│   │   │   ├── .gitignore
│   │   │   ├── conftest.py
│   │   │   ├── README.md
│   │   │   ├── test_models.py
│   │   │   ├── test_novacanvas.py
│   │   │   └── test_server.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── openapi-mcp-server
│   │   ├── .coveragerc
│   │   ├── .dockerignore
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── AUTHENTICATION.md
│   │   ├── AWS_BEST_PRACTICES.md
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── openapi_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── api
│   │   │       │   ├── __init__.py
│   │   │       │   └── config.py
│   │   │       ├── auth
│   │   │       │   ├── __init__.py
│   │   │       │   ├── api_key_auth.py
│   │   │       │   ├── auth_cache.py
│   │   │       │   ├── auth_errors.py
│   │   │       │   ├── auth_factory.py
│   │   │       │   ├── auth_protocol.py
│   │   │       │   ├── auth_provider.py
│   │   │       │   ├── base_auth.py
│   │   │       │   ├── basic_auth.py
│   │   │       │   ├── bearer_auth.py
│   │   │       │   ├── cognito_auth.py
│   │   │       │   └── register.py
│   │   │       ├── patch
│   │   │       │   └── __init__.py
│   │   │       ├── prompts
│   │   │       │   ├── __init__.py
│   │   │       │   ├── generators
│   │   │       │   │   ├── __init__.py
│   │   │       │   │   ├── operation_prompts.py
│   │   │       │   │   └── workflow_prompts.py
│   │   │       │   ├── models.py
│   │   │       │   └── prompt_manager.py
│   │   │       ├── server.py
│   │   │       └── utils
│   │   │           ├── __init__.py
│   │   │           ├── cache_provider.py
│   │   │           ├── config.py
│   │   │           ├── error_handler.py
│   │   │           ├── http_client.py
│   │   │           ├── metrics_provider.py
│   │   │           ├── openapi_validator.py
│   │   │           └── openapi.py
│   │   ├── CHANGELOG.md
│   │   ├── DEPLOYMENT.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── OBSERVABILITY.md
│   │   ├── pyproject.toml
│   │   ├── pyrightconfig.json
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── api
│   │   │   │   └── test_config.py
│   │   │   ├── auth
│   │   │   │   ├── test_api_key_auth.py
│   │   │   │   ├── test_auth_cache.py
│   │   │   │   ├── test_auth_errors.py
│   │   │   │   ├── test_auth_factory_caching.py
│   │   │   │   ├── test_auth_factory_coverage.py
│   │   │   │   ├── test_auth_factory.py
│   │   │   │   ├── test_auth_protocol_additional.py
│   │   │   │   ├── test_auth_protocol_boost.py
│   │   │   │   ├── test_auth_protocol_coverage.py
│   │   │   │   ├── test_auth_protocol_extended.py
│   │   │   │   ├── test_auth_protocol_improved.py
│   │   │   │   ├── test_auth_protocol.py
│   │   │   │   ├── test_auth_provider_additional.py
│   │   │   │   ├── test_base_auth_coverage.py
│   │   │   │   ├── test_base_auth.py
│   │   │   │   ├── test_basic_auth.py
│   │   │   │   ├── test_bearer_auth.py
│   │   │   │   ├── test_cognito_auth_additional_coverage.py
│   │   │   │   ├── test_cognito_auth_boost_coverage.py
│   │   │   │   ├── test_cognito_auth_client_credentials.py
│   │   │   │   ├── test_cognito_auth_coverage_boost.py
│   │   │   │   ├── test_cognito_auth_exceptions.py
│   │   │   │   ├── test_cognito_auth.py
│   │   │   │   ├── test_register_coverage.py
│   │   │   │   └── test_register.py
│   │   │   ├── prompts
│   │   │   │   ├── standalone
│   │   │   │   │   ├── test_operation_prompt.py
│   │   │   │   │   ├── test_prompt_arguments.py
│   │   │   │   │   └── test_secure_operation_prompt.py
│   │   │   │   ├── test_mcp_prompt_manager_integration.py
│   │   │   │   ├── test_mcp_prompt_manager.py
│   │   │   │   ├── test_models_dict_method.py
│   │   │   │   ├── test_operation_prompts_extended.py
│   │   │   │   ├── test_prompt_manager_additional.py
│   │   │   │   ├── test_prompt_manager_comprehensive.py
│   │   │   │   ├── test_prompt_manager_coverage.py
│   │   │   │   └── test_prompt_registration.py
│   │   │   ├── README.md
│   │   │   ├── test_api_name.py
│   │   │   ├── test_cache_coverage_89.py
│   │   │   ├── test_client.py
│   │   │   ├── test_coverage_boost.py
│   │   │   ├── test_init.py
│   │   │   ├── test_main_extended.py
│   │   │   ├── test_main.py
│   │   │   ├── test_openapi_coverage_89.py
│   │   │   ├── test_server_auth_errors.py
│   │   │   ├── test_server_coverage_boost_2.py
│   │   │   ├── test_server_coverage_boost.py
│   │   │   ├── test_server_exception_handling.py
│   │   │   ├── test_server_extended.py
│   │   │   ├── test_server_httpx_version.py
│   │   │   ├── test_server_part1.py
│   │   │   ├── test_server_route_logging.py
│   │   │   ├── test_server_signal_handlers.py
│   │   │   ├── test_server.py
│   │   │   └── utils
│   │   │       ├── test_cache_provider.py
│   │   │       ├── test_error_handler_boost.py
│   │   │       ├── test_error_handler_extended.py
│   │   │       ├── test_error_handler_fix.py
│   │   │       ├── test_error_handler.py
│   │   │       ├── test_http_client_comprehensive.py
│   │   │       ├── test_http_client_extended.py
│   │   │       ├── test_http_client_extended2.py
│   │   │       ├── test_http_client_import_error.py
│   │   │       ├── test_http_client.py
│   │   │       ├── test_metrics_provider_decorators.py
│   │   │       ├── test_metrics_provider_extended2.py
│   │   │       ├── test_metrics_provider_prometheus.py
│   │   │       ├── test_metrics_provider.py
│   │   │       ├── test_openapi_validator.py
│   │   │       └── test_openapi.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── postgres-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── postgres_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── connection
│   │   │       │   ├── __init__.py
│   │   │       │   ├── abstract_db_connection.py
│   │   │       │   ├── db_connection_singleton.py
│   │   │       │   ├── psycopg_pool_connection.py
│   │   │       │   └── rds_api_connection.py
│   │   │       ├── mutable_sql_detector.py
│   │   │       └── server.py
│   │   ├── CHANGELOG.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── conftest.py
│   │   │   ├── test_psycopg_connector.py
│   │   │   ├── test_server.py
│   │   │   └── test_singleton.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── prometheus-mcp-server
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── prometheus_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── consts.py
│   │   │       ├── models.py
│   │   │       └── server.py
│   │   ├── CHANGELOG.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── conftest.py
│   │   │   ├── test_aws_credentials.py
│   │   │   ├── test_config_manager.py
│   │   │   ├── test_consts.py
│   │   │   ├── test_coverage_gaps.py
│   │   │   ├── test_coverage_improvement.py
│   │   │   ├── test_final_coverage.py
│   │   │   ├── test_init.py
│   │   │   ├── test_main.py
│   │   │   ├── test_models.py
│   │   │   ├── test_prometheus_client.py
│   │   │   ├── test_prometheus_connection.py
│   │   │   ├── test_security_validator.py
│   │   │   ├── test_server_coverage.py
│   │   │   ├── test_tools.py
│   │   │   └── test_workspace_config.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── redshift-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── redshift_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── consts.py
│   │   │       ├── models.py
│   │   │       ├── redshift.py
│   │   │       └── server.py
│   │   ├── CHANGELOG.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── test_init.py
│   │   │   ├── test_main.py
│   │   │   ├── test_redshift.py
│   │   │   └── test_server.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── s3-tables-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── s3_tables_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── constants.py
│   │   │       ├── database.py
│   │   │       ├── engines
│   │   │       │   ├── __init__.py
│   │   │       │   └── pyiceberg.py
│   │   │       ├── file_processor
│   │   │       │   ├── __init__.py
│   │   │       │   ├── csv.py
│   │   │       │   ├── parquet.py
│   │   │       │   └── utils.py
│   │   │       ├── models.py
│   │   │       ├── namespaces.py
│   │   │       ├── resources.py
│   │   │       ├── s3_operations.py
│   │   │       ├── server.py
│   │   │       ├── table_buckets.py
│   │   │       ├── tables.py
│   │   │       └── utils.py
│   │   ├── CHANGELOG.md
│   │   ├── CONTEXT.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── test_csv.py
│   │   │   ├── test_database.py
│   │   │   ├── test_file_processor_utils.py
│   │   │   ├── test_init.py
│   │   │   ├── test_main.py
│   │   │   ├── test_namespaces.py
│   │   │   ├── test_parquet.py
│   │   │   ├── test_pyiceberg.py
│   │   │   ├── test_resources.py
│   │   │   ├── test_s3_operations.py
│   │   │   ├── test_server.py
│   │   │   ├── test_table_buckets.py
│   │   │   ├── test_tables.py
│   │   │   └── test_utils.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── stepfunctions-tool-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── stepfunctions_tool_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── aws_helper.py
│   │   │       └── server.py
│   │   ├── CHANGELOG.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── __init__.py
│   │   │   ├── .gitignore
│   │   │   ├── README.md
│   │   │   ├── test_aws_helper.py
│   │   │   ├── test_create_state_machine_tool.py
│   │   │   ├── test_filter_state_machines_by_tag.py
│   │   │   ├── test_format_state_machine_response.py
│   │   │   ├── test_get_schema_arn_from_state_machine_arn.py
│   │   │   ├── test_get_schema_from_registry.py
│   │   │   ├── test_invoke_express_state_machine_impl.py
│   │   │   ├── test_invoke_standard_state_machine_impl.py
│   │   │   ├── test_main.py
│   │   │   ├── test_register_state_machines.py
│   │   │   ├── test_sanitize_tool_name.py
│   │   │   ├── test_server.py
│   │   │   └── test_validate_state_machine_name.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── syntheticdata-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── syntheticdata_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── pandas_interpreter.py
│   │   │       ├── server.py
│   │   │       └── storage
│   │   │           ├── __init__.py
│   │   │           ├── base.py
│   │   │           ├── loader.py
│   │   │           └── s3.py
│   │   ├── CHANGELOG.md
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── __init__.py
│   │   │   ├── conftest.py
│   │   │   ├── test_constants.py
│   │   │   ├── test_pandas_interpreter.py
│   │   │   ├── test_server.py
│   │   │   └── test_storage
│   │   │       ├── __init__.py
│   │   │       ├── test_loader.py
│   │   │       └── test_s3.py
│   │   └── uv.lock
│   ├── terraform-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── terraform_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── impl
│   │   │       │   ├── resources
│   │   │       │   │   ├── __init__.py
│   │   │       │   │   ├── terraform_aws_provider_resources_listing.py
│   │   │       │   │   └── terraform_awscc_provider_resources_listing.py
│   │   │       │   └── tools
│   │   │       │       ├── __init__.py
│   │   │       │       ├── execute_terraform_command.py
│   │   │       │       ├── execute_terragrunt_command.py
│   │   │       │       ├── run_checkov_scan.py
│   │   │       │       ├── search_aws_provider_docs.py
│   │   │       │       ├── search_awscc_provider_docs.py
│   │   │       │       ├── search_specific_aws_ia_modules.py
│   │   │       │       ├── search_user_provided_module.py
│   │   │       │       └── utils.py
│   │   │       ├── models
│   │   │       │   ├── __init__.py
│   │   │       │   └── models.py
│   │   │       ├── scripts
│   │   │       │   ├── generate_aws_provider_resources.py
│   │   │       │   ├── generate_awscc_provider_resources.py
│   │   │       │   └── scrape_aws_terraform_best_practices.py
│   │   │       ├── server.py
│   │   │       └── static
│   │   │           ├── __init__.py
│   │   │           ├── AWS_PROVIDER_RESOURCES.md
│   │   │           ├── AWS_TERRAFORM_BEST_PRACTICES.md
│   │   │           ├── AWSCC_PROVIDER_RESOURCES.md
│   │   │           ├── MCP_INSTRUCTIONS.md
│   │   │           └── TERRAFORM_WORKFLOW_GUIDE.md
│   │   ├── CHANGELOG.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── __init__.py
│   │   │   ├── .gitignore
│   │   │   ├── conftest.py
│   │   │   ├── README.md
│   │   │   ├── test_command_impl.py
│   │   │   ├── test_execute_terraform_command.py
│   │   │   ├── test_execute_terragrunt_command.py
│   │   │   ├── test_models.py
│   │   │   ├── test_parameter_annotations.py
│   │   │   ├── test_resources.py
│   │   │   ├── test_run_checkov_scan.py
│   │   │   ├── test_search_user_provided_module.py
│   │   │   ├── test_server.py
│   │   │   ├── test_tool_implementations.py
│   │   │   ├── test_utils_additional.py
│   │   │   └── test_utils.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── timestream-for-influxdb-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── timestream_for_influxdb_mcp_server
│   │   │       ├── __init__.py
│   │   │       └── server.py
│   │   ├── CHANGELOG.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── test_init.py
│   │   │   ├── test_main.py
│   │   │   └── test_server.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   ├── valkey-mcp-server
│   │   ├── .gitignore
│   │   ├── .python-version
│   │   ├── awslabs
│   │   │   ├── __init__.py
│   │   │   └── valkey_mcp_server
│   │   │       ├── __init__.py
│   │   │       ├── common
│   │   │       │   ├── __init__.py
│   │   │       │   ├── config.py
│   │   │       │   ├── connection.py
│   │   │       │   └── server.py
│   │   │       ├── context.py
│   │   │       ├── main.py
│   │   │       ├── tools
│   │   │       │   ├── __init__.py
│   │   │       │   ├── bitmap.py
│   │   │       │   ├── hash.py
│   │   │       │   ├── hyperloglog.py
│   │   │       │   ├── json.py
│   │   │       │   ├── list.py
│   │   │       │   ├── misc.py
│   │   │       │   ├── server_management.py
│   │   │       │   ├── set.py
│   │   │       │   ├── sorted_set.py
│   │   │       │   ├── stream.py
│   │   │       │   └── string.py
│   │   │       └── version.py
│   │   ├── CHANGELOG.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── ELASTICACHECONNECT.md
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── test_bitmap.py
│   │   │   ├── test_config.py
│   │   │   ├── test_connection.py
│   │   │   ├── test_hash.py
│   │   │   ├── test_hyperloglog.py
│   │   │   ├── test_init.py
│   │   │   ├── test_json_additional.py
│   │   │   ├── test_json_readonly.py
│   │   │   ├── test_json.py
│   │   │   ├── test_list_additional.py
│   │   │   ├── test_list_readonly.py
│   │   │   ├── test_list.py
│   │   │   ├── test_main.py
│   │   │   ├── test_misc.py
│   │   │   ├── test_server_management.py
│   │   │   ├── test_set_readonly.py
│   │   │   ├── test_set.py
│   │   │   ├── test_sorted_set_additional.py
│   │   │   ├── test_sorted_set_readonly.py
│   │   │   ├── test_sorted_set.py
│   │   │   ├── test_stream_additional.py
│   │   │   ├── test_stream_readonly.py
│   │   │   ├── test_stream.py
│   │   │   └── test_string.py
│   │   ├── uv-requirements.txt
│   │   └── uv.lock
│   └── well-architected-security-mcp-server
│       ├── .python-version
│       ├── awslabs
│       │   └── well_architected_security_mcp_server
│       │       ├── __init__.py
│       │       ├── consts.py
│       │       ├── server.py
│       │       └── util
│       │           ├── __init__.py
│       │           ├── network_security.py
│       │           ├── prompt_utils.py
│       │           ├── resource_utils.py
│       │           ├── security_services.py
│       │           └── storage_security.py
│       ├── PROMPT_TEMPLATE.md
│       ├── pyproject.toml
│       ├── README.md
│       ├── tests
│       │   ├── __init__.py
│       │   ├── conftest.py
│       │   ├── README.md
│       │   ├── test_access_analyzer_fix.py
│       │   ├── test_network_security_additional.py
│       │   ├── test_network_security.py
│       │   ├── test_prompt_utils_coverage.py
│       │   ├── test_prompt_utils.py
│       │   ├── test_resource_utils_fix.py
│       │   ├── test_resource_utils.py
│       │   ├── test_security_services_additional.py
│       │   ├── test_security_services_coverage.py
│       │   ├── test_security_services.py
│       │   ├── test_server_additional.py
│       │   ├── test_server_coverage.py
│       │   ├── test_server_prompts.py
│       │   ├── test_server_security_findings.py
│       │   ├── test_server.py
│       │   ├── test_storage_security_additional.py
│       │   ├── test_storage_security_comprehensive.py
│       │   ├── test_storage_security_edge_cases.py
│       │   ├── test_storage_security_recommendations.py
│       │   ├── test_storage_security.py
│       │   └── test_user_agent_config.py
│       └── uv.lock
└── VIBE_CODING_TIPS_TRICKS.md
```

# Files

--------------------------------------------------------------------------------
/src/cloudwatch-applicationsignals-mcp-server/tests/test_server.py:
--------------------------------------------------------------------------------

```python
   1 | """Tests for CloudWatch Application Signals MCP Server."""
   2 | 
   3 | import json
   4 | import pytest
   5 | from awslabs.cloudwatch_applicationsignals_mcp_server.server import _filter_operation_targets, main
   6 | from awslabs.cloudwatch_applicationsignals_mcp_server.service_tools import (
   7 |     get_service_detail,
   8 |     list_monitored_services,
   9 |     query_service_metrics,
  10 | )
  11 | from awslabs.cloudwatch_applicationsignals_mcp_server.slo_tools import get_slo
  12 | from awslabs.cloudwatch_applicationsignals_mcp_server.trace_tools import (
  13 |     check_transaction_search_enabled,
  14 |     get_trace_summaries_paginated,
  15 |     list_slis,
  16 |     query_sampled_traces,
  17 |     search_transaction_spans,
  18 | )
  19 | from awslabs.cloudwatch_applicationsignals_mcp_server.utils import remove_null_values
  20 | from botocore.exceptions import ClientError
  21 | from datetime import datetime, timedelta, timezone
  22 | from unittest.mock import AsyncMock, MagicMock, patch
  23 | 
  24 | 
  25 | @pytest.fixture(autouse=True)
  26 | def mock_aws_clients():
  27 |     """Mock all AWS clients to prevent real API calls during tests."""
  28 |     # Create mock clients
  29 |     mock_logs_client = MagicMock()
  30 |     mock_applicationsignals_client = MagicMock()
  31 |     mock_cloudwatch_client = MagicMock()
  32 |     mock_xray_client = MagicMock()
  33 |     mock_synthetics_client = MagicMock()
  34 |     mock_s3_client = MagicMock()
  35 | 
  36 |     # Patch the clients in all modules where they're imported
  37 |     patches = [
  38 |         # Original aws_clients module
  39 |         patch(
  40 |             'awslabs.cloudwatch_applicationsignals_mcp_server.aws_clients.logs_client',
  41 |             mock_logs_client,
  42 |         ),
  43 |         patch(
  44 |             'awslabs.cloudwatch_applicationsignals_mcp_server.aws_clients.applicationsignals_client',
  45 |             mock_applicationsignals_client,
  46 |         ),
  47 |         patch(
  48 |             'awslabs.cloudwatch_applicationsignals_mcp_server.aws_clients.cloudwatch_client',
  49 |             mock_cloudwatch_client,
  50 |         ),
  51 |         patch(
  52 |             'awslabs.cloudwatch_applicationsignals_mcp_server.aws_clients.xray_client',
  53 |             mock_xray_client,
  54 |         ),
  55 |         patch(
  56 |             'awslabs.cloudwatch_applicationsignals_mcp_server.aws_clients.synthetics_client',
  57 |             mock_synthetics_client,
  58 |         ),
  59 |         patch(
  60 |             'awslabs.cloudwatch_applicationsignals_mcp_server.aws_clients.s3_client',
  61 |             mock_s3_client,
  62 |         ),
  63 |         # Service tools module (check what's actually imported)
  64 |         patch(
  65 |             'awslabs.cloudwatch_applicationsignals_mcp_server.service_tools.applicationsignals_client',
  66 |             mock_applicationsignals_client,
  67 |         ),
  68 |         patch(
  69 |             'awslabs.cloudwatch_applicationsignals_mcp_server.service_tools.cloudwatch_client',
  70 |             mock_cloudwatch_client,
  71 |         ),
  72 |         # SLO tools module (check what's actually imported)
  73 |         patch(
  74 |             'awslabs.cloudwatch_applicationsignals_mcp_server.slo_tools.applicationsignals_client',
  75 |             mock_applicationsignals_client,
  76 |         ),
  77 |         # Trace tools module (logs_client, xray_client, and applicationsignals_client are imported)
  78 |         patch(
  79 |             'awslabs.cloudwatch_applicationsignals_mcp_server.trace_tools.logs_client',
  80 |             mock_logs_client,
  81 |         ),
  82 |         patch(
  83 |             'awslabs.cloudwatch_applicationsignals_mcp_server.trace_tools.xray_client',
  84 |             mock_xray_client,
  85 |         ),
  86 |         patch(
  87 |             'awslabs.cloudwatch_applicationsignals_mcp_server.trace_tools.applicationsignals_client',
  88 |             mock_applicationsignals_client,
  89 |         ),
  90 |         # SLI report client module (applicationsignals_client and cloudwatch_client are imported)
  91 |         patch(
  92 |             'awslabs.cloudwatch_applicationsignals_mcp_server.sli_report_client.applicationsignals_client',
  93 |             mock_applicationsignals_client,
  94 |         ),
  95 |         patch(
  96 |             'awslabs.cloudwatch_applicationsignals_mcp_server.sli_report_client.cloudwatch_client',
  97 |             mock_cloudwatch_client,
  98 |         ),
  99 |         patch(
 100 |             'awslabs.cloudwatch_applicationsignals_mcp_server.server.synthetics_client',
 101 |             mock_synthetics_client,
 102 |         ),
 103 |         patch('awslabs.cloudwatch_applicationsignals_mcp_server.server.s3_client', mock_s3_client),
 104 |         patch('awslabs.cloudwatch_applicationsignals_mcp_server.server.iam_client', MagicMock()),
 105 |     ]
 106 | 
 107 |     # Start all patches
 108 |     for p in patches:
 109 |         p.start()
 110 | 
 111 |     try:
 112 |         yield {
 113 |             'logs_client': mock_logs_client,
 114 |             'applicationsignals_client': mock_applicationsignals_client,
 115 |             'cloudwatch_client': mock_cloudwatch_client,
 116 |             'xray_client': mock_xray_client,
 117 |             'synthetics_client': mock_synthetics_client,
 118 |             's3_client': mock_s3_client,
 119 |         }
 120 |     finally:
 121 |         # Stop all patches
 122 |         for p in patches:
 123 |             p.stop()
 124 | 
 125 | 
 126 | @pytest.fixture
 127 | def mock_mcp():
 128 |     """Mock the FastMCP instance."""
 129 |     with patch('awslabs.cloudwatch_applicationsignals_mcp_server.server.mcp') as mock:
 130 |         yield mock
 131 | 
 132 | 
 133 | @pytest.mark.asyncio
 134 | async def test_list_monitored_services_success(mock_aws_clients):
 135 |     """Test successful listing of monitored services."""
 136 |     mock_response = {
 137 |         'ServiceSummaries': [
 138 |             {
 139 |                 'KeyAttributes': {
 140 |                     'Name': 'test-service',
 141 |                     'Type': 'AWS::ECS::Service',
 142 |                     'Environment': 'production',
 143 |                 }
 144 |             }
 145 |         ]
 146 |     }
 147 | 
 148 |     mock_aws_clients['applicationsignals_client'].list_services.return_value = mock_response
 149 | 
 150 |     result = await list_monitored_services()
 151 | 
 152 |     assert 'Application Signals Services (1 total)' in result
 153 |     assert 'test-service' in result
 154 |     assert 'AWS::ECS::Service' in result
 155 | 
 156 | 
 157 | @pytest.mark.asyncio
 158 | async def test_list_monitored_services_empty(mock_aws_clients):
 159 |     """Test when no services are found."""
 160 |     mock_response = {'ServiceSummaries': []}
 161 | 
 162 |     mock_aws_clients['applicationsignals_client'].list_services.return_value = mock_response
 163 | 
 164 |     result = await list_monitored_services()
 165 | 
 166 |     assert result == 'No services found in Application Signals.'
 167 | 
 168 | 
 169 | @pytest.mark.asyncio
 170 | async def test_get_service_detail_success(mock_aws_clients):
 171 |     """Test successful retrieval of service details."""
 172 |     mock_list_response = {
 173 |         'ServiceSummaries': [
 174 |             {'KeyAttributes': {'Name': 'test-service', 'Type': 'AWS::ECS::Service'}}
 175 |         ]
 176 |     }
 177 | 
 178 |     mock_get_response = {
 179 |         'Service': {
 180 |             'KeyAttributes': {'Name': 'test-service', 'Type': 'AWS::ECS::Service'},
 181 |             'AttributeMaps': [{'Platform': 'ECS', 'Application': 'test-app'}],
 182 |             'MetricReferences': [
 183 |                 {
 184 |                     'Namespace': 'AWS/ApplicationSignals',
 185 |                     'MetricName': 'Latency',
 186 |                     'MetricType': 'GAUGE',
 187 |                     'Dimensions': [{'Name': 'Service', 'Value': 'test-service'}],
 188 |                 }
 189 |             ],
 190 |             'LogGroupReferences': [{'Identifier': '/aws/ecs/test-service'}],
 191 |         }
 192 |     }
 193 | 
 194 |     mock_aws_clients['applicationsignals_client'].list_services.return_value = mock_list_response
 195 |     mock_aws_clients['applicationsignals_client'].get_service.return_value = mock_get_response
 196 | 
 197 |     result = await get_service_detail('test-service')
 198 | 
 199 |     assert 'Service Details: test-service' in result
 200 |     assert 'AWS::ECS::Service' in result
 201 |     assert 'Platform: ECS' in result
 202 |     assert 'AWS/ApplicationSignals/Latency' in result
 203 |     assert '/aws/ecs/test-service' in result
 204 | 
 205 | 
 206 | @pytest.mark.asyncio
 207 | async def test_get_service_detail_not_found(mock_aws_clients):
 208 |     """Test when service is not found."""
 209 |     mock_response = {'ServiceSummaries': []}
 210 | 
 211 |     mock_aws_clients['applicationsignals_client'].list_services.return_value = mock_response
 212 | 
 213 |     result = await get_service_detail('nonexistent-service')
 214 | 
 215 |     assert "Service 'nonexistent-service' not found" in result
 216 | 
 217 | 
 218 | @pytest.mark.asyncio
 219 | async def test_query_service_metrics_success(mock_aws_clients):
 220 |     """Test successful query of service metrics."""
 221 |     mock_list_response = {
 222 |         'ServiceSummaries': [
 223 |             {'KeyAttributes': {'Name': 'test-service', 'Type': 'AWS::ECS::Service'}}
 224 |         ]
 225 |     }
 226 | 
 227 |     mock_get_response = {
 228 |         'Service': {
 229 |             'MetricReferences': [
 230 |                 {
 231 |                     'Namespace': 'AWS/ApplicationSignals',
 232 |                     'MetricName': 'Latency',
 233 |                     'Dimensions': [{'Name': 'Service', 'Value': 'test-service'}],
 234 |                 }
 235 |             ]
 236 |         }
 237 |     }
 238 | 
 239 |     mock_metric_response = {
 240 |         'Datapoints': [
 241 |             {
 242 |                 'Timestamp': datetime.now(timezone.utc),
 243 |                 'Average': 100.5,
 244 |                 'p99': 150.2,
 245 |                 'Unit': 'Milliseconds',
 246 |             }
 247 |         ]
 248 |     }
 249 | 
 250 |     mock_aws_clients['applicationsignals_client'].list_services.return_value = mock_list_response
 251 |     mock_aws_clients['applicationsignals_client'].get_service.return_value = mock_get_response
 252 |     mock_aws_clients['cloudwatch_client'].get_metric_statistics.return_value = mock_metric_response
 253 | 
 254 |     result = await query_service_metrics(
 255 |         service_name='test-service',
 256 |         metric_name='Latency',
 257 |         statistic='Average',
 258 |         extended_statistic='p99',
 259 |         hours=1,
 260 |     )
 261 | 
 262 |     assert 'Metrics for test-service - Latency' in result
 263 |     assert 'Average Statistics:' in result
 264 |     assert 'p99 Statistics:' in result
 265 | 
 266 | 
 267 | @pytest.mark.asyncio
 268 | async def test_query_service_metrics_list_available(mock_aws_clients):
 269 |     """Test listing available metrics when no specific metric is requested."""
 270 |     mock_list_response = {
 271 |         'ServiceSummaries': [
 272 |             {'KeyAttributes': {'Name': 'test-service', 'Type': 'AWS::ECS::Service'}}
 273 |         ]
 274 |     }
 275 | 
 276 |     mock_get_response = {
 277 |         'Service': {
 278 |             'MetricReferences': [
 279 |                 {
 280 |                     'MetricName': 'Latency',
 281 |                     'Namespace': 'AWS/ApplicationSignals',
 282 |                     'MetricType': 'GAUGE',
 283 |                 },
 284 |                 {
 285 |                     'MetricName': 'Error',
 286 |                     'Namespace': 'AWS/ApplicationSignals',
 287 |                     'MetricType': 'COUNT',
 288 |                 },
 289 |             ]
 290 |         }
 291 |     }
 292 | 
 293 |     mock_aws_clients['applicationsignals_client'].list_services.return_value = mock_list_response
 294 |     mock_aws_clients['applicationsignals_client'].get_service.return_value = mock_get_response
 295 | 
 296 |     result = await query_service_metrics(
 297 |         service_name='test-service',
 298 |         metric_name='',  # Empty to list available metrics
 299 |         statistic='Average',
 300 |         extended_statistic='p99',
 301 |         hours=1,
 302 |     )
 303 | 
 304 |     assert "Available metrics for service 'test-service'" in result
 305 |     assert 'Latency' in result
 306 |     assert 'Error' in result
 307 | 
 308 | 
 309 | @pytest.mark.asyncio
 310 | async def test_get_slo_success(mock_aws_clients):
 311 |     """Test successful retrieval of SLO details."""
 312 |     mock_slo_response = {
 313 |         'Slo': {
 314 |             'Name': 'test-slo',
 315 |             'Arn': 'arn:aws:application-signals:us-east-1:123456789012:slo/test-slo',
 316 |             'Description': 'Test SLO for latency',
 317 |             'EvaluationType': 'REQUEST_BASED',
 318 |             'CreatedTime': '2024-01-01T00:00:00Z',
 319 |             'LastUpdatedTime': '2024-01-02T00:00:00Z',
 320 |             'Goal': {
 321 |                 'AttainmentGoal': 99.9,
 322 |                 'WarningThreshold': 99.0,
 323 |                 'Interval': {'RollingInterval': {'Duration': 7, 'DurationUnit': 'DAYS'}},
 324 |             },
 325 |             'RequestBasedSli': {
 326 |                 'RequestBasedSliMetric': {
 327 |                     'KeyAttributes': {'Name': 'test-service', 'Type': 'AWS::ECS::Service'},
 328 |                     'OperationName': 'GET /api/test',
 329 |                     'MetricType': 'LATENCY',
 330 |                     'MetricDataQueries': [
 331 |                         {
 332 |                             'Id': 'query1',
 333 |                             'MetricStat': {
 334 |                                 'Metric': {
 335 |                                     'Namespace': 'AWS/ApplicationSignals',
 336 |                                     'MetricName': 'Latency',
 337 |                                     'Dimensions': [{'Name': 'Service', 'Value': 'test-service'}],
 338 |                                 },
 339 |                                 'Period': 60,
 340 |                                 'Stat': 'Average',
 341 |                             },
 342 |                         }
 343 |                     ],
 344 |                 },
 345 |                 'MetricThreshold': 1000,
 346 |                 'ComparisonOperator': 'GreaterThan',
 347 |             },
 348 |         }
 349 |     }
 350 | 
 351 |     mock_aws_clients[
 352 |         'applicationsignals_client'
 353 |     ].get_service_level_objective.return_value = mock_slo_response
 354 | 
 355 |     result = await get_slo('test-slo-id')
 356 | 
 357 |     assert 'Service Level Objective Details' in result
 358 |     assert 'test-slo' in result
 359 |     assert 'REQUEST_BASED' in result
 360 |     assert '99.9%' in result
 361 |     assert 'GET /api/test' in result
 362 |     assert 'annotation[aws.local.operation]="GET /api/test"' in result
 363 | 
 364 | 
 365 | @pytest.mark.asyncio
 366 | async def test_get_slo_not_found(mock_aws_clients):
 367 |     """Test when SLO is not found."""
 368 |     mock_aws_clients['applicationsignals_client'].get_service_level_objective.return_value = {
 369 |         'Slo': None
 370 |     }
 371 | 
 372 |     result = await get_slo('nonexistent-slo')
 373 | 
 374 |     assert 'No SLO found with ID: nonexistent-slo' in result
 375 | 
 376 | 
 377 | @pytest.mark.asyncio
 378 | async def test_search_transaction_spans_success(mock_aws_clients):
 379 |     """Test successful transaction search."""
 380 |     mock_query_response = {
 381 |         'queryId': 'test-query-id',
 382 |         'status': 'Complete',
 383 |         'statistics': {'recordsMatched': 10},
 384 |         'results': [
 385 |             [
 386 |                 {'field': 'spanId', 'value': 'span1'},
 387 |                 {'field': 'timestamp', 'value': '2024-01-01T00:00:00Z'},
 388 |             ]
 389 |         ],
 390 |     }
 391 | 
 392 |     with patch(
 393 |         'awslabs.cloudwatch_applicationsignals_mcp_server.trace_tools.check_transaction_search_enabled'
 394 |     ) as mock_check:
 395 |         mock_check.return_value = (True, 'CloudWatchLogs', 'ACTIVE')
 396 |         mock_aws_clients['logs_client'].start_query.return_value = {'queryId': 'test-query-id'}
 397 |         mock_aws_clients['logs_client'].get_query_results.return_value = mock_query_response
 398 | 
 399 |         result = await search_transaction_spans(
 400 |             log_group_name='aws/spans',
 401 |             start_time='2024-01-01T00:00:00+00:00',  # Fixed ISO format
 402 |             end_time='2024-01-01T01:00:00+00:00',
 403 |             query_string='fields @timestamp, spanId',
 404 |             limit=100,
 405 |             max_timeout=30,
 406 |         )
 407 | 
 408 |         assert result['status'] == 'Complete'
 409 |         assert result['queryId'] == 'test-query-id'
 410 |         assert len(result['results']) == 1
 411 |         assert result['results'][0]['spanId'] == 'span1'
 412 | 
 413 | 
 414 | @pytest.mark.asyncio
 415 | async def test_search_transaction_spans_not_enabled(mock_aws_clients):
 416 |     """Test when transaction search is not enabled."""
 417 |     with patch(
 418 |         'awslabs.cloudwatch_applicationsignals_mcp_server.trace_tools.check_transaction_search_enabled'
 419 |     ) as mock_check:
 420 |         mock_check.return_value = (False, 'XRay', 'INACTIVE')
 421 | 
 422 |         result = await search_transaction_spans(
 423 |             log_group_name='',
 424 |             start_time='2024-01-01T00:00:00+00:00',
 425 |             end_time='2024-01-01T01:00:00+00:00',
 426 |             query_string='fields @timestamp',
 427 |             limit=None,
 428 |             max_timeout=30,
 429 |         )
 430 | 
 431 |         assert result['status'] == 'Transaction Search Not Available'
 432 |         assert not result['transaction_search_status']['enabled']
 433 | 
 434 | 
 435 | @pytest.mark.asyncio
 436 | async def test_list_slis_success(mock_aws_clients):
 437 |     """Test successful listing of SLI status."""
 438 |     mock_services_response = {
 439 |         'ServiceSummaries': [
 440 |             {
 441 |                 'KeyAttributes': {
 442 |                     'Name': 'test-service',
 443 |                     'Type': 'AWS::ECS::Service',
 444 |                     'Environment': 'production',
 445 |                 }
 446 |             }
 447 |         ]
 448 |     }
 449 | 
 450 |     # Mock boto3.client calls in SLIReportClient
 451 |     with patch('boto3.client') as mock_boto3_client:
 452 |         with patch(
 453 |             'awslabs.cloudwatch_applicationsignals_mcp_server.trace_tools.check_transaction_search_enabled'
 454 |         ) as mock_check:
 455 |             # Configure boto3.client to return our mocked clients
 456 |             def boto3_client_side_effect(service_name, **kwargs):
 457 |                 if service_name == 'application-signals':
 458 |                     return mock_aws_clients['applicationsignals_client']
 459 |                 elif service_name == 'cloudwatch':
 460 |                     return mock_aws_clients['cloudwatch_client']
 461 |                 else:
 462 |                     return MagicMock()
 463 | 
 464 |             mock_boto3_client.side_effect = boto3_client_side_effect
 465 | 
 466 |             mock_aws_clients[
 467 |                 'applicationsignals_client'
 468 |             ].list_services.return_value = mock_services_response
 469 |             mock_check.return_value = (True, 'CloudWatchLogs', 'ACTIVE')
 470 | 
 471 |             # Mock SLO summaries response for SLIReportClient
 472 |             mock_slo_response = {
 473 |                 'SloSummaries': [
 474 |                     {
 475 |                         'Name': 'test-slo',
 476 |                         'Arn': 'arn:aws:application-signals:us-east-1:123456789012:slo/test-slo',
 477 |                         'KeyAttributes': {'Name': 'test-service'},
 478 |                         'OperationName': 'GET /api',
 479 |                         'CreatedTime': datetime.now(timezone.utc),
 480 |                     }
 481 |                 ]
 482 |             }
 483 |             mock_aws_clients[
 484 |                 'applicationsignals_client'
 485 |             ].list_service_level_objectives.return_value = mock_slo_response
 486 | 
 487 |             # Mock metric data response showing breach
 488 |             mock_metric_response = {
 489 |                 'MetricDataResults': [
 490 |                     {
 491 |                         'Id': 'slo0',
 492 |                         'Timestamps': [datetime.now(timezone.utc)],
 493 |                         'Values': [1.0],  # Breach count > 0 indicates breach
 494 |                     }
 495 |                 ]
 496 |             }
 497 |             mock_aws_clients[
 498 |                 'cloudwatch_client'
 499 |             ].get_metric_data.return_value = mock_metric_response
 500 | 
 501 |             result = await list_slis(hours=24)
 502 | 
 503 |             assert 'SLI Status Report - Last 24 hours' in result
 504 |             assert 'Transaction Search: ENABLED' in result
 505 |             assert 'BREACHED SERVICES:' in result
 506 |             assert 'test-service' in result
 507 | 
 508 | 
 509 | @pytest.mark.asyncio
 510 | async def test_query_sampled_traces_success(mock_aws_clients):
 511 |     """Test successful query of sampled traces."""
 512 |     mock_traces = [
 513 |         {
 514 |             'Id': 'trace1',
 515 |             'Duration': 0.5,
 516 |             'ResponseTime': 500,
 517 |             'HasError': False,
 518 |             'HasFault': True,
 519 |             'HasThrottle': False,
 520 |             'Http': {'HttpStatus': 500},
 521 |             'FaultRootCauses': [
 522 |                 {
 523 |                     'Services': [
 524 |                         {
 525 |                             'Name': 'test-service',
 526 |                             'Exceptions': [{'Message': 'Internal server error'}],
 527 |                         }
 528 |                     ]
 529 |                 }
 530 |             ],
 531 |         }
 532 |     ]
 533 | 
 534 |     with patch(
 535 |         'awslabs.cloudwatch_applicationsignals_mcp_server.trace_tools.get_trace_summaries_paginated'
 536 |     ) as mock_get_traces:
 537 |         with patch(
 538 |             'awslabs.cloudwatch_applicationsignals_mcp_server.trace_tools.check_transaction_search_enabled'
 539 |         ) as mock_check:
 540 |             mock_get_traces.return_value = mock_traces
 541 |             mock_check.return_value = (False, 'XRay', 'INACTIVE')
 542 | 
 543 |             result_json = await query_sampled_traces(
 544 |                 start_time='2024-01-01T00:00:00Z',
 545 |                 end_time='2024-01-01T01:00:00Z',
 546 |                 filter_expression='service("test-service"){fault = true}',
 547 |             )
 548 | 
 549 |             result = json.loads(result_json)
 550 |             assert result['TraceCount'] == 1
 551 |             assert result['TraceSummaries'][0]['Id'] == 'trace1'
 552 |             assert result['TraceSummaries'][0]['HasFault'] is True
 553 | 
 554 | 
 555 | @pytest.mark.asyncio
 556 | async def test_query_sampled_traces_time_window_too_large(mock_aws_clients):
 557 |     """Test when time window is too large."""
 558 |     result_json = await query_sampled_traces(
 559 |         start_time='2024-01-01T00:00:00Z',
 560 |         end_time='2024-01-02T00:00:00Z',  # 24 hours > 6 hours max
 561 |         filter_expression='service("test-service")',
 562 |     )
 563 | 
 564 |     result = json.loads(result_json)
 565 |     assert 'error' in result
 566 |     assert 'Time window too large' in result['error']
 567 | 
 568 | 
 569 | def test_get_trace_summaries_paginated():
 570 |     """Test paginated trace retrieval."""
 571 |     mock_client = MagicMock()
 572 |     mock_responses = [
 573 |         {'TraceSummaries': [{'Id': 'trace1'}, {'Id': 'trace2'}], 'NextToken': 'token1'},
 574 |         {'TraceSummaries': [{'Id': 'trace3'}]},
 575 |     ]
 576 |     mock_client.get_trace_summaries.side_effect = mock_responses
 577 | 
 578 |     start_time = datetime.now(timezone.utc) - timedelta(hours=1)
 579 |     end_time = datetime.now(timezone.utc)
 580 | 
 581 |     traces = get_trace_summaries_paginated(
 582 |         mock_client, start_time, end_time, 'service("test")', max_traces=10
 583 |     )
 584 | 
 585 |     assert len(traces) == 3
 586 |     assert traces[0]['Id'] == 'trace1'
 587 |     assert traces[2]['Id'] == 'trace3'
 588 | 
 589 | 
 590 | def test_get_trace_summaries_paginated_with_error():
 591 |     """Test paginated trace retrieval with error."""
 592 |     mock_client = MagicMock()
 593 |     mock_client.get_trace_summaries.side_effect = Exception('API Error')
 594 | 
 595 |     start_time = datetime.now(timezone.utc) - timedelta(hours=1)
 596 |     end_time = datetime.now(timezone.utc)
 597 | 
 598 |     traces = get_trace_summaries_paginated(
 599 |         mock_client, start_time, end_time, 'service("test")', max_traces=10
 600 |     )
 601 | 
 602 |     assert len(traces) == 0  # Should return empty list on error
 603 | 
 604 | 
 605 | def test_check_transaction_search_enabled(mock_aws_clients):
 606 |     """Test checking transaction search status."""
 607 |     mock_aws_clients['xray_client'].get_trace_segment_destination.return_value = {
 608 |         'Destination': 'CloudWatchLogs',
 609 |         'Status': 'ACTIVE',
 610 |     }
 611 | 
 612 |     is_enabled, destination, status = check_transaction_search_enabled()
 613 | 
 614 |     assert is_enabled is True
 615 |     assert destination == 'CloudWatchLogs'
 616 |     assert status == 'ACTIVE'
 617 | 
 618 | 
 619 | def test_check_transaction_search_enabled_not_active(mock_aws_clients):
 620 |     """Test checking transaction search when not active."""
 621 |     mock_aws_clients['xray_client'].get_trace_segment_destination.return_value = {
 622 |         'Destination': 'XRay',
 623 |         'Status': 'INACTIVE',
 624 |     }
 625 | 
 626 |     is_enabled, destination, status = check_transaction_search_enabled()
 627 | 
 628 |     assert is_enabled is False
 629 |     assert destination == 'XRay'
 630 |     assert status == 'INACTIVE'
 631 | 
 632 | 
 633 | def test_check_transaction_search_enabled_error(mock_aws_clients):
 634 |     """Test checking transaction search with error."""
 635 |     mock_aws_clients['xray_client'].get_trace_segment_destination.side_effect = Exception(
 636 |         'API Error'
 637 |     )
 638 | 
 639 |     is_enabled, destination, status = check_transaction_search_enabled()
 640 | 
 641 |     assert is_enabled is False
 642 |     assert destination == 'Unknown'
 643 |     assert status == 'Error'
 644 | 
 645 | 
 646 | def test_remove_null_values():
 647 |     """Test remove_null_values function."""
 648 |     # Test with mix of None and non-None values
 649 |     input_dict = {
 650 |         'key1': 'value1',
 651 |         'key2': None,
 652 |         'key3': 'value3',
 653 |         'key4': None,
 654 |         'key5': 0,  # Should not be removed
 655 |         'key6': '',  # Should not be removed
 656 |         'key7': False,  # Should not be removed
 657 |     }
 658 | 
 659 |     result = remove_null_values(input_dict)
 660 | 
 661 |     assert result == {
 662 |         'key1': 'value1',
 663 |         'key3': 'value3',
 664 |         'key5': 0,
 665 |         'key6': '',
 666 |         'key7': False,
 667 |     }
 668 |     assert 'key2' not in result
 669 |     assert 'key4' not in result
 670 | 
 671 | 
 672 | @pytest.mark.asyncio
 673 | async def test_list_monitored_services_client_error(mock_aws_clients):
 674 |     """Test ClientError handling in list_monitored_services."""
 675 |     mock_aws_clients['applicationsignals_client'].list_services.side_effect = ClientError(
 676 |         error_response={
 677 |             'Error': {
 678 |                 'Code': 'AccessDeniedException',
 679 |                 'Message': 'User is not authorized to perform this action',
 680 |             }
 681 |         },
 682 |         operation_name='ListServices',
 683 |     )
 684 | 
 685 |     result = await list_monitored_services()
 686 | 
 687 |     assert 'AWS Error: User is not authorized to perform this action' in result
 688 | 
 689 | 
 690 | @pytest.mark.asyncio
 691 | async def test_list_monitored_services_general_exception(mock_aws_clients):
 692 |     """Test general exception handling in list_monitored_services."""
 693 |     mock_aws_clients['applicationsignals_client'].list_services.side_effect = Exception(
 694 |         'Unexpected error occurred'
 695 |     )
 696 | 
 697 |     result = await list_monitored_services()
 698 | 
 699 |     assert 'Error: Unexpected error occurred' in result
 700 | 
 701 | 
 702 | @pytest.mark.asyncio
 703 | async def test_get_service_detail_client_error(mock_aws_clients):
 704 |     """Test ClientError handling in get_service_detail."""
 705 |     mock_list_response = {
 706 |         'ServiceSummaries': [
 707 |             {'KeyAttributes': {'Name': 'test-service', 'Type': 'AWS::ECS::Service'}}
 708 |         ]
 709 |     }
 710 | 
 711 |     mock_aws_clients['applicationsignals_client'].list_services.return_value = mock_list_response
 712 |     mock_aws_clients['applicationsignals_client'].get_service.side_effect = ClientError(
 713 |         error_response={
 714 |             'Error': {
 715 |                 'Code': 'ResourceNotFoundException',
 716 |                 'Message': 'Service not found in Application Signals',
 717 |             }
 718 |         },
 719 |         operation_name='GetService',
 720 |     )
 721 | 
 722 |     result = await get_service_detail('test-service')
 723 | 
 724 |     assert 'AWS Error: Service not found in Application Signals' in result
 725 | 
 726 | 
 727 | @pytest.mark.asyncio
 728 | async def test_get_service_detail_general_exception(mock_aws_clients):
 729 |     """Test general exception handling in get_service_detail."""
 730 |     mock_list_response = {
 731 |         'ServiceSummaries': [
 732 |             {'KeyAttributes': {'Name': 'test-service', 'Type': 'AWS::ECS::Service'}}
 733 |         ]
 734 |     }
 735 | 
 736 |     mock_aws_clients['applicationsignals_client'].list_services.return_value = mock_list_response
 737 |     mock_aws_clients['applicationsignals_client'].get_service.side_effect = Exception(
 738 |         'Unexpected error in get_service'
 739 |     )
 740 | 
 741 |     result = await get_service_detail('test-service')
 742 | 
 743 |     assert 'Error: Unexpected error in get_service' in result
 744 | 
 745 | 
 746 | @pytest.mark.asyncio
 747 | async def test_query_service_metrics_no_datapoints(mock_aws_clients):
 748 |     """Test query service metrics when no datapoints are returned."""
 749 |     mock_list_response = {
 750 |         'ServiceSummaries': [
 751 |             {'KeyAttributes': {'Name': 'test-service', 'Type': 'AWS::ECS::Service'}}
 752 |         ]
 753 |     }
 754 | 
 755 |     mock_get_response = {
 756 |         'Service': {
 757 |             'MetricReferences': [
 758 |                 {
 759 |                     'Namespace': 'AWS/ApplicationSignals',
 760 |                     'MetricName': 'Latency',
 761 |                     'Dimensions': [{'Name': 'Service', 'Value': 'test-service'}],
 762 |                 }
 763 |             ]
 764 |         }
 765 |     }
 766 | 
 767 |     mock_metric_response = {'Datapoints': []}
 768 | 
 769 |     mock_aws_clients['applicationsignals_client'].list_services.return_value = mock_list_response
 770 |     mock_aws_clients['applicationsignals_client'].get_service.return_value = mock_get_response
 771 |     mock_aws_clients['cloudwatch_client'].get_metric_statistics.return_value = mock_metric_response
 772 | 
 773 |     result = await query_service_metrics(
 774 |         service_name='test-service',
 775 |         metric_name='Latency',
 776 |         statistic='Average',
 777 |         extended_statistic='p99',
 778 |         hours=1,
 779 |     )
 780 | 
 781 |     assert 'No data points found' in result
 782 | 
 783 | 
 784 | @pytest.mark.asyncio
 785 | async def test_search_transaction_spans_timeout(mock_aws_clients):
 786 |     """Test search transaction spans with timeout."""
 787 |     with patch(
 788 |         'awslabs.cloudwatch_applicationsignals_mcp_server.trace_tools.check_transaction_search_enabled'
 789 |     ) as mock_check:
 790 |         with patch(
 791 |             'awslabs.cloudwatch_applicationsignals_mcp_server.trace_tools.timer'
 792 |         ) as mock_timer:
 793 |             # Mock asyncio.sleep to prevent actual waiting
 794 |             with patch('asyncio.sleep', new_callable=AsyncMock):
 795 |                 mock_check.return_value = (True, 'CloudWatchLogs', 'ACTIVE')
 796 |                 mock_aws_clients['logs_client'].start_query.return_value = {
 797 |                     'queryId': 'test-query-id'
 798 |                 }
 799 |                 mock_aws_clients['logs_client'].get_query_results.return_value = {
 800 |                     'status': 'Running'
 801 |                 }
 802 | 
 803 |                 # Simulate timeout by making timer exceed max_timeout
 804 |                 mock_timer.side_effect = [
 805 |                     0,
 806 |                     0,
 807 |                     0,
 808 |                     31,
 809 |                     31,
 810 |                 ]  # start_time_perf, poll_start, poll check 1, poll check 2
 811 | 
 812 |                 result = await search_transaction_spans(
 813 |                     log_group_name='',
 814 |                     start_time='2024-01-01T00:00:00+00:00',
 815 |                     end_time='2024-01-01T01:00:00+00:00',
 816 |                     query_string='fields @timestamp',
 817 |                     limit=None,
 818 |                     max_timeout=30,
 819 |                 )
 820 | 
 821 |                 assert result['status'] == 'Polling Timeout'
 822 |                 assert 'did not complete within 30 seconds' in result['message']
 823 | 
 824 | 
 825 | def test_main_normal_execution(mock_mcp):
 826 |     """Test normal execution of main function."""
 827 |     main()
 828 |     mock_mcp.run.assert_called_once_with(transport='stdio')
 829 | 
 830 | 
 831 | def test_main_keyboard_interrupt(mock_mcp):
 832 |     """Test KeyboardInterrupt handling in main function."""
 833 |     mock_mcp.run.side_effect = KeyboardInterrupt()
 834 |     # Should not raise an exception
 835 |     main()
 836 |     mock_mcp.run.assert_called_once_with(transport='stdio')
 837 | 
 838 | 
 839 | def test_main_general_exception(mock_mcp):
 840 |     """Test general exception handling in main function."""
 841 |     mock_mcp.run.side_effect = Exception('Server error')
 842 |     with pytest.raises(Exception, match='Server error'):
 843 |         main()
 844 |     mock_mcp.run.assert_called_once_with(transport='stdio')
 845 | 
 846 | 
 847 | @pytest.mark.asyncio
 848 | async def test_get_slo_period_based(mock_aws_clients):
 849 |     """Test get_slo with period-based SLI configuration."""
 850 |     mock_slo_response = {
 851 |         'Slo': {
 852 |             'Name': 'test-slo-period',
 853 |             'Arn': 'arn:aws:application-signals:us-east-1:123456789012:slo/test-slo',
 854 |             'EvaluationType': 'PERIOD_BASED',
 855 |             'Sli': {
 856 |                 'SliMetric': {
 857 |                     'KeyAttributes': {'Name': 'test-service', 'Type': 'AWS::Lambda::Function'},
 858 |                     'OperationName': 'ProcessOrder',
 859 |                     'MetricType': 'AVAILABILITY',
 860 |                     'DependencyConfig': {
 861 |                         'DependencyKeyAttributes': {'Name': 'payment-service'},
 862 |                         'DependencyOperationName': 'ProcessPayment',
 863 |                     },
 864 |                 },
 865 |                 'MetricThreshold': 0.99,
 866 |                 'ComparisonOperator': 'LessThan',
 867 |             },
 868 |             'BurnRateConfigurations': [
 869 |                 {'LookBackWindowMinutes': 5},
 870 |                 {'LookBackWindowMinutes': 60},
 871 |             ],
 872 |         }
 873 |     }
 874 | 
 875 |     mock_aws_clients[
 876 |         'applicationsignals_client'
 877 |     ].get_service_level_objective.return_value = mock_slo_response
 878 | 
 879 |     result = await get_slo('test-slo-period')
 880 | 
 881 |     assert 'PERIOD_BASED' in result
 882 |     assert 'ProcessOrder' in result
 883 |     assert 'annotation[aws.remote.operation]="ProcessPayment"' in result
 884 |     assert 'Burn Rate Configurations' in result
 885 | 
 886 | 
 887 | @pytest.mark.asyncio
 888 | async def test_list_slis_with_error_in_sli_client(mock_aws_clients):
 889 |     """Test list_slis when SLIReportClient throws error for some services."""
 890 |     mock_services_response = {
 891 |         'ServiceSummaries': [
 892 |             {
 893 |                 'KeyAttributes': {
 894 |                     'Name': 'test-service-1',
 895 |                     'Type': 'AWS::ECS::Service',
 896 |                     'Environment': 'production',
 897 |                 }
 898 |             },
 899 |             {
 900 |                 'KeyAttributes': {
 901 |                     'Name': 'test-service-2',
 902 |                     'Type': 'AWS::Lambda::Function',
 903 |                     'Environment': 'staging',
 904 |                 }
 905 |             },
 906 |         ]
 907 |     }
 908 | 
 909 |     with patch(
 910 |         'awslabs.cloudwatch_applicationsignals_mcp_server.trace_tools.SLIReportClient'
 911 |     ) as mock_sli_client:
 912 |         with patch(
 913 |             'awslabs.cloudwatch_applicationsignals_mcp_server.trace_tools.check_transaction_search_enabled'
 914 |         ) as mock_check:
 915 |             mock_aws_clients[
 916 |                 'applicationsignals_client'
 917 |             ].list_services.return_value = mock_services_response
 918 |             mock_check.return_value = (False, 'XRay', 'INACTIVE')
 919 | 
 920 |             # First service succeeds, second fails
 921 |             mock_report = MagicMock()
 922 |             mock_report.breached_slo_count = 0
 923 |             mock_report.ok_slo_count = 3
 924 |             mock_report.total_slo_count = 3
 925 |             mock_report.sli_status = 'OK'
 926 |             mock_report.start_time = datetime.now(timezone.utc) - timedelta(hours=24)
 927 |             mock_report.end_time = datetime.now(timezone.utc)
 928 | 
 929 |             mock_sli_client.return_value.generate_sli_report.side_effect = [
 930 |                 mock_report,
 931 |                 Exception('Failed to get SLI report'),
 932 |             ]
 933 | 
 934 |             result = await list_slis(hours=24)
 935 | 
 936 |             assert 'Transaction Search: NOT ENABLED' in result
 937 |             assert 'HEALTHY SERVICES:' in result
 938 |             assert 'INSUFFICIENT DATA:' in result
 939 |             assert 'test-service-1' in result
 940 |             assert 'test-service-2' in result
 941 | 
 942 | 
 943 | @pytest.mark.asyncio
 944 | async def test_query_service_metrics_service_not_found(mock_aws_clients):
 945 |     """Test query service metrics when service is not found."""
 946 |     mock_list_response = {'ServiceSummaries': []}
 947 | 
 948 |     mock_aws_clients['applicationsignals_client'].list_services.return_value = mock_list_response
 949 | 
 950 |     result = await query_service_metrics(
 951 |         service_name='nonexistent-service',
 952 |         metric_name='Latency',
 953 |         statistic='Average',
 954 |         extended_statistic='p99',
 955 |         hours=1,
 956 |     )
 957 | 
 958 |     assert "Service 'nonexistent-service' not found" in result
 959 | 
 960 | 
 961 | @pytest.mark.asyncio
 962 | async def test_query_service_metrics_no_metrics(mock_aws_clients):
 963 |     """Test query service metrics when service has no metrics."""
 964 |     mock_list_response = {
 965 |         'ServiceSummaries': [
 966 |             {'KeyAttributes': {'Name': 'test-service', 'Type': 'AWS::ECS::Service'}}
 967 |         ]
 968 |     }
 969 | 
 970 |     mock_get_response = {'Service': {'MetricReferences': []}}
 971 | 
 972 |     mock_aws_clients['applicationsignals_client'].list_services.return_value = mock_list_response
 973 |     mock_aws_clients['applicationsignals_client'].get_service.return_value = mock_get_response
 974 | 
 975 |     result = await query_service_metrics(
 976 |         service_name='test-service',
 977 |         metric_name='Latency',
 978 |         statistic='Average',
 979 |         extended_statistic='p99',
 980 |         hours=1,
 981 |     )
 982 | 
 983 |     assert "No metrics found for service 'test-service'" in result
 984 | 
 985 | 
 986 | @pytest.mark.asyncio
 987 | async def test_query_service_metrics_metric_not_found(mock_aws_clients):
 988 |     """Test query service metrics when specific metric is not found."""
 989 |     mock_list_response = {
 990 |         'ServiceSummaries': [
 991 |             {'KeyAttributes': {'Name': 'test-service', 'Type': 'AWS::ECS::Service'}}
 992 |         ]
 993 |     }
 994 | 
 995 |     mock_get_response = {
 996 |         'Service': {
 997 |             'MetricReferences': [
 998 |                 {
 999 |                     'Namespace': 'AWS/ApplicationSignals',
1000 |                     'MetricName': 'Error',
1001 |                     'Dimensions': [{'Name': 'Service', 'Value': 'test-service'}],
1002 |                 }
1003 |             ]
1004 |         }
1005 |     }
1006 | 
1007 |     mock_aws_clients['applicationsignals_client'].list_services.return_value = mock_list_response
1008 |     mock_aws_clients['applicationsignals_client'].get_service.return_value = mock_get_response
1009 | 
1010 |     result = await query_service_metrics(
1011 |         service_name='test-service',
1012 |         metric_name='Latency',  # Looking for Latency but only Error exists
1013 |         statistic='Average',
1014 |         extended_statistic='p99',
1015 |         hours=1,
1016 |     )
1017 | 
1018 |     assert "Metric 'Latency' not found" in result
1019 |     assert 'Available: Error' in result
1020 | 
1021 | 
1022 | @pytest.mark.asyncio
1023 | async def test_query_service_metrics_client_error(mock_aws_clients):
1024 |     """Test query service metrics with client error."""
1025 |     mock_aws_clients['applicationsignals_client'].list_services.side_effect = ClientError(
1026 |         error_response={
1027 |             'Error': {
1028 |                 'Code': 'AccessDeniedException',
1029 |                 'Message': 'User is not authorized',
1030 |             }
1031 |         },
1032 |         operation_name='ListServices',
1033 |     )
1034 | 
1035 |     result = await query_service_metrics(
1036 |         service_name='test-service',
1037 |         metric_name='Latency',
1038 |         statistic='Average',
1039 |         extended_statistic='p99',
1040 |         hours=1,
1041 |     )
1042 | 
1043 |     assert 'AWS Error: User is not authorized' in result
1044 | 
1045 | 
1046 | @pytest.mark.asyncio
1047 | async def test_search_transaction_spans_failed_query(mock_aws_clients):
1048 |     """Test search transaction spans when query fails."""
1049 |     with patch(
1050 |         'awslabs.cloudwatch_applicationsignals_mcp_server.trace_tools.check_transaction_search_enabled'
1051 |     ) as mock_check:
1052 |         mock_check.return_value = (True, 'CloudWatchLogs', 'ACTIVE')
1053 |         mock_aws_clients['logs_client'].start_query.return_value = {'queryId': 'test-query-id'}
1054 |         mock_aws_clients['logs_client'].get_query_results.return_value = {
1055 |             'queryId': 'test-query-id',
1056 |             'status': 'Failed',
1057 |             'statistics': {'error': 'Query syntax error'},
1058 |         }
1059 | 
1060 |         result = await search_transaction_spans(
1061 |             log_group_name='',
1062 |             start_time='2024-01-01T00:00:00+00:00',
1063 |             end_time='2024-01-01T01:00:00+00:00',
1064 |             query_string='invalid query',
1065 |             limit=None,
1066 |             max_timeout=30,
1067 |         )
1068 | 
1069 |         assert result['status'] == 'Failed'
1070 | 
1071 | 
1072 | @pytest.mark.asyncio
1073 | async def test_get_slo_client_error(mock_aws_clients):
1074 |     """Test get_slo with client error."""
1075 |     mock_aws_clients[
1076 |         'applicationsignals_client'
1077 |     ].get_service_level_objective.side_effect = ClientError(
1078 |         error_response={
1079 |             'Error': {
1080 |                 'Code': 'ResourceNotFoundException',
1081 |                 'Message': 'SLO not found',
1082 |             }
1083 |         },
1084 |         operation_name='GetServiceLevelObjective',
1085 |     )
1086 | 
1087 |     result = await get_slo('test-slo-id')
1088 | 
1089 |     assert 'AWS Error: SLO not found' in result
1090 | 
1091 | 
1092 | @pytest.mark.asyncio
1093 | async def test_search_transaction_spans_empty_log_group(mock_aws_clients):
1094 |     """Test search transaction spans with empty log group defaults to aws/spans."""
1095 |     with patch(
1096 |         'awslabs.cloudwatch_applicationsignals_mcp_server.trace_tools.check_transaction_search_enabled'
1097 |     ) as mock_check:
1098 |         mock_check.return_value = (True, 'CloudWatchLogs', 'ACTIVE')
1099 |         mock_aws_clients['logs_client'].start_query.return_value = {'queryId': 'test-query-id'}
1100 |         mock_aws_clients['logs_client'].get_query_results.return_value = {
1101 |             'queryId': 'test-query-id',
1102 |             'status': 'Complete',
1103 |             'results': [],
1104 |         }
1105 | 
1106 |         await search_transaction_spans(
1107 |             log_group_name='',  # Empty string should default to 'aws/spans'
1108 |             start_time='2024-01-01T00:00:00+00:00',
1109 |             end_time='2024-01-01T01:00:00+00:00',
1110 |             query_string='fields @timestamp',
1111 |             limit=None,
1112 |             max_timeout=30,
1113 |         )
1114 | 
1115 |         # Verify start_query was called with default 'aws/spans'
1116 |         mock_aws_clients['logs_client'].start_query.assert_called()
1117 |         call_args = mock_aws_clients['logs_client'].start_query.call_args[1]
1118 |         assert 'aws/spans' in call_args['logGroupNames']
1119 | 
1120 | 
1121 | @pytest.mark.asyncio
1122 | async def test_list_slis_no_services(mock_aws_clients):
1123 |     """Test list_slis when no services exist."""
1124 |     mock_aws_clients['applicationsignals_client'].list_services.return_value = {
1125 |         'ServiceSummaries': []
1126 |     }
1127 | 
1128 |     result = await list_slis(hours=24)
1129 | 
1130 |     assert 'No services found in Application Signals.' in result
1131 | 
1132 | 
1133 | @pytest.mark.asyncio
1134 | async def test_get_slo_with_calendar_interval(mock_aws_clients):
1135 |     """Test get_slo with calendar interval in goal."""
1136 |     mock_slo_response = {
1137 |         'Slo': {
1138 |             'Name': 'test-slo-calendar',
1139 |             'Goal': {
1140 |                 'AttainmentGoal': 99.5,
1141 |                 'Interval': {
1142 |                     'CalendarInterval': {
1143 |                         'Duration': 1,
1144 |                         'DurationUnit': 'MONTH',
1145 |                         'StartTime': '2024-01-01T00:00:00Z',
1146 |                     }
1147 |                 },
1148 |             },
1149 |         }
1150 |     }
1151 | 
1152 |     mock_aws_clients[
1153 |         'applicationsignals_client'
1154 |     ].get_service_level_objective.return_value = mock_slo_response
1155 | 
1156 |     result = await get_slo('test-slo-calendar')
1157 | 
1158 |     assert 'Calendar 1 MONTH starting 2024-01-01T00:00:00Z' in result
1159 | 
1160 | 
1161 | @pytest.mark.asyncio
1162 | async def test_query_service_metrics_different_periods(mock_aws_clients):
1163 |     """Test query service metrics with different time periods."""
1164 |     # Test data for different hour ranges
1165 |     test_cases = [
1166 |         (2, 60),  # 2 hours -> 1 minute period
1167 |         (12, 300),  # 12 hours -> 5 minute period
1168 |         (48, 3600),  # 48 hours -> 1 hour period
1169 |     ]
1170 | 
1171 |     for hours, expected_period in test_cases:
1172 |         mock_list_response = {
1173 |             'ServiceSummaries': [
1174 |                 {'KeyAttributes': {'Name': 'test-service', 'Type': 'AWS::ECS::Service'}}
1175 |             ]
1176 |         }
1177 | 
1178 |         mock_get_response = {
1179 |             'Service': {
1180 |                 'MetricReferences': [
1181 |                     {
1182 |                         'Namespace': 'AWS/ApplicationSignals',
1183 |                         'MetricName': 'Latency',
1184 |                         'Dimensions': [],
1185 |                     }
1186 |                 ]
1187 |             }
1188 |         }
1189 | 
1190 |         mock_metric_response = {
1191 |             'Datapoints': [{'Timestamp': datetime.now(timezone.utc), 'Average': 100.0}]
1192 |         }
1193 | 
1194 |         mock_aws_clients[
1195 |             'applicationsignals_client'
1196 |         ].list_services.return_value = mock_list_response
1197 |         mock_aws_clients['applicationsignals_client'].get_service.return_value = mock_get_response
1198 |         mock_aws_clients[
1199 |             'cloudwatch_client'
1200 |         ].get_metric_statistics.return_value = mock_metric_response
1201 | 
1202 |         await query_service_metrics(
1203 |             service_name='test-service',
1204 |             metric_name='Latency',
1205 |             statistic='Average',
1206 |             extended_statistic='p99',
1207 |             hours=hours,
1208 |         )
1209 | 
1210 |         # Verify the period was set correctly
1211 |         call_args = mock_aws_clients['cloudwatch_client'].get_metric_statistics.call_args[1]
1212 |         assert call_args['Period'] == expected_period
1213 | 
1214 | 
1215 | @pytest.mark.asyncio
1216 | async def test_query_service_metrics_general_exception(mock_aws_clients):
1217 |     """Test query service metrics with unexpected exception."""
1218 |     mock_aws_clients['applicationsignals_client'].list_services.side_effect = Exception(
1219 |         'Unexpected error'
1220 |     )
1221 | 
1222 |     result = await query_service_metrics(
1223 |         service_name='test-service',
1224 |         metric_name='Latency',
1225 |         statistic='Average',
1226 |         extended_statistic='p99',
1227 |         hours=1,
1228 |     )
1229 | 
1230 |     assert 'Error: Unexpected error' in result
1231 | 
1232 | 
1233 | @pytest.mark.asyncio
1234 | async def test_search_transaction_spans_general_exception(mock_aws_clients):
1235 |     """Test search transaction spans with general exception."""
1236 |     with patch(
1237 |         'awslabs.cloudwatch_applicationsignals_mcp_server.trace_tools.check_transaction_search_enabled'
1238 |     ) as mock_check:
1239 |         mock_check.return_value = (True, 'CloudWatchLogs', 'ACTIVE')
1240 |         mock_aws_clients['logs_client'].start_query.side_effect = Exception('Query failed')
1241 | 
1242 |         with pytest.raises(Exception) as exc_info:
1243 |             await search_transaction_spans(
1244 |                 log_group_name='aws/spans',
1245 |                 start_time='2024-01-01T00:00:00+00:00',
1246 |                 end_time='2024-01-01T01:00:00+00:00',
1247 |                 query_string='fields @timestamp',
1248 |                 limit=100,
1249 |                 max_timeout=30,
1250 |             )
1251 | 
1252 |         assert 'Query failed' in str(exc_info.value)
1253 | 
1254 | 
1255 | @pytest.mark.asyncio
1256 | async def test_list_monitored_services_with_attributes_branch(mock_aws_clients):
1257 |     """Test list_monitored_services with key attributes that trigger the branch."""
1258 |     mock_response = {
1259 |         'ServiceSummaries': [
1260 |             {
1261 |                 'KeyAttributes': {}  # Empty attributes to test the branch
1262 |             }
1263 |         ]
1264 |     }
1265 | 
1266 |     mock_aws_clients['applicationsignals_client'].list_services.return_value = mock_response
1267 | 
1268 |     result = await list_monitored_services()
1269 | 
1270 |     assert 'Application Signals Services (1 total)' in result
1271 |     assert 'Key Attributes:' not in result  # Should not show when empty
1272 | 
1273 | 
1274 | @pytest.mark.asyncio
1275 | async def test_get_trace_summaries_paginated_with_limit(mock_aws_clients):
1276 |     """Test get_trace_summaries_paginated when it hits the max_traces limit."""
1277 |     # Mock responses with more traces than the limit
1278 |     mock_response_1 = {
1279 |         'TraceSummaries': [{'Id': f'trace-{i}', 'Duration': 100} for i in range(10)],
1280 |         'NextToken': 'token1',
1281 |     }
1282 |     mock_response_2 = {
1283 |         'TraceSummaries': [{'Id': f'trace-{i}', 'Duration': 100} for i in range(10, 15)]
1284 |     }
1285 | 
1286 |     mock_aws_clients['xray_client'].get_trace_summaries.side_effect = [
1287 |         mock_response_1,
1288 |         mock_response_2,
1289 |     ]
1290 | 
1291 |     # Test with max_traces=12
1292 |     traces = get_trace_summaries_paginated(
1293 |         mock_aws_clients['xray_client'],
1294 |         datetime.now(timezone.utc),
1295 |         datetime.now(timezone.utc),
1296 |         'service("test")',
1297 |         max_traces=12,
1298 |     )
1299 | 
1300 |     # The function continues until it gets all traces from the current page
1301 |     # before checking the limit, so we might get more than max_traces
1302 |     assert len(traces) >= 12  # Should have at least the limit
1303 | 
1304 | 
1305 | @pytest.mark.asyncio
1306 | async def test_get_slo_with_period_based_sli_full_details(mock_aws_clients):
1307 |     """Test get_slo with comprehensive period-based SLI configuration."""
1308 |     mock_response = {
1309 |         'Slo': {
1310 |             'Name': 'test-slo',
1311 |             'Arn': 'arn:aws:slo:test',
1312 |             'Description': 'Test SLO',
1313 |             'EvaluationType': 'PERIOD_BASED',
1314 |             'CreatedTime': datetime.now(timezone.utc),
1315 |             'LastUpdatedTime': datetime.now(timezone.utc),
1316 |             'Goal': {
1317 |                 'AttainmentGoal': 99.9,
1318 |                 'WarningThreshold': 95,
1319 |                 'Interval': {
1320 |                     'CalendarInterval': {
1321 |                         'Duration': 1,
1322 |                         'DurationUnit': 'MONTH',
1323 |                         'StartTime': datetime.now(timezone.utc),
1324 |                     }
1325 |                 },
1326 |             },
1327 |             'Sli': {
1328 |                 'SliMetric': {
1329 |                     'KeyAttributes': {'Service': 'test-service', 'Environment': 'prod'},
1330 |                     'OperationName': 'GetItem',
1331 |                     'MetricType': 'LATENCY',
1332 |                     'MetricDataQueries': [
1333 |                         {
1334 |                             'Id': 'query1',
1335 |                             'MetricStat': {
1336 |                                 'Metric': {
1337 |                                     'Namespace': 'AWS/ApplicationSignals',
1338 |                                     'MetricName': 'Latency',
1339 |                                     'Dimensions': [
1340 |                                         {'Name': 'Service', 'Value': 'test-service'},
1341 |                                         {'Name': 'Operation', 'Value': 'GetItem'},
1342 |                                     ],
1343 |                                 },
1344 |                                 'Period': 300,
1345 |                                 'Stat': 'p99',
1346 |                                 'Unit': 'Milliseconds',
1347 |                             },
1348 |                             'ReturnData': True,
1349 |                         },
1350 |                         {'Id': 'query2', 'Expression': 'query1 * 2', 'ReturnData': False},
1351 |                     ],
1352 |                     'DependencyConfig': {
1353 |                         'DependencyKeyAttributes': {
1354 |                             'RemoteService': 'downstream-service',
1355 |                             'RemoteEnvironment': 'prod',
1356 |                         },
1357 |                         'DependencyOperationName': 'ProcessRequest',
1358 |                     },
1359 |                 },
1360 |                 'MetricThreshold': 1000,
1361 |                 'ComparisonOperator': 'LessThan',
1362 |             },
1363 |             'BurnRateConfigurations': [
1364 |                 {'LookBackWindowMinutes': 5},
1365 |                 {'LookBackWindowMinutes': 60},
1366 |             ],
1367 |         }
1368 |     }
1369 | 
1370 |     mock_aws_clients[
1371 |         'applicationsignals_client'
1372 |     ].get_service_level_objective.return_value = mock_response
1373 | 
1374 |     result = await get_slo('test-slo-id')
1375 | 
1376 |     # Verify all sections are present
1377 |     assert 'Service Level Objective Details' in result
1378 |     assert 'Goal Configuration' in result
1379 |     assert 'Calendar 1 MONTH' in result
1380 |     assert 'Period-Based SLI Configuration' in result
1381 |     assert 'Key Attributes:' in result
1382 |     assert 'Service: test-service' in result
1383 |     assert 'Operation Name: GetItem' in result
1384 |     assert 'Metric Data Queries:' in result
1385 |     assert 'Query ID: query1' in result
1386 |     assert 'Namespace: AWS/ApplicationSignals' in result
1387 |     assert 'Dimensions:' in result
1388 |     assert 'Expression: query1 * 2' in result
1389 |     assert 'ReturnData: False' in result
1390 |     assert 'Dependency Configuration:' in result
1391 |     assert 'RemoteService: downstream-service' in result
1392 |     assert 'Dependency Operation: ProcessRequest' in result
1393 |     assert 'Burn Rate Configurations:' in result
1394 | 
1395 | 
1396 | @pytest.mark.asyncio
1397 | async def test_get_slo_with_request_based_sli_full_details(mock_aws_clients):
1398 |     """Test get_slo with comprehensive request-based SLI configuration."""
1399 |     mock_response = {
1400 |         'Slo': {
1401 |             'Name': 'test-slo-rbs',
1402 |             'Arn': 'arn:aws:slo:test-rbs',
1403 |             'Goal': {
1404 |                 'AttainmentGoal': 99.5,
1405 |                 'Interval': {'RollingInterval': {'Duration': 7, 'DurationUnit': 'DAY'}},
1406 |             },
1407 |             'RequestBasedSli': {
1408 |                 'RequestBasedSliMetric': {
1409 |                     'KeyAttributes': {'Service': 'api-service', 'Type': 'AWS::Lambda::Function'},
1410 |                     'OperationName': 'ProcessOrder',
1411 |                     'MetricType': 'AVAILABILITY',
1412 |                     'MetricDataQueries': [
1413 |                         {
1414 |                             'Id': 'success',
1415 |                             'MetricStat': {
1416 |                                 'Metric': {
1417 |                                     'Namespace': 'AWS/Lambda',
1418 |                                     'MetricName': 'Success',
1419 |                                     'Dimensions': [
1420 |                                         {'Name': 'FunctionName', 'Value': 'process-order'}
1421 |                                     ],
1422 |                                 },
1423 |                                 'Period': 60,
1424 |                                 'Stat': 'Sum',
1425 |                             },
1426 |                         },
1427 |                         {
1428 |                             'Id': 'errors',
1429 |                             'MetricStat': {
1430 |                                 'Metric': {
1431 |                                     'Namespace': 'AWS/Lambda',
1432 |                                     'MetricName': 'Errors',
1433 |                                     'Dimensions': [
1434 |                                         {'Name': 'FunctionName', 'Value': 'process-order'}
1435 |                                     ],
1436 |                                 },
1437 |                                 'Period': 60,
1438 |                                 'Stat': 'Sum',
1439 |                                 'Unit': 'Count',
1440 |                             },
1441 |                         },
1442 |                         {'Id': 'availability', 'Expression': 'success / (success + errors) * 100'},
1443 |                     ],
1444 |                     'DependencyConfig': {
1445 |                         'DependencyKeyAttributes': {'Database': 'orders-db'},
1446 |                         'DependencyOperationName': 'Query',
1447 |                     },
1448 |                 },
1449 |                 'MetricThreshold': 99.0,
1450 |                 'ComparisonOperator': 'GreaterThan',
1451 |             },
1452 |         }
1453 |     }
1454 | 
1455 |     mock_aws_clients[
1456 |         'applicationsignals_client'
1457 |     ].get_service_level_objective.return_value = mock_response
1458 | 
1459 |     result = await get_slo('test-slo-rbs-id')
1460 | 
1461 |     # Verify request-based sections
1462 |     assert 'Request-Based SLI Configuration:' in result
1463 |     assert 'api-service' in result
1464 |     assert 'ProcessOrder' in result
1465 |     assert 'AVAILABILITY' in result
1466 |     assert 'Expression: success / (success + errors) * 100' in result
1467 |     assert 'Dependency Configuration:' in result
1468 |     assert 'Database: orders-db' in result
1469 |     assert 'Unit: Count' in result
1470 | 
1471 | 
1472 | @pytest.mark.asyncio
1473 | async def test_get_slo_general_exception(mock_aws_clients):
1474 |     """Test get_slo with general exception."""
1475 |     mock_aws_clients[
1476 |         'applicationsignals_client'
1477 |     ].get_service_level_objective.side_effect = Exception('Unexpected error')
1478 | 
1479 |     result = await get_slo('test-slo-id')
1480 | 
1481 |     assert 'Error: Unexpected error' in result
1482 | 
1483 | 
1484 | @pytest.mark.asyncio
1485 | async def test_search_transaction_spans_with_none_log_group(mock_aws_clients):
1486 |     """Test search_transaction_spans when log_group_name is None."""
1487 |     with patch(
1488 |         'awslabs.cloudwatch_applicationsignals_mcp_server.trace_tools.check_transaction_search_enabled'
1489 |     ) as mock_check:
1490 |         mock_check.return_value = (True, 'CloudWatchLogs', 'ACTIVE')
1491 |         mock_aws_clients['logs_client'].start_query.return_value = {'queryId': 'test-query-id'}
1492 |         mock_aws_clients['logs_client'].get_query_results.return_value = {
1493 |             'queryId': 'test-query-id',
1494 |             'status': 'Complete',
1495 |             'results': [],
1496 |         }
1497 | 
1498 |         # Pass None for log_group_name to test the default handling
1499 |         await search_transaction_spans(
1500 |             log_group_name=None,  # type: ignore
1501 |             start_time='2024-01-01T00:00:00+00:00',
1502 |             end_time='2024-01-01T01:00:00+00:00',
1503 |             query_string='fields @timestamp',
1504 |             limit=100,
1505 |             max_timeout=30,
1506 |         )
1507 | 
1508 |         # Verify it used the default log group
1509 |         call_args = mock_aws_clients['logs_client'].start_query.call_args[1]
1510 |         assert 'aws/spans' in call_args['logGroupNames']
1511 | 
1512 | 
1513 | @pytest.mark.asyncio
1514 | async def test_search_transaction_spans_complete_with_statistics(mock_aws_clients):
1515 |     """Test search_transaction_spans when query completes with detailed statistics."""
1516 |     with patch(
1517 |         'awslabs.cloudwatch_applicationsignals_mcp_server.trace_tools.check_transaction_search_enabled'
1518 |     ) as mock_check:
1519 |         mock_check.return_value = (True, 'CloudWatchLogs', 'ACTIVE')
1520 |         mock_aws_clients['logs_client'].start_query.return_value = {'queryId': 'test-query-id'}
1521 | 
1522 |         # First return Running, then Complete
1523 |         mock_aws_clients['logs_client'].get_query_results.side_effect = [
1524 |             {'queryId': 'test-query-id', 'status': 'Running'},
1525 |             {
1526 |                 'queryId': 'test-query-id',
1527 |                 'status': 'Complete',
1528 |                 'statistics': {
1529 |                     'recordsMatched': 100,
1530 |                     'recordsScanned': 1000,
1531 |                     'bytesScanned': 50000,
1532 |                 },
1533 |                 'results': [
1534 |                     [
1535 |                         {'field': 'spanId', 'value': 'span1'},
1536 |                         {'field': '@timestamp', 'value': '2024-01-01 00:00:00'},
1537 |                     ]
1538 |                 ],
1539 |             },
1540 |         ]
1541 | 
1542 |         result = await search_transaction_spans(
1543 |             log_group_name='aws/spans',
1544 |             start_time='2024-01-01T00:00:00+00:00',
1545 |             end_time='2024-01-01T01:00:00+00:00',
1546 |             query_string='fields @timestamp, spanId',
1547 |             limit=100,
1548 |             max_timeout=30,
1549 |         )
1550 | 
1551 |         assert result['status'] == 'Complete'
1552 |         assert result['statistics']['recordsMatched'] == 100
1553 |         assert len(result['results']) == 1
1554 | 
1555 | 
1556 | @pytest.mark.asyncio
1557 | async def test_list_slis_general_exception(mock_aws_clients):
1558 |     """Test list_slis with general exception."""
1559 |     mock_aws_clients['applicationsignals_client'].list_services.side_effect = Exception(
1560 |         'Service unavailable'
1561 |     )
1562 | 
1563 |     result = await list_slis(hours=24)
1564 | 
1565 |     assert 'Error getting SLI status: Service unavailable' in result
1566 | 
1567 | 
1568 | @pytest.mark.asyncio
1569 | async def test_query_sampled_traces_with_defaults(mock_aws_clients):
1570 |     """Test query_sampled_traces with default start_time and end_time."""
1571 |     mock_trace_response = {
1572 |         'TraceSummaries': [
1573 |             {
1574 |                 'Id': 'trace1',
1575 |                 'Duration': 100,
1576 |                 'HasError': True,
1577 |                 'ErrorRootCauses': [
1578 |                     {
1579 |                         'Services': [
1580 |                             {
1581 |                                 'Name': 'test-service',
1582 |                                 'Names': ['test-service'],
1583 |                                 'Type': 'AWS::ECS::Service',
1584 |                                 'AccountId': '123456789012',
1585 |                                 'EntityPath': [
1586 |                                     {'Name': 'test-service', 'Coverage': 1.0, 'Remote': False}
1587 |                                 ],
1588 |                                 'Inferred': False,
1589 |                             }
1590 |                         ],
1591 |                         'ClientImpacting': True,
1592 |                     }
1593 |                 ],
1594 |             }
1595 |         ]
1596 |     }
1597 | 
1598 |     with patch(
1599 |         'awslabs.cloudwatch_applicationsignals_mcp_server.trace_tools.get_trace_summaries_paginated'
1600 |     ) as mock_paginated:
1601 |         mock_paginated.return_value = mock_trace_response['TraceSummaries']
1602 | 
1603 |         # Call without start_time and end_time to test defaults
1604 |         result_json = await query_sampled_traces(
1605 |             filter_expression='service("test-service")',
1606 |             start_time=None,
1607 |             end_time=None,
1608 |             region='us-east-1',
1609 |         )
1610 | 
1611 |         result = json.loads(result_json)
1612 |         assert result['TraceCount'] == 1
1613 |         assert result['TraceSummaries'][0]['HasError'] is True
1614 | 
1615 |         # Verify the time window was set to 3 hours
1616 |         call_args = mock_paginated.call_args[0]
1617 |         time_diff = call_args[2] - call_args[1]  # end_time - start_time
1618 |         assert 2.9 < time_diff.total_seconds() / 3600 < 3.1  # Approximately 3 hours
1619 | 
1620 | 
1621 | @pytest.mark.asyncio
1622 | async def test_query_sampled_traces_with_annotations(mock_aws_clients):
1623 |     """Test query_sampled_traces with annotations filtering."""
1624 |     mock_trace = {
1625 |         'Id': 'trace1',
1626 |         'Duration': 100,
1627 |         'Annotations': {
1628 |             'aws.local.operation': 'GetItem',
1629 |             'aws.remote.operation': 'Query',
1630 |             'custom.field': 'should-be-filtered',
1631 |             'another.field': 'also-filtered',
1632 |         },
1633 |         'Users': [
1634 |             {'UserName': 'user1', 'ServiceIds': []},
1635 |             {'UserName': 'user2', 'ServiceIds': []},
1636 |             {'UserName': 'user3', 'ServiceIds': []},  # Should be limited to 2
1637 |         ],
1638 |     }
1639 | 
1640 |     with patch(
1641 |         'awslabs.cloudwatch_applicationsignals_mcp_server.trace_tools.get_trace_summaries_paginated'
1642 |     ) as mock_paginated:
1643 |         mock_paginated.return_value = [mock_trace]
1644 | 
1645 |         result_json = await query_sampled_traces(
1646 |             start_time='2024-01-01T00:00:00Z',
1647 |             end_time='2024-01-01T01:00:00Z',
1648 |             filter_expression='service("test")',
1649 |         )
1650 | 
1651 |         result = json.loads(result_json)
1652 |         trace_summary = result['TraceSummaries'][0]
1653 | 
1654 |         # Check annotations were filtered
1655 |         assert 'Annotations' in trace_summary
1656 |         assert 'aws.local.operation' in trace_summary['Annotations']
1657 |         assert 'aws.remote.operation' in trace_summary['Annotations']
1658 |         assert 'custom.field' not in trace_summary['Annotations']
1659 | 
1660 |         # Check users were limited
1661 |         assert len(trace_summary['Users']) == 2
1662 | 
1663 | 
1664 | @pytest.mark.asyncio
1665 | async def test_query_sampled_traces_with_fault_causes(mock_aws_clients):
1666 |     """Test query_sampled_traces with fault root causes."""
1667 |     mock_trace = {
1668 |         'Id': 'trace1',
1669 |         'Duration': 100,
1670 |         'HasFault': True,
1671 |         'FaultRootCauses': [
1672 |             {'Services': [{'Name': 'service1', 'Exceptions': [{'Message': 'Test fault error'}]}]},
1673 |             {'Services': [{'Name': 'service2'}]},
1674 |             {'Services': [{'Name': 'service3'}]},
1675 |             {'Services': [{'Name': 'service4'}]},  # Should be limited to 3
1676 |         ],
1677 |         'ResponseTimeRootCauses': [{'Services': [{'Name': 'slow-service'}]}],
1678 |     }
1679 | 
1680 |     with patch(
1681 |         'awslabs.cloudwatch_applicationsignals_mcp_server.trace_tools.get_trace_summaries_paginated'
1682 |     ) as mock_paginated:
1683 |         mock_paginated.return_value = [mock_trace]
1684 | 
1685 |         result_json = await query_sampled_traces(
1686 |             start_time='2024-01-01T00:00:00Z', end_time='2024-01-01T01:00:00Z'
1687 |         )
1688 | 
1689 |         result = json.loads(result_json)
1690 |         trace_summary = result['TraceSummaries'][0]
1691 | 
1692 |         # Check root causes were limited to 3
1693 |         assert len(trace_summary['FaultRootCauses']) == 3
1694 |         assert 'ResponseTimeRootCauses' in trace_summary
1695 | 
1696 | 
1697 | @pytest.mark.asyncio
1698 | async def test_query_sampled_traces_general_exception(mock_aws_clients):
1699 |     """Test query_sampled_traces with general exception."""
1700 |     with patch(
1701 |         'awslabs.cloudwatch_applicationsignals_mcp_server.trace_tools.get_trace_summaries_paginated'
1702 |     ) as mock_paginated:
1703 |         mock_paginated.side_effect = Exception('Trace query failed')
1704 | 
1705 |         result_json = await query_sampled_traces(
1706 |             start_time='2024-01-01T00:00:00Z', end_time='2024-01-01T01:00:00Z'
1707 |         )
1708 | 
1709 |         result = json.loads(result_json)
1710 |         assert 'error' in result
1711 |         assert 'Trace query failed' in result['error']
1712 | 
1713 | 
1714 | @pytest.mark.asyncio
1715 | async def test_query_sampled_traces_datetime_conversion(mock_aws_clients):
1716 |     """Test query_sampled_traces with datetime objects that need conversion."""
1717 |     # The convert_datetime function in server.py only processes top-level fields,
1718 |     # not nested datetime objects. Let's test with a datetime at the top level.
1719 |     mock_trace = {
1720 |         'Id': 'trace1',
1721 |         'Duration': 100,
1722 |         'Http': {'HttpStatus': 200, 'HttpMethod': 'GET'},
1723 |         'StartTime': datetime.now(timezone.utc),  # This will be processed by convert_datetime
1724 |         'EndTime': datetime.now(timezone.utc) + timedelta(minutes=1),
1725 |     }
1726 | 
1727 |     with patch(
1728 |         'awslabs.cloudwatch_applicationsignals_mcp_server.trace_tools.get_trace_summaries_paginated'
1729 |     ) as mock_paginated:
1730 |         mock_paginated.return_value = [mock_trace]
1731 | 
1732 |         result_json = await query_sampled_traces(
1733 |             start_time='2024-01-01T00:00:00Z', end_time='2024-01-01T01:00:00Z'
1734 |         )
1735 | 
1736 |         # Should not raise JSON serialization error
1737 |         result = json.loads(result_json)
1738 |         assert result['TraceCount'] == 1
1739 |         # The datetime fields should have been converted during processing
1740 |         trace_summary = result['TraceSummaries'][0]
1741 |         assert (
1742 |             'StartTime' not in trace_summary
1743 |         )  # These fields are not included in the simplified output
1744 |         assert 'EndTime' not in trace_summary
1745 | 
1746 | 
1747 | @pytest.mark.asyncio
1748 | async def test_query_sampled_traces_deduplication(mock_aws_clients):
1749 |     """Test query_sampled_traces deduplicates traces with same fault message.
1750 | 
1751 |     Note: Only FaultRootCauses are deduplicated, not ErrorRootCauses.
1752 |     This is because the primary use case is investigating server faults (5xx errors),
1753 |     not client errors (4xx).
1754 |     """
1755 |     # Create 5 traces with the same fault message
1756 |     mock_traces = [
1757 |         {
1758 |             'Id': f'trace{i}',
1759 |             'Duration': 100 + i * 10,
1760 |             'ResponseTime': 95 + i * 10,
1761 |             'HasFault': True,
1762 |             'FaultRootCauses': [
1763 |                 {
1764 |                     'Services': [
1765 |                         {
1766 |                             'Name': 'test-service',
1767 |                             'Exceptions': [{'Message': 'Database connection timeout'}],
1768 |                         }
1769 |                     ]
1770 |                 }
1771 |             ],
1772 |         }
1773 |         for i in range(1, 6)
1774 |     ]
1775 | 
1776 |     # Add 2 traces with ErrorRootCauses (these should NOT be deduplicated)
1777 |     mock_traces.extend(
1778 |         [
1779 |             {
1780 |                 'Id': 'trace6',
1781 |                 'Duration': 200,
1782 |                 'HasError': True,
1783 |                 'ErrorRootCauses': [
1784 |                     {
1785 |                         'Services': [
1786 |                             {
1787 |                                 'Name': 'api-service',
1788 |                                 'Exceptions': [{'Message': 'Invalid API key'}],
1789 |                             }
1790 |                         ]
1791 |                     }
1792 |                 ],
1793 |             },
1794 |             {
1795 |                 'Id': 'trace7',
1796 |                 'Duration': 210,
1797 |                 'HasError': True,
1798 |                 'ErrorRootCauses': [
1799 |                     {
1800 |                         'Services': [
1801 |                             {
1802 |                                 'Name': 'api-service',
1803 |                                 'Exceptions': [{'Message': 'Invalid API key'}],
1804 |                             }
1805 |                         ]
1806 |                     }
1807 |                 ],
1808 |             },
1809 |         ]
1810 |     )
1811 | 
1812 |     # Add 2 healthy traces
1813 |     mock_traces.extend(
1814 |         [
1815 |             {
1816 |                 'Id': 'trace8',
1817 |                 'Duration': 50,
1818 |                 'ResponseTime': 45,
1819 |                 'HasError': False,
1820 |                 'HasFault': False,
1821 |             },
1822 |             {
1823 |                 'Id': 'trace9',
1824 |                 'Duration': 55,
1825 |                 'ResponseTime': 50,
1826 |                 'HasError': False,
1827 |                 'HasFault': False,
1828 |             },
1829 |         ]
1830 |     )
1831 | 
1832 |     with patch(
1833 |         'awslabs.cloudwatch_applicationsignals_mcp_server.trace_tools.get_trace_summaries_paginated'
1834 |     ) as mock_paginated:
1835 |         mock_paginated.return_value = mock_traces
1836 | 
1837 |         result_json = await query_sampled_traces(
1838 |             start_time='2024-01-01T00:00:00Z', end_time='2024-01-01T01:00:00Z'
1839 |         )
1840 | 
1841 |         result = json.loads(result_json)
1842 | 
1843 |         # Verify deduplication worked - should only have 5 traces
1844 |         # 1 for database timeout fault (deduplicated from 5)
1845 |         # 2 for API key errors (NOT deduplicated - only faults are deduped)
1846 |         # 2 healthy traces (not deduplicated)
1847 |         assert result['TraceCount'] == 5
1848 |         assert len(result['TraceSummaries']) == 5
1849 | 
1850 |         # Verify deduplication stats
1851 |         assert 'DeduplicationStats' in result
1852 |         assert result['DeduplicationStats']['OriginalTraceCount'] == 9
1853 |         assert result['DeduplicationStats']['DuplicatesRemoved'] == 4  # 9 - 5 = 4
1854 |         assert (
1855 |             result['DeduplicationStats']['UniqueFaultMessages'] == 1
1856 |         )  # Only counting FaultRootCauses
1857 | 
1858 |         # Find the trace with fault
1859 |         db_trace = next(
1860 |             (
1861 |                 t
1862 |                 for t in result['TraceSummaries']
1863 |                 if t.get('FaultRootCauses')
1864 |                 and any(
1865 |                     'Database connection timeout' in str(s.get('Exceptions', []))
1866 |                     for cause in t['FaultRootCauses']
1867 |                     for s in cause.get('Services', [])
1868 |                 )
1869 |             ),
1870 |             None,
1871 |         )
1872 |         assert db_trace is not None
1873 |         assert db_trace['HasFault'] is True
1874 | 
1875 |         # Verify both error traces are present (not deduplicated)
1876 |         error_traces = [
1877 |             t
1878 |             for t in result['TraceSummaries']
1879 |             if t.get('ErrorRootCauses')
1880 |             and any(
1881 |                 'Invalid API key' in str(s.get('Exceptions', []))
1882 |                 for cause in t['ErrorRootCauses']
1883 |                 for s in cause.get('Services', [])
1884 |             )
1885 |         ]
1886 |         assert len(error_traces) == 2  # Both error traces should be kept
1887 |         assert all(t['HasError'] is True for t in error_traces)
1888 | 
1889 |         # Verify healthy traces are included
1890 |         healthy_count = sum(
1891 |             1
1892 |             for t in result['TraceSummaries']
1893 |             if not t.get('HasError') and not t.get('HasFault') and not t.get('HasThrottle')
1894 |         )
1895 |         assert healthy_count == 2
1896 | 
1897 | 
1898 | def test_main_success(mock_aws_clients):
1899 |     """Test main function normal execution."""
1900 |     with patch('awslabs.cloudwatch_applicationsignals_mcp_server.server.mcp') as mock_mcp:
1901 |         main()
1902 |         mock_mcp.run.assert_called_once_with(transport='stdio')
1903 | 
1904 | 
1905 | def test_main_exception(mock_aws_clients):
1906 |     """Test main function with general exception."""
1907 |     with patch('awslabs.cloudwatch_applicationsignals_mcp_server.server.mcp') as mock_mcp:
1908 |         mock_mcp.run.side_effect = Exception('Server error')
1909 | 
1910 |         with pytest.raises(Exception) as exc_info:
1911 |             main()
1912 | 
1913 |         assert 'Server error' in str(exc_info.value)
1914 | 
1915 | 
1916 | def test_main_entry_point(mock_aws_clients):
1917 |     """Test the if __name__ == '__main__' entry point."""
1918 |     # The __main__ block is simple and just calls main()
1919 |     # We can't easily test it without executing the module
1920 |     # So we'll just ensure the main() function works
1921 |     # The actual line 1346 will be covered when the module is imported
1922 |     # during normal test execution
1923 | 
1924 |     # Instead, let's just verify the main function exists and is callable
1925 |     from awslabs.cloudwatch_applicationsignals_mcp_server.server import main
1926 | 
1927 |     assert callable(main)
1928 | 
1929 |     # And verify that running main with mocked mcp doesn't raise
1930 |     with patch('awslabs.cloudwatch_applicationsignals_mcp_server.server.mcp') as mock_mcp:
1931 |         mock_mcp.run.side_effect = KeyboardInterrupt()
1932 |         # Should handle KeyboardInterrupt gracefully
1933 |         main()
1934 | 
1935 | 
1936 | @pytest.mark.asyncio
1937 | async def test_analyze_canary_failures_no_runs(mock_aws_clients):
1938 |     """Test analyze_canary_failures when no runs are found."""
1939 |     from awslabs.cloudwatch_applicationsignals_mcp_server.server import analyze_canary_failures
1940 | 
1941 |     mock_aws_clients['synthetics_client'].get_canary_runs.return_value = {'CanaryRuns': []}
1942 |     mock_aws_clients['synthetics_client'].get_canary.return_value = {
1943 |         'Canary': {'Name': 'test-canary'}
1944 |     }
1945 | 
1946 |     result = await analyze_canary_failures('test-canary', 'us-east-1')
1947 | 
1948 |     assert 'No run history found for test-canary' in result
1949 | 
1950 | 
1951 | @pytest.mark.asyncio
1952 | async def test_analyze_canary_failures_healthy_canary(mock_aws_clients):
1953 |     """Test analyze_canary_failures with healthy canary."""
1954 |     from awslabs.cloudwatch_applicationsignals_mcp_server.server import analyze_canary_failures
1955 | 
1956 |     mock_runs = [
1957 |         {
1958 |             'Id': 'run1',
1959 |             'Status': {'State': 'PASSED'},
1960 |             'Timeline': {'Started': '2024-01-01T00:00:00Z'},
1961 |         }
1962 |     ]
1963 | 
1964 |     mock_aws_clients['synthetics_client'].get_canary_runs.return_value = {'CanaryRuns': mock_runs}
1965 |     mock_aws_clients['synthetics_client'].get_canary.return_value = {
1966 |         'Canary': {'Name': 'test-canary'}
1967 |     }
1968 | 
1969 |     with patch(
1970 |         'awslabs.cloudwatch_applicationsignals_mcp_server.server.get_canary_metrics_and_service_insights'
1971 |     ) as mock_insights:
1972 |         mock_insights.return_value = 'Telemetry insights available'
1973 | 
1974 |         result = await analyze_canary_failures('test-canary', 'us-east-1')
1975 | 
1976 |         assert 'Canary is healthy - no failures since last success' in result
1977 |         assert '🔍 Comprehensive Failure Analysis for test-canary' in result
1978 | 
1979 | 
1980 | @pytest.mark.asyncio
1981 | async def test_analyze_canary_failures_telemetry_unavailable(mock_aws_clients):
1982 |     """Test analyze_canary_failures when telemetry is unavailable."""
1983 |     from awslabs.cloudwatch_applicationsignals_mcp_server.server import analyze_canary_failures
1984 | 
1985 |     mock_runs = [
1986 |         {
1987 |             'Id': 'run1',
1988 |             'Status': {'State': 'PASSED'},
1989 |             'Timeline': {'Started': '2024-01-01T00:00:00Z'},
1990 |         }
1991 |     ]
1992 | 
1993 |     mock_aws_clients['synthetics_client'].get_canary_runs.return_value = {'CanaryRuns': mock_runs}
1994 |     mock_aws_clients['synthetics_client'].get_canary.return_value = {
1995 |         'Canary': {'Name': 'test-canary'}
1996 |     }
1997 | 
1998 |     with patch(
1999 |         'awslabs.cloudwatch_applicationsignals_mcp_server.server.get_canary_metrics_and_service_insights'
2000 |     ) as mock_insights:
2001 |         mock_insights.side_effect = Exception('Telemetry API error')
2002 | 
2003 |         result = await analyze_canary_failures('test-canary', 'us-east-1')
2004 | 
2005 |         assert 'Telemetry API unavailable: Telemetry API error' in result
2006 | 
2007 | 
2008 | @pytest.mark.asyncio
2009 | async def test_analyze_canary_failures_with_failures(mock_aws_clients):
2010 |     """Test analyze_canary_failures with actual failures."""
2011 |     from awslabs.cloudwatch_applicationsignals_mcp_server.server import analyze_canary_failures
2012 | 
2013 |     mock_runs = [
2014 |         {
2015 |             'Id': 'failed-run-1',
2016 |             'Status': {'State': 'FAILED', 'StateReason': 'Navigation timeout'},
2017 |             'Timeline': {'Started': '2024-01-01T01:00:00Z'},
2018 |         },
2019 |         {
2020 |             'Id': 'failed-run-2',
2021 |             'Status': {'State': 'FAILED', 'StateReason': 'Navigation timeout'},
2022 |             'Timeline': {'Started': '2024-01-01T00:30:00Z'},
2023 |         },
2024 |         {
2025 |             'Id': 'success-run',
2026 |             'Status': {'State': 'PASSED'},
2027 |             'Timeline': {'Started': '2024-01-01T00:00:00Z'},
2028 |         },
2029 |     ]
2030 | 
2031 |     mock_canary = {
2032 |         'Name': 'test-canary',
2033 |         'ArtifactS3Location': 's3://test-bucket/canary/us-east-1/test-canary',
2034 |     }
2035 | 
2036 |     mock_aws_clients['synthetics_client'].get_canary_runs.return_value = {'CanaryRuns': mock_runs}
2037 |     mock_aws_clients['synthetics_client'].get_canary.return_value = {'Canary': mock_canary}
2038 | 
2039 |     # Mock S3 artifacts
2040 |     mock_aws_clients['s3_client'].list_objects_v2.return_value = {
2041 |         'Contents': [
2042 |             {'Key': 'canary/us-east-1/test-canary/2024/01/01/test.har'},
2043 |             {'Key': 'canary/us-east-1/test-canary/2024/01/01/screenshot.png'},
2044 |             {'Key': 'canary/us-east-1/test-canary/2024/01/01/logs.txt'},
2045 |         ]
2046 |     }
2047 | 
2048 |     with patch(
2049 |         'awslabs.cloudwatch_applicationsignals_mcp_server.server.get_canary_metrics_and_service_insights'
2050 |     ) as mock_insights:
2051 |         with patch(
2052 |             'awslabs.cloudwatch_applicationsignals_mcp_server.server.analyze_har_file'
2053 |         ) as mock_har:
2054 |             with patch(
2055 |                 'awslabs.cloudwatch_applicationsignals_mcp_server.server.analyze_screenshots'
2056 |             ) as mock_screenshots:
2057 |                 with patch(
2058 |                     'awslabs.cloudwatch_applicationsignals_mcp_server.server.analyze_log_files'
2059 |                 ) as mock_logs:
2060 |                     mock_insights.return_value = 'Telemetry insights'
2061 |                     mock_har.return_value = {
2062 |                         'failed_requests': 2,
2063 |                         'total_requests': 10,
2064 |                         'request_details': [
2065 |                             {'url': 'https://example.com', 'status': 500, 'time': 1000}
2066 |                         ],
2067 |                     }
2068 |                     mock_screenshots.return_value = {'insights': ['Screenshot analysis']}
2069 |                     mock_logs.return_value = {'insights': ['Log analysis']}
2070 | 
2071 |                     result = await analyze_canary_failures('test-canary', 'us-east-1')
2072 | 
2073 |                     assert 'Found 2 consecutive failures since last success' in result
2074 |                     assert 'All failures have same cause: Navigation timeout' in result
2075 | 
2076 | 
2077 | @pytest.mark.asyncio
2078 | async def test_analyze_canary_failures_iam_analysis(mock_aws_clients):
2079 |     """Test analyze_canary_failures with IAM-related failures."""
2080 |     from awslabs.cloudwatch_applicationsignals_mcp_server.server import analyze_canary_failures
2081 | 
2082 |     mock_runs = [
2083 |         {
2084 |             'Id': 'failed-run',
2085 |             'Status': {'State': 'FAILED', 'StateReason': 'Access denied'},
2086 |             'Timeline': {'Started': '2024-01-01T00:00:00Z'},
2087 |         }
2088 |     ]
2089 | 
2090 |     mock_canary = {'Name': 'test-canary', 'ArtifactS3Location': ''}
2091 | 
2092 |     mock_aws_clients['synthetics_client'].get_canary_runs.return_value = {'CanaryRuns': mock_runs}
2093 |     mock_aws_clients['synthetics_client'].get_canary.return_value = {'Canary': mock_canary}
2094 | 
2095 |     with patch(
2096 |         'awslabs.cloudwatch_applicationsignals_mcp_server.server.get_canary_metrics_and_service_insights'
2097 |     ) as mock_insights:
2098 |         with patch(
2099 |             'awslabs.cloudwatch_applicationsignals_mcp_server.server.analyze_iam_role_and_policies'
2100 |         ) as mock_iam:
2101 |             with patch(
2102 |                 'awslabs.cloudwatch_applicationsignals_mcp_server.server.check_resource_arns_correct'
2103 |             ) as mock_arn:
2104 |                 mock_insights.return_value = 'Telemetry insights'
2105 |                 mock_iam.return_value = {
2106 |                     'status': 'issues_found',
2107 |                     'checks': {'role_exists': 'PASS', 'policies_attached': 'FAIL'},
2108 |                     'issues_found': ['Missing S3 permissions'],
2109 |                     'recommendations': ['Add S3 read permissions'],
2110 |                 }
2111 |                 mock_arn.return_value = {
2112 |                     'correct': False,
2113 |                     'error': 'Invalid bucket ARN',
2114 |                     'issues': ['Bucket name mismatch'],
2115 |                 }
2116 | 
2117 |                 result = await analyze_canary_failures('test-canary', 'us-east-1')
2118 | 
2119 |                 assert 'RUNNING COMPREHENSIVE IAM ANALYSIS' in result
2120 |                 assert 'IAM Role Analysis Status: issues_found' in result
2121 |                 assert 'ALL IAM ISSUES FOUND (2 total):' in result
2122 |                 assert 'IAM Policy: Missing S3 permissions' in result
2123 |                 assert 'Resource ARN: Bucket name mismatch' in result
2124 | 
2125 | 
2126 | @pytest.mark.asyncio
2127 | async def test_analyze_canary_failures_enospc_error(mock_aws_clients):
2128 |     """Test analyze_canary_failures with ENOSPC error."""
2129 |     from awslabs.cloudwatch_applicationsignals_mcp_server.server import analyze_canary_failures
2130 | 
2131 |     mock_runs = [
2132 |         {
2133 |             'Id': 'failed-run',
2134 |             'Status': {'State': 'FAILED', 'StateReason': 'ENOSPC: no space left on device'},
2135 |             'Timeline': {'Started': '2024-01-01T00:00:00Z'},
2136 |         }
2137 |     ]
2138 | 
2139 |     mock_canary = {'Name': 'test-canary', 'ArtifactS3Location': ''}
2140 | 
2141 |     mock_aws_clients['synthetics_client'].get_canary_runs.return_value = {'CanaryRuns': mock_runs}
2142 |     mock_aws_clients['synthetics_client'].get_canary.return_value = {'Canary': mock_canary}
2143 | 
2144 |     with patch(
2145 |         'awslabs.cloudwatch_applicationsignals_mcp_server.server.get_canary_metrics_and_service_insights'
2146 |     ) as mock_insights:
2147 |         with patch(
2148 |             'awslabs.cloudwatch_applicationsignals_mcp_server.server.extract_disk_memory_usage_metrics'
2149 |         ) as mock_metrics:
2150 |             mock_insights.return_value = 'Telemetry insights'
2151 |             mock_metrics.return_value = {
2152 |                 'maxEphemeralStorageUsageInMb': 512.5,
2153 |                 'maxEphemeralStorageUsagePercent': 95.2,
2154 |             }
2155 | 
2156 |             result = await analyze_canary_failures('test-canary', 'us-east-1')
2157 | 
2158 |             assert 'DISK USAGE ROOT CAUSE ANALYSIS:' in result
2159 |             assert 'Storage: 512.5 MB peak' in result
2160 |             assert 'Usage: 95.2% peak' in result
2161 | 
2162 | 
2163 | @pytest.mark.asyncio
2164 | async def test_analyze_canary_failures_protocol_error(mock_aws_clients):
2165 |     """Test analyze_canary_failures with protocol error."""
2166 |     from awslabs.cloudwatch_applicationsignals_mcp_server.server import analyze_canary_failures
2167 | 
2168 |     mock_runs = [
2169 |         {
2170 |             'Id': 'failed-run',
2171 |             'Status': {
2172 |                 'State': 'FAILED',
2173 |                 'StateReason': 'Protocol error (Target.activateTarget): Session closed',
2174 |             },
2175 |             'Timeline': {'Started': '2024-01-01T00:00:00Z'},
2176 |         }
2177 |     ]
2178 | 
2179 |     mock_canary = {'Name': 'test-canary', 'ArtifactS3Location': ''}
2180 | 
2181 |     mock_aws_clients['synthetics_client'].get_canary_runs.return_value = {'CanaryRuns': mock_runs}
2182 |     mock_aws_clients['synthetics_client'].get_canary.return_value = {'Canary': mock_canary}
2183 | 
2184 |     with patch(
2185 |         'awslabs.cloudwatch_applicationsignals_mcp_server.server.get_canary_metrics_and_service_insights'
2186 |     ) as mock_insights:
2187 |         with patch(
2188 |             'awslabs.cloudwatch_applicationsignals_mcp_server.server.extract_disk_memory_usage_metrics'
2189 |         ) as mock_metrics:
2190 |             mock_insights.return_value = 'Telemetry insights'
2191 |             mock_metrics.return_value = {'maxSyntheticsMemoryUsageInMB': 256.8}
2192 | 
2193 |             result = await analyze_canary_failures('test-canary', 'us-east-1')
2194 | 
2195 |             assert 'MEMORY USAGE ROOT CAUSE ANALYSIS:' in result
2196 |             assert 'Memory: 256.8 MB peak' in result
2197 | 
2198 | 
2199 | @pytest.mark.asyncio
2200 | async def test_analyze_canary_failures_navigation_timeout_with_har(mock_aws_clients):
2201 |     """Test analyze_canary_failures with navigation timeout and HAR analysis."""
2202 |     from awslabs.cloudwatch_applicationsignals_mcp_server.server import analyze_canary_failures
2203 | 
2204 |     mock_runs = [
2205 |         {
2206 |             'Id': 'failed-run',
2207 |             'Status': {'State': 'FAILED', 'StateReason': 'Navigation timed out after 30000ms'},
2208 |             'Timeline': {'Started': '2024-01-01T00:00:00Z'},
2209 |         }
2210 |     ]
2211 | 
2212 |     mock_canary = {
2213 |         'Name': 'test-canary',
2214 |         'ArtifactS3Location': 's3://test-bucket/canary/us-east-1/test-canary',
2215 |     }
2216 | 
2217 |     mock_aws_clients['synthetics_client'].get_canary_runs.return_value = {'CanaryRuns': mock_runs}
2218 |     mock_aws_clients['synthetics_client'].get_canary.return_value = {'Canary': mock_canary}
2219 | 
2220 |     # Mock S3 to return HAR files
2221 |     mock_aws_clients['s3_client'].list_objects_v2.return_value = {
2222 |         'Contents': [
2223 |             {'Key': 'canary/us-east-1/test-canary/2024/01/01/test.har'},
2224 |         ]
2225 |     }
2226 | 
2227 |     with patch(
2228 |         'awslabs.cloudwatch_applicationsignals_mcp_server.server.get_canary_metrics_and_service_insights'
2229 |     ) as mock_insights:
2230 |         with patch(
2231 |             'awslabs.cloudwatch_applicationsignals_mcp_server.server.analyze_har_file'
2232 |         ) as mock_har:
2233 |             mock_insights.return_value = 'Telemetry insights'
2234 |             mock_har.return_value = {
2235 |                 'failed_requests': 5,
2236 |                 'total_requests': 10,
2237 |                 'request_details': [
2238 |                     {'url': 'https://example.com/slow', 'status': 200, 'time': 5000}
2239 |                 ],
2240 |                 'insights': [
2241 |                     'Slow DNS resolution detected',
2242 |                     'High server response time',
2243 |                     'Network connectivity issues',
2244 |                     'Resource loading delays',
2245 |                     'JavaScript execution timeout',
2246 |                 ],
2247 |             }
2248 | 
2249 |             result = await analyze_canary_failures('test-canary', 'us-east-1')
2250 | 
2251 |             assert '🔍 Comprehensive Failure Analysis for test-canary' in result
2252 |             assert 'Slow DNS resolution detected' in result
2253 | 
2254 | 
2255 | @pytest.mark.asyncio
2256 | async def test_analyze_canary_failures_s3_exception(mock_aws_clients):
2257 |     """Test analyze_canary_failures when S3 operations fail."""
2258 |     from awslabs.cloudwatch_applicationsignals_mcp_server.server import analyze_canary_failures
2259 | 
2260 |     mock_runs = [
2261 |         {
2262 |             'Id': 'failed-run',
2263 |             'Status': {'State': 'FAILED', 'StateReason': 'Test failure'},
2264 |             'Timeline': {'Started': '2024-01-01T00:00:00Z'},
2265 |         }
2266 |     ]
2267 | 
2268 |     mock_canary = {
2269 |         'Name': 'test-canary',
2270 |         'ArtifactS3Location': 's3://test-bucket/canary/us-east-1/test-canary',
2271 |     }
2272 | 
2273 |     mock_aws_clients['synthetics_client'].get_canary_runs.return_value = {'CanaryRuns': mock_runs}
2274 |     mock_aws_clients['synthetics_client'].get_canary.return_value = {'Canary': mock_canary}
2275 | 
2276 |     mock_aws_clients['s3_client'].list_objects_v2.side_effect = Exception('S3 access denied')
2277 | 
2278 |     with patch(
2279 |         'awslabs.cloudwatch_applicationsignals_mcp_server.server.get_canary_metrics_and_service_insights'
2280 |     ) as mock_insights:
2281 |         with patch(
2282 |             'awslabs.cloudwatch_applicationsignals_mcp_server.server.analyze_canary_logs_with_time_window'
2283 |         ) as mock_logs:
2284 |             mock_insights.return_value = 'Telemetry insights'
2285 |             mock_logs.return_value = {
2286 |                 'status': 'success',
2287 |                 'time_window': '2024-01-01 00:00:00 - 2024-01-01 00:05:00',
2288 |                 'total_events': 5,
2289 |                 'error_events': [
2290 |                     {'timestamp': datetime.now(timezone.utc), 'message': 'Test error message'}
2291 |                 ],
2292 |             }
2293 | 
2294 |             result = await analyze_canary_failures('test-canary', 'us-east-1')
2295 | 
2296 |             # Should fall back to CloudWatch Logs analysis when S3 fails
2297 |             assert '⚠️ Artifacts not available - Checking CloudWatch Logs for root cause' in result
2298 |             assert 'CLOUDWATCH LOGS ANALYSIS' in result
2299 | 
2300 | 
2301 | @pytest.mark.asyncio
2302 | async def test_analyze_canary_failures_visual_variation(mock_aws_clients):
2303 |     """Test analyze_canary_failures with visual variation error."""
2304 |     from awslabs.cloudwatch_applicationsignals_mcp_server.server import analyze_canary_failures
2305 | 
2306 |     mock_runs = [
2307 |         {
2308 |             'Id': 'failed-run',
2309 |             'Status': {'State': 'FAILED', 'StateReason': 'Visual variation detected'},
2310 |             'Timeline': {'Started': '2024-01-01T00:00:00Z'},
2311 |         }
2312 |     ]
2313 | 
2314 |     mock_canary = {'Name': 'test-canary', 'ArtifactS3Location': ''}
2315 | 
2316 |     mock_aws_clients['synthetics_client'].get_canary_runs.return_value = {'CanaryRuns': mock_runs}
2317 |     mock_aws_clients['synthetics_client'].get_canary.return_value = {'Canary': mock_canary}
2318 | 
2319 |     with patch(
2320 |         'awslabs.cloudwatch_applicationsignals_mcp_server.server.get_canary_metrics_and_service_insights'
2321 |     ) as mock_insights:
2322 |         with patch(
2323 |             'awslabs.cloudwatch_applicationsignals_mcp_server.server.get_canary_code'
2324 |         ) as mock_code:
2325 |             mock_insights.return_value = 'Telemetry insights'
2326 |             mock_code.return_value = {'code_content': 'const synthetics = require("Synthetics");'}
2327 | 
2328 |             result = await analyze_canary_failures('test-canary', 'us-east-1')
2329 | 
2330 |             assert 'VISUAL MONITORING ISSUE DETECTED' in result
2331 |             assert 'Website UI changed - not a technical failure' in result
2332 |             assert 'canary code:' in result
2333 | 
2334 | 
2335 | @pytest.mark.asyncio
2336 | async def test_analyze_canary_failures_get_canary_code_exception(mock_aws_clients):
2337 |     """Test analyze_canary_failures when get_canary_code fails."""
2338 |     from awslabs.cloudwatch_applicationsignals_mcp_server.server import analyze_canary_failures
2339 | 
2340 |     mock_runs = [
2341 |         {
2342 |             'Id': 'failed-run',
2343 |             'Status': {'State': 'FAILED', 'StateReason': 'Test failure'},
2344 |             'Timeline': {'Started': '2024-01-01T00:00:00Z'},
2345 |         }
2346 |     ]
2347 | 
2348 |     mock_canary = {'Name': 'test-canary', 'ArtifactS3Location': ''}
2349 | 
2350 |     mock_aws_clients['synthetics_client'].get_canary_runs.return_value = {'CanaryRuns': mock_runs}
2351 |     mock_aws_clients['synthetics_client'].get_canary.return_value = {'Canary': mock_canary}
2352 | 
2353 |     with patch(
2354 |         'awslabs.cloudwatch_applicationsignals_mcp_server.server.get_canary_metrics_and_service_insights'
2355 |     ) as mock_insights:
2356 |         with patch(
2357 |             'awslabs.cloudwatch_applicationsignals_mcp_server.server.get_canary_code'
2358 |         ) as mock_code:
2359 |             mock_insights.return_value = 'Telemetry insights'
2360 |             # Make get_canary_code raise an exception
2361 |             mock_code.side_effect = Exception('Code retrieval failed')
2362 | 
2363 |             result = await analyze_canary_failures('test-canary', 'us-east-1')
2364 | 
2365 |             assert 'Note: Could not retrieve canary code: Code retrieval failed' in result
2366 | 
2367 | 
2368 | @pytest.mark.asyncio
2369 | async def test_analyze_canary_failures_iam_analysis_exception(mock_aws_clients):
2370 |     """Test analyze_canary_failures when IAM analysis fails."""
2371 |     from awslabs.cloudwatch_applicationsignals_mcp_server.server import analyze_canary_failures
2372 | 
2373 |     mock_runs = [
2374 |         {
2375 |             'Id': 'failed-run',
2376 |             'Status': {'State': 'FAILED', 'StateReason': 'Access denied'},
2377 |             'Timeline': {'Started': '2024-01-01T00:00:00Z'},
2378 |         }
2379 |     ]
2380 | 
2381 |     mock_canary = {'Name': 'test-canary', 'ArtifactS3Location': ''}
2382 | 
2383 |     mock_aws_clients['synthetics_client'].get_canary_runs.return_value = {'CanaryRuns': mock_runs}
2384 |     mock_aws_clients['synthetics_client'].get_canary.return_value = {'Canary': mock_canary}
2385 | 
2386 |     with patch(
2387 |         'awslabs.cloudwatch_applicationsignals_mcp_server.server.get_canary_metrics_and_service_insights'
2388 |     ) as mock_insights:
2389 |         with patch(
2390 |             'awslabs.cloudwatch_applicationsignals_mcp_server.server.analyze_iam_role_and_policies'
2391 |         ) as mock_iam:
2392 |             mock_insights.return_value = 'Telemetry insights'
2393 |             # Make IAM analysis raise an exception
2394 |             mock_iam.side_effect = Exception('IAM analysis failed')
2395 | 
2396 |             result = await analyze_canary_failures('test-canary', 'us-east-1')
2397 | 
2398 |             assert '⚠️ IAM analysis failed: IAM analysis failed' in result
2399 | 
2400 | 
2401 | @pytest.mark.asyncio
2402 | async def test_analyze_canary_failures_disk_usage_exception(mock_aws_clients):
2403 |     """Test analyze_canary_failures when disk usage analysis fails."""
2404 |     from awslabs.cloudwatch_applicationsignals_mcp_server.server import analyze_canary_failures
2405 | 
2406 |     mock_runs = [
2407 |         {
2408 |             'Id': 'failed-run',
2409 |             'Status': {'State': 'FAILED', 'StateReason': 'ENOSPC: no space left on device'},
2410 |             'Timeline': {'Started': '2024-01-01T00:00:00Z'},
2411 |         }
2412 |     ]
2413 | 
2414 |     mock_canary = {'Name': 'test-canary', 'ArtifactS3Location': ''}
2415 | 
2416 |     mock_aws_clients['synthetics_client'].get_canary_runs.return_value = {'CanaryRuns': mock_runs}
2417 |     mock_aws_clients['synthetics_client'].get_canary.return_value = {'Canary': mock_canary}
2418 | 
2419 |     with patch(
2420 |         'awslabs.cloudwatch_applicationsignals_mcp_server.server.get_canary_metrics_and_service_insights'
2421 |     ) as mock_insights:
2422 |         with patch(
2423 |             'awslabs.cloudwatch_applicationsignals_mcp_server.server.extract_disk_memory_usage_metrics'
2424 |         ) as mock_metrics:
2425 |             mock_insights.return_value = 'Telemetry insights'
2426 |             # Make disk usage analysis raise an exception
2427 |             mock_metrics.side_effect = Exception('Disk usage analysis failed')
2428 | 
2429 |             result = await analyze_canary_failures('test-canary', 'us-east-1')
2430 | 
2431 |             assert (
2432 |                 '⚠️ Could not generate disk usage debugging code: Disk usage analysis failed'
2433 |                 in result
2434 |             )
2435 | 
2436 | 
2437 | @pytest.mark.asyncio
2438 | async def test_analyze_canary_failures_memory_usage_exception(mock_aws_clients):
2439 |     """Test analyze_canary_failures when memory usage analysis fails."""
2440 |     from awslabs.cloudwatch_applicationsignals_mcp_server.server import analyze_canary_failures
2441 | 
2442 |     mock_runs = [
2443 |         {
2444 |             'Id': 'failed-run',
2445 |             'Status': {
2446 |                 'State': 'FAILED',
2447 |                 'StateReason': 'Protocol error (Target.activateTarget): Session closed',
2448 |             },
2449 |             'Timeline': {'Started': '2024-01-01T00:00:00Z'},
2450 |         }
2451 |     ]
2452 | 
2453 |     mock_canary = {'Name': 'test-canary', 'ArtifactS3Location': ''}
2454 | 
2455 |     mock_aws_clients['synthetics_client'].get_canary_runs.return_value = {'CanaryRuns': mock_runs}
2456 |     mock_aws_clients['synthetics_client'].get_canary.return_value = {'Canary': mock_canary}
2457 | 
2458 |     with patch(
2459 |         'awslabs.cloudwatch_applicationsignals_mcp_server.server.get_canary_metrics_and_service_insights'
2460 |     ) as mock_insights:
2461 |         with patch(
2462 |             'awslabs.cloudwatch_applicationsignals_mcp_server.server.extract_disk_memory_usage_metrics'
2463 |         ) as mock_metrics:
2464 |             mock_insights.return_value = 'Telemetry insights'
2465 |             # Make memory usage analysis raise an exception
2466 |             mock_metrics.side_effect = Exception('Memory usage analysis failed')
2467 | 
2468 |             result = await analyze_canary_failures('test-canary', 'us-east-1')
2469 | 
2470 |             assert (
2471 |                 '⚠️ Could not collect memory usage metrics: Memory usage analysis failed' in result
2472 |             )
2473 | 
2474 | 
2475 | @pytest.mark.asyncio
2476 | async def test_analyze_canary_failures_har_timeout_exception(mock_aws_clients):
2477 |     """Test analyze_canary_failures when HAR timeout analysis fails."""
2478 |     from awslabs.cloudwatch_applicationsignals_mcp_server.server import analyze_canary_failures
2479 | 
2480 |     mock_runs = [
2481 |         {
2482 |             'Id': 'failed-run',
2483 |             'Status': {'State': 'FAILED', 'StateReason': 'Navigation timed out after 30000ms'},
2484 |             'Timeline': {'Started': '2024-01-01T00:00:00Z'},
2485 |         }
2486 |     ]
2487 | 
2488 |     mock_canary = {
2489 |         'Name': 'test-canary',
2490 |         'ArtifactS3Location': 's3://test-bucket/canary/us-east-1/test-canary',
2491 |     }
2492 | 
2493 |     mock_aws_clients['synthetics_client'].get_canary_runs.return_value = {'CanaryRuns': mock_runs}
2494 |     mock_aws_clients['synthetics_client'].get_canary.return_value = {'Canary': mock_canary}
2495 | 
2496 |     # Mock S3 to return HAR files
2497 |     mock_aws_clients['s3_client'].list_objects_v2.return_value = {
2498 |         'Contents': [
2499 |             {'Key': 'canary/us-east-1/test-canary/2024/01/01/test.har'},
2500 |         ]
2501 |     }
2502 | 
2503 |     with patch(
2504 |         'awslabs.cloudwatch_applicationsignals_mcp_server.server.get_canary_metrics_and_service_insights'
2505 |     ) as mock_insights:
2506 |         with patch(
2507 |             'awslabs.cloudwatch_applicationsignals_mcp_server.server.analyze_har_file'
2508 |         ) as mock_har:
2509 |             mock_insights.return_value = 'Telemetry insights'
2510 |             # Make HAR analysis raise an exception
2511 |             mock_har.side_effect = Exception('HAR analysis failed')
2512 | 
2513 |             result = await analyze_canary_failures('test-canary', 'us-east-1')
2514 | 
2515 |             assert '⚠️ HAR analysis failed: HAR analysis failed' in result
2516 | 
2517 | 
2518 | @pytest.mark.asyncio
2519 | async def test_analyze_canary_failures_success_artifacts_exception(mock_aws_clients):
2520 |     """Test analyze_canary_failures when success artifacts retrieval fails."""
2521 |     from awslabs.cloudwatch_applicationsignals_mcp_server.server import analyze_canary_failures
2522 | 
2523 |     mock_runs = [
2524 |         {
2525 |             'Id': 'failed-run',
2526 |             'Status': {'State': 'FAILED', 'StateReason': 'Test failure'},
2527 |             'Timeline': {'Started': '2024-01-01T00:00:00Z'},
2528 |         },
2529 |         {
2530 |             'Id': 'success-run',
2531 |             'Status': {'State': 'PASSED'},
2532 |             'Timeline': {'Started': '2024-01-01T00:00:00Z'},
2533 |         },
2534 |     ]
2535 | 
2536 |     mock_canary = {
2537 |         'Name': 'test-canary',
2538 |         'ArtifactS3Location': 's3://test-bucket/canary/us-east-1/test-canary',
2539 |     }
2540 | 
2541 |     mock_aws_clients['synthetics_client'].get_canary_runs.return_value = {'CanaryRuns': mock_runs}
2542 |     mock_aws_clients['synthetics_client'].get_canary.return_value = {'Canary': mock_canary}
2543 | 
2544 |     # Mock S3 to return failure artifacts but fail on success artifacts
2545 |     def s3_side_effect(*args, **kwargs):
2546 |         prefix = kwargs.get('Prefix', '')
2547 |         if 'success' in prefix or len(prefix.split('/')) > 5:  # Simulate success path failure
2548 |             raise Exception('Success artifacts access failed')
2549 |         return {
2550 |             'Contents': [
2551 |                 {'Key': 'canary/us-east-1/test-canary/2024/01/01/test.har'},
2552 |             ]
2553 |         }
2554 | 
2555 |     mock_aws_clients['s3_client'].list_objects_v2.side_effect = s3_side_effect
2556 | 
2557 |     with patch(
2558 |         'awslabs.cloudwatch_applicationsignals_mcp_server.server.get_canary_metrics_and_service_insights'
2559 |     ) as mock_insights:
2560 |         with patch(
2561 |             'awslabs.cloudwatch_applicationsignals_mcp_server.server.analyze_har_file'
2562 |         ) as mock_har:
2563 |             mock_insights.return_value = 'Telemetry insights'
2564 |             mock_har.return_value = {
2565 |                 'failed_requests': 2,
2566 |                 'total_requests': 10,
2567 |                 'request_details': [],
2568 |             }
2569 | 
2570 |             result = await analyze_canary_failures('test-canary', 'us-east-1')
2571 | 
2572 |             # Should still process failure artifacts even if success artifacts fail
2573 |             assert '🔍 Comprehensive Failure Analysis for test-canary' in result
2574 | 
2575 | 
2576 | @pytest.mark.asyncio
2577 | async def test_analyze_canary_failures_no_failure_timestamp(mock_aws_clients):
2578 |     """Test analyze_canary_failures when failure has no timestamp."""
2579 |     from awslabs.cloudwatch_applicationsignals_mcp_server.server import analyze_canary_failures
2580 | 
2581 |     mock_runs = [
2582 |         {
2583 |             'Id': 'failed-run',
2584 |             'Status': {'State': 'FAILED', 'StateReason': 'Test failure'},
2585 |             'Timeline': {},  # No Started timestamp
2586 |         }
2587 |     ]
2588 | 
2589 |     mock_canary = {'Name': 'test-canary', 'ArtifactS3Location': ''}
2590 | 
2591 |     mock_aws_clients['synthetics_client'].get_canary_runs.return_value = {'CanaryRuns': mock_runs}
2592 |     mock_aws_clients['synthetics_client'].get_canary.return_value = {'Canary': mock_canary}
2593 | 
2594 |     with patch(
2595 |         'awslabs.cloudwatch_applicationsignals_mcp_server.server.get_canary_metrics_and_service_insights'
2596 |     ) as mock_insights:
2597 |         mock_insights.return_value = 'Telemetry insights'
2598 | 
2599 |         result = await analyze_canary_failures('test-canary', 'us-east-1')
2600 | 
2601 |         assert '📋 No failure timestamp available for targeted log analysis' in result
2602 | 
2603 | 
2604 | @pytest.mark.asyncio
2605 | async def test_analyze_canary_failures_log_analysis_failure(mock_aws_clients):
2606 |     """Test analyze_canary_failures when log analysis fails."""
2607 |     from awslabs.cloudwatch_applicationsignals_mcp_server.server import analyze_canary_failures
2608 | 
2609 |     mock_runs = [
2610 |         {
2611 |             'Id': 'failed-run',
2612 |             'Status': {'State': 'FAILED', 'StateReason': 'Test failure'},
2613 |             'Timeline': {'Started': '2024-01-01T00:00:00Z'},
2614 |         }
2615 |     ]
2616 | 
2617 |     mock_canary = {'Name': 'test-canary', 'ArtifactS3Location': ''}
2618 | 
2619 |     mock_aws_clients['synthetics_client'].get_canary_runs.return_value = {'CanaryRuns': mock_runs}
2620 |     mock_aws_clients['synthetics_client'].get_canary.return_value = {'Canary': mock_canary}
2621 | 
2622 |     with patch(
2623 |         'awslabs.cloudwatch_applicationsignals_mcp_server.server.get_canary_metrics_and_service_insights'
2624 |     ) as mock_insights:
2625 |         with patch(
2626 |             'awslabs.cloudwatch_applicationsignals_mcp_server.server.analyze_canary_logs_with_time_window'
2627 |         ) as mock_logs:
2628 |             mock_insights.return_value = 'Telemetry insights'
2629 |             mock_logs.return_value = {
2630 |                 'status': 'failed',
2631 |                 'insights': ['Log analysis failed due to missing log group'],
2632 |             }
2633 | 
2634 |             result = await analyze_canary_failures('test-canary', 'us-east-1')
2635 | 
2636 |             assert '📋 Log analysis failed due to missing log group' in result
2637 | 
2638 | 
2639 | @pytest.mark.asyncio
2640 | async def test_analyze_canary_failures_main_exception(mock_aws_clients):
2641 |     """Test analyze_canary_failures when main function fails."""
2642 |     from awslabs.cloudwatch_applicationsignals_mcp_server.server import analyze_canary_failures
2643 | 
2644 |     # Make get_canary_runs raise an exception
2645 |     mock_aws_clients['synthetics_client'].get_canary_runs.side_effect = Exception('API error')
2646 | 
2647 |     result = await analyze_canary_failures('test-canary', 'us-east-1')
2648 | 
2649 |     assert '❌ Error in comprehensive failure analysis: API error' in result
2650 | 
2651 | 
2652 | @pytest.mark.asyncio
2653 | async def test_analyze_canary_failures_no_har_files_navigation_timeout(mock_aws_clients):
2654 |     """Test analyze_canary_failures navigation timeout without HAR files."""
2655 |     from awslabs.cloudwatch_applicationsignals_mcp_server.server import analyze_canary_failures
2656 | 
2657 |     mock_runs = [
2658 |         {
2659 |             'Id': 'failed-run',
2660 |             'Status': {'State': 'FAILED', 'StateReason': 'Navigation timed out after 30000ms'},
2661 |             'Timeline': {'Started': '2024-01-01T00:00:00Z'},
2662 |         }
2663 |     ]
2664 | 
2665 |     mock_canary = {'Name': 'test-canary', 'ArtifactS3Location': ''}
2666 | 
2667 |     mock_aws_clients['synthetics_client'].get_canary_runs.return_value = {'CanaryRuns': mock_runs}
2668 |     mock_aws_clients['synthetics_client'].get_canary.return_value = {'Canary': mock_canary}
2669 | 
2670 |     with patch(
2671 |         'awslabs.cloudwatch_applicationsignals_mcp_server.server.get_canary_metrics_and_service_insights'
2672 |     ) as mock_insights:
2673 |         mock_insights.return_value = 'Telemetry insights'
2674 | 
2675 |         result = await analyze_canary_failures('test-canary', 'us-east-1')
2676 | 
2677 |         assert 'NAVIGATION TIMEOUT DETECTED:' in result
2678 |         assert 'No HAR files available for detailed analysis' in result
2679 | 
2680 | 
2681 | @pytest.mark.asyncio
2682 | async def test_analyze_canary_failures_artifact_location_without_s3_prefix(mock_aws_clients):
2683 |     """Test analyze_canary_failures with artifact location without s3:// prefix."""
2684 |     from awslabs.cloudwatch_applicationsignals_mcp_server.server import analyze_canary_failures
2685 | 
2686 |     mock_runs = [
2687 |         {
2688 |             'Id': 'failed-run',
2689 |             'Status': {'State': 'FAILED', 'StateReason': 'Test failure'},
2690 |             'Timeline': {'Started': '2024-01-01T00:00:00Z'},
2691 |         }
2692 |     ]
2693 | 
2694 |     mock_canary = {
2695 |         'Name': 'test-canary',
2696 |         'ArtifactS3Location': 'test-bucket/canary/us-east-1/test-canary',  # No s3:// prefix
2697 |     }
2698 | 
2699 |     mock_aws_clients['synthetics_client'].get_canary_runs.return_value = {'CanaryRuns': mock_runs}
2700 |     mock_aws_clients['synthetics_client'].get_canary.return_value = {'Canary': mock_canary}
2701 | 
2702 |     # Mock S3 to return artifacts
2703 |     mock_aws_clients['s3_client'].list_objects_v2.return_value = {
2704 |         'Contents': [
2705 |             {'Key': 'canary/us-east-1/test-canary/2024/01/01/test.har'},
2706 |         ]
2707 |     }
2708 | 
2709 |     with patch(
2710 |         'awslabs.cloudwatch_applicationsignals_mcp_server.server.get_canary_metrics_and_service_insights'
2711 |     ) as mock_insights:
2712 |         with patch(
2713 |             'awslabs.cloudwatch_applicationsignals_mcp_server.server.analyze_har_file'
2714 |         ) as mock_har:
2715 |             mock_insights.return_value = 'Telemetry insights'
2716 |             mock_har.return_value = {
2717 |                 'failed_requests': 1,
2718 |                 'total_requests': 5,
2719 |                 'request_details': [],
2720 |             }
2721 | 
2722 |             result = await analyze_canary_failures('test-canary', 'us-east-1')
2723 | 
2724 |             # Should still process artifacts even without s3:// prefix
2725 |             assert 'FAILURE ANALYSIS' in result
2726 | 
2727 | 
2728 | @pytest.mark.asyncio
2729 | async def test_analyze_canary_failures_empty_base_path(mock_aws_clients):
2730 |     """Test analyze_canary_failures with empty base path."""
2731 |     from awslabs.cloudwatch_applicationsignals_mcp_server.server import analyze_canary_failures
2732 | 
2733 |     mock_runs = [
2734 |         {
2735 |             'Id': 'failed-run',
2736 |             'Status': {'State': 'FAILED', 'StateReason': 'Test failure'},
2737 |             'Timeline': {'Started': '2024-01-01T00:00:00Z'},
2738 |         }
2739 |     ]
2740 | 
2741 |     mock_canary = {
2742 |         'Name': 'test-canary',
2743 |         'ArtifactS3Location': 's3://test-bucket',  # Only bucket, no path
2744 |     }
2745 | 
2746 |     mock_aws_clients['synthetics_client'].get_canary_runs.return_value = {'CanaryRuns': mock_runs}
2747 |     mock_aws_clients['synthetics_client'].get_canary.return_value = {'Canary': mock_canary}
2748 | 
2749 |     # Mock S3 to return artifacts
2750 |     mock_aws_clients['s3_client'].list_objects_v2.return_value = {
2751 |         'Contents': [
2752 |             {'Key': 'canary/us-east-1/test-canary/2024/01/01/test.har'},
2753 |         ]
2754 |     }
2755 | 
2756 |     with patch(
2757 |         'awslabs.cloudwatch_applicationsignals_mcp_server.server.get_canary_metrics_and_service_insights'
2758 |     ) as mock_insights:
2759 |         with patch(
2760 |             'awslabs.cloudwatch_applicationsignals_mcp_server.server.analyze_har_file'
2761 |         ) as mock_har:
2762 |             mock_insights.return_value = 'Telemetry insights'
2763 |             mock_har.return_value = {
2764 |                 'failed_requests': 1,
2765 |                 'total_requests': 5,
2766 |                 'request_details': [],
2767 |             }
2768 | 
2769 |             result = await analyze_canary_failures('test-canary', 'us-east-1')
2770 | 
2771 |             # Should construct default canary path when base_path is empty
2772 |             assert 'FAILURE ANALYSIS' in result
2773 | 
2774 | 
2775 | @pytest.mark.asyncio
2776 | async def test_analyze_canary_failures_multiple_failure_causes(mock_aws_clients):
2777 |     """Test analyze_canary_failures with multiple different failure causes."""
2778 |     from awslabs.cloudwatch_applicationsignals_mcp_server.server import analyze_canary_failures
2779 | 
2780 |     mock_runs = [
2781 |         {
2782 |             'Id': 'failed-run-1',
2783 |             'Status': {'State': 'FAILED', 'StateReason': 'Navigation timeout'},
2784 |             'Timeline': {'Started': '2024-01-01T00:00:00Z'},
2785 |         },
2786 |         {
2787 |             'Id': 'failed-run-2',
2788 |             'Status': {'State': 'FAILED', 'StateReason': 'Access denied'},
2789 |             'Timeline': {'Started': '2024-01-01T00:01:00Z'},
2790 |         },
2791 |         {
2792 |             'Id': 'success-run',
2793 |             'Status': {'State': 'PASSED'},
2794 |             'Timeline': {'Started': '2023-12-31T23:59:00Z'},
2795 |         },
2796 |     ]
2797 | 
2798 |     mock_canary = {'Name': 'test-canary', 'ArtifactS3Location': ''}
2799 | 
2800 |     mock_aws_clients['synthetics_client'].get_canary_runs.return_value = {'CanaryRuns': mock_runs}
2801 |     mock_aws_clients['synthetics_client'].get_canary.return_value = {'Canary': mock_canary}
2802 | 
2803 |     with patch(
2804 |         'awslabs.cloudwatch_applicationsignals_mcp_server.server.get_canary_metrics_and_service_insights'
2805 |     ) as mock_insights:
2806 |         mock_insights.return_value = 'Telemetry insights'
2807 | 
2808 |         result = await analyze_canary_failures('test-canary', 'us-east-1')
2809 | 
2810 |         assert 'Multiple failure causes (2 different issues):' in result
2811 |         assert '1. **Navigation timeout** (1 occurrences)' in result
2812 |         assert '2. **Access denied** (1 occurrences)' in result
2813 | 
2814 | 
2815 | @pytest.mark.asyncio
2816 | async def test_analyze_canary_failures_no_failure_time_fallback(mock_aws_clients):
2817 |     """Test analyze_canary_failures fallback when no failure time."""
2818 |     from awslabs.cloudwatch_applicationsignals_mcp_server.server import analyze_canary_failures
2819 | 
2820 |     mock_runs = [
2821 |         {
2822 |             'Id': 'failed-run',
2823 |             'Status': {'State': 'FAILED', 'StateReason': 'Test failure'},
2824 |             'Timeline': {},  # No Started time
2825 |         }
2826 |     ]
2827 | 
2828 |     mock_canary = {
2829 |         'Name': 'test-canary',
2830 |         'ArtifactS3Location': 's3://test-bucket/canary/us-east-1/test-canary',
2831 |     }
2832 | 
2833 |     mock_aws_clients['synthetics_client'].get_canary_runs.return_value = {'CanaryRuns': mock_runs}
2834 |     mock_aws_clients['synthetics_client'].get_canary.return_value = {'Canary': mock_canary}
2835 | 
2836 |     # Mock S3 to return artifacts
2837 |     mock_aws_clients['s3_client'].list_objects_v2.return_value = {
2838 |         'Contents': [
2839 |             {'Key': 'canary/us-east-1/test-canary/2024/01/01/test.har'},
2840 |         ]
2841 |     }
2842 | 
2843 |     with patch(
2844 |         'awslabs.cloudwatch_applicationsignals_mcp_server.server.get_canary_metrics_and_service_insights'
2845 |     ) as mock_insights:
2846 |         with patch(
2847 |             'awslabs.cloudwatch_applicationsignals_mcp_server.server.analyze_har_file'
2848 |         ) as mock_har:
2849 |             mock_insights.return_value = 'Telemetry insights'
2850 |             mock_har.return_value = {
2851 |                 'failed_requests': 1,
2852 |                 'total_requests': 5,
2853 |                 'request_details': [],
2854 |             }
2855 | 
2856 |             result = await analyze_canary_failures('test-canary', 'us-east-1')
2857 | 
2858 |             # Should use current time when no failure time available
2859 |             assert 'FAILURE ANALYSIS' in result
2860 | 
2861 | 
2862 | def test_filter_operation_targets_fault_to_availability():
2863 |     """Test _filter_operation_targets converts Fault to Availability."""
2864 |     provided = [
2865 |         {
2866 |             'Type': 'service_operation',
2867 |             'Data': {
2868 |                 'ServiceOperation': {
2869 |                     'Service': {'Type': 'Service', 'Name': 'test-service'},
2870 |                     'Operation': 'GET /api',
2871 |                     'MetricType': 'Fault',
2872 |                 }
2873 |             },
2874 |         }
2875 |     ]
2876 | 
2877 |     operation_targets, has_wildcards = _filter_operation_targets(provided)
2878 | 
2879 |     # Verify the MetricType was changed from Fault to Availability
2880 |     assert len(operation_targets) == 1
2881 |     assert operation_targets[0]['Data']['ServiceOperation']['MetricType'] == 'Availability'
2882 |     assert has_wildcards is False
2883 | 
2884 | 
2885 | def test_filter_operation_targets_non_fault_unchanged():
2886 |     """Test _filter_operation_targets leaves non-Fault MetricTypes unchanged."""
2887 |     provided = [
2888 |         {
2889 |             'Type': 'service_operation',
2890 |             'Data': {
2891 |                 'ServiceOperation': {
2892 |                     'Service': {'Type': 'Service', 'Name': 'test-service'},
2893 |                     'Operation': 'GET /api',
2894 |                     'MetricType': 'Latency',
2895 |                 }
2896 |             },
2897 |         },
2898 |         {
2899 |             'Type': 'service_operation',
2900 |             'Data': {
2901 |                 'ServiceOperation': {
2902 |                     'Service': {'Type': 'Service', 'Name': 'test-service-2'},
2903 |                     'Operation': 'POST /api',
2904 |                     'MetricType': 'Error',
2905 |                 }
2906 |             },
2907 |         },
2908 |     ]
2909 | 
2910 |     operation_targets, has_wildcards = _filter_operation_targets(provided)
2911 | 
2912 |     # Verify non-Fault MetricTypes are unchanged
2913 |     assert len(operation_targets) == 2
2914 |     assert operation_targets[0]['Data']['ServiceOperation']['MetricType'] == 'Latency'
2915 |     assert operation_targets[1]['Data']['ServiceOperation']['MetricType'] == 'Error'
2916 |     assert has_wildcards is False
2917 | 
2918 | 
2919 | def test_filter_operation_targets_multiple_fault_conversions():
2920 |     """Test _filter_operation_targets converts multiple Fault entries to Availability."""
2921 |     provided = [
2922 |         {
2923 |             'Type': 'service_operation',
2924 |             'Data': {
2925 |                 'ServiceOperation': {
2926 |                     'Service': {'Type': 'Service', 'Name': 'service-1'},
2927 |                     'Operation': 'GET /api',
2928 |                     'MetricType': 'Fault',
2929 |                 }
2930 |             },
2931 |         },
2932 |         {
2933 |             'Type': 'service_operation',
2934 |             'Data': {
2935 |                 'ServiceOperation': {
2936 |                     'Service': {'Type': 'Service', 'Name': 'service-2'},
2937 |                     'Operation': 'POST /api',
2938 |                     'MetricType': 'Latency',
2939 |                 }
2940 |             },
2941 |         },
2942 |         {
2943 |             'Type': 'service_operation',
2944 |             'Data': {
2945 |                 'ServiceOperation': {
2946 |                     'Service': {'Type': 'Service', 'Name': 'service-3'},
2947 |                     'Operation': 'PUT /api',
2948 |                     'MetricType': 'Fault',
2949 |                 }
2950 |             },
2951 |         },
2952 |     ]
2953 | 
2954 |     operation_targets, has_wildcards = _filter_operation_targets(provided)
2955 | 
2956 |     # Verify multiple Fault entries are converted
2957 |     assert len(operation_targets) == 3
2958 |     assert operation_targets[0]['Data']['ServiceOperation']['MetricType'] == 'Availability'
2959 |     assert operation_targets[1]['Data']['ServiceOperation']['MetricType'] == 'Latency'
2960 |     assert operation_targets[2]['Data']['ServiceOperation']['MetricType'] == 'Availability'
2961 |     assert has_wildcards is False
2962 | 
2963 | 
2964 | def test_filter_operation_targets_with_wildcards():
2965 |     """Test _filter_operation_targets detects wildcards and converts Fault to Availability."""
2966 |     provided = [
2967 |         {
2968 |             'Type': 'service_operation',
2969 |             'Data': {
2970 |                 'ServiceOperation': {
2971 |                     'Service': {'Type': 'Service', 'Name': '*payment*'},
2972 |                     'Operation': '*GET*',
2973 |                     'MetricType': 'Fault',
2974 |                 }
2975 |             },
2976 |         }
2977 |     ]
2978 | 
2979 |     operation_targets, has_wildcards = _filter_operation_targets(provided)
2980 | 
2981 |     # Verify wildcard detection and Fault conversion
2982 |     assert len(operation_targets) == 1
2983 |     assert operation_targets[0]['Data']['ServiceOperation']['MetricType'] == 'Availability'
2984 |     assert has_wildcards is True
2985 | 
2986 | 
2987 | def test_filter_operation_targets_ignores_non_service_operation():
2988 |     """Test _filter_operation_targets ignores non-service_operation targets."""
2989 |     provided = [
2990 |         {
2991 |             'Type': 'service',
2992 |             'Data': {'Service': {'Type': 'Service', 'Name': 'test-service'}},
2993 |         },
2994 |         {
2995 |             'Type': 'service_operation',
2996 |             'Data': {
2997 |                 'ServiceOperation': {
2998 |                     'Service': {'Type': 'Service', 'Name': 'test-service'},
2999 |                     'Operation': 'GET /api',
3000 |                     'MetricType': 'Fault',
3001 |                 }
3002 |             },
3003 |         },
3004 |     ]
3005 | 
3006 |     operation_targets, has_wildcards = _filter_operation_targets(provided)
3007 | 
3008 |     # Verify only service_operation targets are included
3009 |     assert len(operation_targets) == 1
3010 |     assert operation_targets[0]['Type'] == 'service_operation'
3011 |     assert operation_targets[0]['Data']['ServiceOperation']['MetricType'] == 'Availability'
3012 |     assert has_wildcards is False
3013 | 
3014 | 
3015 | def test_filter_operation_targets_empty_metric_type():
3016 |     """Test _filter_operation_targets handles empty MetricType gracefully."""
3017 |     provided = [
3018 |         {
3019 |             'Type': 'service_operation',
3020 |             'Data': {
3021 |                 'ServiceOperation': {
3022 |                     'Service': {'Type': 'Service', 'Name': 'test-service'},
3023 |                     'Operation': 'GET /api',
3024 |                     'MetricType': '',
3025 |                 }
3026 |             },
3027 |         }
3028 |     ]
3029 | 
3030 |     operation_targets, has_wildcards = _filter_operation_targets(provided)
3031 | 
3032 |     # Verify empty MetricType is unchanged
3033 |     assert len(operation_targets) == 1
3034 |     assert operation_targets[0]['Data']['ServiceOperation']['MetricType'] == ''
3035 |     assert has_wildcards is False
3036 | 
3037 | 
3038 | def test_filter_operation_targets_missing_metric_type():
3039 |     """Test _filter_operation_targets handles missing MetricType gracefully."""
3040 |     provided = [
3041 |         {
3042 |             'Type': 'service_operation',
3043 |             'Data': {
3044 |                 'ServiceOperation': {
3045 |                     'Service': {'Type': 'Service', 'Name': 'test-service'},
3046 |                     'Operation': 'GET /api',
3047 |                     # MetricType is missing
3048 |                 }
3049 |             },
3050 |         }
3051 |     ]
3052 | 
3053 |     operation_targets, has_wildcards = _filter_operation_targets(provided)
3054 | 
3055 |     # Verify missing MetricType doesn't cause errors
3056 |     assert len(operation_targets) == 1
3057 |     # MetricType should remain missing (empty string from .get())
3058 |     assert operation_targets[0]['Data']['ServiceOperation'].get('MetricType', '') == ''
3059 |     assert has_wildcards is False
3060 | 
3061 | 
3062 | def test_filter_operation_targets_case_sensitive():
3063 |     """Test _filter_operation_targets is case-sensitive for Fault conversion."""
3064 |     provided = [
3065 |         {
3066 |             'Type': 'service_operation',
3067 |             'Data': {
3068 |                 'ServiceOperation': {
3069 |                     'Service': {'Type': 'Service', 'Name': 'test-service'},
3070 |                     'Operation': 'GET /api',
3071 |                     'MetricType': 'fault',  # lowercase
3072 |                 }
3073 |             },
3074 |         },
3075 |         {
3076 |             'Type': 'service_operation',
3077 |             'Data': {
3078 |                 'ServiceOperation': {
3079 |                     'Service': {'Type': 'Service', 'Name': 'test-service-2'},
3080 |                     'Operation': 'POST /api',
3081 |                     'MetricType': 'FAULT',  # uppercase
3082 |                 }
3083 |             },
3084 |         },
3085 |     ]
3086 | 
3087 |     operation_targets, has_wildcards = _filter_operation_targets(provided)
3088 | 
3089 |     # Verify only exact case "Fault" is converted
3090 |     assert len(operation_targets) == 2
3091 |     assert operation_targets[0]['Data']['ServiceOperation']['MetricType'] == 'fault'  # unchanged
3092 |     assert operation_targets[1]['Data']['ServiceOperation']['MetricType'] == 'FAULT'  # unchanged
3093 |     assert has_wildcards is False
3094 | 
```
Page 609/612FirstPrevNextLast