#
tokens: 62620/50000 1/2439 files (page 508/514)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 508 of 514. 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-appsignals-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
├── 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
│   │   │       └── 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
│   │   │   ├── 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
│   │   │           └── mutable_sql_detector.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
│   │   ├── 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.py
│   │   │       ├── prompts
│   │   │       │   ├── __init__.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_data.py
│   │   │       │   ├── sitewise_gateways.py
│   │   │       │   └── sitewise_metadata_transfer.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
│   │   │   ├── test_client.py
│   │   │   ├── test_init.py
│   │   │   ├── test_main.py
│   │   │   ├── test_models.py
│   │   │   ├── test_server.py
│   │   │   ├── test_sitewise_access.py
│   │   │   ├── test_sitewise_asset_models.py
│   │   │   ├── test_sitewise_assets.py
│   │   │   ├── test_sitewise_data.py
│   │   │   ├── test_sitewise_gateways.py
│   │   │   ├── test_sitewise_metadata_transfer.py
│   │   │   └── test_validation.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
│   │   ├── 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
│   │   │       ├── tools
│   │   │       │   ├── common
│   │   │       │   │   └── base_tool.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
│   │   │       │   ├── 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
│   │   │           ├── 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_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_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_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_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-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
│   │   │       ├── 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-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
│   │   │       │   ├── data
│   │   │       │   │   └── metric_metadata.json
│   │   │       │   ├── 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_metrics_error_handling.py
│   │   │   │   ├── test_metrics_models.py
│   │   │   │   ├── test_metrics_server.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
│   │   │       ├── 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_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
│   │   │       ├── mutable_sql_detector.py
│   │   │       └── server.py
│   │   ├── CHANGELOG.md
│   │   ├── docker-healthcheck.sh
│   │   ├── Dockerfile
│   │   ├── LICENSE
│   │   ├── NOTICE
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── tests
│   │   │   ├── conftest.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/aws-pricing-mcp-server/tests/test_server.py:
--------------------------------------------------------------------------------

```python
   1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
   2 | #
   3 | # Licensed under the Apache License, Version 2.0 (the "License");
   4 | # you may not use this file except in compliance with the License.
   5 | # You may obtain a copy of the License at
   6 | #
   7 | #     http://www.apache.org/licenses/LICENSE-2.0
   8 | #
   9 | # Unless required by applicable law or agreed to in writing, software
  10 | # distributed under the License is distributed on an "AS IS" BASIS,
  11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 | # See the License for the specific language governing permissions and
  13 | # limitations under the License.
  14 | 
  15 | """Tests for the server module of the aws-pricing-mcp-server."""
  16 | 
  17 | import pytest
  18 | from awslabs.aws_pricing_mcp_server.models import PricingFilter
  19 | from awslabs.aws_pricing_mcp_server.pricing_transformer import (
  20 |     _is_free_product,
  21 | )
  22 | from awslabs.aws_pricing_mcp_server.server import (
  23 |     analyze_cdk_project_wrapper,
  24 |     generate_cost_report_wrapper,
  25 |     get_bedrock_patterns,
  26 |     get_price_list_urls,
  27 |     get_pricing,
  28 |     get_pricing_attribute_values,
  29 |     get_pricing_service_attributes,
  30 |     get_pricing_service_codes,
  31 | )
  32 | from unittest.mock import patch
  33 | 
  34 | 
  35 | class TestAnalyzeCdkProject:
  36 |     """Tests for the analyze_cdk_project_wrapper function."""
  37 | 
  38 |     @pytest.mark.asyncio
  39 |     async def test_analyze_valid_project(self, mock_context, sample_cdk_project):
  40 |         """Test analyzing a valid CDK project."""
  41 |         result = await analyze_cdk_project_wrapper(mock_context, sample_cdk_project)
  42 | 
  43 |         assert result is not None
  44 |         assert result['status'] == 'success'
  45 |         assert 'services' in result
  46 | 
  47 |         # Check for expected services
  48 |         services = {service['name'] for service in result['services']}
  49 |         assert 'lambda' in services
  50 |         assert 'dynamodb' in services
  51 |         assert 's3' in services
  52 |         assert 'iam' in services
  53 | 
  54 |     @pytest.mark.asyncio
  55 |     async def test_analyze_invalid_project(self, mock_context, temp_output_dir):
  56 |         """Test analyzing an invalid/empty project directory."""
  57 |         result = await analyze_cdk_project_wrapper(mock_context, temp_output_dir)
  58 | 
  59 |         assert result is not None
  60 |         assert result['status'] == 'success'
  61 |         assert 'services' in result
  62 |         assert (
  63 |             len(result['services']) == 0
  64 |         )  # Empty project still returns success with empty services
  65 | 
  66 |     @pytest.mark.asyncio
  67 |     async def test_analyze_nonexistent_project(self, mock_context):
  68 |         """Test analyzing a nonexistent project directory."""
  69 |         result = await analyze_cdk_project_wrapper(mock_context, '/nonexistent/path')
  70 | 
  71 |         assert result is not None
  72 |         assert 'services' in result
  73 |         assert len(result['services']) == 0  # Nonexistent path returns success with empty services
  74 | 
  75 | 
  76 | class TestGetPricing:
  77 |     """Tests for the get_pricing function."""
  78 | 
  79 |     @pytest.mark.asyncio
  80 |     async def test_get_valid_pricing(self, mock_boto3, mock_context):
  81 |         """Test getting pricing for a valid service."""
  82 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
  83 |             result = await get_pricing(mock_context, 'AWSLambda', 'us-west-2')
  84 | 
  85 |         assert result is not None
  86 |         assert result['status'] == 'success'
  87 |         assert result['service_name'] == 'AWSLambda'
  88 |         assert 'data' in result
  89 |         assert isinstance(result['data'], list)
  90 |         assert len(result['data']) > 0
  91 |         assert 'message' in result
  92 |         assert 'AWSLambda' in result['message']
  93 |         assert 'us-west-2' in result['message']
  94 | 
  95 |     @pytest.mark.asyncio
  96 |     async def test_get_pricing_with_filters(self, mock_boto3, mock_context):
  97 |         """Test getting pricing with filters."""
  98 |         # Create filters using the Pydantic models
  99 |         filters = [
 100 |             PricingFilter(Field='instanceType', Value='t3.medium'),
 101 |             PricingFilter(Field='location', Value='US East (N. Virginia)', Type='EQUALS'),
 102 |         ]
 103 | 
 104 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
 105 |             result = await get_pricing(mock_context, 'AmazonEC2', 'us-east-1', filters)
 106 | 
 107 |         assert result is not None
 108 |         assert result['status'] == 'success'
 109 |         assert result['service_name'] == 'AmazonEC2'
 110 |         assert isinstance(result['data'], list)
 111 | 
 112 |         # Verify that the mocked pricing client was called with correct filters
 113 |         pricing_client = mock_boto3.Session().client('pricing')
 114 |         pricing_client.get_products.assert_called_once()
 115 |         call_args = pricing_client.get_products.call_args[1]
 116 |         assert 'Filters' in call_args
 117 |         assert len(call_args['Filters']) == 3  # region + 2 custom filters
 118 | 
 119 |         # Check that our custom filters are included
 120 |         filter_fields = [f['Field'] for f in call_args['Filters']]
 121 |         assert 'instanceType' in filter_fields
 122 |         assert 'location' in filter_fields
 123 |         assert 'regionCode' in filter_fields  # Always added by the function
 124 | 
 125 |     @pytest.mark.asyncio
 126 |     async def test_pricing_filter_model_validation(self):
 127 |         """Test that PricingFilter model validates correctly."""
 128 |         # Test valid filter creation
 129 |         valid_filter = PricingFilter(Field='instanceType', Value='t3.medium')
 130 |         assert valid_filter.field == 'instanceType'
 131 |         assert valid_filter.value == 't3.medium'
 132 |         assert valid_filter.type == 'EQUALS'
 133 | 
 134 |         # Test serialization with aliases
 135 |         filter_dict = valid_filter.model_dump(by_alias=True)
 136 |         assert 'Field' in filter_dict
 137 |         assert 'Value' in filter_dict
 138 |         assert 'Type' in filter_dict
 139 |         assert filter_dict['Field'] == 'instanceType'
 140 |         assert filter_dict['Value'] == 't3.medium'
 141 |         assert filter_dict['Type'] == 'EQUALS'
 142 | 
 143 |     @pytest.mark.asyncio
 144 |     async def test_new_filter_types_validation(self):
 145 |         """Test that new filter types work correctly."""
 146 |         # Test ANY_OF filter type
 147 |         any_of_filter = PricingFilter(
 148 |             Field='instanceType', Value=['t3.medium', 'm5.large'], Type='ANY_OF'
 149 |         )
 150 |         assert any_of_filter.type == 'ANY_OF'
 151 |         assert any_of_filter.value == ['t3.medium', 'm5.large']
 152 | 
 153 |         # Test CONTAINS filter type
 154 |         contains_filter = PricingFilter(Field='instanceType', Value='m5', Type='CONTAINS')
 155 |         assert contains_filter.type == 'CONTAINS'
 156 |         assert contains_filter.value == 'm5'
 157 | 
 158 |         # Test NONE_OF filter type
 159 |         none_of_filter = PricingFilter(Field='instanceType', Value=['t2', 'm4'], Type='NONE_OF')
 160 |         assert none_of_filter.type == 'NONE_OF'
 161 |         assert none_of_filter.value == ['t2', 'm4']
 162 | 
 163 |         # Test serialization converts ANY_OF and NONE_OF to comma-separated strings
 164 |         any_of_dict = any_of_filter.model_dump(by_alias=True)
 165 |         assert any_of_dict['Type'] == 'ANY_OF'
 166 |         assert any_of_dict['Value'] == 't3.medium,m5.large'  # Should be comma-separated string
 167 | 
 168 |         contains_dict = contains_filter.model_dump(by_alias=True)
 169 |         assert contains_dict['Type'] == 'CONTAINS'
 170 |         assert contains_dict['Value'] == 'm5'  # Should remain as string
 171 | 
 172 |         none_of_dict = none_of_filter.model_dump(by_alias=True)
 173 |         assert none_of_dict['Type'] == 'NONE_OF'
 174 |         assert none_of_dict['Value'] == 't2,m4'  # Should be comma-separated string
 175 | 
 176 |     @pytest.mark.asyncio
 177 |     async def test_filter_serialization_comma_separated(self):
 178 |         """Test that ANY_OF and NONE_OF filters serialize values as comma-separated strings."""
 179 |         # Test ANY_OF filter serialization
 180 |         any_of_filter = PricingFilter(
 181 |             Field='instanceType', Value=['t3.medium', 'm5.large'], Type='ANY_OF'
 182 |         )
 183 |         serialized = any_of_filter.model_dump(by_alias=True)
 184 |         assert serialized['Value'] == 't3.medium,m5.large'  # Should be comma-separated string
 185 |         assert serialized['Type'] == 'ANY_OF'
 186 | 
 187 |         # Test NONE_OF filter serialization
 188 |         none_of_filter = PricingFilter(
 189 |             Field='instanceType', Value=['t2.micro', 'm4.large'], Type='NONE_OF'
 190 |         )
 191 |         serialized = none_of_filter.model_dump(by_alias=True)
 192 |         assert serialized['Value'] == 't2.micro,m4.large'  # Should be comma-separated string
 193 |         assert serialized['Type'] == 'NONE_OF'
 194 | 
 195 |         # Test EQUALS filter serialization (should not change)
 196 |         equals_filter = PricingFilter(Field='instanceType', Value='m5.large', Type='EQUALS')
 197 |         serialized = equals_filter.model_dump(by_alias=True)
 198 |         assert serialized['Value'] == 'm5.large'  # Should remain a string
 199 |         assert serialized['Type'] == 'EQUALS'
 200 | 
 201 |         # Test CONTAINS filter serialization (should not change)
 202 |         contains_filter = PricingFilter(Field='instanceType', Value='m5', Type='CONTAINS')
 203 |         serialized = contains_filter.model_dump(by_alias=True)
 204 |         assert serialized['Value'] == 'm5'  # Should remain a string
 205 |         assert serialized['Type'] == 'CONTAINS'
 206 | 
 207 |     @pytest.mark.asyncio
 208 |     async def test_multi_region_pricing(self, mock_boto3, mock_context):
 209 |         """Test getting pricing for multiple regions using ANY_OF filter."""
 210 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
 211 |             result = await get_pricing(
 212 |                 mock_context, 'AmazonEC2', ['us-east-1', 'us-west-2', 'eu-west-1']
 213 |             )
 214 | 
 215 |         assert result is not None
 216 |         assert result['status'] == 'success'
 217 |         assert result['service_name'] == 'AmazonEC2'
 218 | 
 219 |         # Verify that the mocked pricing client was called with correct multi-region filter
 220 |         pricing_client = mock_boto3.Session().client('pricing')
 221 |         pricing_client.get_products.assert_called_once()
 222 |         call_args = pricing_client.get_products.call_args[1]
 223 |         assert 'Filters' in call_args
 224 | 
 225 |         # Should have exactly one region filter (automatically added)
 226 |         region_filters = [f for f in call_args['Filters'] if f['Field'] == 'regionCode']
 227 |         assert len(region_filters) == 1
 228 | 
 229 |         # The region filter should use ANY_OF with comma-separated values
 230 |         region_filter = region_filters[0]
 231 |         assert region_filter['Type'] == 'ANY_OF'
 232 |         assert region_filter['Value'] == 'us-east-1,us-west-2,eu-west-1'
 233 | 
 234 |     @pytest.mark.asyncio
 235 |     async def test_single_region_backward_compatibility(self, mock_boto3, mock_context):
 236 |         """Test that single region strings still work with EQUALS for backward compatibility."""
 237 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
 238 |             result = await get_pricing(mock_context, 'AmazonEC2', 'us-east-1')
 239 | 
 240 |         assert result is not None
 241 |         assert result['status'] == 'success'
 242 |         assert result['service_name'] == 'AmazonEC2'
 243 | 
 244 |         # Verify that the mocked pricing client was called with EQUALS for single region
 245 |         pricing_client = mock_boto3.Session().client('pricing')
 246 |         pricing_client.get_products.assert_called_once()
 247 |         call_args = pricing_client.get_products.call_args[1]
 248 |         assert 'Filters' in call_args
 249 | 
 250 |         # Should have exactly one region filter
 251 |         region_filters = [f for f in call_args['Filters'] if f['Field'] == 'regionCode']
 252 |         assert len(region_filters) == 1
 253 | 
 254 |         # The region filter should use EQUALS for backward compatibility
 255 |         region_filter = region_filters[0]
 256 |         assert region_filter['Type'] == 'EQUALS'
 257 |         assert region_filter['Value'] == 'us-east-1'
 258 | 
 259 |     @pytest.mark.asyncio
 260 |     async def test_get_pricing_response_structure_validation(self, mock_boto3, mock_context):
 261 |         """Test that the response structure is properly validated."""
 262 |         # Mock a more realistic pricing response
 263 |         pricing_client = mock_boto3.Session().client('pricing')
 264 |         pricing_client.get_products.return_value = {
 265 |             'PriceList': [
 266 |                 '{"product":{"sku":"ABC123","productFamily":"Compute","attributes":{"instanceType":"t3.medium"}},"terms":{"OnDemand":{"ABC123.TERM1":{"priceDimensions":{"ABC123.TERM1.DIM1":{"unit":"Hrs","pricePerUnit":{"USD":"0.0416"}}}}}},"serviceCode":"AmazonEC2"}'
 267 |             ]
 268 |         }
 269 | 
 270 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
 271 |             result = await get_pricing(mock_context, 'AmazonEC2', 'us-east-1')
 272 | 
 273 |         # Validate top-level response structure
 274 |         assert result['status'] == 'success'
 275 |         assert result['service_name'] == 'AmazonEC2'
 276 |         assert isinstance(result['data'], list)
 277 |         assert len(result['data']) == 1
 278 |         assert isinstance(result['message'], str)
 279 | 
 280 |         # Validate the pricing data structure (data is already parsed from JSON)
 281 |         pricing_item = result['data'][0]
 282 | 
 283 |         # Validate required fields in pricing item
 284 |         assert 'product' in pricing_item
 285 |         assert 'terms' in pricing_item
 286 |         assert 'sku' in pricing_item['product']
 287 |         assert 'attributes' in pricing_item['product']
 288 |         assert 'OnDemand' in pricing_item['terms']
 289 | 
 290 |         # Validate pricing structure
 291 |         product = pricing_item['product']
 292 |         assert product['sku'] == 'ABC123'
 293 |         assert 'instanceType' in product['attributes']
 294 |         assert product['attributes']['instanceType'] == 't3.medium'
 295 | 
 296 |     @pytest.mark.asyncio
 297 |     async def test_get_pricing_empty_results(self, mock_boto3, mock_context):
 298 |         """Test handling of empty pricing results."""
 299 |         pricing_client = mock_boto3.Session().client('pricing')
 300 |         pricing_client.get_products.return_value = {'PriceList': []}
 301 | 
 302 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
 303 |             result = await get_pricing(mock_context, 'InvalidService', 'us-west-2')
 304 | 
 305 |         assert result is not None
 306 |         assert result['status'] == 'error'
 307 |         assert result['error_type'] == 'empty_results'
 308 |         assert 'InvalidService' in result['message']
 309 |         assert 'No results found for given filters' in result['message']
 310 |         assert result['service_code'] == 'InvalidService'
 311 |         assert result['region'] == 'us-west-2'
 312 |         assert 'examples' in result
 313 |         assert 'Example service codes' in result['examples']
 314 |         assert 'Example regions' in result['examples']
 315 |         assert 'suggestion' in result
 316 |         assert (
 317 |             'Verify that the service code is valid. Use get_service_codes() to get valid service codes'
 318 |             in result['suggestion']
 319 |         )
 320 |         assert (
 321 |             'Validate region and filter values using get_pricing_attribute_values()'
 322 |             in result['suggestion']
 323 |         )
 324 |         assert 'Test with fewer filters' in result['suggestion']
 325 |         mock_context.error.assert_called_once()
 326 | 
 327 |     @pytest.mark.asyncio
 328 |     async def test_get_pricing_api_error(self, mock_boto3, mock_context):
 329 |         """Test handling of API errors."""
 330 |         pricing_client = mock_boto3.Session().client('pricing')
 331 |         pricing_client.get_products.side_effect = Exception('API Error')
 332 | 
 333 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
 334 |             result = await get_pricing(mock_context, 'AWSLambda', 'us-west-2')
 335 | 
 336 |         assert result is not None
 337 |         assert result['status'] == 'error'
 338 |         assert result['error_type'] == 'api_error'
 339 |         assert 'API Error' in result['message']
 340 |         assert result['service_code'] == 'AWSLambda'
 341 |         assert result['region'] == 'us-west-2'
 342 |         assert 'suggestion' in result
 343 |         mock_context.error.assert_called_once()
 344 | 
 345 |     @pytest.mark.asyncio
 346 |     async def test_get_pricing_data_processing_error(self, mock_boto3, mock_context):
 347 |         """Test handling of data processing errors in transform_pricing_data."""
 348 |         pricing_client = mock_boto3.Session().client('pricing')
 349 |         pricing_client.get_products.return_value = {'PriceList': ['invalid json']}
 350 | 
 351 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
 352 |             result = await get_pricing(mock_context, 'AWSLambda', 'us-west-2')
 353 | 
 354 |         assert result is not None
 355 |         assert result['status'] == 'error'
 356 |         assert result['error_type'] == 'data_processing_error'
 357 |         assert 'Failed to process pricing data' in result['message']
 358 |         assert result['service_code'] == 'AWSLambda'
 359 |         assert result['region'] == 'us-west-2'
 360 |         mock_context.error.assert_called_once()
 361 | 
 362 |     @pytest.mark.asyncio
 363 |     async def test_get_pricing_client_creation_error(self, mock_context):
 364 |         """Test handling of client creation errors."""
 365 |         with patch(
 366 |             'awslabs.aws_pricing_mcp_server.server.create_pricing_client',
 367 |             side_effect=Exception('Client creation failed'),
 368 |         ):
 369 |             result = await get_pricing(mock_context, 'AWSLambda', 'us-west-2')
 370 | 
 371 |         assert result is not None
 372 |         assert result['status'] == 'error'
 373 |         assert result['error_type'] == 'client_creation_failed'
 374 |         assert 'Failed to create AWS Pricing client' in result['message']
 375 |         assert 'Client creation failed' in result['message']
 376 |         assert result['service_code'] == 'AWSLambda'
 377 |         assert result['region'] == 'us-west-2'
 378 |         mock_context.error.assert_called_once()
 379 | 
 380 |     @pytest.mark.asyncio
 381 |     async def test_get_pricing_result_threshold_exceeded(self, mock_boto3, mock_context):
 382 |         """Test that the tool returns an error when result character count exceeds the threshold."""
 383 |         # Create a mock response with large JSON records that exceed character threshold
 384 |         # Each record is about 500 characters, so 100 records = ~50,000 characters (exceeds 40,000 default)
 385 |         large_price_list = []
 386 |         for i in range(100):
 387 |             record = f'{{"sku":"SKU{i:03d}","product":{{"productFamily":"Compute Instance","attributes":{{"instanceType":"m5.large","location":"US East (N. Virginia)","tenancy":"Shared","operatingSystem":"Linux"}}}},"terms":{{"OnDemand":{{"SKU{i:03d}.JRTCKXETXF":{{"priceDimensions":{{"SKU{i:03d}.JRTCKXETXF.6YS6EN2CT7":{{"unit":"Hrs","pricePerUnit":{{"USD":"0.096"}}}}}}}}}}}}}}'
 388 |             large_price_list.append(record)
 389 | 
 390 |         pricing_client = mock_boto3.Session().client('pricing')
 391 |         pricing_client.get_products.return_value = {'PriceList': large_price_list}
 392 | 
 393 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
 394 |             result = await get_pricing(
 395 |                 mock_context, 'AmazonEC2', 'us-east-1', max_allowed_characters=10000
 396 |             )
 397 | 
 398 |         assert result['status'] == 'error'
 399 |         assert result['error_type'] == 'result_too_large'
 400 |         assert 'exceeding the limit of 10,000' in result['message']
 401 |         assert 'output_options={"pricing_terms": ["OnDemand"]}' in result['message']
 402 |         assert 'significantly reduce response size' in result['suggestion']
 403 |         assert result['total_count'] == 100
 404 |         assert result['max_allowed_characters'] == 10000
 405 |         assert len(result['sample_records']) == 3  # First 3 records as context
 406 |         assert 'Add more specific filters' in result['suggestion']
 407 |         mock_context.error.assert_called_once()
 408 | 
 409 |     @pytest.mark.asyncio
 410 |     async def test_get_pricing_unlimited_results(self, mock_boto3, mock_context):
 411 |         """Test that max_allowed_characters=-1 allows unlimited results."""
 412 |         # Create a mock response with large records that would normally exceed character limit
 413 |         large_price_list = []
 414 |         for i in range(100):
 415 |             record = f'{{"sku":"SKU{i:03d}","product":{{"productFamily":"Compute Instance","attributes":{{"instanceType":"m5.large","location":"US East (N. Virginia)","tenancy":"Shared","operatingSystem":"Linux"}}}},"terms":{{"OnDemand":{{"SKU{i:03d}.JRTCKXETXF":{{"priceDimensions":{{"SKU{i:03d}.JRTCKXETXF.6YS6EN2CT7":{{"unit":"Hrs","pricePerUnit":{{"USD":"0.096"}}}}}}}}}}}}}}'
 416 |             large_price_list.append(record)
 417 | 
 418 |         pricing_client = mock_boto3.Session().client('pricing')
 419 |         pricing_client.get_products.return_value = {'PriceList': large_price_list}
 420 | 
 421 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
 422 |             result = await get_pricing(
 423 |                 mock_context, 'AmazonEC2', 'us-east-1', max_allowed_characters=-1
 424 |             )
 425 | 
 426 |         assert result['status'] == 'success'
 427 |         assert len(result['data']) == 100  # All results should be returned
 428 |         assert 'Retrieved pricing for AmazonEC2' in result['message']
 429 |         mock_context.info.assert_called_once()
 430 | 
 431 |     @pytest.mark.asyncio
 432 |     async def test_get_pricing_without_region(self, mock_boto3, mock_context):
 433 |         """Test get_pricing works without region parameter for global services."""
 434 |         pricing_client = mock_boto3.Session().client('pricing')
 435 |         pricing_client.get_products.return_value = {
 436 |             'PriceList': ['{"sku":"ABC123","product":{"productFamily":"Data Transfer"}}']
 437 |         }
 438 | 
 439 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
 440 |             result = await get_pricing(mock_context, 'AWSDataTransfer', region=None)
 441 | 
 442 |         assert result['status'] == 'success'
 443 |         assert result['service_name'] == 'AWSDataTransfer'
 444 | 
 445 |         # Verify no region filter was added
 446 |         pricing_client.get_products.assert_called_once()
 447 |         call_kwargs = pricing_client.get_products.call_args[1]
 448 |         assert 'Filters' in call_kwargs
 449 |         # Should have no filters since region is None and no other filters provided
 450 |         assert len(call_kwargs['Filters']) == 0
 451 | 
 452 |     @pytest.mark.asyncio
 453 |     async def test_get_pricing_region_none_explicit(self, mock_boto3, mock_context):
 454 |         """Test get_pricing with explicit region=None."""
 455 |         pricing_client = mock_boto3.Session().client('pricing')
 456 |         pricing_client.get_products.return_value = {
 457 |             'PriceList': ['{"sku":"DEF456","product":{"productFamily":"CloudFront"}}']
 458 |         }
 459 | 
 460 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
 461 |             result = await get_pricing(mock_context, 'AmazonCloudFront', None)
 462 | 
 463 |         assert result['status'] == 'success'
 464 |         assert result['service_name'] == 'AmazonCloudFront'
 465 | 
 466 |         # Verify API was called without region filter
 467 |         pricing_client.get_products.assert_called_once()
 468 |         call_kwargs = pricing_client.get_products.call_args[1]
 469 |         region_filters = [f for f in call_kwargs['Filters'] if f['Field'] == 'regionCode']
 470 |         assert len(region_filters) == 0
 471 | 
 472 |     @pytest.mark.asyncio
 473 |     async def test_get_pricing_with_filters_no_region(self, mock_boto3, mock_context):
 474 |         """Test get_pricing with filters but no region."""
 475 |         filters = [PricingFilter(Field='operation', Value='DataTransfer-Out-Bytes')]
 476 | 
 477 |         pricing_client = mock_boto3.Session().client('pricing')
 478 |         pricing_client.get_products.return_value = {
 479 |             'PriceList': ['{"sku":"GHI789","product":{"productFamily":"Data Transfer"}}']
 480 |         }
 481 | 
 482 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
 483 |             result = await get_pricing(mock_context, 'AWSDataTransfer', None, filters)
 484 | 
 485 |         assert result['status'] == 'success'
 486 | 
 487 |         # Verify only custom filters were added, no region filter
 488 |         pricing_client.get_products.assert_called_once()
 489 |         call_kwargs = pricing_client.get_products.call_args[1]
 490 |         assert len(call_kwargs['Filters']) == 1
 491 |         assert call_kwargs['Filters'][0]['Field'] == 'operation'
 492 | 
 493 |     @pytest.mark.asyncio
 494 |     async def test_get_pricing_custom_threshold(self, mock_context, mock_boto3):
 495 |         """Test that custom max_allowed_characters threshold works correctly."""
 496 |         # Create a mock response with small records that fit within lower thresholds
 497 |         small_price_list = [f'{{"sku":"SKU{i}","product":{{}}}}' for i in range(10)]
 498 | 
 499 |         pricing_client = mock_boto3.Session().client('pricing')
 500 |         pricing_client.get_products.return_value = {'PriceList': small_price_list}
 501 | 
 502 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
 503 |             # Should succeed with threshold of 1000 characters (small records should fit)
 504 |             result = await get_pricing(
 505 |                 mock_context, 'AmazonEC2', 'us-east-1', None, max_allowed_characters=1000
 506 |             )
 507 |             assert result['status'] == 'success'
 508 |             assert len(result['data']) == 10
 509 | 
 510 |             # Should fail with threshold of 100 characters (records are too large)
 511 |             result = await get_pricing(
 512 |                 mock_context, 'AmazonEC2', 'us-east-1', None, max_allowed_characters=100
 513 |             )
 514 |             assert result['status'] == 'error'
 515 |             assert result['error_type'] == 'result_too_large'
 516 |             assert result['total_count'] == 10
 517 |             assert result['max_allowed_characters'] == 100
 518 | 
 519 |     @pytest.mark.asyncio
 520 |     @pytest.mark.parametrize(
 521 |         'max_results,next_token,expected_max_results,expect_next_token',
 522 |         [
 523 |             (None, None, 100, False),  # Default values
 524 |             (25, None, 25, False),  # Custom max_results
 525 |             (None, 'test-token-123', 100, True),  # Custom next_token
 526 |             (50, 'input-token-abc', 50, True),  # Both parameters
 527 |         ],
 528 |     )
 529 |     async def test_get_pricing_pagination_parameters(
 530 |         self,
 531 |         mock_context,
 532 |         mock_boto3,
 533 |         max_results,
 534 |         next_token,
 535 |         expected_max_results,
 536 |         expect_next_token,
 537 |     ):
 538 |         """Test various pagination parameter combinations."""
 539 |         pricing_client = mock_boto3.Session().client('pricing')
 540 |         pricing_client.get_products.return_value = {'PriceList': ['{"sku":"ABC123"}']}
 541 | 
 542 |         kwargs = {'service_code': 'AmazonEC2', 'region': 'us-east-1'}
 543 |         if max_results is not None:
 544 |             kwargs['max_results'] = max_results
 545 |         if next_token is not None:
 546 |             kwargs['next_token'] = next_token
 547 | 
 548 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
 549 |             result = await get_pricing(mock_context, **kwargs)
 550 | 
 551 |         assert result['status'] == 'success'
 552 | 
 553 |         # Verify pagination parameters were passed correctly
 554 |         pricing_client.get_products.assert_called_once()
 555 |         call_kwargs = pricing_client.get_products.call_args[1]
 556 |         assert call_kwargs['MaxResults'] == expected_max_results
 557 | 
 558 |         if expect_next_token:
 559 |             assert call_kwargs['NextToken'] == next_token
 560 |         else:
 561 |             assert 'NextToken' not in call_kwargs
 562 | 
 563 |     @pytest.mark.asyncio
 564 |     @pytest.mark.parametrize(
 565 |         'api_response,expected_next_token_in_result',
 566 |         [
 567 |             (
 568 |                 {'PriceList': ['{"sku":"ABC123"}'], 'NextToken': 'next-page-token-456'},
 569 |                 'next-page-token-456',
 570 |             ),  # API returns NextToken
 571 |             ({'PriceList': ['{"sku":"ABC123"}']}, None),  # API doesn't return NextToken
 572 |             (
 573 |                 {
 574 |                     'PriceList': ['{"sku":"ABC123"}', '{"sku":"DEF456"}'],
 575 |                     'NextToken': 'final-token-789',
 576 |                 },
 577 |                 'final-token-789',
 578 |             ),  # Multiple records with NextToken
 579 |         ],
 580 |     )
 581 |     async def test_get_pricing_response_next_token(
 582 |         self, mock_context, mock_boto3, api_response, expected_next_token_in_result
 583 |     ):
 584 |         """Test next_token handling in response based on API response."""
 585 |         pricing_client = mock_boto3.Session().client('pricing')
 586 |         pricing_client.get_products.return_value = api_response
 587 | 
 588 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
 589 |             result = await get_pricing(mock_context, 'AmazonEC2', 'us-east-1')
 590 | 
 591 |         assert result['status'] == 'success'
 592 | 
 593 |         if expected_next_token_in_result:
 594 |             assert 'next_token' in result
 595 |             assert result['next_token'] == expected_next_token_in_result
 596 |         else:
 597 |             assert 'next_token' not in result
 598 | 
 599 | 
 600 | class TestGetBedrockPatterns:
 601 |     """Tests for the get_bedrock_patterns function."""
 602 | 
 603 |     @pytest.mark.asyncio
 604 |     async def test_get_patterns(self, mock_context):
 605 |         """Test getting Bedrock architecture patterns."""
 606 |         result = await get_bedrock_patterns(mock_context)
 607 | 
 608 |         assert result is not None
 609 |         assert isinstance(result, str)
 610 |         assert 'Bedrock' in result
 611 |         assert 'Knowledge Base' in result
 612 | 
 613 | 
 614 | class TestGenerateCostReport:
 615 |     """Tests for the generate_cost_report_wrapper function."""
 616 | 
 617 |     @pytest.mark.asyncio
 618 |     async def test_generate_markdown_report(self, mock_context, sample_pricing_data_web):
 619 |         """Test generating a markdown cost report."""
 620 |         result = await generate_cost_report_wrapper(
 621 |             mock_context,
 622 |             pricing_data=sample_pricing_data_web,
 623 |             service_name='AWS Lambda',
 624 |             related_services=['DynamoDB'],
 625 |             pricing_model='ON DEMAND',
 626 |             assumptions=['Standard configuration'],
 627 |             exclusions=['Custom configurations'],
 628 |             format='markdown',
 629 |         )
 630 | 
 631 |         assert result is not None
 632 |         assert isinstance(result, str)
 633 | 
 634 |     @pytest.mark.asyncio
 635 |     async def test_generate_csv_report(self, mock_context, sample_pricing_data_web):
 636 |         """Test generating a CSV cost report."""
 637 |         result = await generate_cost_report_wrapper(
 638 |             mock_context,
 639 |             pricing_data=sample_pricing_data_web,
 640 |             service_name='AWS Lambda',
 641 |             format='csv',
 642 |             pricing_model='ON DEMAND',
 643 |             related_services=None,
 644 |             assumptions=None,
 645 |             exclusions=None,
 646 |             output_file=None,
 647 |             detailed_cost_data=None,
 648 |             recommendations=None,
 649 |         )
 650 | 
 651 |         assert result is not None
 652 |         assert isinstance(result, str)
 653 |         assert ',' in result  # Verify it's CSV format
 654 | 
 655 |         # Verify basic structure
 656 |         lines = result.split('\n')
 657 |         assert len(lines) > 1  # Has header and data
 658 | 
 659 |     @pytest.mark.asyncio
 660 |     async def test_generate_report_with_detailed_data(
 661 |         self, mock_context, sample_pricing_data_web, temp_output_dir
 662 |     ):
 663 |         """Test generating a report with detailed cost data."""
 664 |         detailed_cost_data = {
 665 |             'services': {
 666 |                 'AWS Lambda': {
 667 |                     'usage': '1M requests per month',
 668 |                     'estimated_cost': '$20.00',
 669 |                     'unit_pricing': {
 670 |                         'requests': '$0.20 per 1M requests',
 671 |                         'compute': '$0.0000166667 per GB-second',
 672 |                     },
 673 |                 }
 674 |             }
 675 |         }
 676 | 
 677 |         result = await generate_cost_report_wrapper(
 678 |             mock_context,
 679 |             pricing_data=sample_pricing_data_web,
 680 |             service_name='AWS Lambda',
 681 |             detailed_cost_data=detailed_cost_data,
 682 |             output_file=f'{temp_output_dir}/report.md',
 683 |             pricing_model='ON DEMAND',
 684 |             related_services=None,
 685 |             assumptions=None,
 686 |             exclusions=None,
 687 |             recommendations=None,
 688 |         )
 689 | 
 690 |         assert result is not None
 691 |         assert isinstance(result, str)
 692 |         assert 'AWS Lambda' in result
 693 |         assert '$20.00' in result
 694 |         assert '1M requests per month' in result
 695 | 
 696 |     @pytest.mark.asyncio
 697 |     async def test_generate_report_error_handling(self, mock_context):
 698 |         """Test error handling in report generation."""
 699 |         result = await generate_cost_report_wrapper(
 700 |             mock_context,
 701 |             pricing_data={'status': 'error'},
 702 |             service_name='Invalid Service',
 703 |             pricing_model='ON DEMAND',
 704 |             related_services=None,
 705 |             assumptions=None,
 706 |             exclusions=None,
 707 |             output_file=None,
 708 |             detailed_cost_data=None,
 709 |             recommendations=None,
 710 |         )
 711 | 
 712 |         assert '# Invalid Service Cost Analysis' in result
 713 | 
 714 | 
 715 | class TestGetPricingServiceAttributes:
 716 |     """Tests for the get_pricing_service_attributes function."""
 717 | 
 718 |     @pytest.mark.asyncio
 719 |     @pytest.mark.parametrize(
 720 |         'service_code,attributes,expected',
 721 |         [
 722 |             (
 723 |                 'AmazonEC2',
 724 |                 ['instanceType', 'location', 'tenancy', 'operatingSystem'],
 725 |                 ['instanceType', 'location', 'operatingSystem', 'tenancy'],
 726 |             ),
 727 |             (
 728 |                 'AmazonRDS',
 729 |                 ['engineCode', 'instanceType', 'location', 'databaseEngine'],
 730 |                 ['databaseEngine', 'engineCode', 'instanceType', 'location'],
 731 |             ),
 732 |         ],
 733 |     )
 734 |     async def test_get_pricing_service_attributes(
 735 |         self, mock_context, mock_boto3, service_code, attributes, expected
 736 |     ):
 737 |         """Test getting service attributes for various AWS services."""
 738 |         pricing_client = mock_boto3.Session().client('pricing')
 739 |         pricing_client.describe_services.return_value = {
 740 |             'Services': [{'ServiceCode': service_code, 'AttributeNames': attributes}]
 741 |         }
 742 | 
 743 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
 744 |             result = await get_pricing_service_attributes(mock_context, service_code)
 745 | 
 746 |             assert result == expected
 747 |             pricing_client.describe_services.assert_called_once_with(ServiceCode=service_code)
 748 |             mock_context.info.assert_called()
 749 | 
 750 |     @pytest.mark.asyncio
 751 |     @pytest.mark.parametrize(
 752 |         'service_code,attributes,filter_pattern,expected_matches,expected_count,test_description',
 753 |         [
 754 |             # Basic filtering tests
 755 |             (
 756 |                 'AmazonEC2',
 757 |                 ['instanceType', 'instanceFamily', 'location', 'memory', 'vcpu'],
 758 |                 'instance',
 759 |                 ['instanceFamily', 'instanceType'],
 760 |                 None,
 761 |                 'basic_instance_filter',
 762 |             ),
 763 |             (
 764 |                 'AmazonRDS',
 765 |                 ['engineCode', 'instanceType', 'location', 'databaseEngine', 'storageType'],
 766 |                 'engine',
 767 |                 ['databaseEngine', 'engineCode'],
 768 |                 None,
 769 |                 'engine_attributes_filter',
 770 |             ),
 771 |             (
 772 |                 'AmazonEC2',
 773 |                 ['instanceType', 'location', 'tenancy', 'operatingSystem', 'storage'],
 774 |                 'Type',
 775 |                 ['instanceType', 'storageType']
 776 |                 if 'storageType'
 777 |                 in ['instanceType', 'location', 'tenancy', 'operatingSystem', 'storage']
 778 |                 else ['instanceType'],
 779 |                 None,
 780 |                 'case_insensitive_type_filter',
 781 |             ),
 782 |             # Regex pattern tests
 783 |             (
 784 |                 'AmazonEC2',
 785 |                 [
 786 |                     'instanceType',
 787 |                     'instanceFamily',
 788 |                     'location',
 789 |                     'memory',
 790 |                     'vcpu',
 791 |                     'networkPerformance',
 792 |                 ],
 793 |                 '^instance',
 794 |                 ['instanceFamily', 'instanceType'],
 795 |                 None,
 796 |                 'starts_with_instance_regex',
 797 |             ),
 798 |             (
 799 |                 'AmazonRDS',
 800 |                 ['engineCode', 'instanceType', 'location', 'databaseEngine', 'deploymentOption'],
 801 |                 'Type$',
 802 |                 ['instanceType'],
 803 |                 None,
 804 |                 'ends_with_type_regex',
 805 |             ),
 806 |             (
 807 |                 'AmazonS3',
 808 |                 ['storageClass', 'location', 'durability', 'availability'],
 809 |                 'location|durability',
 810 |                 ['durability', 'location'],
 811 |                 None,
 812 |                 'alternation_regex',
 813 |             ),
 814 |             # No filter cases
 815 |             (
 816 |                 'AmazonEC2',
 817 |                 ['instanceType', 'location', 'tenancy'],
 818 |                 None,
 819 |                 None,
 820 |                 3,
 821 |                 'no_filter_all_attributes',
 822 |             ),
 823 |             (
 824 |                 'AmazonRDS',
 825 |                 ['engineCode', 'instanceType', 'location'],
 826 |                 '',
 827 |                 None,
 828 |                 3,
 829 |                 'empty_filter_all_attributes',
 830 |             ),
 831 |             # Edge cases - removed filter_no_matches as it's properly tested in error scenarios
 832 |             (
 833 |                 'AmazonS3',
 834 |                 ['storageClass', 'location'],
 835 |                 'Storage',
 836 |                 ['storageClass'],
 837 |                 None,
 838 |                 'case_insensitive_partial_match',
 839 |             ),
 840 |         ],
 841 |     )
 842 |     async def test_get_pricing_service_attributes_filtering_happy_path(
 843 |         self,
 844 |         mock_context,
 845 |         mock_boto3,
 846 |         service_code,
 847 |         attributes,
 848 |         filter_pattern,
 849 |         expected_matches,
 850 |         expected_count,
 851 |         test_description,
 852 |     ):
 853 |         """Test successful filtering of service attributes with various regex patterns."""
 854 |         pricing_client = mock_boto3.Session().client('pricing')
 855 |         pricing_client.describe_services.return_value = {
 856 |             'Services': [{'ServiceCode': service_code, 'AttributeNames': attributes}]
 857 |         }
 858 | 
 859 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
 860 |             result = await get_pricing_service_attributes(
 861 |                 mock_context, service_code, filter=filter_pattern
 862 |             )
 863 | 
 864 |             assert isinstance(result, list), (
 865 |                 f'Failed {test_description}: expected list, got {type(result)}'
 866 |             )
 867 | 
 868 |             if expected_matches is not None:
 869 |                 # Test specific matches
 870 |                 assert len(result) == len(expected_matches), (
 871 |                     f'Failed {test_description}: expected {len(expected_matches)} matches, got {len(result)}'
 872 |                 )
 873 |                 for attr in expected_matches:
 874 |                     assert attr in result, f'Failed {test_description}: missing {attr} in results'
 875 |                 # Verify results are sorted
 876 |                 assert result == sorted(result), (
 877 |                     f'Failed {test_description}: results not sorted properly'
 878 |                 )
 879 |             elif expected_count is not None:
 880 |                 # Test count-only cases (like no filter)
 881 |                 assert len(result) == expected_count, (
 882 |                     f'Failed {test_description}: expected {expected_count} attributes, got {len(result)}'
 883 |                 )
 884 | 
 885 |             pricing_client.describe_services.assert_called_once_with(ServiceCode=service_code)
 886 |             mock_context.info.assert_called()
 887 | 
 888 |     @pytest.mark.asyncio
 889 |     @pytest.mark.parametrize(
 890 |         'service_code,attributes,filter_pattern,expected_error_type,test_description',
 891 |         [
 892 |             (
 893 |                 'AmazonEC2',
 894 |                 ['instanceType', 'location', 'tenancy'],
 895 |                 'nonexistent',
 896 |                 'no_matches_found',
 897 |                 'filter_no_matches',
 898 |             ),
 899 |             (
 900 |                 'AmazonRDS',
 901 |                 ['engineCode', 'instanceType', 'location'],
 902 |                 '[invalid',
 903 |                 'invalid_regex',
 904 |                 'invalid_regex_pattern',
 905 |             ),
 906 |             (
 907 |                 'AmazonS3',
 908 |                 ['storageClass', 'location'],
 909 |                 '\\',
 910 |                 'invalid_regex',
 911 |                 'invalid_escape_sequence',
 912 |             ),
 913 |         ],
 914 |     )
 915 |     async def test_get_pricing_service_attributes_filtering_errors(
 916 |         self,
 917 |         mock_context,
 918 |         mock_boto3,
 919 |         service_code,
 920 |         attributes,
 921 |         filter_pattern,
 922 |         expected_error_type,
 923 |         test_description,
 924 |     ):
 925 |         """Test error scenarios in service attributes filtering."""
 926 |         pricing_client = mock_boto3.Session().client('pricing')
 927 |         pricing_client.describe_services.return_value = {
 928 |             'Services': [{'ServiceCode': service_code, 'AttributeNames': attributes}]
 929 |         }
 930 | 
 931 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
 932 |             result = await get_pricing_service_attributes(
 933 |                 mock_context, service_code, filter=filter_pattern
 934 |             )
 935 | 
 936 |             assert isinstance(result, dict), (
 937 |                 f'Failed {test_description}: expected dict (error), got {type(result)}'
 938 |             )
 939 |             assert result['status'] == 'error', f'Failed {test_description}: expected error status'
 940 |             assert result['error_type'] == expected_error_type, (
 941 |                 f'Failed {test_description}: expected error_type {expected_error_type}, got {result.get("error_type")}'
 942 |             )
 943 |             assert result['service_code'] == service_code, (
 944 |                 f'Failed {test_description}: service_code not in error response'
 945 |             )
 946 | 
 947 |             if expected_error_type == 'invalid_regex':
 948 |                 assert (
 949 |                     filter_pattern in result['message']
 950 |                     or 'Invalid regex pattern' in result['message']
 951 |                 ), f'Failed {test_description}: filter pattern or regex error not in error message'
 952 |                 assert 'examples' in result, (
 953 |                     f'Failed {test_description}: examples not provided in error response'
 954 |                 )
 955 |             elif expected_error_type == 'no_matches_found':
 956 |                 assert 'No service attributes match' in result['message'], (
 957 |                     f'Failed {test_description}: no matches message not in error response'
 958 |                 )
 959 | 
 960 |             mock_context.error.assert_called()
 961 | 
 962 |     @pytest.mark.asyncio
 963 |     @pytest.mark.parametrize(
 964 |         'error_scenario,service_code,expected_error_type,expected_in_message',
 965 |         [
 966 |             ('service_not_found', 'InvalidService', 'service_not_found', 'InvalidService'),
 967 |             ('api_error', 'AmazonEC2', 'api_error', 'API Error'),
 968 |             (
 969 |                 'empty_attributes',
 970 |                 'TestService',
 971 |                 'empty_results',
 972 |                 'no filterable attributes available',
 973 |             ),
 974 |         ],
 975 |     )
 976 |     async def test_get_pricing_service_attributes_errors(
 977 |         self,
 978 |         mock_context,
 979 |         mock_boto3,
 980 |         error_scenario,
 981 |         service_code,
 982 |         expected_error_type,
 983 |         expected_in_message,
 984 |     ):
 985 |         """Test various error scenarios for get_pricing_service_attributes."""
 986 |         if error_scenario == 'service_not_found':
 987 |             pricing_client = mock_boto3.Session().client('pricing')
 988 |             pricing_client.describe_services.return_value = {'Services': []}
 989 | 
 990 |         elif error_scenario == 'api_error':
 991 |             pricing_client = mock_boto3.Session().client('pricing')
 992 |             pricing_client.describe_services.side_effect = Exception('API Error')
 993 | 
 994 |         elif error_scenario == 'empty_attributes':
 995 |             pricing_client = mock_boto3.Session().client('pricing')
 996 |             pricing_client.describe_services.return_value = {
 997 |                 'Services': [{'ServiceCode': service_code, 'AttributeNames': []}]
 998 |             }
 999 | 
1000 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
1001 |             result = await get_pricing_service_attributes(mock_context, service_code)
1002 | 
1003 |         # Common assertions for all error scenarios
1004 |         assert isinstance(result, dict)
1005 |         assert result['status'] == 'error'
1006 |         assert result['error_type'] == expected_error_type
1007 |         assert expected_in_message in result['message']
1008 |         assert result['service_code'] == service_code
1009 |         assert 'suggestion' in result or 'examples' in result
1010 |         mock_context.error.assert_called()
1011 | 
1012 |     @pytest.mark.asyncio
1013 |     async def test_get_pricing_service_attributes_client_creation_error(self, mock_context):
1014 |         """Test handling of client creation errors."""
1015 |         with patch(
1016 |             'awslabs.aws_pricing_mcp_server.server.create_pricing_client',
1017 |             side_effect=Exception('Client creation failed'),
1018 |         ):
1019 |             result = await get_pricing_service_attributes(mock_context, 'AmazonEC2')
1020 | 
1021 |         assert isinstance(result, dict)
1022 |         assert result['status'] == 'error'
1023 |         assert result['error_type'] == 'client_creation_failed'
1024 |         assert 'Failed to create AWS Pricing client' in result['message']
1025 |         assert 'Client creation failed' in result['message']
1026 |         assert result['service_code'] == 'AmazonEC2'
1027 |         mock_context.error.assert_called()
1028 | 
1029 |     @pytest.mark.asyncio
1030 |     async def test_get_pricing_service_attributes_filter_with_api_errors(
1031 |         self, mock_context, mock_boto3
1032 |     ):
1033 |         """Test that filtering errors are handled properly when combined with API errors."""
1034 |         pricing_client = mock_boto3.Session().client('pricing')
1035 |         pricing_client.describe_services.side_effect = Exception('API Error')
1036 | 
1037 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
1038 |             result = await get_pricing_service_attributes(
1039 |                 mock_context, 'AmazonEC2', filter='instance'
1040 |             )
1041 | 
1042 |             # Should return API error, not filter error
1043 |             assert isinstance(result, dict)
1044 |             assert result['status'] == 'error'
1045 |             assert result['error_type'] == 'api_error'
1046 |             assert 'API Error' in result['message']
1047 |             mock_context.error.assert_called()
1048 | 
1049 | 
1050 | class TestGetPricingAttributeValues:
1051 |     """Tests for the get_pricing_attribute_values function."""
1052 | 
1053 |     @pytest.mark.asyncio
1054 |     @pytest.mark.parametrize(
1055 |         'service_code,attribute_names,raw_values_map,filters,expected,test_description',
1056 |         [
1057 |             # Basic success cases without filters
1058 |             (
1059 |                 'AmazonEC2',
1060 |                 ['instanceType'],
1061 |                 {'instanceType': ['t2.micro', 't2.small', 't3.medium', 'm5.large']},
1062 |                 None,
1063 |                 {'instanceType': ['m5.large', 't2.micro', 't2.small', 't3.medium']},
1064 |                 'single_attribute_no_filter',
1065 |             ),
1066 |             (
1067 |                 'AmazonEC2',
1068 |                 ['instanceType', 'location'],
1069 |                 {
1070 |                     'instanceType': ['t2.micro', 't2.small', 't3.medium'],
1071 |                     'location': ['US East (N. Virginia)', 'US West (Oregon)', 'EU (Ireland)'],
1072 |                 },
1073 |                 None,
1074 |                 {
1075 |                     'instanceType': ['t2.micro', 't2.small', 't3.medium'],
1076 |                     'location': ['EU (Ireland)', 'US East (N. Virginia)', 'US West (Oregon)'],
1077 |                 },
1078 |                 'multiple_attributes_no_filter',
1079 |             ),
1080 |             (
1081 |                 'AmazonRDS',
1082 |                 ['engineCode', 'instanceType'],
1083 |                 {
1084 |                     'engineCode': ['mysql', 'postgres', 'aurora-mysql'],
1085 |                     'instanceType': ['db.t3.micro', 'db.t3.small'],
1086 |                 },
1087 |                 None,
1088 |                 {
1089 |                     'engineCode': ['aurora-mysql', 'mysql', 'postgres'],
1090 |                     'instanceType': ['db.t3.micro', 'db.t3.small'],
1091 |                 },
1092 |                 'different_service_no_filter',
1093 |             ),
1094 |             # Success cases with filters
1095 |             (
1096 |                 'AmazonEC2',
1097 |                 ['instanceType', 'location'],
1098 |                 {
1099 |                     'instanceType': ['t2.micro', 't2.small', 't3.medium', 'm5.large'],
1100 |                     'location': ['US East (N. Virginia)', 'US West (Oregon)', 'EU (Ireland)'],
1101 |                 },
1102 |                 {'instanceType': 't3'},
1103 |                 {
1104 |                     'instanceType': ['t3.medium'],  # Filtered
1105 |                     'location': [
1106 |                         'EU (Ireland)',
1107 |                         'US East (N. Virginia)',
1108 |                         'US West (Oregon)',
1109 |                     ],  # All values
1110 |                 },
1111 |                 'partial_filtering',
1112 |             ),
1113 |             (
1114 |                 'AmazonEC2',
1115 |                 ['instanceType', 'location'],
1116 |                 {
1117 |                     'instanceType': ['t2.micro', 't2.small', 't3.medium', 'm5.large'],
1118 |                     'location': ['US East (N. Virginia)', 'US West (Oregon)', 'EU (Ireland)'],
1119 |                 },
1120 |                 {'instanceType': 't3', 'location': 'US'},
1121 |                 {
1122 |                     'instanceType': ['t3.medium'],  # Filtered
1123 |                     'location': ['US East (N. Virginia)', 'US West (Oregon)'],  # Filtered
1124 |                 },
1125 |                 'filter_all_attributes',
1126 |             ),
1127 |             (
1128 |                 'AmazonRDS',
1129 |                 ['engineCode', 'instanceType'],
1130 |                 {
1131 |                     'engineCode': ['mysql', 'postgres', 'aurora-mysql', 'aurora-postgres'],
1132 |                     'instanceType': ['db.t3.micro', 'db.t3.small', 'db.m5.large'],
1133 |                 },
1134 |                 {'engineCode': '^aurora', 'instanceType': r'\.t3\.'},
1135 |                 {
1136 |                     'engineCode': ['aurora-mysql', 'aurora-postgres'],  # Starts with aurora
1137 |                     'instanceType': ['db.t3.micro', 'db.t3.small'],  # Contains .t3.
1138 |                 },
1139 |                 'regex_patterns',
1140 |             ),
1141 |             (
1142 |                 'AmazonEC2',
1143 |                 ['instanceType', 'location'],
1144 |                 {
1145 |                     'instanceType': ['t2.micro', 't2.small', 't3.medium'],
1146 |                     'location': ['US East (N. Virginia)', 'US West (Oregon)'],
1147 |                 },
1148 |                 {'instanceType': 'nonexistent'},
1149 |                 {
1150 |                     'instanceType': [],  # No matches
1151 |                     'location': ['US East (N. Virginia)', 'US West (Oregon)'],  # All values
1152 |                 },
1153 |                 'filter_no_matches',
1154 |             ),
1155 |             # Additional filter test cases
1156 |             (
1157 |                 'AmazonEC2',
1158 |                 ['instanceType'],
1159 |                 {'instanceType': ['t2.micro', 't3.medium']},
1160 |                 {},
1161 |                 {'instanceType': ['t2.micro', 't3.medium']},
1162 |                 'empty_filters_dict',
1163 |             ),
1164 |             (
1165 |                 'AmazonEC2',
1166 |                 ['location'],
1167 |                 {'location': ['US East (N. Virginia)', 'US West (Oregon)', 'EU (Ireland)']},
1168 |                 {'location': 'us'},
1169 |                 {'location': ['US East (N. Virginia)', 'US West (Oregon)']},
1170 |                 'case_insensitive_filtering',
1171 |             ),
1172 |             (
1173 |                 'AmazonEC2',
1174 |                 ['instanceType'],
1175 |                 {'instanceType': ['t2.micro', 't3.medium']},
1176 |                 {'instanceType': 't3', 'nonRequestedAttribute': 'someFilter'},
1177 |                 {'instanceType': ['t3.medium']},
1178 |                 'ignore_non_requested_attribute_filter',
1179 |             ),
1180 |         ],
1181 |     )
1182 |     async def test_get_pricing_attribute_values_happy_path(
1183 |         self,
1184 |         mock_context,
1185 |         mock_boto3,
1186 |         service_code,
1187 |         attribute_names,
1188 |         raw_values_map,
1189 |         filters,
1190 |         expected,
1191 |         test_description,
1192 |     ):
1193 |         """Test successful cases for getting attribute values with and without filtering."""
1194 |         pricing_client = mock_boto3.Session().client('pricing')
1195 | 
1196 |         # Set up mock to return different values based on the attribute name
1197 |         def mock_get_attribute_values(ServiceCode, AttributeName, **kwargs):
1198 |             if AttributeName in raw_values_map:
1199 |                 return {
1200 |                     'AttributeValues': [{'Value': val} for val in raw_values_map[AttributeName]]
1201 |                 }
1202 |             return {'AttributeValues': []}
1203 | 
1204 |         pricing_client.get_attribute_values.side_effect = mock_get_attribute_values
1205 | 
1206 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
1207 |             result = await get_pricing_attribute_values(
1208 |                 mock_context, service_code, attribute_names, filters
1209 |             )
1210 | 
1211 |             assert result == expected, f"Failed test case '{test_description}'"
1212 |             assert pricing_client.get_attribute_values.call_count == len(attribute_names)
1213 |             mock_context.info.assert_called()
1214 | 
1215 |     @pytest.mark.asyncio
1216 |     async def test_get_pricing_attribute_values_filter_invalid_regex(
1217 |         self, mock_context, mock_boto3
1218 |     ):
1219 |         """Test error handling when invalid regex pattern is provided."""
1220 |         pricing_client = mock_boto3.Session().client('pricing')
1221 |         pricing_client.get_attribute_values.return_value = {
1222 |             'AttributeValues': [{'Value': 't2.micro'}, {'Value': 't3.medium'}]
1223 |         }
1224 | 
1225 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
1226 |             result = await get_pricing_attribute_values(
1227 |                 mock_context, 'AmazonEC2', ['instanceType'], {'instanceType': '[invalid'}
1228 |             )
1229 | 
1230 |             # Should return error due to invalid regex
1231 |             assert isinstance(result, dict)
1232 |             assert result['status'] == 'error'
1233 |             assert result['error_type'] == 'invalid_regex'
1234 |             assert 'Invalid regex pattern "[invalid"' in result['message']
1235 |             assert result['service_code'] == 'AmazonEC2'
1236 |             assert result['attribute_name'] == 'instanceType'
1237 |             assert result['filter_pattern'] == '[invalid'
1238 |             assert 'examples' in result
1239 |             mock_context.error.assert_called()
1240 | 
1241 |     @pytest.mark.asyncio
1242 |     async def test_get_pricing_attribute_values_filter_for_non_requested_attribute(
1243 |         self, mock_context, mock_boto3
1244 |     ):
1245 |         """Test that filters for non-requested attributes are ignored."""
1246 |         pricing_client = mock_boto3.Session().client('pricing')
1247 |         pricing_client.get_attribute_values.return_value = {
1248 |             'AttributeValues': [{'Value': 't2.micro'}, {'Value': 't3.medium'}]
1249 |         }
1250 | 
1251 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
1252 |             result = await get_pricing_attribute_values(
1253 |                 mock_context,
1254 |                 'AmazonEC2',
1255 |                 ['instanceType'],
1256 |                 {'instanceType': 't3', 'nonRequestedAttribute': 'someFilter'},
1257 |             )
1258 | 
1259 |             # Should succeed and ignore the filter for non-requested attribute
1260 |             assert result == {'instanceType': ['t3.medium']}
1261 |             assert pricing_client.get_attribute_values.call_count == 1
1262 |             mock_context.info.assert_called()
1263 | 
1264 |     @pytest.mark.asyncio
1265 |     async def test_get_pricing_attribute_values_empty_filters_dict(self, mock_context, mock_boto3):
1266 |         """Test that empty filters dictionary works like no filters."""
1267 |         pricing_client = mock_boto3.Session().client('pricing')
1268 |         pricing_client.get_attribute_values.return_value = {
1269 |             'AttributeValues': [{'Value': 't2.micro'}, {'Value': 't3.medium'}]
1270 |         }
1271 | 
1272 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
1273 |             result = await get_pricing_attribute_values(
1274 |                 mock_context, 'AmazonEC2', ['instanceType'], {}
1275 |             )
1276 | 
1277 |             # Should return all values (no filtering applied)
1278 |             assert result == {'instanceType': ['t2.micro', 't3.medium']}
1279 |             assert pricing_client.get_attribute_values.call_count == 1
1280 |             mock_context.info.assert_called()
1281 | 
1282 |     @pytest.mark.asyncio
1283 |     async def test_get_pricing_attribute_values_case_insensitive_filtering(
1284 |         self, mock_context, mock_boto3
1285 |     ):
1286 |         """Test that filtering is case-insensitive."""
1287 |         pricing_client = mock_boto3.Session().client('pricing')
1288 |         pricing_client.get_attribute_values.return_value = {
1289 |             'AttributeValues': [
1290 |                 {'Value': 'US East (N. Virginia)'},
1291 |                 {'Value': 'US West (Oregon)'},
1292 |                 {'Value': 'EU (Ireland)'},
1293 |             ]
1294 |         }
1295 | 
1296 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
1297 |             result = await get_pricing_attribute_values(
1298 |                 mock_context, 'AmazonEC2', ['location'], {'location': 'us'}
1299 |             )
1300 | 
1301 |             # Should match both US regions (case-insensitive)
1302 |             assert result == {'location': ['US East (N. Virginia)', 'US West (Oregon)']}
1303 |             assert pricing_client.get_attribute_values.call_count == 1
1304 |             mock_context.info.assert_called()
1305 | 
1306 |     @pytest.mark.asyncio
1307 |     async def test_get_pricing_attribute_values_single_attribute_with_pagination(
1308 |         self, mock_context, mock_boto3
1309 |     ):
1310 |         """Test getting attribute values with pagination handling for single attribute."""
1311 |         pricing_client = mock_boto3.Session().client('pricing')
1312 |         pricing_client.get_attribute_values.side_effect = [
1313 |             {
1314 |                 'AttributeValues': [{'Value': 't2.micro'}, {'Value': 't2.small'}],
1315 |                 'NextToken': 'token',
1316 |             },
1317 |             {'AttributeValues': [{'Value': 't3.medium'}, {'Value': 'm5.large'}]},
1318 |         ]
1319 | 
1320 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
1321 |             result = await get_pricing_attribute_values(
1322 |                 mock_context, 'AmazonEC2', ['instanceType']
1323 |             )
1324 | 
1325 |             expected = {'instanceType': ['m5.large', 't2.micro', 't2.small', 't3.medium']}
1326 |             assert result == expected
1327 |             assert pricing_client.get_attribute_values.call_count == 2
1328 |             assert (
1329 |                 pricing_client.get_attribute_values.call_args_list[1][1].get('NextToken')
1330 |                 == 'token'
1331 |             )
1332 | 
1333 |     @pytest.mark.asyncio
1334 |     async def test_get_pricing_attribute_values_empty_attribute_list(
1335 |         self, mock_context, mock_boto3
1336 |     ):
1337 |         """Test error handling when empty attribute list is provided."""
1338 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
1339 |             result = await get_pricing_attribute_values(mock_context, 'AmazonEC2', [])
1340 | 
1341 |             # Verify error response structure
1342 |             assert isinstance(result, dict)
1343 |             assert result['status'] == 'error'
1344 |             assert result['error_type'] == 'empty_attribute_list'
1345 |             assert 'No attribute names provided' in result['message']
1346 |             assert result['service_code'] == 'AmazonEC2'
1347 |             assert result['attribute_names'] == []
1348 |             assert 'get_pricing_service_attributes()' in result['suggestion']
1349 |             mock_context.error.assert_called()
1350 | 
1351 |     @pytest.mark.asyncio
1352 |     async def test_get_pricing_attribute_values_single_attribute_empty(
1353 |         self, mock_context, mock_boto3
1354 |     ):
1355 |         """Test getting attribute values when no values are returned for single attribute."""
1356 |         pricing_client = mock_boto3.Session().client('pricing')
1357 |         pricing_client.get_attribute_values.return_value = {'AttributeValues': []}
1358 | 
1359 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
1360 |             result = await get_pricing_attribute_values(
1361 |                 mock_context, 'InvalidService', ['invalidAttribute']
1362 |             )
1363 | 
1364 |             # Verify error response structure
1365 |             assert isinstance(result, dict)
1366 |             assert result['status'] == 'error'
1367 |             assert result['error_type'] == 'no_attribute_values_found'
1368 |             assert 'InvalidService' in result['message']
1369 |             assert 'invalidAttribute' in result['message']
1370 |             assert result['service_code'] == 'InvalidService'
1371 |             assert result['attribute_name'] == 'invalidAttribute'
1372 |             assert result['failed_attribute'] == 'invalidAttribute'
1373 |             assert result['requested_attributes'] == ['invalidAttribute']
1374 |             assert 'get_service_codes()' in result['suggestion']
1375 |             assert 'get_service_attributes()' in result['suggestion']
1376 |             assert 'examples' in result
1377 |             assert 'Common service codes' in result['examples']
1378 |             assert 'Common attributes' in result['examples']
1379 |             mock_context.error.assert_called()
1380 | 
1381 |     @pytest.mark.asyncio
1382 |     async def test_get_pricing_attribute_values_all_or_nothing_failure(
1383 |         self, mock_context, mock_boto3
1384 |     ):
1385 |         """Test all-or-nothing behavior when one attribute fails in multi-attribute request."""
1386 |         pricing_client = mock_boto3.Session().client('pricing')
1387 | 
1388 |         # First attribute succeeds, second fails
1389 |         def mock_get_attribute_values(ServiceCode, AttributeName, **kwargs):
1390 |             if AttributeName == 'instanceType':
1391 |                 return {'AttributeValues': [{'Value': 't2.micro'}, {'Value': 't3.medium'}]}
1392 |             elif AttributeName == 'invalidAttribute':
1393 |                 return {'AttributeValues': []}  # Empty result causes failure
1394 | 
1395 |         pricing_client.get_attribute_values.side_effect = mock_get_attribute_values
1396 | 
1397 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
1398 |             result = await get_pricing_attribute_values(
1399 |                 mock_context, 'AmazonEC2', ['instanceType', 'invalidAttribute']
1400 |             )
1401 | 
1402 |             # Should return error because second attribute failed
1403 |             assert isinstance(result, dict)
1404 |             assert result['status'] == 'error'
1405 |             assert result['error_type'] == 'no_attribute_values_found'
1406 |             assert (
1407 |                 'Failed to retrieve values for attribute "invalidAttribute"' in result['message']
1408 |             )
1409 |             assert result['failed_attribute'] == 'invalidAttribute'
1410 |             assert result['requested_attributes'] == ['instanceType', 'invalidAttribute']
1411 | 
1412 |     @pytest.mark.asyncio
1413 |     async def test_get_pricing_attribute_values_api_error_in_multi_attribute(
1414 |         self, mock_context, mock_boto3
1415 |     ):
1416 |         """Test handling of API errors when getting attribute values in multi-attribute request."""
1417 |         pricing_client = mock_boto3.Session().client('pricing')
1418 | 
1419 |         # First attribute succeeds, second raises API error
1420 |         def mock_get_attribute_values(ServiceCode, AttributeName, **kwargs):
1421 |             if AttributeName == 'instanceType':
1422 |                 return {'AttributeValues': [{'Value': 't2.micro'}, {'Value': 't3.medium'}]}
1423 |             elif AttributeName == 'location':
1424 |                 raise Exception('API Error')
1425 | 
1426 |         pricing_client.get_attribute_values.side_effect = mock_get_attribute_values
1427 | 
1428 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
1429 |             result = await get_pricing_attribute_values(
1430 |                 mock_context, 'AmazonEC2', ['instanceType', 'location']
1431 |             )
1432 | 
1433 |             # Should return error because second attribute had API error
1434 |             assert isinstance(result, dict)
1435 |             assert result['status'] == 'error'
1436 |             assert result['error_type'] == 'api_error'
1437 |             assert 'Failed to retrieve values for attribute "location"' in result['message']
1438 |             assert 'API Error' in result['message']
1439 |             assert result['failed_attribute'] == 'location'
1440 |             assert result['requested_attributes'] == ['instanceType', 'location']
1441 | 
1442 |     @pytest.mark.asyncio
1443 |     async def test_get_pricing_attribute_values_client_creation_error(self, mock_context):
1444 |         """Test handling of client creation errors."""
1445 |         with patch(
1446 |             'awslabs.aws_pricing_mcp_server.server.create_pricing_client',
1447 |             side_effect=Exception('Client creation failed'),
1448 |         ):
1449 |             result = await get_pricing_attribute_values(
1450 |                 mock_context, 'AmazonEC2', ['instanceType']
1451 |             )
1452 | 
1453 |         assert isinstance(result, dict)
1454 |         assert result['status'] == 'error'
1455 |         assert result['error_type'] == 'client_creation_failed'
1456 |         assert 'Failed to create AWS Pricing client' in result['message']
1457 |         assert 'Client creation failed' in result['message']
1458 |         assert result['service_code'] == 'AmazonEC2'
1459 |         assert result['attribute_names'] == ['instanceType']
1460 |         mock_context.error.assert_called()
1461 | 
1462 | 
1463 | class TestGetPricingServiceCodesFiltering:
1464 |     """Tests for regex filtering functionality in get_pricing_service_codes."""
1465 | 
1466 |     @pytest.fixture
1467 |     def mock_service_codes_response(self, mock_boto3):
1468 |         """Mock service codes response with a variety of AWS services for testing filters."""
1469 |         pricing_client = mock_boto3.Session().client('pricing')
1470 |         pricing_client.describe_services.return_value = {
1471 |             'Services': [
1472 |                 {'ServiceCode': 'AmazonBedrock'},
1473 |                 {'ServiceCode': 'AmazonBedrockService'},
1474 |                 {'ServiceCode': 'AmazonEC2'},
1475 |                 {'ServiceCode': 'AmazonS3'},
1476 |                 {'ServiceCode': 'AmazonRDS'},
1477 |                 {'ServiceCode': 'AWSLambda'},
1478 |                 {'ServiceCode': 'AmazonDynamoDB'},
1479 |                 {'ServiceCode': 'AmazonElasticSearch'},
1480 |                 {'ServiceCode': 'AmazonKendra'},
1481 |                 {'ServiceCode': 'AmazonSageMaker'},
1482 |             ]
1483 |         }
1484 |         return mock_boto3
1485 | 
1486 |     @pytest.mark.asyncio
1487 |     @pytest.mark.parametrize(
1488 |         'filter_pattern,expected_matches,expected_count,test_description',
1489 |         [
1490 |             # Case sensitivity tests
1491 |             ('bedrock', ['AmazonBedrock', 'AmazonBedrockService'], None, 'basic_case_insensitive'),
1492 |             (
1493 |                 'BEDROCK',
1494 |                 ['AmazonBedrock', 'AmazonBedrockService'],
1495 |                 None,
1496 |                 'uppercase_case_insensitive',
1497 |             ),
1498 |             ('BeDrOcK', ['AmazonBedrock', 'AmazonBedrockService'], None, 'mixed_case_insensitive'),
1499 |             # Regex pattern tests
1500 |             ('^AmazonBedrock$', ['AmazonBedrock'], None, 'exact_match_regex'),
1501 |             (
1502 |                 '^Amazon',
1503 |                 [
1504 |                     'AmazonBedrock',
1505 |                     'AmazonBedrockService',
1506 |                     'AmazonEC2',
1507 |                     'AmazonS3',
1508 |                     'AmazonRDS',
1509 |                     'AmazonDynamoDB',
1510 |                     'AmazonElasticSearch',
1511 |                     'AmazonKendra',
1512 |                     'AmazonSageMaker',
1513 |                 ],
1514 |                 None,
1515 |                 'starts_with_regex',
1516 |             ),
1517 |             ('Lambda|S3', ['AWSLambda', 'AmazonS3'], None, 'alternation_regex'),
1518 |             ('Amazon.*DB', ['AmazonDynamoDB'], None, 'wildcard_regex'),
1519 |             ('EC2', ['AmazonEC2'], None, 'simple_substring'),
1520 |             ('AWS', ['AWSLambda'], None, 'aws_prefix'),
1521 |             (
1522 |                 'Kendra|SageMaker',
1523 |                 ['AmazonKendra', 'AmazonSageMaker'],
1524 |                 None,
1525 |                 'multiple_alternation',
1526 |             ),
1527 |             ('Search', ['AmazonElasticSearch'], None, 'partial_match'),
1528 |             # No filter cases
1529 |             ('', None, 10, 'empty_filter_all_services'),
1530 |             (None, None, 10, 'none_filter_all_services'),
1531 |         ],
1532 |     )
1533 |     async def test_regex_filtering_happy_path(
1534 |         self,
1535 |         mock_context,
1536 |         mock_service_codes_response,
1537 |         filter_pattern,
1538 |         expected_matches,
1539 |         expected_count,
1540 |         test_description,
1541 |     ):
1542 |         """Test successful regex filter patterns and no-filter cases."""
1543 |         with patch('boto3.Session', return_value=mock_service_codes_response.Session()):
1544 |             result = await get_pricing_service_codes(mock_context, filter=filter_pattern)
1545 | 
1546 |             assert isinstance(result, list), (
1547 |                 f'Failed {test_description}: expected list, got {type(result)}'
1548 |             )
1549 | 
1550 |             if expected_matches is not None:
1551 |                 # Test specific matches
1552 |                 assert len(result) == len(expected_matches), (
1553 |                     f'Failed {test_description}: expected {len(expected_matches)} matches, got {len(result)}'
1554 |                 )
1555 |                 for service in expected_matches:
1556 |                     assert service in result, (
1557 |                         f'Failed {test_description}: missing {service} in results'
1558 |                     )
1559 |             elif expected_count is not None:
1560 |                 # Test count-only cases (like no filter)
1561 |                 assert len(result) == expected_count, (
1562 |                     f'Failed {test_description}: expected {expected_count} services, got {len(result)}'
1563 |                 )
1564 | 
1565 |     @pytest.mark.asyncio
1566 |     @pytest.mark.parametrize(
1567 |         'filter_pattern,expected_error_type,test_description',
1568 |         [
1569 |             (r'\bEC2\b', 'no_matches_found', 'word_boundary_no_matches'),
1570 |             (r'\.', 'no_matches_found', 'literal_dot_no_matches'),
1571 |             ('NonExistentService', 'no_matches_found', 'nonexistent_service'),
1572 |             ('[invalid', 'invalid_regex', 'invalid_regex_pattern'),
1573 |         ],
1574 |     )
1575 |     async def test_regex_filtering_error_cases(
1576 |         self,
1577 |         mock_context,
1578 |         mock_service_codes_response,
1579 |         filter_pattern,
1580 |         expected_error_type,
1581 |         test_description,
1582 |     ):
1583 |         """Test regex filter patterns that result in errors (invalid regex or no matches)."""
1584 |         with patch('boto3.Session', return_value=mock_service_codes_response.Session()):
1585 |             result = await get_pricing_service_codes(mock_context, filter=filter_pattern)
1586 | 
1587 |             assert isinstance(result, dict), (
1588 |                 f'Failed {test_description}: expected dict (error), got {type(result)}'
1589 |             )
1590 |             assert result['status'] == 'error', f'Failed {test_description}: expected error status'
1591 |             assert result['error_type'] == expected_error_type, (
1592 |                 f'Failed {test_description}: expected error_type {expected_error_type}, got {result.get("error_type")}'
1593 |             )
1594 | 
1595 |             if expected_error_type == 'invalid_regex':
1596 |                 assert filter_pattern in result['message'], (
1597 |                     f'Failed {test_description}: filter pattern not in error message'
1598 |                 )
1599 |             elif expected_error_type == 'no_matches_found':
1600 |                 assert (
1601 |                     'No service codes match' in result['message']
1602 |                     or 'no matches' in result['message'].lower()
1603 |                 )
1604 | 
1605 |             mock_context.error.assert_called()
1606 | 
1607 |     @pytest.mark.asyncio
1608 |     @pytest.mark.parametrize(
1609 |         'error_scenario,setup_error,expected_error_type',
1610 |         [
1611 |             ('api_error', Exception('API Error'), 'api_error'),
1612 |             ('client_error', 'client_creation', 'client_creation_failed'),
1613 |         ],
1614 |     )
1615 |     async def test_filter_error_scenarios(
1616 |         self, mock_context, mock_boto3, error_scenario, setup_error, expected_error_type
1617 |     ):
1618 |         """Test error handling scenarios with filtering enabled."""
1619 |         if error_scenario == 'api_error':
1620 |             pricing_client = mock_boto3.Session().client('pricing')
1621 |             pricing_client.describe_services.side_effect = setup_error
1622 |             with patch('boto3.Session', return_value=mock_boto3.Session()):
1623 |                 result = await get_pricing_service_codes(mock_context, filter='bedrock')
1624 |         else:  # client_error
1625 |             with patch(
1626 |                 'awslabs.aws_pricing_mcp_server.server.create_pricing_client',
1627 |                 side_effect=Exception('Client creation failed'),
1628 |             ):
1629 |                 result = await get_pricing_service_codes(mock_context, filter='bedrock')
1630 | 
1631 |         assert isinstance(result, dict)
1632 |         assert result['status'] == 'error'
1633 |         assert result['error_type'] == expected_error_type
1634 |         mock_context.error.assert_called()
1635 | 
1636 |     @pytest.mark.asyncio
1637 |     async def test_filter_with_pagination(self, mock_context, mock_boto3):
1638 |         """Test that filtering works correctly with paginated API responses."""
1639 |         pricing_client = mock_boto3.Session().client('pricing')
1640 | 
1641 |         # Set up mock with pagination
1642 |         pricing_client.describe_services.side_effect = [
1643 |             # First page
1644 |             {
1645 |                 'Services': [
1646 |                     {'ServiceCode': 'AmazonBedrock'},
1647 |                     {'ServiceCode': 'AmazonEC2'},
1648 |                 ],
1649 |                 'NextToken': 'page2token',
1650 |             },
1651 |             # Second page
1652 |             {
1653 |                 'Services': [
1654 |                     {'ServiceCode': 'AmazonBedrockService'},
1655 |                     {'ServiceCode': 'AWSLambda'},
1656 |                 ]
1657 |             },
1658 |         ]
1659 | 
1660 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
1661 |             # Filter for services containing "bedrock"
1662 |             result = await get_pricing_service_codes(mock_context, filter='bedrock')
1663 | 
1664 |             assert isinstance(result, list)
1665 |             assert len(result) == 2  # Should find matches from both pages
1666 |             assert 'AmazonBedrock' in result
1667 |             assert 'AmazonBedrockService' in result
1668 |             assert 'AmazonEC2' not in result
1669 |             assert 'AWSLambda' not in result
1670 | 
1671 | 
1672 | class TestServerIntegration:
1673 |     """Integration tests for the server module."""
1674 | 
1675 |     @pytest.mark.asyncio
1676 |     async def test_get_pricing_service_codes_integration(self, mock_context, mock_boto3):
1677 |         """Test the get_pricing_service_codes tool returns well-known service codes."""
1678 |         # Mock the boto3 pricing client response
1679 |         pricing_client = mock_boto3.Session().client('pricing')
1680 |         pricing_client.describe_services.return_value = {
1681 |             'Services': [
1682 |                 {'ServiceCode': 'AmazonEC2'},
1683 |                 {'ServiceCode': 'AmazonS3'},
1684 |                 {'ServiceCode': 'AmazonRDS'},
1685 |                 {'ServiceCode': 'AWSLambda'},
1686 |                 {'ServiceCode': 'AmazonDynamoDB'},
1687 |             ]
1688 |         }
1689 | 
1690 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
1691 |             # Call the get_pricing_service_codes function directly
1692 |             service_codes = await get_pricing_service_codes(mock_context, filter=None)
1693 | 
1694 |             # Verify we got a successful response
1695 |             assert service_codes is not None
1696 |             assert isinstance(service_codes, list)
1697 | 
1698 |             # Check for well-known AWS service codes that should be present
1699 |             expected_codes = ['AmazonEC2', 'AmazonS3', 'AmazonRDS', 'AWSLambda', 'AmazonDynamoDB']
1700 | 
1701 |             # Assert that the expected codes are present in the response
1702 |             for code in expected_codes:
1703 |                 assert code in service_codes, f'Expected service code {code} not found in response'
1704 | 
1705 |             # Verify that the mock was called correctly
1706 |             pricing_client.describe_services.assert_called()
1707 | 
1708 |             # Verify context was used correctly
1709 |             mock_context.info.assert_called()
1710 | 
1711 |     @pytest.mark.asyncio
1712 |     @pytest.mark.parametrize(
1713 |         'error_scenario,side_effect,expected_error_type',
1714 |         [
1715 |             ('client_creation_failed', 'create_pricing_client', 'client_creation_failed'),
1716 |             ('api_error', 'describe_services', 'api_error'),
1717 |             ('empty_results', None, 'empty_results'),
1718 |         ],
1719 |     )
1720 |     async def test_get_pricing_service_codes_errors(
1721 |         self, mock_context, mock_boto3, error_scenario, side_effect, expected_error_type
1722 |     ):
1723 |         """Test error handling scenarios for get_pricing_service_codes."""
1724 |         if error_scenario == 'client_creation_failed':
1725 |             with patch(
1726 |                 'awslabs.aws_pricing_mcp_server.server.create_pricing_client',
1727 |                 side_effect=Exception('Client creation failed'),
1728 |             ):
1729 |                 result = await get_pricing_service_codes(mock_context)
1730 |         elif error_scenario == 'api_error':
1731 |             pricing_client = mock_boto3.Session().client('pricing')
1732 |             pricing_client.describe_services.side_effect = Exception('API Error')
1733 |             with patch('boto3.Session', return_value=mock_boto3.Session()):
1734 |                 result = await get_pricing_service_codes(mock_context)
1735 |         elif error_scenario == 'empty_results':
1736 |             pricing_client = mock_boto3.Session().client('pricing')
1737 |             pricing_client.describe_services.return_value = {'Services': []}
1738 |             with patch('boto3.Session', return_value=mock_boto3.Session()):
1739 |                 result = await get_pricing_service_codes(mock_context)
1740 |         else:
1741 |             # Should not reach here with current parametrize values
1742 |             raise ValueError(f'Unknown error scenario: {error_scenario}')
1743 | 
1744 |         assert isinstance(result, dict)
1745 |         assert result['status'] == 'error'
1746 |         assert result['error_type'] == expected_error_type
1747 |         mock_context.error.assert_called()
1748 | 
1749 |     @pytest.mark.asyncio
1750 |     async def test_get_pricing_service_codes_pagination(self, mock_context, mock_boto3):
1751 |         """Test that get_pricing_service_codes correctly handles pagination."""
1752 |         # Mock the boto3 pricing client response for pagination
1753 |         pricing_client = mock_boto3.Session().client('pricing')
1754 | 
1755 |         # Set up a mock with pagination
1756 |         pricing_client.describe_services.side_effect = [
1757 |             # First call returns first page with NextToken
1758 |             {
1759 |                 'Services': [
1760 |                     {'ServiceCode': 'AmazonEC2'},
1761 |                     {'ServiceCode': 'AmazonS3'},
1762 |                 ],
1763 |                 'NextToken': 'page2token',
1764 |             },
1765 |             # Second call with NextToken returns second page
1766 |             {
1767 |                 'Services': [
1768 |                     {'ServiceCode': 'AmazonRDS'},
1769 |                     {'ServiceCode': 'AWSLambda'},
1770 |                     {'ServiceCode': 'AmazonDynamoDB'},
1771 |                 ]
1772 |                 # No NextToken in the response means this is the last page
1773 |             },
1774 |         ]
1775 | 
1776 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
1777 |             # Call the get_pricing_service_codes function directly
1778 |             service_codes = await get_pricing_service_codes(mock_context, filter=None)
1779 | 
1780 |             # Verify we got a successful response that combines both pages
1781 |             assert service_codes is not None
1782 |             assert isinstance(service_codes, list)
1783 |             assert len(service_codes) == 5  # Total from both pages
1784 | 
1785 |             # Verify pagination happened
1786 |             assert pricing_client.describe_services.call_count == 2
1787 | 
1788 |             # First call should have no NextToken
1789 |             first_call_kwargs = pricing_client.describe_services.call_args_list[0][1]
1790 |             assert 'NextToken' not in first_call_kwargs
1791 | 
1792 |             # Second call should include the NextToken from the first response
1793 |             second_call_kwargs = pricing_client.describe_services.call_args_list[1][1]
1794 |             assert second_call_kwargs.get('NextToken') == 'page2token'
1795 | 
1796 |     @pytest.mark.asyncio
1797 |     async def test_pricing_workflow(self, mock_context, mock_boto3):
1798 |         """Test the complete pricing analysis workflow."""
1799 |         # 1. Get pricing from API
1800 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
1801 |             api_pricing = await get_pricing(mock_context, 'AWSLambda', 'us-west-2')
1802 |         assert api_pricing is not None
1803 |         assert api_pricing['status'] == 'success'
1804 | 
1805 |         # 2. Generate cost report
1806 |         report = await generate_cost_report_wrapper(
1807 |             mock_context,
1808 |             pricing_data=api_pricing,
1809 |             service_name='AWS Lambda',
1810 |             pricing_model='ON DEMAND',
1811 |             related_services=None,
1812 |             assumptions=None,
1813 |             exclusions=None,
1814 |             output_file=None,
1815 |             detailed_cost_data=None,
1816 |             recommendations=None,
1817 |         )
1818 |         assert report is not None
1819 |         assert isinstance(report, str)
1820 |         assert 'AWS Lambda' in report
1821 | 
1822 | 
1823 | class TestIsFreeProduct:
1824 |     """Tests for the _is_free_product function with multi-currency support."""
1825 | 
1826 |     def _create_pricing_data(self, price_per_unit: dict) -> dict:
1827 |         """Helper to create test pricing data structure."""
1828 |         return {
1829 |             'terms': {
1830 |                 'OnDemand': {
1831 |                     'TEST.TERM.CODE': {
1832 |                         'priceDimensions': {'TEST.TERM.CODE.DIM': {'pricePerUnit': price_per_unit}}
1833 |                     }
1834 |                 }
1835 |             }
1836 |         }
1837 | 
1838 |     @pytest.mark.parametrize(
1839 |         'price_per_unit,expected_result,test_description',
1840 |         [
1841 |             # Test case 1: All currencies zero (truly free)
1842 |             ({'USD': '0.0000', 'CNY': '0.0000'}, True, 'truly_free_all_zero'),
1843 |             # Test case 2: CNY only, non-zero (should be False)
1844 |             ({'CNY': '5.2000'}, False, 'cny_only_paid'),
1845 |             # Test case 3: Free in USD, paid in CNY (should be False)
1846 |             ({'USD': '0.0000', 'CNY': '3.5000'}, False, 'usd_free_cny_paid'),
1847 |             # Test case 4: Invalid CNY price format (should be False)
1848 |             ({'CNY': 'N/A'}, False, 'invalid_cny_format'),
1849 |             # Test case 5: Multiple currencies with CNY paid
1850 |             (
1851 |                 {'USD': '0.0000', 'EUR': '0.0000', 'CNY': '8.7500'},
1852 |                 False,
1853 |                 'multi_currency_cny_paid',
1854 |             ),
1855 |         ],
1856 |     )
1857 |     def test_is_free_product_multi_currency(
1858 |         self, price_per_unit, expected_result, test_description
1859 |     ):
1860 |         """Test _is_free_product correctly handles CNY and other currencies."""
1861 |         pricing_data = self._create_pricing_data(price_per_unit)
1862 |         result = _is_free_product(pricing_data)
1863 | 
1864 |         assert result == expected_result, (
1865 |             f"Failed test case '{test_description}': "
1866 |             f'Expected {expected_result}, got {result} for pricing {price_per_unit}'
1867 |         )
1868 | 
1869 | 
1870 | class TestGetPriceListUrls:
1871 |     """Tests for the get_price_list_urls function."""
1872 | 
1873 |     @pytest.mark.asyncio
1874 |     async def test_get_price_list_urls_success(self, mock_context, mock_boto3):
1875 |         """Test successful retrieval of price list file URLs for all formats."""
1876 |         pricing_client = mock_boto3.Session().client('pricing')
1877 | 
1878 |         # Mock list_price_lists response
1879 |         pricing_client.list_price_lists.return_value = {
1880 |             'PriceLists': [
1881 |                 {
1882 |                     'PriceListArn': 'arn:aws:pricing::123456789012:price-list/AmazonEC2',
1883 |                     'FileFormats': ['CSV', 'JSON'],
1884 |                 }
1885 |             ]
1886 |         }
1887 | 
1888 |         # Mock get_price_list_file_url response - called for each format
1889 |         pricing_client.get_price_list_file_url.side_effect = [
1890 |             {'Url': 'https://example.com/pricing.csv'},
1891 |             {'Url': 'https://example.com/pricing.json'},
1892 |         ]
1893 | 
1894 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
1895 |             result = await get_price_list_urls(
1896 |                 mock_context, 'AmazonEC2', 'us-east-1', '2023-06-01 00:00'
1897 |             )
1898 | 
1899 |         # Check that we get all available format URLs
1900 |         assert len(result) == 2  # csv + json
1901 |         assert result['csv'] == 'https://example.com/pricing.csv'
1902 |         assert result['json'] == 'https://example.com/pricing.json'
1903 | 
1904 |         # Verify API calls
1905 |         pricing_client.list_price_lists.assert_called_once_with(
1906 |             ServiceCode='AmazonEC2',
1907 |             EffectiveDate='2023-06-01 00:00',
1908 |             RegionCode='us-east-1',
1909 |             CurrencyCode='USD',
1910 |         )
1911 | 
1912 |         # Verify get_price_list_file_url was called for each format
1913 |         assert pricing_client.get_price_list_file_url.call_count == 2
1914 |         pricing_client.get_price_list_file_url.assert_any_call(
1915 |             PriceListArn='arn:aws:pricing::123456789012:price-list/AmazonEC2', FileFormat='CSV'
1916 |         )
1917 |         pricing_client.get_price_list_file_url.assert_any_call(
1918 |             PriceListArn='arn:aws:pricing::123456789012:price-list/AmazonEC2', FileFormat='JSON'
1919 |         )
1920 | 
1921 |     @pytest.mark.asyncio
1922 |     async def test_get_price_list_urls_default_date(self, mock_context, mock_boto3):
1923 |         """Test that current timestamp is used when effective_date is not provided."""
1924 |         pricing_client = mock_boto3.Session().client('pricing')
1925 | 
1926 |         pricing_client.list_price_lists.return_value = {
1927 |             'PriceLists': [
1928 |                 {
1929 |                     'PriceListArn': 'arn:aws:pricing::123456789012:price-list/AmazonS3',
1930 |                     'FileFormats': ['CSV'],
1931 |                 }
1932 |             ]
1933 |         }
1934 | 
1935 |         pricing_client.get_price_list_file_url.return_value = {
1936 |             'Url': 'https://example.com/pricing.csv'
1937 |         }
1938 | 
1939 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
1940 |             result = await get_price_list_urls(mock_context, 'AmazonS3', 'us-west-2')
1941 | 
1942 |         # Check that we get all available format URLs
1943 |         assert len(result) == 1  # csv only
1944 |         assert result['csv'] == 'https://example.com/pricing.csv'
1945 | 
1946 |     @pytest.mark.asyncio
1947 |     async def test_get_price_list_urls_format_failure(self, mock_context, mock_boto3):
1948 |         """Test that any format failure results in an error."""
1949 |         pricing_client = mock_boto3.Session().client('pricing')
1950 | 
1951 |         # Mock list_price_lists response with both formats
1952 |         pricing_client.list_price_lists.return_value = {
1953 |             'PriceLists': [
1954 |                 {
1955 |                     'PriceListArn': 'arn:aws:pricing::123456789012:price-list/AmazonEC2',
1956 |                     'FileFormats': ['CSV', 'JSON'],
1957 |                 }
1958 |             ]
1959 |         }
1960 | 
1961 |         # Mock CSV succeeding but JSON failing
1962 |         pricing_client.get_price_list_file_url.side_effect = [
1963 |             {'Url': 'https://example.com/pricing.csv'},  # CSV succeeds
1964 |             Exception('Failed to get JSON URL'),  # JSON fails
1965 |         ]
1966 | 
1967 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
1968 |             result = await get_price_list_urls(mock_context, 'AmazonEC2', 'us-east-1')
1969 | 
1970 |         # Should return error when any format fails
1971 |         assert result['status'] == 'error'
1972 |         assert result['error_type'] == 'format_url_failed'
1973 |         assert 'Failed to get download URL for format "JSON"' in result['message']
1974 |         assert result['price_list_arn'] == 'arn:aws:pricing::123456789012:price-list/AmazonEC2'
1975 |         assert result['file_format'] == 'json'
1976 | 
1977 |         # Verify error was logged
1978 |         mock_context.error.assert_called_once()
1979 | 
1980 |     @pytest.mark.asyncio
1981 |     async def test_get_price_list_urls_no_price_lists(self, mock_context, mock_boto3):
1982 |         """Test error handling when no price lists are found."""
1983 |         pricing_client = mock_boto3.Session().client('pricing')
1984 |         pricing_client.list_price_lists.return_value = {'PriceLists': []}
1985 | 
1986 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
1987 |             result = await get_price_list_urls(mock_context, 'InvalidService', 'us-east-1')
1988 | 
1989 |         assert result['status'] == 'error'
1990 |         assert result['error_type'] == 'no_price_list_found'
1991 |         assert 'InvalidService' in result['message']
1992 |         assert result['service_code'] == 'InvalidService'
1993 |         assert result['region'] == 'us-east-1'
1994 |         mock_context.error.assert_called()
1995 | 
1996 |     @pytest.mark.asyncio
1997 |     async def test_get_price_list_urls_unsupported_format(self, mock_context, mock_boto3):
1998 |         """Test handling when some formats are not supported."""
1999 |         pricing_client = mock_boto3.Session().client('pricing')
2000 |         pricing_client.list_price_lists.return_value = {
2001 |             'PriceLists': [
2002 |                 {
2003 |                     'PriceListArn': 'arn:aws:pricing::123456789012:price-list/AmazonEC2',
2004 |                     'FileFormats': ['CSV'],  # Only CSV supported
2005 |                 }
2006 |             ]
2007 |         }
2008 | 
2009 |         pricing_client.get_price_list_file_url.return_value = {
2010 |             'Url': 'https://example.com/pricing.csv'
2011 |         }
2012 | 
2013 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
2014 |             result = await get_price_list_urls(mock_context, 'AmazonEC2', 'us-east-1')
2015 | 
2016 |         # Should still return successful result with available formats
2017 |         assert len(result) == 1  # csv only
2018 |         assert result['csv'] == 'https://example.com/pricing.csv'
2019 |         assert 'json' not in result  # JSON format not supported
2020 | 
2021 |     @pytest.mark.asyncio
2022 |     async def test_get_price_list_urls_list_api_error(self, mock_context, mock_boto3):
2023 |         """Test error handling when list_price_lists API call fails."""
2024 |         pricing_client = mock_boto3.Session().client('pricing')
2025 |         pricing_client.list_price_lists.side_effect = Exception('API Error')
2026 | 
2027 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
2028 |             result = await get_price_list_urls(mock_context, 'AmazonEC2', 'us-east-1')
2029 | 
2030 |         assert result['status'] == 'error'
2031 |         assert result['error_type'] == 'list_price_lists_failed'
2032 |         assert 'API Error' in result['message']
2033 |         assert result['service_code'] == 'AmazonEC2'
2034 |         assert result['region'] == 'us-east-1'
2035 |         mock_context.error.assert_called()
2036 | 
2037 |     @pytest.mark.asyncio
2038 |     async def test_get_price_list_urls_get_url_api_error(self, mock_context, mock_boto3):
2039 |         """Test error handling when get_price_list_file_url API call fails."""
2040 |         pricing_client = mock_boto3.Session().client('pricing')
2041 | 
2042 |         pricing_client.list_price_lists.return_value = {
2043 |             'PriceLists': [
2044 |                 {
2045 |                     'PriceListArn': 'arn:aws:pricing::123456789012:price-list/AmazonEC2',
2046 |                     'FileFormats': ['CSV'],
2047 |                 }
2048 |             ]
2049 |         }
2050 | 
2051 |         pricing_client.get_price_list_file_url.side_effect = Exception('URL API Error')
2052 | 
2053 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
2054 |             result = await get_price_list_urls(mock_context, 'AmazonEC2', 'us-east-1')
2055 | 
2056 |         assert result['status'] == 'error'
2057 |         assert result['error_type'] == 'format_url_failed'
2058 |         assert 'Failed to get download URL for format "CSV"' in result['message']
2059 |         assert result['price_list_arn'] == 'arn:aws:pricing::123456789012:price-list/AmazonEC2'
2060 |         assert result['file_format'] == 'csv'
2061 |         mock_context.error.assert_called()
2062 | 
2063 |     @pytest.mark.asyncio
2064 |     async def test_get_price_list_urls_no_download_url(self, mock_context, mock_boto3):
2065 |         """Test error handling when no download URL is returned."""
2066 |         pricing_client = mock_boto3.Session().client('pricing')
2067 | 
2068 |         pricing_client.list_price_lists.return_value = {
2069 |             'PriceLists': [
2070 |                 {
2071 |                     'PriceListArn': 'arn:aws:pricing::123456789012:price-list/AmazonEC2',
2072 |                     'FileFormats': ['CSV'],
2073 |                 }
2074 |             ]
2075 |         }
2076 | 
2077 |         pricing_client.get_price_list_file_url.return_value = {}  # No URL
2078 | 
2079 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
2080 |             result = await get_price_list_urls(mock_context, 'AmazonEC2', 'us-east-1')
2081 | 
2082 |         assert result['status'] == 'error'
2083 |         assert result['error_type'] == 'empty_url_response'
2084 |         assert 'AWS API returned empty URL for format "CSV"' in result['message']
2085 |         assert result['price_list_arn'] == 'arn:aws:pricing::123456789012:price-list/AmazonEC2'
2086 |         assert result['file_format'] == 'csv'
2087 |         mock_context.error.assert_called()
2088 | 
2089 |     @pytest.mark.asyncio
2090 |     async def test_get_price_list_urls_unexpected_error(self, mock_context):
2091 |         """Test error handling for unexpected errors."""
2092 |         with patch('boto3.Session', side_effect=Exception('Unexpected Error')):
2093 |             result = await get_price_list_urls(mock_context, 'AmazonEC2', 'us-east-1')
2094 | 
2095 |         assert result['status'] == 'error'
2096 |         assert result['error_type'] == 'client_creation_failed'
2097 |         assert 'Unexpected Error' in result['message']
2098 |         assert result['service_code'] == 'AmazonEC2'
2099 |         assert result['region'] == 'us-east-1'
2100 |         mock_context.error.assert_called()
2101 | 
2102 |     @pytest.mark.asyncio
2103 |     async def test_get_price_list_urls_no_supported_formats(self, mock_context, mock_boto3):
2104 |         """Test error handling when price list has no supported formats."""
2105 |         pricing_client = mock_boto3.Session().client('pricing')
2106 | 
2107 |         pricing_client.list_price_lists.return_value = {
2108 |             'PriceLists': [
2109 |                 {
2110 |                     'PriceListArn': 'arn:aws:pricing::123456789012:price-list/AmazonEC2',
2111 |                     'FileFormats': [],  # Empty list of formats
2112 |                 }
2113 |             ]
2114 |         }
2115 | 
2116 |         with patch('boto3.Session', return_value=mock_boto3.Session()):
2117 |             result = await get_price_list_urls(mock_context, 'AmazonEC2', 'us-east-1')
2118 | 
2119 |         assert result['status'] == 'error'
2120 |         assert result['error_type'] == 'no_formats_available'
2121 |         assert 'no file formats are available for service "AmazonEC2"' in result['message']
2122 |         assert result['service_code'] == 'AmazonEC2'
2123 |         assert result['region'] == 'us-east-1'
2124 |         assert result['price_list_arn'] == 'arn:aws:pricing::123456789012:price-list/AmazonEC2'
2125 |         mock_context.error.assert_called()
2126 | 
```
Page 508/514FirstPrevNextLast