This is page 704 of 717. 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-slash.txt
│ ├── check-license-header.json
│ ├── check-license-header.yml
│ ├── checkov.yml
│ ├── codeql.yml
│ ├── dependency-review-action.yml
│ ├── detect-secrets-requirements.txt
│ ├── gh-pages.yml
│ ├── merge-prevention.yml
│ ├── powershell.yml
│ ├── pre-commit-requirements.txt
│ ├── pre-commit.yml
│ ├── pull-request-lint.yml
│ ├── python.yml
│ ├── RELEASE_INSTRUCTIONS.md
│ ├── release-initiate-branch.yml
│ ├── release-merge-tag.yml
│ ├── release.py
│ ├── release.yml
│ ├── scanners.yml
│ ├── scorecard-analysis.yml
│ ├── semgrep-requirements.txt
│ ├── semgrep.yml
│ ├── stale.yml
│ ├── trivy.yml
│ └── typescript.yml
├── .gitignore
├── .pre-commit-config.yaml
├── .python-version
├── .ruff.toml
├── .secrets.baseline
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── DESIGN_GUIDELINES.md
├── DEVELOPER_GUIDE.md
├── docs
│ └── images
│ └── root-readme
│ ├── cline-api-provider-filled.png
│ ├── cline-chat-interface.png
│ ├── cline-custom-instructions.png
│ ├── cline-select-aws-profile.png
│ ├── cline-select-bedrock.png
│ ├── configure-mcp-servers.png
│ ├── install-cline-extension.png
│ ├── mcp-servers-installed.png
│ └── select-mcp-servers.png
├── docusaurus
│ ├── .gitignore
│ ├── docs
│ │ ├── installation.md
│ │ ├── intro.md
│ │ ├── samples
│ │ │ ├── index.md
│ │ │ ├── mcp-integration-with-kb.md
│ │ │ ├── mcp-integration-with-nova-canvas.md
│ │ │ └── stepfunctions-tool-mcp-server.md
│ │ ├── servers
│ │ │ ├── amazon-bedrock-agentcore-mcp-server.md
│ │ │ ├── amazon-keyspaces-mcp-server.md
│ │ │ ├── amazon-mq-mcp-server.md
│ │ │ ├── amazon-neptune-mcp-server.md
│ │ │ ├── amazon-qbusiness-anonymous-mcp-server.md
│ │ │ ├── amazon-qindex-mcp-server.md
│ │ │ ├── amazon-sns-sqs-mcp-server.md
│ │ │ ├── aurora-dsql-mcp-server.md
│ │ │ ├── aws-api-mcp-server.md
│ │ │ ├── aws-appsync-mcp-server.md
│ │ │ ├── aws-bedrock-custom-model-import-mcp-server.md
│ │ │ ├── aws-bedrock-data-automation-mcp-server.md
│ │ │ ├── aws-dataprocessing-mcp-server.md
│ │ │ ├── aws-diagram-mcp-server.md
│ │ │ ├── aws-documentation-mcp-server.md
│ │ │ ├── aws-healthomics-mcp-server.md
│ │ │ ├── aws-iot-sitewise-mcp-server.md
│ │ │ ├── aws-knowledge-mcp-server.md
│ │ │ ├── aws-location-mcp-server.md
│ │ │ ├── aws-msk-mcp-server.md
│ │ │ ├── aws-pricing-mcp-server.md
│ │ │ ├── aws-serverless-mcp-server.md
│ │ │ ├── aws-support-mcp-server.md
│ │ │ ├── bedrock-kb-retrieval-mcp-server.md
│ │ │ ├── billing-cost-management-mcp-server.md
│ │ │ ├── ccapi-mcp-server.md
│ │ │ ├── cdk-mcp-server.md
│ │ │ ├── cfn-mcp-server.md
│ │ │ ├── cloudtrail-mcp-server.md
│ │ │ ├── cloudwatch-applicationsignals-mcp-server.md
│ │ │ ├── cloudwatch-mcp-server.md
│ │ │ ├── code-doc-gen-mcp-server.md
│ │ │ ├── core-mcp-server.md
│ │ │ ├── cost-explorer-mcp-server.md
│ │ │ ├── document-loader-mcp-server.md
│ │ │ ├── documentdb-mcp-server.md
│ │ │ ├── dynamodb-mcp-server.md
│ │ │ ├── ecs-mcp-server.md
│ │ │ ├── eks-mcp-server.md
│ │ │ ├── elasticache-mcp-server.md
│ │ │ ├── finch-mcp-server.md
│ │ │ ├── frontend-mcp-server.md
│ │ │ ├── git-repo-research-mcp-server.md
│ │ │ ├── healthlake-mcp-server.md
│ │ │ ├── iam-mcp-server.md
│ │ │ ├── kendra-index-mcp-server.md
│ │ │ ├── lambda-tool-mcp-server.md
│ │ │ ├── memcached-mcp-server.md
│ │ │ ├── mysql-mcp-server.md
│ │ │ ├── nova-canvas-mcp-server.md
│ │ │ ├── openapi-mcp-server.md
│ │ │ ├── postgres-mcp-server.md
│ │ │ ├── prometheus-mcp-server.md
│ │ │ ├── redshift-mcp-server.md
│ │ │ ├── s3-tables-mcp-server.md
│ │ │ ├── stepfunctions-tool-mcp-server.md
│ │ │ ├── syntheticdata-mcp-server.md
│ │ │ ├── terraform-mcp-server.md
│ │ │ ├── timestream-for-influxdb-mcp-server.md
│ │ │ ├── valkey-mcp-server.md
│ │ │ └── well-architected-security-mcp-server.mdx
│ │ └── vibe_coding.md
│ ├── docusaurus.config.ts
│ ├── package-lock.json
│ ├── package.json
│ ├── README.md
│ ├── sidebars.ts
│ ├── src
│ │ ├── components
│ │ │ ├── HomepageFeatures
│ │ │ │ └── styles.module.css
│ │ │ └── ServerCards
│ │ │ ├── index.tsx
│ │ │ └── styles.module.css
│ │ ├── css
│ │ │ ├── custom.css
│ │ │ └── doc-override.css
│ │ └── pages
│ │ ├── index.module.css
│ │ └── servers.tsx
│ ├── static
│ │ ├── .nojekyll
│ │ ├── assets
│ │ │ ├── icons
│ │ │ │ ├── activity.svg
│ │ │ │ ├── book-open.svg
│ │ │ │ ├── cpu.svg
│ │ │ │ ├── database.svg
│ │ │ │ ├── dollar-sign.svg
│ │ │ │ ├── help-circle.svg
│ │ │ │ ├── key.svg
│ │ │ │ ├── server.svg
│ │ │ │ ├── share-2.svg
│ │ │ │ ├── tool.svg
│ │ │ │ └── zap.svg
│ │ │ └── server-cards.json
│ │ └── img
│ │ ├── aws-logo.svg
│ │ └── logo.png
│ └── tsconfig.json
├── LICENSE
├── NOTICE
├── README.md
├── samples
│ ├── mcp-integration-with-kb
│ │ ├── .env.example
│ │ ├── .python-version
│ │ ├── assets
│ │ │ └── simplified-mcp-flow-diagram.png
│ │ ├── clients
│ │ │ └── client_server.py
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── user_interfaces
│ │ │ └── chat_bedrock_st.py
│ │ └── uv.lock
│ ├── mcp-integration-with-nova-canvas
│ │ ├── .env.example
│ │ ├── .python-version
│ │ ├── clients
│ │ │ └── client_server.py
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── user_interfaces
│ │ │ └── image_generator_st.py
│ │ └── uv.lock
│ ├── README.md
│ └── stepfunctions-tool-mcp-server
│ ├── README.md
│ └── sample_state_machines
│ ├── customer-create
│ │ └── app.py
│ ├── customer-id-from-email
│ │ └── app.py
│ ├── customer-info-from-id
│ │ └── app.py
│ └── template.yml
├── scripts
│ ├── README.md
│ └── verify_package_name.py
├── src
│ ├── amazon-bedrock-agentcore-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── amazon_bedrock_agentcore_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── config.py
│ │ │ ├── server.py
│ │ │ └── utils
│ │ │ ├── __init__.py
│ │ │ ├── cache.py
│ │ │ ├── doc_fetcher.py
│ │ │ ├── indexer.py
│ │ │ ├── text_processor.py
│ │ │ └── url_validator.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── SECURITY.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── conftest.py
│ │ │ ├── test_cache.py
│ │ │ ├── test_config.py
│ │ │ ├── test_doc_fetcher.py
│ │ │ ├── test_indexer.py
│ │ │ ├── test_init.py
│ │ │ ├── test_main.py
│ │ │ ├── test_server.py
│ │ │ ├── test_text_processor.py
│ │ │ └── test_url_validator.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── amazon-kendra-index-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── amazon_kendra_index_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── server.py
│ │ │ └── util.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── test_init.py
│ │ │ ├── test_main.py
│ │ │ └── test_server.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── amazon-keyspaces-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── amazon_keyspaces_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── client.py
│ │ │ ├── config.py
│ │ │ ├── consts.py
│ │ │ ├── llm_context.py
│ │ │ ├── models.py
│ │ │ ├── server.py
│ │ │ └── services.py
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── run_tests.sh
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── test_client.py
│ │ │ ├── test_init.py
│ │ │ ├── test_main.py
│ │ │ ├── test_query_analysis_service.py
│ │ │ ├── test_server.py
│ │ │ └── test_services.py
│ │ └── uv.lock
│ ├── amazon-mq-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── amazon_mq_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── aws_service_mcp_generator.py
│ │ │ ├── consts.py
│ │ │ ├── rabbitmq
│ │ │ │ ├── __init__.py
│ │ │ │ ├── admin.py
│ │ │ │ ├── connection.py
│ │ │ │ ├── doc
│ │ │ │ │ ├── rabbitmq_broker_sizing_guide.md
│ │ │ │ │ ├── rabbitmq_performance_optimization_best_practice.md
│ │ │ │ │ ├── rabbitmq_production_deployment_guidelines.md
│ │ │ │ │ ├── rabbitmq_quorum_queue_migration_guide.md
│ │ │ │ │ └── rabbitmq_setup_best_practice.md
│ │ │ │ ├── handlers.py
│ │ │ │ └── module.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── example
│ │ │ └── sample_mcp_q_cli.json
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── .gitignore
│ │ │ ├── rabbitmq
│ │ │ │ ├── __init__.py
│ │ │ │ ├── conftest.py
│ │ │ │ ├── test_admin.py
│ │ │ │ ├── test_connection.py
│ │ │ │ ├── test_handlers.py
│ │ │ │ └── test_module.py
│ │ │ ├── test_aws_service_mcp_generator.py
│ │ │ └── test_server.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── amazon-neptune-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── amazon_neptune_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── exceptions.py
│ │ │ ├── graph_store
│ │ │ │ ├── __init__.py
│ │ │ │ ├── analytics.py
│ │ │ │ ├── base.py
│ │ │ │ └── database.py
│ │ │ ├── models.py
│ │ │ ├── neptune.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── conftest.py
│ │ │ ├── test_analytics.py
│ │ │ ├── test_database.py
│ │ │ ├── test_exceptions.py
│ │ │ ├── test_init.py
│ │ │ ├── test_main.py
│ │ │ ├── test_models.py
│ │ │ ├── test_neptune.py
│ │ │ └── test_server.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── amazon-qbusiness-anonymous-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── amazon_qbusiness_anonymous_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── clients.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── conftest.py
│ │ │ ├── test_init.py
│ │ │ ├── test_main.py
│ │ │ └── test_server.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── amazon-qindex-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── amazon_qindex_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── clients.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── test_clients.py
│ │ │ ├── test_init.py
│ │ │ ├── test_main.py
│ │ │ └── test_server.py
│ │ └── uv.lock
│ ├── amazon-sns-sqs-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── amazon_sns_sqs_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── common.py
│ │ │ ├── consts.py
│ │ │ ├── generator.py
│ │ │ ├── server.py
│ │ │ ├── sns.py
│ │ │ └── sqs.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── print_tools.py
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── run_tests.sh
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── test_common.py
│ │ │ ├── test_generator.py
│ │ │ ├── test_server.py
│ │ │ ├── test_sns.py
│ │ │ └── test_sqs.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── aurora-dsql-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── aurora_dsql_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── consts.py
│ │ │ ├── mutable_sql_detector.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── test_connection_reuse.py
│ │ │ ├── test_init.py
│ │ │ ├── test_main.py
│ │ │ ├── test_profile_option.py
│ │ │ ├── test_readonly_enforcement.py
│ │ │ └── test_server.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── aws-api-mcp-server
│ │ ├── .gitattributes
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── aws_api_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── core
│ │ │ │ ├── __init__.py
│ │ │ │ ├── agent_scripts
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── manager.py
│ │ │ │ │ ├── models.py
│ │ │ │ │ └── registry
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── application-failure-troubleshooting.script.md
│ │ │ │ │ ├── cloudtral-mutli-region-setup.script.md
│ │ │ │ │ ├── create_amazon_aurora_db_cluster_with_instances.script.md
│ │ │ │ │ ├── lambda-timeout-debugging.script.md
│ │ │ │ │ ├── scripts_format.md
│ │ │ │ │ └── troubleshoot-permissions-with-cloudtrail-events.script.md
│ │ │ │ ├── aws
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── driver.py
│ │ │ │ │ ├── pagination.py
│ │ │ │ │ ├── regions.py
│ │ │ │ │ ├── service.py
│ │ │ │ │ └── services.py
│ │ │ │ ├── common
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── command_metadata.py
│ │ │ │ │ ├── command.py
│ │ │ │ │ ├── config.py
│ │ │ │ │ ├── errors.py
│ │ │ │ │ ├── file_operations.py
│ │ │ │ │ ├── file_system_controls.py
│ │ │ │ │ ├── helpers.py
│ │ │ │ │ ├── models.py
│ │ │ │ │ └── py.typed
│ │ │ │ ├── data
│ │ │ │ │ └── api_metadata.json
│ │ │ │ ├── metadata
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── read_only_operations_list.py
│ │ │ │ ├── parser
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── custom_validators
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── botocore_param_validator.py
│ │ │ │ │ │ ├── ec2_validator.py
│ │ │ │ │ │ └── ssm_validator.py
│ │ │ │ │ ├── interpretation.py
│ │ │ │ │ ├── lexer.py
│ │ │ │ │ └── parser.py
│ │ │ │ ├── py.typed
│ │ │ │ └── security
│ │ │ │ ├── __init__.py
│ │ │ │ ├── aws_api_customization.json
│ │ │ │ └── policy.py
│ │ │ ├── middleware
│ │ │ │ ├── __init__.py
│ │ │ │ └── http_header_validation_middleware.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── CONTRIBUTING.md
│ │ ├── DEPLOYMENT.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── agent_scripts
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_manager.py
│ │ │ │ └── test_registry
│ │ │ │ ├── another_valid_script.script.md
│ │ │ │ ├── test_script.script.md
│ │ │ │ └── valid_script.script.md
│ │ │ ├── aws
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_driver.py
│ │ │ │ ├── test_pagination.py
│ │ │ │ ├── test_service.py
│ │ │ │ └── test_services.py
│ │ │ ├── common
│ │ │ │ ├── test_command.py
│ │ │ │ ├── test_config.py
│ │ │ │ ├── test_file_operations.py
│ │ │ │ ├── test_file_system_controls.py
│ │ │ │ ├── test_file_validation.py
│ │ │ │ └── test_helpers.py
│ │ │ ├── fixtures.py
│ │ │ ├── history_handler.py
│ │ │ ├── metadata
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_read_only_operations_list.py
│ │ │ ├── middleware
│ │ │ │ └── test_http_header_validation_middleware.py
│ │ │ ├── parser
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_file_path_detection.py
│ │ │ │ ├── test_lexer.py
│ │ │ │ ├── test_parser_customizations.py
│ │ │ │ └── test_parser.py
│ │ │ ├── test_security_policy.py
│ │ │ └── test_server.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── aws-appsync-mcp-server
│ │ ├── .dockerignore
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── aws_appsync_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── decorators.py
│ │ │ ├── helpers.py
│ │ │ ├── operations
│ │ │ │ ├── __init__.py
│ │ │ │ ├── create_api_cache.py
│ │ │ │ ├── create_api_key.py
│ │ │ │ ├── create_api.py
│ │ │ │ ├── create_channel_namespace.py
│ │ │ │ ├── create_datasource.py
│ │ │ │ ├── create_domain_name.py
│ │ │ │ ├── create_function.py
│ │ │ │ ├── create_graphql_api.py
│ │ │ │ ├── create_resolver.py
│ │ │ │ └── create_schema.py
│ │ │ ├── server.py
│ │ │ ├── tools
│ │ │ │ ├── __init__.py
│ │ │ │ ├── create_api_cache.py
│ │ │ │ ├── create_api_key.py
│ │ │ │ ├── create_api.py
│ │ │ │ ├── create_channel_namespace.py
│ │ │ │ ├── create_datasource.py
│ │ │ │ ├── create_domain_name.py
│ │ │ │ ├── create_function.py
│ │ │ │ ├── create_graphql_api.py
│ │ │ │ ├── create_resolver.py
│ │ │ │ └── create_schema.py
│ │ │ └── validators.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── test_all_create_tools_write_protection.py
│ │ │ ├── test_create_api_cache.py
│ │ │ ├── test_create_api_key.py
│ │ │ ├── test_create_api.py
│ │ │ ├── test_create_channel_namespace.py
│ │ │ ├── test_create_datasource_tool.py
│ │ │ ├── test_create_datasource.py
│ │ │ ├── test_create_domain_name.py
│ │ │ ├── test_create_function.py
│ │ │ ├── test_create_graphql_api.py
│ │ │ ├── test_create_resolver.py
│ │ │ ├── test_create_schema_tool.py
│ │ │ ├── test_create_schema.py
│ │ │ ├── test_helpers.py
│ │ │ ├── test_server.py
│ │ │ ├── test_validators.py
│ │ │ └── test_write_operation.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── aws-bedrock-custom-model-import-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── aws_bedrock_custom_model_import_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── client.py
│ │ │ ├── llm_context.py
│ │ │ ├── models.py
│ │ │ ├── prompts.py
│ │ │ ├── server.py
│ │ │ ├── services
│ │ │ │ ├── __init__.py
│ │ │ │ ├── imported_model_service.py
│ │ │ │ └── model_import_service.py
│ │ │ ├── tools
│ │ │ │ ├── create_model_import_job.py
│ │ │ │ ├── delete_imported_model.py
│ │ │ │ ├── get_imported_model.py
│ │ │ │ ├── get_model_import_job.py
│ │ │ │ ├── list_imported_models.py
│ │ │ │ └── list_model_import_jobs.py
│ │ │ └── utils
│ │ │ ├── __init__.py
│ │ │ ├── aws.py
│ │ │ ├── config.py
│ │ │ ├── consts.py
│ │ │ └── matching.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── services
│ │ │ │ ├── test_imported_model_service.py
│ │ │ │ └── test_model_import_service.py
│ │ │ ├── test_client.py
│ │ │ ├── test_init.py
│ │ │ ├── test_llm_context.py
│ │ │ ├── test_prompts.py
│ │ │ ├── test_server.py
│ │ │ ├── tools
│ │ │ │ ├── test_create_model_import_job.py
│ │ │ │ ├── test_delete_imported_model.py
│ │ │ │ ├── test_get_imported_model.py
│ │ │ │ ├── test_get_model_import_job.py
│ │ │ │ ├── test_list_imported_models.py
│ │ │ │ └── test_list_model_import_jobs.py
│ │ │ └── utils
│ │ │ ├── test_aws.py
│ │ │ ├── test_config.py
│ │ │ └── test_matching.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── aws-bedrock-data-automation-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── aws_bedrock_data_automation_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── helpers.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── test_helpers.py
│ │ │ ├── test_init.py
│ │ │ ├── test_main.py
│ │ │ └── test_server.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── aws-dataprocessing-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── aws_dataprocessing_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── core
│ │ │ │ ├── __init__.py
│ │ │ │ └── glue_data_catalog
│ │ │ │ ├── __init__.py
│ │ │ │ ├── data_catalog_database_manager.py
│ │ │ │ ├── data_catalog_handler.py
│ │ │ │ └── data_catalog_table_manager.py
│ │ │ ├── handlers
│ │ │ │ ├── __init__.py
│ │ │ │ ├── athena
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── athena_data_catalog_handler.py
│ │ │ │ │ ├── athena_query_handler.py
│ │ │ │ │ └── athena_workgroup_handler.py
│ │ │ │ ├── commons
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── common_resource_handler.py
│ │ │ │ ├── emr
│ │ │ │ │ ├── emr_ec2_cluster_handler.py
│ │ │ │ │ ├── emr_ec2_instance_handler.py
│ │ │ │ │ └── emr_ec2_steps_handler.py
│ │ │ │ └── glue
│ │ │ │ ├── __init__.py
│ │ │ │ ├── crawler_handler.py
│ │ │ │ ├── data_catalog_handler.py
│ │ │ │ ├── glue_commons_handler.py
│ │ │ │ ├── glue_etl_handler.py
│ │ │ │ ├── interactive_sessions_handler.py
│ │ │ │ └── worklows_handler.py
│ │ │ ├── models
│ │ │ │ ├── __init__.py
│ │ │ │ ├── athena_models.py
│ │ │ │ ├── common_resource_models.py
│ │ │ │ ├── data_catalog_models.py
│ │ │ │ ├── emr_models.py
│ │ │ │ └── glue_models.py
│ │ │ ├── server.py
│ │ │ └── utils
│ │ │ ├── __init__.py
│ │ │ ├── aws_helper.py
│ │ │ ├── consts.py
│ │ │ ├── logging_helper.py
│ │ │ └── sql_analyzer.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── core
│ │ │ │ ├── __init__.py
│ │ │ │ └── glue_data_catalog
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_data_catalog_database_manager.py
│ │ │ │ ├── test_data_catalog_handler.py
│ │ │ │ └── test_data_catalog_table_manager.py
│ │ │ ├── handlers
│ │ │ │ ├── __init__.py
│ │ │ │ ├── athena
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── test_athena_data_catalog_handler.py
│ │ │ │ │ ├── test_athena_query_handler.py
│ │ │ │ │ ├── test_athena_workgroup_handler.py
│ │ │ │ │ └── test_custom_tags_athena.py
│ │ │ │ ├── commons
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── test_common_resource_handler.py
│ │ │ │ ├── emr
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── test_custom_tags_emr.py
│ │ │ │ │ ├── test_emr_ec2_cluster_handler.py
│ │ │ │ │ ├── test_emr_ec2_instance_handler.py
│ │ │ │ │ └── test_emr_ec2_steps_handler.py
│ │ │ │ └── glue
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_crawler_handler.py
│ │ │ │ ├── test_custom_tags_glue.py
│ │ │ │ ├── test_data_catalog_handler.py
│ │ │ │ ├── test_glue_commons_handler.py
│ │ │ │ ├── test_glue_etl_handler.py
│ │ │ │ ├── test_glue_interactive_sessions_handler.py
│ │ │ │ └── test_glue_workflows_handler.py
│ │ │ ├── models
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_athena_models.py
│ │ │ │ ├── test_common_resource_models.py
│ │ │ │ ├── test_data_catalog_models.py
│ │ │ │ ├── test_emr_models.py
│ │ │ │ ├── test_glue_models.py
│ │ │ │ ├── test_interactive_sessions_models.py
│ │ │ │ └── test_workflows_models.py
│ │ │ ├── test_init.py
│ │ │ ├── test_server.py
│ │ │ └── utils
│ │ │ ├── __init__.py
│ │ │ ├── test_aws_helper.py
│ │ │ ├── test_custom_tags.py
│ │ │ ├── test_logging_helper.py
│ │ │ └── test_sql_analyzer.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── aws-diagram-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── aws_diagram_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── diagrams_tools.py
│ │ │ ├── models.py
│ │ │ ├── scanner.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── .gitignore
│ │ │ ├── conftest.py
│ │ │ ├── README.md
│ │ │ ├── resources
│ │ │ │ ├── __init__.py
│ │ │ │ └── example_diagrams
│ │ │ │ ├── __init__.py
│ │ │ │ ├── aws_example.py
│ │ │ │ ├── flow_example.py
│ │ │ │ └── sequence_example.py
│ │ │ ├── test_diagrams.py
│ │ │ ├── test_models.py
│ │ │ ├── test_sarif_fix.py
│ │ │ ├── test_scanner.py
│ │ │ └── test_server.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── aws-documentation-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── aws_documentation_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── models.py
│ │ │ ├── server_aws_cn.py
│ │ │ ├── server_aws.py
│ │ │ ├── server_utils.py
│ │ │ ├── server.py
│ │ │ └── util.py
│ │ ├── basic-usage.gif
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── conftest.py
│ │ │ ├── constants.py
│ │ │ ├── resources
│ │ │ │ └── lambda_sns_raw.html
│ │ │ ├── test_aws_cn_get_available_services_live.py
│ │ │ ├── test_aws_cn_read_documentation_live.py
│ │ │ ├── test_aws_read_documentation_live.py
│ │ │ ├── test_aws_recommend_live.py
│ │ │ ├── test_aws_search_live.py
│ │ │ ├── test_integ_basic.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
│ │ │ │ ├── __init__.py
│ │ │ │ ├── core.py
│ │ │ │ ├── s3.py
│ │ │ │ └── search.py
│ │ │ ├── search
│ │ │ │ ├── __init__.py
│ │ │ │ ├── file_association_engine.py
│ │ │ │ ├── file_type_detector.py
│ │ │ │ ├── genomics_search_orchestrator.py
│ │ │ │ ├── healthomics_search_engine.py
│ │ │ │ ├── json_response_builder.py
│ │ │ │ ├── pattern_matcher.py
│ │ │ │ ├── result_ranker.py
│ │ │ │ ├── s3_search_engine.py
│ │ │ │ └── scoring_engine.py
│ │ │ ├── server.py
│ │ │ ├── tools
│ │ │ │ ├── __init__.py
│ │ │ │ ├── genomics_file_search.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
│ │ │ ├── search_config.py
│ │ │ └── validation_utils.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── docs
│ │ │ └── workflow_linting.md
│ │ ├── LICENSE
│ │ ├── MCP_INSPECTOR_SETUP.md
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── conftest.py
│ │ │ ├── fixtures
│ │ │ │ └── genomics_test_data.py
│ │ │ ├── INTEGRATION_TESTS_README.md
│ │ │ ├── QUICK_REFERENCE.md
│ │ │ ├── test_aws_utils.py
│ │ │ ├── test_consts.py
│ │ │ ├── test_file_association_engine.py
│ │ │ ├── test_file_type_detector.py
│ │ │ ├── test_genomics_file_search_integration_working.py
│ │ │ ├── test_genomics_search_orchestrator.py
│ │ │ ├── test_healthomics_search_engine.py
│ │ │ ├── test_helper_tools.py
│ │ │ ├── test_helpers.py
│ │ │ ├── test_init.py
│ │ │ ├── test_integration_framework.py
│ │ │ ├── test_json_response_builder.py
│ │ │ ├── test_main.py
│ │ │ ├── test_models.py
│ │ │ ├── test_pagination.py
│ │ │ ├── test_pattern_matcher.py
│ │ │ ├── test_performance_comparison.py
│ │ │ ├── test_result_ranker.py
│ │ │ ├── test_run_analysis.py
│ │ │ ├── test_s3_file_model.py
│ │ │ ├── test_s3_search_engine.py
│ │ │ ├── test_s3_utils.py
│ │ │ ├── test_scoring_engine.py
│ │ │ ├── test_search_config.py
│ │ │ ├── test_server.py
│ │ │ ├── test_troubleshooting.py
│ │ │ ├── test_validation_utils.py
│ │ │ ├── test_workflow_analysis.py
│ │ │ ├── test_workflow_execution.py
│ │ │ ├── test_workflow_linting.py
│ │ │ ├── test_workflow_management.py
│ │ │ ├── test_workflow_tools.py
│ │ │ └── TESTING_FRAMEWORK.md
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── aws-iot-sitewise-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── aws_iot_sitewise_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── client.py
│ │ │ ├── models
│ │ │ │ ├── computation_data_models.py
│ │ │ │ └── metadata_transfer_data_models.py
│ │ │ ├── prompts
│ │ │ │ ├── __init__.py
│ │ │ │ ├── anomaly_detection_workflow.py
│ │ │ │ ├── asset_hierarchy.py
│ │ │ │ ├── bulk_import_workflow.py
│ │ │ │ ├── data_exploration.py
│ │ │ │ └── data_ingestion.py
│ │ │ ├── server.py
│ │ │ ├── tool_metadata.py
│ │ │ ├── tools
│ │ │ │ ├── __init__.py
│ │ │ │ ├── sitewise_access.py
│ │ │ │ ├── sitewise_asset_models.py
│ │ │ │ ├── sitewise_assets.py
│ │ │ │ ├── sitewise_computation_models.py
│ │ │ │ ├── sitewise_data.py
│ │ │ │ ├── sitewise_executions.py
│ │ │ │ ├── sitewise_gateways.py
│ │ │ │ ├── sitewise_metadata_transfer.py
│ │ │ │ └── timestamp_tools.py
│ │ │ ├── validation_utils.py
│ │ │ └── validation.py
│ │ ├── CHANGELOG.md
│ │ ├── DEVELOPMENT.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── examples
│ │ │ └── wind_farm_example.py
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── run_server.py
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── conftest.py
│ │ │ ├── models
│ │ │ │ ├── test_computation_data_models.py
│ │ │ │ └── test_metadata_transfer_data_models.py
│ │ │ ├── test_client.py
│ │ │ ├── test_init.py
│ │ │ ├── test_main.py
│ │ │ ├── test_server.py
│ │ │ ├── test_validation_utils.py
│ │ │ ├── test_validation.py
│ │ │ └── tools
│ │ │ ├── test_sitewise_access.py
│ │ │ ├── test_sitewise_asset_models.py
│ │ │ ├── test_sitewise_assets.py
│ │ │ ├── test_sitewise_computation_models.py
│ │ │ ├── test_sitewise_data.py
│ │ │ ├── test_sitewise_executions.py
│ │ │ ├── test_sitewise_gateways.py
│ │ │ ├── test_sitewise_metadata_transfer.py
│ │ │ └── test_timestamp_tools.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── aws-knowledge-mcp-server
│ │ └── README.md
│ ├── aws-location-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── aws_location_server
│ │ │ ├── __init__.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── conftest.py
│ │ │ ├── test_server_integration.py
│ │ │ └── test_server.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── aws-msk-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── aws_msk_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── server.py
│ │ │ └── tools
│ │ │ ├── __init__.py
│ │ │ ├── common_functions
│ │ │ │ ├── __init__.py
│ │ │ │ ├── client_manager.py
│ │ │ │ └── common_functions.py
│ │ │ ├── logs_and_telemetry
│ │ │ │ ├── __init__.py
│ │ │ │ ├── cluster_metrics_tools.py
│ │ │ │ ├── list_customer_iam_access.py
│ │ │ │ └── metric_config.py
│ │ │ ├── mutate_cluster
│ │ │ │ ├── __init__.py
│ │ │ │ ├── batch_associate_scram_secret.py
│ │ │ │ ├── batch_disassociate_scram_secret.py
│ │ │ │ ├── create_cluster_v2.py
│ │ │ │ ├── put_cluster_policy.py
│ │ │ │ ├── reboot_broker.py
│ │ │ │ ├── update_broker_count.py
│ │ │ │ ├── update_broker_storage.py
│ │ │ │ ├── update_broker_type.py
│ │ │ │ ├── update_cluster_configuration.py
│ │ │ │ ├── update_monitoring.py
│ │ │ │ └── update_security.py
│ │ │ ├── mutate_config
│ │ │ │ ├── __init__.py
│ │ │ │ ├── create_configuration.py
│ │ │ │ ├── tag_resource.py
│ │ │ │ ├── untag_resource.py
│ │ │ │ └── update_configuration.py
│ │ │ ├── mutate_vpc
│ │ │ │ ├── __init__.py
│ │ │ │ ├── create_vpc_connection.py
│ │ │ │ ├── delete_vpc_connection.py
│ │ │ │ └── reject_client_vpc_connection.py
│ │ │ ├── read_cluster
│ │ │ │ ├── __init__.py
│ │ │ │ ├── describe_cluster_operation.py
│ │ │ │ ├── describe_cluster.py
│ │ │ │ ├── get_bootstrap_brokers.py
│ │ │ │ ├── get_cluster_policy.py
│ │ │ │ ├── get_compatible_kafka_versions.py
│ │ │ │ ├── list_client_vpc_connections.py
│ │ │ │ ├── list_cluster_operations.py
│ │ │ │ ├── list_nodes.py
│ │ │ │ └── list_scram_secrets.py
│ │ │ ├── read_config
│ │ │ │ ├── __init__.py
│ │ │ │ ├── describe_configuration_revision.py
│ │ │ │ ├── describe_configuration.py
│ │ │ │ ├── list_configuration_revisions.py
│ │ │ │ └── list_tags_for_resource.py
│ │ │ ├── read_global
│ │ │ │ ├── __init__.py
│ │ │ │ ├── list_clusters.py
│ │ │ │ ├── list_configurations.py
│ │ │ │ ├── list_kafka_versions.py
│ │ │ │ └── list_vpc_connections.py
│ │ │ ├── read_vpc
│ │ │ │ ├── __init__.py
│ │ │ │ └── describe_vpc_connection.py
│ │ │ └── static_tools
│ │ │ ├── __init__.py
│ │ │ └── cluster_best_practices.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── test_client_manager.py
│ │ │ ├── test_cluster_metrics_tools.py
│ │ │ ├── test_common_functions.py
│ │ │ ├── test_create_cluster_v2.py
│ │ │ ├── test_create_configuration.py
│ │ │ ├── test_create_vpc_connection.py
│ │ │ ├── test_delete_vpc_connection.py
│ │ │ ├── test_describe_cluster_operation.py
│ │ │ ├── test_describe_cluster.py
│ │ │ ├── test_describe_configuration_revision.py
│ │ │ ├── test_describe_configuration.py
│ │ │ ├── test_describe_vpc_connection.py
│ │ │ ├── test_get_bootstrap_brokers.py
│ │ │ ├── test_get_cluster_policy.py
│ │ │ ├── test_get_compatible_kafka_versions.py
│ │ │ ├── test_init.py
│ │ │ ├── test_list_client_vpc_connections.py
│ │ │ ├── test_list_cluster_operations.py
│ │ │ ├── test_list_clusters.py
│ │ │ ├── test_list_configuration_revisions.py
│ │ │ ├── test_list_configurations.py
│ │ │ ├── test_list_customer_iam_access.py
│ │ │ ├── test_list_kafka_versions.py
│ │ │ ├── test_list_nodes.py
│ │ │ ├── test_list_scram_secrets.py
│ │ │ ├── test_list_tags_for_resource.py
│ │ │ ├── test_list_vpc_connections.py
│ │ │ ├── test_logs_and_telemetry.py
│ │ │ ├── test_main.py
│ │ │ ├── test_mutate_cluster_init.py
│ │ │ ├── test_mutate_cluster_success_cases.py
│ │ │ ├── test_mutate_cluster.py
│ │ │ ├── test_mutate_config_init.py
│ │ │ ├── test_mutate_vpc_init.py
│ │ │ ├── test_read_cluster_init_updated.py
│ │ │ ├── test_read_cluster_init.py
│ │ │ ├── test_read_config_init.py
│ │ │ ├── test_read_global_init.py
│ │ │ ├── test_read_vpc_init.py
│ │ │ ├── test_reject_client_vpc_connection.py
│ │ │ ├── test_server.py
│ │ │ ├── test_static_tools_init.py
│ │ │ ├── test_tag_resource.py
│ │ │ ├── test_tool_descriptions.py
│ │ │ ├── test_untag_resource.py
│ │ │ └── test_update_configuration.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── aws-pricing-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── aws_pricing_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── cdk_analyzer.py
│ │ │ ├── consts.py
│ │ │ ├── helpers.py
│ │ │ ├── models.py
│ │ │ ├── pricing_client.py
│ │ │ ├── pricing_transformer.py
│ │ │ ├── report_generator.py
│ │ │ ├── server.py
│ │ │ ├── static
│ │ │ │ ├── __init__.py
│ │ │ │ ├── COST_REPORT_TEMPLATE.md
│ │ │ │ └── patterns
│ │ │ │ ├── __init__.py
│ │ │ │ └── BEDROCK.md
│ │ │ └── terraform_analyzer.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── conftest.py
│ │ │ ├── test_cdk_analyzer.py
│ │ │ ├── test_helpers.py
│ │ │ ├── test_pricing_client.py
│ │ │ ├── test_pricing_transformer.py
│ │ │ ├── test_report_generator.py
│ │ │ ├── test_server.py
│ │ │ └── test_terraform_analyzer.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── aws-serverless-mcp-server
│ │ ├── .pre-commit.config.yaml
│ │ ├── .python-version
│ │ ├── .secrets.baseline
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── aws_serverless_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── models.py
│ │ │ ├── resources
│ │ │ │ ├── __init__.py
│ │ │ │ ├── deployment_details.py
│ │ │ │ ├── deployment_list.py
│ │ │ │ ├── template_details.py
│ │ │ │ └── template_list.py
│ │ │ ├── server.py
│ │ │ ├── template
│ │ │ │ ├── __init__.py
│ │ │ │ ├── registry.py
│ │ │ │ ├── renderer.py
│ │ │ │ └── templates
│ │ │ │ ├── backend.j2
│ │ │ │ ├── frontend.j2
│ │ │ │ ├── fullstack.j2
│ │ │ │ └── README.md
│ │ │ ├── templates
│ │ │ │ ├── __init__.py
│ │ │ │ └── iam_policies.py
│ │ │ ├── tools
│ │ │ │ ├── common
│ │ │ │ │ └── base_tool.py
│ │ │ │ ├── esm
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── esm_diagnosis.py
│ │ │ │ │ ├── esm_guidance.py
│ │ │ │ │ ├── esm_recommend.py
│ │ │ │ │ └── secure_esm_guidance.py
│ │ │ │ ├── guidance
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── deploy_serverless_app_help.py
│ │ │ │ │ ├── get_iac_guidance.py
│ │ │ │ │ ├── get_lambda_event_schemas.py
│ │ │ │ │ ├── get_lambda_guidance.py
│ │ │ │ │ └── get_serverless_templates.py
│ │ │ │ ├── poller
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── esm_diagnosis.py
│ │ │ │ │ ├── esm_guidance.py
│ │ │ │ │ └── esm_recommend.py
│ │ │ │ ├── sam
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── sam_build.py
│ │ │ │ │ ├── sam_deploy.py
│ │ │ │ │ ├── sam_init.py
│ │ │ │ │ ├── sam_local_invoke.py
│ │ │ │ │ └── sam_logs.py
│ │ │ │ ├── schemas
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── describe_schema.py
│ │ │ │ │ ├── list_registries.py
│ │ │ │ │ └── search_schema.py
│ │ │ │ └── webapps
│ │ │ │ ├── __init__.py
│ │ │ │ ├── configure_domain.py
│ │ │ │ ├── deploy_webapp.py
│ │ │ │ ├── get_metrics.py
│ │ │ │ ├── update_webapp_frontend.py
│ │ │ │ ├── utils
│ │ │ │ │ ├── deploy_service.py
│ │ │ │ │ ├── frontend_uploader.py
│ │ │ │ │ └── startup_script_generator.py
│ │ │ │ └── webapp_deployment_help.py
│ │ │ └── utils
│ │ │ ├── __init__.py
│ │ │ ├── aws_client_helper.py
│ │ │ ├── cloudformation.py
│ │ │ ├── const.py
│ │ │ ├── data_scrubber.py
│ │ │ ├── deployment_manager.py
│ │ │ ├── github.py
│ │ │ └── process.py
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── conftest.py
│ │ │ ├── README.md
│ │ │ ├── test_cloudformation.py
│ │ │ ├── test_configure_domain.py
│ │ │ ├── test_data_scrubber.py
│ │ │ ├── test_deploy_serverless_app_help.py
│ │ │ ├── test_deploy_service.py
│ │ │ ├── test_deploy_webapp.py
│ │ │ ├── test_deployment_details.py
│ │ │ ├── test_deployment_help.py
│ │ │ ├── test_deployment_list.py
│ │ │ ├── test_deployment_manager.py
│ │ │ ├── test_esm_diagnosis.py
│ │ │ ├── test_esm_guidance.py
│ │ │ ├── test_esm_recommend.py
│ │ │ ├── test_frontend_uploader.py
│ │ │ ├── test_get_iac_guidance.py
│ │ │ ├── test_get_lambda_event_schemas.py
│ │ │ ├── test_get_lambda_guidance.py
│ │ │ ├── test_get_metrics.py
│ │ │ ├── test_get_serverless_templates.py
│ │ │ ├── test_github.py
│ │ │ ├── test_iam_policies.py
│ │ │ ├── test_models.py
│ │ │ ├── test_process.py
│ │ │ ├── test_sam_build.py
│ │ │ ├── test_sam_deploy.py
│ │ │ ├── test_sam_init.py
│ │ │ ├── test_sam_local_invoke.py
│ │ │ ├── test_sam_logs.py
│ │ │ ├── test_schemas.py
│ │ │ ├── test_secure_esm_guidance.py
│ │ │ ├── test_server.py
│ │ │ ├── test_startup_script_generator.py
│ │ │ ├── test_template_details.py
│ │ │ ├── test_template_list.py
│ │ │ ├── test_template_registry.py
│ │ │ ├── test_template_renderer.py
│ │ │ └── test_update_webapp_frontend.py
│ │ └── uv.lock
│ ├── aws-support-mcp-server
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── aws_support_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── client.py
│ │ │ ├── consts.py
│ │ │ ├── debug_helper.py
│ │ │ ├── errors.py
│ │ │ ├── formatters.py
│ │ │ ├── models.py
│ │ │ └── server.py
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── conftests.py
│ │ │ ├── test_aws_support_mcp_server.py
│ │ │ └── test_models.py
│ │ └── uv.lock
│ ├── bedrock-kb-retrieval-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── bedrock_kb_retrieval_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── knowledgebases
│ │ │ │ ├── __init__.py
│ │ │ │ ├── clients.py
│ │ │ │ ├── discovery.py
│ │ │ │ └── retrieval.py
│ │ │ ├── models.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── run_tests.sh
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── .gitignore
│ │ │ ├── conftest.py
│ │ │ ├── README.md
│ │ │ ├── test_clients.py
│ │ │ ├── test_discovery.py
│ │ │ ├── test_env_config.py
│ │ │ ├── test_models.py
│ │ │ ├── test_retrieval.py
│ │ │ └── test_server.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── billing-cost-management-mcp-server
│ │ ├── __init__.py
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── billing_cost_management_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── models.py
│ │ │ ├── prompts
│ │ │ │ ├── __init__.py
│ │ │ │ ├── decorator.py
│ │ │ │ ├── graviton_migration.py
│ │ │ │ ├── README.md
│ │ │ │ ├── savings_plans.py
│ │ │ │ └── types.py
│ │ │ ├── server.py
│ │ │ ├── templates
│ │ │ │ └── recommendation_templates
│ │ │ │ ├── ebs_volume.template
│ │ │ │ ├── ec2_asg.template
│ │ │ │ ├── ec2_instance.template
│ │ │ │ ├── ecs_service.template
│ │ │ │ ├── idle.template
│ │ │ │ ├── lambda_function.template
│ │ │ │ ├── rds_database.template
│ │ │ │ ├── reserved_instances.template
│ │ │ │ └── savings_plans.template
│ │ │ ├── tools
│ │ │ │ ├── __init__.py
│ │ │ │ ├── aws_pricing_operations.py
│ │ │ │ ├── aws_pricing_tools.py
│ │ │ │ ├── bcm_pricing_calculator_tools.py
│ │ │ │ ├── budget_tools.py
│ │ │ │ ├── compute_optimizer_tools.py
│ │ │ │ ├── cost_anomaly_tools.py
│ │ │ │ ├── cost_comparison_tools.py
│ │ │ │ ├── cost_explorer_operations.py
│ │ │ │ ├── cost_explorer_tools.py
│ │ │ │ ├── cost_optimization_hub_helpers.py
│ │ │ │ ├── cost_optimization_hub_tools.py
│ │ │ │ ├── free_tier_usage_tools.py
│ │ │ │ ├── recommendation_details_tools.py
│ │ │ │ ├── ri_performance_tools.py
│ │ │ │ ├── sp_performance_tools.py
│ │ │ │ ├── storage_lens_tools.py
│ │ │ │ └── unified_sql_tools.py
│ │ │ └── utilities
│ │ │ ├── __init__.py
│ │ │ ├── aws_service_base.py
│ │ │ ├── constants.py
│ │ │ ├── logging_utils.py
│ │ │ └── sql_utils.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── requirements.txt
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── conftest.py
│ │ │ ├── prompts
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_prompts.py
│ │ │ ├── README.md
│ │ │ ├── test_models.py
│ │ │ ├── test_server.py
│ │ │ ├── tools
│ │ │ │ ├── __init__.py
│ │ │ │ ├── fixtures.py
│ │ │ │ ├── test_aws_bcm_pricing_calculator_tools.py
│ │ │ │ ├── test_aws_pricing_tools.py
│ │ │ │ ├── test_budget_tools.py
│ │ │ │ ├── test_compute_optimizer_tools.py
│ │ │ │ ├── test_cost_anomaly_tools_enhanced.py
│ │ │ │ ├── test_cost_anomaly_tools.py
│ │ │ │ ├── test_cost_comparison_tools.py
│ │ │ │ ├── test_cost_explorer_operations.py
│ │ │ │ ├── test_cost_explorer_tools.py
│ │ │ │ ├── test_cost_optimization_hub_helpers.py
│ │ │ │ ├── test_cost_optimization_hub_tools.py
│ │ │ │ ├── test_free_tier_usage_tools_new.py
│ │ │ │ ├── test_recommendation_details_tools.py
│ │ │ │ ├── test_ri_performance_tools.py
│ │ │ │ ├── test_sp_performance_tools.py
│ │ │ │ ├── test_storage_lens_tools.py
│ │ │ │ └── test_unified_sql_tools.py
│ │ │ └── utilities
│ │ │ ├── test_aws_service_base.py
│ │ │ └── test_sql_utils.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── ccapi-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── ccapi_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── aws_client.py
│ │ │ ├── cloud_control_utils.py
│ │ │ ├── context.py
│ │ │ ├── errors.py
│ │ │ ├── iac_generator.py
│ │ │ ├── impl
│ │ │ │ ├── __init__.py
│ │ │ │ ├── tools
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── explanation.py
│ │ │ │ │ ├── infrastructure_generation.py
│ │ │ │ │ ├── resource_operations.py
│ │ │ │ │ ├── security_scanning.py
│ │ │ │ │ └── session_management.py
│ │ │ │ └── utils
│ │ │ │ ├── __init__.py
│ │ │ │ └── validation.py
│ │ │ ├── infrastructure_generator.py
│ │ │ ├── models
│ │ │ │ ├── __init__.py
│ │ │ │ └── models.py
│ │ │ ├── schema_manager.py
│ │ │ ├── server.py
│ │ │ └── static
│ │ │ └── __init__.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── run_tests.sh
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── test_aws_client.py
│ │ │ ├── test_checkov_install.py
│ │ │ ├── test_cloud_control_utils.py
│ │ │ ├── test_context.py
│ │ │ ├── test_errors.py
│ │ │ ├── test_explanation.py
│ │ │ ├── test_iac_generator.py
│ │ │ ├── test_infrastructure_generation.py
│ │ │ ├── test_infrastructure_generator.py
│ │ │ ├── test_models.py
│ │ │ ├── test_resource_operations.py
│ │ │ ├── test_schema_manager.py
│ │ │ ├── test_security_scanning.py
│ │ │ ├── test_server.py
│ │ │ ├── test_session_management.py
│ │ │ └── test_validation.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── cdk-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── cdk_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── core
│ │ │ │ ├── __init__.py
│ │ │ │ ├── resources.py
│ │ │ │ ├── search_utils.py
│ │ │ │ ├── server.py
│ │ │ │ └── tools.py
│ │ │ ├── data
│ │ │ │ ├── __init__.py
│ │ │ │ ├── cdk_nag_parser.py
│ │ │ │ ├── construct_descriptions.py
│ │ │ │ ├── genai_cdk_loader.py
│ │ │ │ ├── lambda_layer_parser.py
│ │ │ │ ├── lambda_powertools_loader.py
│ │ │ │ ├── schema_generator.py
│ │ │ │ └── solutions_constructs_parser.py
│ │ │ ├── server.py
│ │ │ └── static
│ │ │ ├── __init__.py
│ │ │ ├── CDK_GENERAL_GUIDANCE.md
│ │ │ ├── CDK_NAG_GUIDANCE.md
│ │ │ └── lambda_powertools
│ │ │ ├── bedrock.md
│ │ │ ├── cdk.md
│ │ │ ├── dependencies.md
│ │ │ ├── index.md
│ │ │ ├── insights.md
│ │ │ ├── logging.md
│ │ │ ├── metrics.md
│ │ │ └── tracing.md
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── core
│ │ │ │ ├── test_resources_enhanced.py
│ │ │ │ ├── test_resources.py
│ │ │ │ ├── test_search_utils.py
│ │ │ │ ├── test_server.py
│ │ │ │ └── test_tools.py
│ │ │ └── data
│ │ │ ├── test_cdk_nag_parser.py
│ │ │ ├── test_genai_cdk_loader.py
│ │ │ ├── test_lambda_powertools_loader.py
│ │ │ ├── test_schema_generator.py
│ │ │ └── test_solutions_constructs_parser.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── cfn-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── cfn_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── aws_client.py
│ │ │ ├── cloud_control_utils.py
│ │ │ ├── context.py
│ │ │ ├── errors.py
│ │ │ ├── iac_generator.py
│ │ │ ├── schema_manager.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── run_tests.sh
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── test_aws_client.py
│ │ │ ├── test_cloud_control_utils.py
│ │ │ ├── test_errors.py
│ │ │ ├── test_iac_generator.py
│ │ │ ├── test_init.py
│ │ │ ├── test_main.py
│ │ │ ├── test_schema_manager.py
│ │ │ └── test_server.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── cloudtrail-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── cloudtrail_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── common.py
│ │ │ ├── models.py
│ │ │ ├── server.py
│ │ │ └── tools.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── conftest.py
│ │ │ ├── test_init.py
│ │ │ ├── test_main.py
│ │ │ ├── test_models.py
│ │ │ ├── test_server.py
│ │ │ └── test_tools.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── cloudwatch-applicationsignals-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── cloudwatch_applicationsignals_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── audit_presentation_utils.py
│ │ │ ├── audit_utils.py
│ │ │ ├── aws_clients.py
│ │ │ ├── canary_utils.py
│ │ │ ├── enablement_guides
│ │ │ │ └── templates
│ │ │ │ └── ec2
│ │ │ │ └── ec2-python-enablement.md
│ │ │ ├── enablement_tools.py
│ │ │ ├── server.py
│ │ │ ├── service_audit_utils.py
│ │ │ ├── service_tools.py
│ │ │ ├── sli_report_client.py
│ │ │ ├── slo_tools.py
│ │ │ ├── trace_tools.py
│ │ │ └── utils.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── evals
│ │ │ ├── __init__.py
│ │ │ ├── __main__.py
│ │ │ ├── core
│ │ │ │ ├── __init__.py
│ │ │ │ ├── captor.py
│ │ │ │ ├── conversation_runner.py
│ │ │ │ ├── eval_config.py
│ │ │ │ ├── eval_mcp_server_wrapper.py
│ │ │ │ ├── eval_runner.py
│ │ │ │ ├── file_tools.py
│ │ │ │ ├── llm_provider.py
│ │ │ │ ├── mcp_client.py
│ │ │ │ ├── mcp_dependency_mocking_handler.py
│ │ │ │ ├── metrics_tracker.py
│ │ │ │ ├── mock_config_path_normalizer.py
│ │ │ │ ├── process_executor.py
│ │ │ │ ├── task_result.py
│ │ │ │ ├── task.py
│ │ │ │ ├── validation_prompts.py
│ │ │ │ └── validator.py
│ │ │ ├── README.md
│ │ │ ├── requirements.txt
│ │ │ └── tasks
│ │ │ ├── __init__.py
│ │ │ └── applicationsignals
│ │ │ ├── __init__.py
│ │ │ ├── base.py
│ │ │ ├── get_enablement_guide
│ │ │ │ ├── __init__.py
│ │ │ │ └── enablement_tasks.py
│ │ │ └── investigations
│ │ │ ├── __init__.py
│ │ │ ├── fixtures
│ │ │ │ ├── bug-4-list-audit-findings-all-services-all-auditors.json
│ │ │ │ ├── bug-4-list-audit-findings-all-services-default-auditors.json
│ │ │ │ ├── bug-4-list-audit-findings-document-service-and-all-auditors.json
│ │ │ │ └── bug-4-list-services.json
│ │ │ └── investigation_tasks.py
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── conftest.py
│ │ │ ├── test_audit_presentation_utils.py
│ │ │ ├── test_audit_utils.py
│ │ │ ├── test_aws_profile.py
│ │ │ ├── test_canary_utils.py
│ │ │ ├── test_enablement_tools.py
│ │ │ ├── test_initialization.py
│ │ │ ├── test_server_audit_functions.py
│ │ │ ├── test_server_audit_tools.py
│ │ │ ├── test_server.py
│ │ │ ├── test_service_audit_utils.py
│ │ │ ├── test_service_tools_operations.py
│ │ │ ├── test_sli_report_client.py
│ │ │ ├── test_slo_tools.py
│ │ │ └── test_utils.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── cloudwatch-appsignals-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── cloudwatch_appsignals_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── audit_presentation_utils.py
│ │ │ ├── audit_utils.py
│ │ │ ├── aws_clients.py
│ │ │ ├── canary_utils.py
│ │ │ ├── enablement_guides
│ │ │ │ └── templates
│ │ │ │ └── ec2
│ │ │ │ └── ec2-python-enablement.md
│ │ │ ├── enablement_tools.py
│ │ │ ├── server.py
│ │ │ ├── service_audit_utils.py
│ │ │ ├── service_tools.py
│ │ │ ├── sli_report_client.py
│ │ │ ├── slo_tools.py
│ │ │ ├── trace_tools.py
│ │ │ └── utils.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── conftest.py
│ │ │ ├── test_audit_presentation_utils.py
│ │ │ ├── test_audit_utils.py
│ │ │ ├── test_aws_profile.py
│ │ │ ├── test_canary_utils.py
│ │ │ ├── test_enablement_tools.py
│ │ │ ├── test_initialization.py
│ │ │ ├── test_server_audit_functions.py
│ │ │ ├── test_server_audit_tools.py
│ │ │ ├── test_server.py
│ │ │ ├── test_service_audit_utils.py
│ │ │ ├── test_service_tools_operations.py
│ │ │ ├── test_sli_report_client.py
│ │ │ ├── test_slo_tools.py
│ │ │ └── test_utils.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── cloudwatch-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── cloudwatch_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── cloudwatch_alarms
│ │ │ │ ├── models.py
│ │ │ │ └── tools.py
│ │ │ ├── cloudwatch_logs
│ │ │ │ ├── models.py
│ │ │ │ └── tools.py
│ │ │ ├── cloudwatch_metrics
│ │ │ │ ├── cloudformation_template_generator.py
│ │ │ │ ├── constants.py
│ │ │ │ ├── data
│ │ │ │ │ └── metric_metadata.json
│ │ │ │ ├── metric_analyzer.py
│ │ │ │ ├── metric_data_decomposer.py
│ │ │ │ ├── models.py
│ │ │ │ └── tools.py
│ │ │ ├── common.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── cloudwatch_alarms
│ │ │ │ ├── test_active_alarms.py
│ │ │ │ ├── test_alarm_history_integration.py
│ │ │ │ ├── test_alarm_history.py
│ │ │ │ └── test_alarms_error_handling.py
│ │ │ ├── cloudwatch_logs
│ │ │ │ ├── test_logs_error_handling.py
│ │ │ │ ├── test_logs_models.py
│ │ │ │ └── test_logs_server.py
│ │ │ ├── cloudwatch_metrics
│ │ │ │ ├── test_analyze_metric.py
│ │ │ │ ├── test_cloudformation_template_generator.py
│ │ │ │ ├── test_decomposer_trend.py
│ │ │ │ ├── test_metric_analyzer.py
│ │ │ │ ├── test_metrics_error_handling.py
│ │ │ │ ├── test_metrics_models.py
│ │ │ │ ├── test_metrics_server.py
│ │ │ │ ├── test_seasonal_detector.py
│ │ │ │ ├── test_seasonality_enum.py
│ │ │ │ ├── test_utils.py
│ │ │ │ └── test_validation_error.py
│ │ │ ├── test_common_and_server.py
│ │ │ ├── test_init.py
│ │ │ └── test_main.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── code-doc-gen-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── code_doc_gen_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── server.py
│ │ │ └── utils
│ │ │ ├── doc_generator.py
│ │ │ ├── models.py
│ │ │ ├── repomix_manager.py
│ │ │ └── templates.py
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── test_doc_generator_edge_cases.py
│ │ │ ├── test_doc_generator.py
│ │ │ ├── test_init.py
│ │ │ ├── test_main.py
│ │ │ ├── test_repomix_manager_scenarios.py
│ │ │ ├── test_repomix_manager.py
│ │ │ ├── test_repomix_statistics.py
│ │ │ ├── test_server_extended.py
│ │ │ ├── test_server.py
│ │ │ └── test_templates.py
│ │ └── uv.lock
│ ├── core-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── core_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── server.py
│ │ │ └── static
│ │ │ ├── __init__.py
│ │ │ └── PROMPT_UNDERSTANDING.md
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── conftest.py
│ │ │ ├── README.md
│ │ │ ├── test_init.py
│ │ │ ├── test_main.py
│ │ │ ├── test_response_types.py
│ │ │ ├── test_server.py
│ │ │ └── test_static.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── cost-explorer-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── cost_explorer_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── comparison_handler.py
│ │ │ ├── constants.py
│ │ │ ├── cost_usage_handler.py
│ │ │ ├── forecasting_handler.py
│ │ │ ├── helpers.py
│ │ │ ├── metadata_handler.py
│ │ │ ├── models.py
│ │ │ ├── server.py
│ │ │ └── utility_handler.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── conftest.py
│ │ │ ├── test_comparison_handler.py
│ │ │ ├── test_cost_usage_handler.py
│ │ │ ├── test_forecasting_handler.py
│ │ │ ├── test_helpers.py
│ │ │ ├── test_metadata_handler.py
│ │ │ ├── test_models.py
│ │ │ ├── test_server.py
│ │ │ └── test_utility_handler.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── document-loader-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ ├── document_loader_mcp_server
│ │ │ │ ├── __init__.py
│ │ │ │ └── server.py
│ │ │ └── py.typed
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── test_document_parsing.py
│ │ │ └── test_server.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── documentdb-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ └── documentdb_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── analytic_tools.py
│ │ │ ├── config.py
│ │ │ ├── connection_tools.py
│ │ │ ├── db_management_tools.py
│ │ │ ├── query_tools.py
│ │ │ ├── server.py
│ │ │ └── write_tools.py
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── conftest.py
│ │ │ ├── test_analytic_tools.py
│ │ │ ├── test_connection_tools.py
│ │ │ ├── test_db_management_tools.py
│ │ │ ├── test_init.py
│ │ │ ├── test_main.py
│ │ │ ├── test_query_tools.py
│ │ │ └── test_write_tools.py
│ │ └── uv.lock
│ ├── dynamodb-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── dynamodb_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── common.py
│ │ │ ├── database_analysis_queries.py
│ │ │ ├── database_analyzers.py
│ │ │ ├── markdown_formatter.py
│ │ │ ├── prompts
│ │ │ │ └── dynamodb_architect.md
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── conftest.py
│ │ │ ├── evals
│ │ │ │ ├── dynamic_evaluators.py
│ │ │ │ ├── evaluation_registry.py
│ │ │ │ ├── logging_config.py
│ │ │ │ ├── multiturn_evaluator.py
│ │ │ │ ├── README.md
│ │ │ │ ├── scenarios.py
│ │ │ │ └── test_dspy_evals.py
│ │ │ ├── test_dynamodb_server.py
│ │ │ ├── test_markdown_formatter.py
│ │ │ └── test_source_db_integration.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── ecs-mcp-server
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── ecs_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── api
│ │ │ │ ├── __init__.py
│ │ │ │ ├── containerize.py
│ │ │ │ ├── delete.py
│ │ │ │ ├── ecs_troubleshooting.py
│ │ │ │ ├── infrastructure.py
│ │ │ │ ├── resource_management.py
│ │ │ │ ├── status.py
│ │ │ │ └── troubleshooting_tools
│ │ │ │ ├── __init__.py
│ │ │ │ ├── detect_image_pull_failures.py
│ │ │ │ ├── fetch_cloudformation_status.py
│ │ │ │ ├── fetch_network_configuration.py
│ │ │ │ ├── fetch_service_events.py
│ │ │ │ ├── fetch_task_failures.py
│ │ │ │ ├── fetch_task_logs.py
│ │ │ │ ├── get_ecs_troubleshooting_guidance.py
│ │ │ │ └── utils.py
│ │ │ ├── main.py
│ │ │ ├── modules
│ │ │ │ ├── __init__.py
│ │ │ │ ├── aws_knowledge_proxy.py
│ │ │ │ ├── containerize.py
│ │ │ │ ├── delete.py
│ │ │ │ ├── deployment_status.py
│ │ │ │ ├── infrastructure.py
│ │ │ │ ├── resource_management.py
│ │ │ │ └── troubleshooting.py
│ │ │ ├── templates
│ │ │ │ ├── ecr_infrastructure.json
│ │ │ │ └── ecs_infrastructure.json
│ │ │ └── utils
│ │ │ ├── arn_parser.py
│ │ │ ├── aws.py
│ │ │ ├── config.py
│ │ │ ├── docker.py
│ │ │ ├── security.py
│ │ │ ├── templates.py
│ │ │ └── time_utils.py
│ │ ├── DEVELOPMENT.md
│ │ ├── pyproject.toml
│ │ ├── pyrightconfig.json
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── conftest.py
│ │ │ ├── integ
│ │ │ │ └── mcp-inspector
│ │ │ │ ├── .gitignore
│ │ │ │ ├── README.md
│ │ │ │ ├── run-tests.sh
│ │ │ │ └── scenarios
│ │ │ │ ├── 01_comprehensive_troubleshooting
│ │ │ │ │ ├── 01_create.sh
│ │ │ │ │ ├── 02_validate.sh
│ │ │ │ │ ├── 03_cleanup.sh
│ │ │ │ │ ├── description.txt
│ │ │ │ │ └── utils
│ │ │ │ │ ├── mcp_helpers.sh
│ │ │ │ │ └── validation_helpers.sh
│ │ │ │ └── 02_test_knowledge_proxy_tools
│ │ │ │ ├── 01_create.sh
│ │ │ │ ├── 02_validate.sh
│ │ │ │ ├── 03_cleanup.sh
│ │ │ │ ├── description.txt
│ │ │ │ └── utils
│ │ │ │ ├── knowledge_validation_helpers.sh
│ │ │ │ └── mcp_knowledge_helpers.sh
│ │ │ ├── llm_testing
│ │ │ │ ├── invalid_cfn_template.yaml
│ │ │ │ ├── README.md
│ │ │ │ ├── run_tests.sh
│ │ │ │ ├── scenarios
│ │ │ │ │ ├── 01_cloudformation_failure
│ │ │ │ │ │ ├── 01_create.sh
│ │ │ │ │ │ ├── 02_validate.sh
│ │ │ │ │ │ ├── 03_prompts.txt
│ │ │ │ │ │ ├── 04_evaluation.md
│ │ │ │ │ │ ├── 05_cleanup.sh
│ │ │ │ │ │ └── description.txt
│ │ │ │ │ ├── 02_service_failure
│ │ │ │ │ │ ├── 01_create.sh
│ │ │ │ │ │ ├── 02_validate.sh
│ │ │ │ │ │ ├── 03_prompts.txt
│ │ │ │ │ │ ├── 04_evaluation.md
│ │ │ │ │ │ ├── 05_cleanup.sh
│ │ │ │ │ │ └── description.txt
│ │ │ │ │ ├── 03_task_exit_failure
│ │ │ │ │ │ ├── 01_create.sh
│ │ │ │ │ │ ├── 02_validate.sh
│ │ │ │ │ │ ├── 03_prompts.txt
│ │ │ │ │ │ ├── 04_evaluation.md
│ │ │ │ │ │ ├── 05_cleanup.sh
│ │ │ │ │ │ └── description.txt
│ │ │ │ │ ├── 04_network_configuration_failure
│ │ │ │ │ │ ├── 01_create.sh
│ │ │ │ │ │ ├── 02_validate.sh
│ │ │ │ │ │ ├── 03_prompts.txt
│ │ │ │ │ │ ├── 05_cleanup.sh
│ │ │ │ │ │ └── description.txt
│ │ │ │ │ ├── 05_resource_constraint_failure
│ │ │ │ │ │ ├── 01_create.sh
│ │ │ │ │ │ ├── 02_validate.sh
│ │ │ │ │ │ ├── 03_prompts.txt
│ │ │ │ │ │ ├── 05_cleanup.sh
│ │ │ │ │ │ └── description.txt
│ │ │ │ │ └── 06_load_balancer_failure
│ │ │ │ │ ├── 01_create.sh
│ │ │ │ │ ├── 02_validate.sh
│ │ │ │ │ ├── 03_prompts.txt
│ │ │ │ │ ├── 05_cleanup.sh
│ │ │ │ │ └── description.txt
│ │ │ │ ├── SCRIPT_IMPROVEMENTS.md
│ │ │ │ └── utils
│ │ │ │ ├── aws_helpers.sh
│ │ │ │ └── evaluation_template.md
│ │ │ └── unit
│ │ │ ├── __init__.py
│ │ │ ├── api
│ │ │ │ ├── conftest.py
│ │ │ │ ├── test_delete_api.py
│ │ │ │ ├── test_ecs_troubleshooting.py
│ │ │ │ ├── test_resource_management_api.py
│ │ │ │ └── troubleshooting_tools
│ │ │ │ └── test_fetch_network_configuration.py
│ │ │ ├── conftest.py
│ │ │ ├── modules
│ │ │ │ ├── test_aws_knowledge_proxy.py
│ │ │ │ └── test_resource_management_module.py
│ │ │ ├── test_aws_role_utils.py
│ │ │ ├── test_aws_utils.py
│ │ │ ├── test_containerize.py
│ │ │ ├── test_delete.py
│ │ │ ├── test_docker_utils.py
│ │ │ ├── test_docker_with_role.py
│ │ │ ├── test_image_pull_failure_extended.py
│ │ │ ├── test_image_pull_failure.py
│ │ │ ├── test_infrastructure_role.py
│ │ │ ├── test_infrastructure.py
│ │ │ ├── test_integration.py
│ │ │ ├── test_main.py
│ │ │ ├── test_resource_management_api_operation.py
│ │ │ ├── test_resource_management_tool.py
│ │ │ ├── test_resource_management.py
│ │ │ ├── test_security_integration.py
│ │ │ ├── test_status_pytest.py
│ │ │ ├── test_status.py
│ │ │ ├── troubleshooting_tools
│ │ │ │ ├── __init__.py
│ │ │ │ ├── conftest.py
│ │ │ │ ├── test_detect_image_pull_failures.py
│ │ │ │ ├── test_fetch_cloudformation_status.py
│ │ │ │ ├── test_fetch_service_events.py
│ │ │ │ ├── test_fetch_task_failures.py
│ │ │ │ ├── test_fetch_task_logs.py
│ │ │ │ ├── test_get_ecs_troubleshooting_guidance.py
│ │ │ │ ├── test_is_ecr_image_security.py
│ │ │ │ └── test_utils.py
│ │ │ └── utils
│ │ │ ├── __init__.py
│ │ │ ├── async_test_utils.py
│ │ │ ├── test_arn_parser.py
│ │ │ ├── test_config.py
│ │ │ ├── test_docker.py
│ │ │ ├── test_response_sanitization.py
│ │ │ ├── test_security_extended.py
│ │ │ ├── test_security.py
│ │ │ ├── test_templates.py
│ │ │ └── test_time_utils.py
│ │ └── uv.lock
│ ├── eks-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── eks_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── aws_helper.py
│ │ │ ├── cloudwatch_handler.py
│ │ │ ├── cloudwatch_metrics_guidance_handler.py
│ │ │ ├── consts.py
│ │ │ ├── data
│ │ │ │ └── eks_cloudwatch_metrics_guidance.json
│ │ │ ├── eks_kb_handler.py
│ │ │ ├── eks_stack_handler.py
│ │ │ ├── iam_handler.py
│ │ │ ├── insights_handler.py
│ │ │ ├── k8s_apis.py
│ │ │ ├── k8s_client_cache.py
│ │ │ ├── k8s_handler.py
│ │ │ ├── logging_helper.py
│ │ │ ├── models.py
│ │ │ ├── scripts
│ │ │ │ └── update_eks_cloudwatch_metrics_guidance.py
│ │ │ ├── server.py
│ │ │ ├── templates
│ │ │ │ ├── eks-templates
│ │ │ │ │ └── eks-with-vpc.yaml
│ │ │ │ └── k8s-templates
│ │ │ │ ├── deployment.yaml
│ │ │ │ └── service.yaml
│ │ │ └── vpc_config_handler.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── test_aws_helper.py
│ │ │ ├── test_cloudwatch_handler.py
│ │ │ ├── test_cloudwatch_metrics_guidance_handler.py
│ │ │ ├── test_eks_kb_handler.py
│ │ │ ├── test_eks_stack_handler.py
│ │ │ ├── test_iam_handler.py
│ │ │ ├── test_init.py
│ │ │ ├── test_insights_handler.py
│ │ │ ├── test_k8s_apis.py
│ │ │ ├── test_k8s_client_cache.py
│ │ │ ├── test_k8s_handler.py
│ │ │ ├── test_logging_helper.py
│ │ │ ├── test_main.py
│ │ │ ├── test_models.py
│ │ │ ├── test_server.py
│ │ │ └── test_vpc_config_handler.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── elasticache-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── elasticache_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── common
│ │ │ │ ├── __init__.py
│ │ │ │ ├── connection.py
│ │ │ │ ├── decorators.py
│ │ │ │ └── server.py
│ │ │ ├── context.py
│ │ │ ├── main.py
│ │ │ └── tools
│ │ │ ├── __init__.py
│ │ │ ├── cc
│ │ │ │ ├── __init__.py
│ │ │ │ ├── connect.py
│ │ │ │ ├── create.py
│ │ │ │ ├── delete.py
│ │ │ │ ├── describe.py
│ │ │ │ ├── modify.py
│ │ │ │ ├── parsers.py
│ │ │ │ └── processors.py
│ │ │ ├── ce
│ │ │ │ ├── __init__.py
│ │ │ │ └── get_cost_and_usage.py
│ │ │ ├── cw
│ │ │ │ ├── __init__.py
│ │ │ │ └── get_metric_statistics.py
│ │ │ ├── cwlogs
│ │ │ │ ├── __init__.py
│ │ │ │ ├── create_log_group.py
│ │ │ │ ├── describe_log_groups.py
│ │ │ │ ├── describe_log_streams.py
│ │ │ │ ├── filter_log_events.py
│ │ │ │ └── get_log_events.py
│ │ │ ├── firehose
│ │ │ │ ├── __init__.py
│ │ │ │ └── list_delivery_streams.py
│ │ │ ├── misc
│ │ │ │ ├── __init__.py
│ │ │ │ ├── batch_apply_update_action.py
│ │ │ │ ├── batch_stop_update_action.py
│ │ │ │ ├── describe_cache_engine_versions.py
│ │ │ │ ├── describe_engine_default_parameters.py
│ │ │ │ ├── describe_events.py
│ │ │ │ └── describe_service_updates.py
│ │ │ ├── rg
│ │ │ │ ├── __init__.py
│ │ │ │ ├── complete_migration.py
│ │ │ │ ├── connect.py
│ │ │ │ ├── create.py
│ │ │ │ ├── delete.py
│ │ │ │ ├── describe.py
│ │ │ │ ├── modify.py
│ │ │ │ ├── parsers.py
│ │ │ │ ├── processors.py
│ │ │ │ ├── start_migration.py
│ │ │ │ └── test_migration.py
│ │ │ └── serverless
│ │ │ ├── __init__.py
│ │ │ ├── connect.py
│ │ │ ├── create.py
│ │ │ ├── delete.py
│ │ │ ├── describe.py
│ │ │ ├── models.py
│ │ │ └── modify.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── test_connection.py
│ │ │ ├── test_decorators.py
│ │ │ ├── test_init.py
│ │ │ ├── test_main.py
│ │ │ └── tools
│ │ │ ├── cc
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_connect_additional.py
│ │ │ │ ├── test_connect_coverage_additional.py
│ │ │ │ ├── test_connect_coverage.py
│ │ │ │ ├── test_connect.py
│ │ │ │ ├── test_create_additional.py
│ │ │ │ ├── test_create.py
│ │ │ │ ├── test_delete.py
│ │ │ │ ├── test_describe.py
│ │ │ │ ├── test_modify.py
│ │ │ │ ├── test_parsers.py
│ │ │ │ └── test_processors.py
│ │ │ ├── ce
│ │ │ │ ├── __init__.py
│ │ │ │ └── test_get_cost_and_usage.py
│ │ │ ├── cw
│ │ │ │ └── test_get_metric_statistics.py
│ │ │ ├── cwlogs
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_create_log_group.py
│ │ │ │ ├── test_describe_log_groups.py
│ │ │ │ ├── test_describe_log_streams.py
│ │ │ │ ├── test_filter_log_events.py
│ │ │ │ └── test_get_log_events.py
│ │ │ ├── firehose
│ │ │ │ └── test_list_delivery_streams.py
│ │ │ ├── misc
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_batch_apply_update_action.py
│ │ │ │ ├── test_batch_stop_update_action.py
│ │ │ │ ├── test_describe_cache_engine_versions.py
│ │ │ │ ├── test_describe_engine_default_parameters.py
│ │ │ │ ├── test_describe_events.py
│ │ │ │ └── test_describe_service_updates.py
│ │ │ ├── rg
│ │ │ │ ├── __init__.py
│ │ │ │ ├── test_complete_migration.py
│ │ │ │ ├── test_connect_additional.py
│ │ │ │ ├── test_connect_coverage_additional.py
│ │ │ │ ├── test_connect_optional_fields.py
│ │ │ │ ├── test_connect_partial_coverage.py
│ │ │ │ ├── test_connect.py
│ │ │ │ ├── test_create.py
│ │ │ │ ├── test_delete.py
│ │ │ │ ├── test_describe.py
│ │ │ │ ├── test_modify.py
│ │ │ │ ├── test_parsers.py
│ │ │ │ ├── test_processors.py
│ │ │ │ ├── test_start_migration.py
│ │ │ │ └── test_test_migration.py
│ │ │ └── serverless
│ │ │ ├── test_connect_additional.py
│ │ │ ├── test_connect_coverage_additional.py
│ │ │ ├── test_connect_optional_fields.py
│ │ │ ├── test_connect.py
│ │ │ ├── test_create.py
│ │ │ ├── test_delete.py
│ │ │ ├── test_describe.py
│ │ │ └── test_modify.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── finch-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── finch_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── consts.py
│ │ │ ├── models.py
│ │ │ ├── server.py
│ │ │ └── utils
│ │ │ ├── __init__.py
│ │ │ ├── build.py
│ │ │ ├── common.py
│ │ │ ├── ecr.py
│ │ │ ├── push.py
│ │ │ └── vm.py
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── test_cli_flags.py
│ │ │ ├── test_logging_configuration.py
│ │ │ ├── test_server.py
│ │ │ ├── test_utils_build.py
│ │ │ ├── test_utils_common.py
│ │ │ ├── test_utils_ecr.py
│ │ │ ├── test_utils_push.py
│ │ │ └── test_utils_vm.py
│ │ └── uv.lock
│ ├── frontend-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── frontend_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── server.py
│ │ │ ├── static
│ │ │ │ └── react
│ │ │ │ ├── essential-knowledge.md
│ │ │ │ └── troubleshooting.md
│ │ │ └── utils
│ │ │ ├── __init__.py
│ │ │ └── file_utils.py
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── test_file_utils.py
│ │ │ ├── test_init.py
│ │ │ ├── test_main.py
│ │ │ └── test_server.py
│ │ └── uv.lock
│ ├── git-repo-research-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── git_repo_research_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── defaults.py
│ │ │ ├── embeddings.py
│ │ │ ├── github_search.py
│ │ │ ├── indexer.py
│ │ │ ├── models.py
│ │ │ ├── repository.py
│ │ │ ├── search.py
│ │ │ ├── server.py
│ │ │ └── utils.py
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── run_tests.sh
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── conftest.py
│ │ │ ├── test_errors_repository.py
│ │ │ ├── test_github_search_edge_cases.py
│ │ │ ├── test_graphql_github_search.py
│ │ │ ├── test_local_repository.py
│ │ │ ├── test_repository_utils.py
│ │ │ ├── test_rest_github_search.py
│ │ │ ├── test_search.py
│ │ │ ├── test_server.py
│ │ │ └── test_url_repository.py
│ │ └── uv.lock
│ ├── healthlake-mcp-server
│ │ ├── .dockerignore
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── healthlake_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── fhir_operations.py
│ │ │ ├── main.py
│ │ │ ├── models.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── CONTRIBUTING.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── examples
│ │ │ ├── mcp_config.json
│ │ │ └── README.md
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── conftest.py
│ │ │ ├── test_fhir_client_comprehensive.py
│ │ │ ├── test_fhir_error_scenarios.py
│ │ │ ├── test_fhir_operations.py
│ │ │ ├── test_integration_mock_based.py
│ │ │ ├── test_main_edge_cases.py
│ │ │ ├── test_main.py
│ │ │ ├── test_mcp_integration_coverage.py
│ │ │ ├── test_models_edge_cases.py
│ │ │ ├── test_models.py
│ │ │ ├── test_readonly_mode.py
│ │ │ ├── test_server_core.py
│ │ │ ├── test_server_error_handling.py
│ │ │ ├── test_server_mcp_handlers.py
│ │ │ ├── test_server_toolhandler.py
│ │ │ └── test_server_validation.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── iam-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── iam_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── aws_client.py
│ │ │ ├── context.py
│ │ │ ├── errors.py
│ │ │ ├── models.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── DESIGN_COMPLIANCE.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── examples
│ │ │ ├── get_policy_document_example.py
│ │ │ └── inline_policy_demo.py
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── run_tests.sh
│ │ ├── tests
│ │ │ ├── test_context.py
│ │ │ ├── test_errors.py
│ │ │ ├── test_inline_policies.py
│ │ │ └── test_server.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── lambda-tool-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── lambda_tool_mcp_server
│ │ │ ├── __init__.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── examples
│ │ │ ├── README.md
│ │ │ └── sample_functions
│ │ │ ├── customer-create
│ │ │ │ └── app.py
│ │ │ ├── customer-id-from-email
│ │ │ │ └── app.py
│ │ │ ├── customer-info-from-id
│ │ │ │ └── app.py
│ │ │ └── template.yml
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── .gitignore
│ │ │ ├── conftest.py
│ │ │ ├── README.md
│ │ │ ├── test_format_lambda_response.py
│ │ │ ├── test_integration_coverage.py
│ │ │ ├── test_integration.py
│ │ │ ├── test_register_lambda_functions.py
│ │ │ ├── test_schema_integration.py
│ │ │ ├── test_server_coverage_additional.py
│ │ │ ├── test_server_coverage.py
│ │ │ └── test_server.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── mcp-lambda-handler
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ └── mcp_lambda_handler
│ │ │ ├── __init__.py
│ │ │ ├── mcp_lambda_handler.py
│ │ │ ├── session.py
│ │ │ └── types.py
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ └── test_lambda_handler.py
│ │ └── uv.lock
│ ├── memcached-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── memcached_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── common
│ │ │ │ ├── config.py
│ │ │ │ ├── connection.py
│ │ │ │ └── server.py
│ │ │ ├── context.py
│ │ │ ├── main.py
│ │ │ └── tools
│ │ │ └── cache.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── ELASTICACHECONNECT.md
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── test_cache_readonly.py
│ │ │ ├── test_cache.py
│ │ │ ├── test_connection.py
│ │ │ ├── test_init.py
│ │ │ └── test_main.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── mysql-mcp-server
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── mysql_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── connection
│ │ │ │ ├── __init__.py
│ │ │ │ ├── abstract_db_connection.py
│ │ │ │ ├── asyncmy_pool_connection.py
│ │ │ │ ├── db_connection_singleton.py
│ │ │ │ └── rds_data_api_connection.py
│ │ │ ├── mutable_sql_detector.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── conftest.py
│ │ │ ├── test_abstract_db_connection.py
│ │ │ ├── test_asyncmy_pool_connection.py
│ │ │ ├── test_db_connection_singleton.py
│ │ │ ├── test_rds_data_api_connection.py
│ │ │ └── test_server.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── nova-canvas-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── nova_canvas_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── consts.py
│ │ │ ├── models.py
│ │ │ ├── novacanvas.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── .gitignore
│ │ │ ├── conftest.py
│ │ │ ├── README.md
│ │ │ ├── test_models.py
│ │ │ ├── test_novacanvas.py
│ │ │ └── test_server.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── openapi-mcp-server
│ │ ├── .coveragerc
│ │ ├── .dockerignore
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── AUTHENTICATION.md
│ │ ├── AWS_BEST_PRACTICES.md
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── openapi_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── api
│ │ │ │ ├── __init__.py
│ │ │ │ └── config.py
│ │ │ ├── auth
│ │ │ │ ├── __init__.py
│ │ │ │ ├── api_key_auth.py
│ │ │ │ ├── auth_cache.py
│ │ │ │ ├── auth_errors.py
│ │ │ │ ├── auth_factory.py
│ │ │ │ ├── auth_protocol.py
│ │ │ │ ├── auth_provider.py
│ │ │ │ ├── base_auth.py
│ │ │ │ ├── basic_auth.py
│ │ │ │ ├── bearer_auth.py
│ │ │ │ ├── cognito_auth.py
│ │ │ │ └── register.py
│ │ │ ├── patch
│ │ │ │ └── __init__.py
│ │ │ ├── prompts
│ │ │ │ ├── __init__.py
│ │ │ │ ├── generators
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── operation_prompts.py
│ │ │ │ │ └── workflow_prompts.py
│ │ │ │ ├── models.py
│ │ │ │ └── prompt_manager.py
│ │ │ ├── server.py
│ │ │ └── utils
│ │ │ ├── __init__.py
│ │ │ ├── cache_provider.py
│ │ │ ├── config.py
│ │ │ ├── error_handler.py
│ │ │ ├── http_client.py
│ │ │ ├── metrics_provider.py
│ │ │ ├── openapi_validator.py
│ │ │ └── openapi.py
│ │ ├── CHANGELOG.md
│ │ ├── DEPLOYMENT.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── OBSERVABILITY.md
│ │ ├── pyproject.toml
│ │ ├── pyrightconfig.json
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── api
│ │ │ │ └── test_config.py
│ │ │ ├── auth
│ │ │ │ ├── test_api_key_auth.py
│ │ │ │ ├── test_auth_cache.py
│ │ │ │ ├── test_auth_errors.py
│ │ │ │ ├── test_auth_factory_caching.py
│ │ │ │ ├── test_auth_factory_coverage.py
│ │ │ │ ├── test_auth_factory.py
│ │ │ │ ├── test_auth_protocol_additional.py
│ │ │ │ ├── test_auth_protocol_boost.py
│ │ │ │ ├── test_auth_protocol_coverage.py
│ │ │ │ ├── test_auth_protocol_extended.py
│ │ │ │ ├── test_auth_protocol_improved.py
│ │ │ │ ├── test_auth_protocol.py
│ │ │ │ ├── test_auth_provider_additional.py
│ │ │ │ ├── test_base_auth_coverage.py
│ │ │ │ ├── test_base_auth.py
│ │ │ │ ├── test_basic_auth.py
│ │ │ │ ├── test_bearer_auth.py
│ │ │ │ ├── test_cognito_auth_additional_coverage.py
│ │ │ │ ├── test_cognito_auth_boost_coverage.py
│ │ │ │ ├── test_cognito_auth_client_credentials.py
│ │ │ │ ├── test_cognito_auth_coverage_boost.py
│ │ │ │ ├── test_cognito_auth_exceptions.py
│ │ │ │ ├── test_cognito_auth.py
│ │ │ │ ├── test_register_coverage.py
│ │ │ │ └── test_register.py
│ │ │ ├── prompts
│ │ │ │ ├── standalone
│ │ │ │ │ ├── test_operation_prompt.py
│ │ │ │ │ ├── test_prompt_arguments.py
│ │ │ │ │ └── test_secure_operation_prompt.py
│ │ │ │ ├── test_mcp_prompt_manager_integration.py
│ │ │ │ ├── test_mcp_prompt_manager.py
│ │ │ │ ├── test_models_dict_method.py
│ │ │ │ ├── test_operation_prompts_extended.py
│ │ │ │ ├── test_prompt_manager_additional.py
│ │ │ │ ├── test_prompt_manager_comprehensive.py
│ │ │ │ ├── test_prompt_manager_coverage.py
│ │ │ │ └── test_prompt_registration.py
│ │ │ ├── README.md
│ │ │ ├── test_api_name.py
│ │ │ ├── test_cache_coverage_89.py
│ │ │ ├── test_client.py
│ │ │ ├── test_coverage_boost.py
│ │ │ ├── test_init.py
│ │ │ ├── test_main_extended.py
│ │ │ ├── test_main.py
│ │ │ ├── test_openapi_coverage_89.py
│ │ │ ├── test_server_auth_errors.py
│ │ │ ├── test_server_coverage_boost_2.py
│ │ │ ├── test_server_coverage_boost.py
│ │ │ ├── test_server_exception_handling.py
│ │ │ ├── test_server_extended.py
│ │ │ ├── test_server_httpx_version.py
│ │ │ ├── test_server_part1.py
│ │ │ ├── test_server_route_logging.py
│ │ │ ├── test_server_signal_handlers.py
│ │ │ ├── test_server.py
│ │ │ └── utils
│ │ │ ├── test_cache_provider.py
│ │ │ ├── test_error_handler_boost.py
│ │ │ ├── test_error_handler_extended.py
│ │ │ ├── test_error_handler_fix.py
│ │ │ ├── test_error_handler.py
│ │ │ ├── test_http_client_comprehensive.py
│ │ │ ├── test_http_client_extended.py
│ │ │ ├── test_http_client_extended2.py
│ │ │ ├── test_http_client_import_error.py
│ │ │ ├── test_http_client.py
│ │ │ ├── test_metrics_provider_decorators.py
│ │ │ ├── test_metrics_provider_extended2.py
│ │ │ ├── test_metrics_provider_prometheus.py
│ │ │ ├── test_metrics_provider.py
│ │ │ ├── test_openapi_validator.py
│ │ │ └── test_openapi.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── postgres-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── postgres_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── connection
│ │ │ │ ├── __init__.py
│ │ │ │ ├── abstract_db_connection.py
│ │ │ │ ├── db_connection_singleton.py
│ │ │ │ ├── psycopg_pool_connection.py
│ │ │ │ └── rds_api_connection.py
│ │ │ ├── mutable_sql_detector.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── conftest.py
│ │ │ ├── test_psycopg_connector.py
│ │ │ ├── test_server.py
│ │ │ └── test_singleton.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── prometheus-mcp-server
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── prometheus_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── consts.py
│ │ │ ├── models.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── conftest.py
│ │ │ ├── test_aws_credentials.py
│ │ │ ├── test_config_manager.py
│ │ │ ├── test_consts.py
│ │ │ ├── test_coverage_gaps.py
│ │ │ ├── test_coverage_improvement.py
│ │ │ ├── test_final_coverage.py
│ │ │ ├── test_init.py
│ │ │ ├── test_main.py
│ │ │ ├── test_models.py
│ │ │ ├── test_prometheus_client.py
│ │ │ ├── test_prometheus_connection.py
│ │ │ ├── test_security_validator.py
│ │ │ ├── test_server_coverage.py
│ │ │ ├── test_tools.py
│ │ │ └── test_workspace_config.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── redshift-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── redshift_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── consts.py
│ │ │ ├── models.py
│ │ │ ├── redshift.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── test_init.py
│ │ │ ├── test_main.py
│ │ │ ├── test_redshift.py
│ │ │ └── test_server.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── s3-tables-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── s3_tables_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── constants.py
│ │ │ ├── database.py
│ │ │ ├── engines
│ │ │ │ ├── __init__.py
│ │ │ │ └── pyiceberg.py
│ │ │ ├── file_processor
│ │ │ │ ├── __init__.py
│ │ │ │ ├── csv.py
│ │ │ │ ├── parquet.py
│ │ │ │ └── utils.py
│ │ │ ├── models.py
│ │ │ ├── namespaces.py
│ │ │ ├── resources.py
│ │ │ ├── s3_operations.py
│ │ │ ├── server.py
│ │ │ ├── table_buckets.py
│ │ │ ├── tables.py
│ │ │ └── utils.py
│ │ ├── CHANGELOG.md
│ │ ├── CONTEXT.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── test_csv.py
│ │ │ ├── test_database.py
│ │ │ ├── test_file_processor_utils.py
│ │ │ ├── test_init.py
│ │ │ ├── test_main.py
│ │ │ ├── test_namespaces.py
│ │ │ ├── test_parquet.py
│ │ │ ├── test_pyiceberg.py
│ │ │ ├── test_resources.py
│ │ │ ├── test_s3_operations.py
│ │ │ ├── test_server.py
│ │ │ ├── test_table_buckets.py
│ │ │ ├── test_tables.py
│ │ │ └── test_utils.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── stepfunctions-tool-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── stepfunctions_tool_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── aws_helper.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── test_aws_helper.py
│ │ │ ├── test_create_state_machine_tool.py
│ │ │ ├── test_filter_state_machines_by_tag.py
│ │ │ ├── test_format_state_machine_response.py
│ │ │ ├── test_get_schema_arn_from_state_machine_arn.py
│ │ │ ├── test_get_schema_from_registry.py
│ │ │ ├── test_invoke_express_state_machine_impl.py
│ │ │ ├── test_invoke_standard_state_machine_impl.py
│ │ │ ├── test_main.py
│ │ │ ├── test_register_state_machines.py
│ │ │ ├── test_sanitize_tool_name.py
│ │ │ ├── test_server.py
│ │ │ └── test_validate_state_machine_name.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── syntheticdata-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── syntheticdata_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── pandas_interpreter.py
│ │ │ ├── server.py
│ │ │ └── storage
│ │ │ ├── __init__.py
│ │ │ ├── base.py
│ │ │ ├── loader.py
│ │ │ └── s3.py
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── conftest.py
│ │ │ ├── test_constants.py
│ │ │ ├── test_pandas_interpreter.py
│ │ │ ├── test_server.py
│ │ │ └── test_storage
│ │ │ ├── __init__.py
│ │ │ ├── test_loader.py
│ │ │ └── test_s3.py
│ │ └── uv.lock
│ ├── terraform-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── terraform_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── impl
│ │ │ │ ├── resources
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── terraform_aws_provider_resources_listing.py
│ │ │ │ │ └── terraform_awscc_provider_resources_listing.py
│ │ │ │ └── tools
│ │ │ │ ├── __init__.py
│ │ │ │ ├── execute_terraform_command.py
│ │ │ │ ├── execute_terragrunt_command.py
│ │ │ │ ├── run_checkov_scan.py
│ │ │ │ ├── search_aws_provider_docs.py
│ │ │ │ ├── search_awscc_provider_docs.py
│ │ │ │ ├── search_specific_aws_ia_modules.py
│ │ │ │ ├── search_user_provided_module.py
│ │ │ │ └── utils.py
│ │ │ ├── models
│ │ │ │ ├── __init__.py
│ │ │ │ └── models.py
│ │ │ ├── scripts
│ │ │ │ ├── generate_aws_provider_resources.py
│ │ │ │ ├── generate_awscc_provider_resources.py
│ │ │ │ └── scrape_aws_terraform_best_practices.py
│ │ │ ├── server.py
│ │ │ └── static
│ │ │ ├── __init__.py
│ │ │ ├── AWS_PROVIDER_RESOURCES.md
│ │ │ ├── AWS_TERRAFORM_BEST_PRACTICES.md
│ │ │ ├── AWSCC_PROVIDER_RESOURCES.md
│ │ │ ├── MCP_INSTRUCTIONS.md
│ │ │ └── TERRAFORM_WORKFLOW_GUIDE.md
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ ├── .gitignore
│ │ │ ├── conftest.py
│ │ │ ├── README.md
│ │ │ ├── test_command_impl.py
│ │ │ ├── test_execute_terraform_command.py
│ │ │ ├── test_execute_terragrunt_command.py
│ │ │ ├── test_models.py
│ │ │ ├── test_parameter_annotations.py
│ │ │ ├── test_resources.py
│ │ │ ├── test_run_checkov_scan.py
│ │ │ ├── test_search_user_provided_module.py
│ │ │ ├── test_server.py
│ │ │ ├── test_tool_implementations.py
│ │ │ ├── test_utils_additional.py
│ │ │ └── test_utils.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── timestream-for-influxdb-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── timestream_for_influxdb_mcp_server
│ │ │ ├── __init__.py
│ │ │ └── server.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── test_init.py
│ │ │ ├── test_main.py
│ │ │ └── test_server.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ ├── valkey-mcp-server
│ │ ├── .gitignore
│ │ ├── .python-version
│ │ ├── awslabs
│ │ │ ├── __init__.py
│ │ │ └── valkey_mcp_server
│ │ │ ├── __init__.py
│ │ │ ├── common
│ │ │ │ ├── __init__.py
│ │ │ │ ├── config.py
│ │ │ │ ├── connection.py
│ │ │ │ └── server.py
│ │ │ ├── context.py
│ │ │ ├── main.py
│ │ │ ├── tools
│ │ │ │ ├── __init__.py
│ │ │ │ ├── bitmap.py
│ │ │ │ ├── hash.py
│ │ │ │ ├── hyperloglog.py
│ │ │ │ ├── json.py
│ │ │ │ ├── list.py
│ │ │ │ ├── misc.py
│ │ │ │ ├── server_management.py
│ │ │ │ ├── set.py
│ │ │ │ ├── sorted_set.py
│ │ │ │ ├── stream.py
│ │ │ │ └── string.py
│ │ │ └── version.py
│ │ ├── CHANGELOG.md
│ │ ├── docker-healthcheck.sh
│ │ ├── Dockerfile
│ │ ├── ELASTICACHECONNECT.md
│ │ ├── LICENSE
│ │ ├── NOTICE
│ │ ├── pyproject.toml
│ │ ├── README.md
│ │ ├── tests
│ │ │ ├── test_bitmap.py
│ │ │ ├── test_config.py
│ │ │ ├── test_connection.py
│ │ │ ├── test_hash.py
│ │ │ ├── test_hyperloglog.py
│ │ │ ├── test_init.py
│ │ │ ├── test_json_additional.py
│ │ │ ├── test_json_readonly.py
│ │ │ ├── test_json.py
│ │ │ ├── test_list_additional.py
│ │ │ ├── test_list_readonly.py
│ │ │ ├── test_list.py
│ │ │ ├── test_main.py
│ │ │ ├── test_misc.py
│ │ │ ├── test_server_management.py
│ │ │ ├── test_set_readonly.py
│ │ │ ├── test_set.py
│ │ │ ├── test_sorted_set_additional.py
│ │ │ ├── test_sorted_set_readonly.py
│ │ │ ├── test_sorted_set.py
│ │ │ ├── test_stream_additional.py
│ │ │ ├── test_stream_readonly.py
│ │ │ ├── test_stream.py
│ │ │ └── test_string.py
│ │ ├── uv-requirements.txt
│ │ └── uv.lock
│ └── well-architected-security-mcp-server
│ ├── .python-version
│ ├── awslabs
│ │ └── well_architected_security_mcp_server
│ │ ├── __init__.py
│ │ ├── consts.py
│ │ ├── server.py
│ │ └── util
│ │ ├── __init__.py
│ │ ├── network_security.py
│ │ ├── prompt_utils.py
│ │ ├── resource_utils.py
│ │ ├── security_services.py
│ │ └── storage_security.py
│ ├── PROMPT_TEMPLATE.md
│ ├── pyproject.toml
│ ├── README.md
│ ├── tests
│ │ ├── __init__.py
│ │ ├── conftest.py
│ │ ├── README.md
│ │ ├── test_access_analyzer_fix.py
│ │ ├── test_network_security_additional.py
│ │ ├── test_network_security.py
│ │ ├── test_prompt_utils_coverage.py
│ │ ├── test_prompt_utils.py
│ │ ├── test_resource_utils_fix.py
│ │ ├── test_resource_utils.py
│ │ ├── test_security_services_additional.py
│ │ ├── test_security_services_coverage.py
│ │ ├── test_security_services.py
│ │ ├── test_server_additional.py
│ │ ├── test_server_coverage.py
│ │ ├── test_server_prompts.py
│ │ ├── test_server_security_findings.py
│ │ ├── test_server.py
│ │ ├── test_storage_security_additional.py
│ │ ├── test_storage_security_comprehensive.py
│ │ ├── test_storage_security_edge_cases.py
│ │ ├── test_storage_security_recommendations.py
│ │ ├── test_storage_security.py
│ │ └── test_user_agent_config.py
│ └── uv.lock
├── testing
│ ├── __init__.py
│ ├── mcp_test_client.py
│ ├── mcp_test_runner.py
│ ├── pytest_utils.py
│ ├── README.md
│ └── types.py
└── VIBE_CODING_TIPS_TRICKS.md
```
# Files
--------------------------------------------------------------------------------
/src/aws-iot-sitewise-mcp-server/tests/tools/test_sitewise_data.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 AWS IoT SiteWise Data Ingestion and Retrieval Tools."""
16 |
17 | import os
18 | import pytest
19 | import sys
20 | from awslabs.aws_iot_sitewise_mcp_server.tools.sitewise_data import (
21 | batch_get_asset_property_aggregates,
22 | batch_get_asset_property_value,
23 | batch_get_asset_property_value_history,
24 | batch_put_asset_property_value,
25 | create_buffered_ingestion_job,
26 | create_bulk_import_iam_role,
27 | create_bulk_import_job,
28 | describe_bulk_import_job,
29 | execute_query,
30 | get_asset_property_aggregates,
31 | get_asset_property_value,
32 | get_asset_property_value_history,
33 | get_interpolated_asset_property_values,
34 | list_bulk_import_jobs,
35 | )
36 | from botocore.exceptions import ClientError
37 | from unittest.mock import Mock, patch
38 |
39 |
40 | # Add the project root directory and its parent to Python path
41 | script_dir = os.path.dirname(os.path.abspath(__file__))
42 | project_dir = os.path.dirname(script_dir)
43 | sys.path.insert(0, project_dir)
44 | sys.path.insert(0, os.path.dirname(project_dir))
45 | sys.path.insert(0, os.path.dirname(os.path.dirname(project_dir)))
46 |
47 |
48 | class TestSiteWiseData:
49 | """Test cases for SiteWise data ingestion and retrieval tools."""
50 |
51 | @patch('awslabs.aws_iot_sitewise_mcp_server.tools.sitewise_data.create_sitewise_client')
52 | def test_batch_put_asset_property_value_success(self, mock_boto_client):
53 | """Test successful batch data ingestion."""
54 | # Mock the boto3 client
55 | mock_client = Mock()
56 | mock_boto_client.return_value = mock_client
57 |
58 | # Mock the response
59 | mock_response = {'errorEntries': []}
60 | mock_client.batch_put_asset_property_value.return_value = mock_response
61 |
62 | # Test data
63 | entries = [
64 | {
65 | 'entryId': 'entry1',
66 | 'assetId': '12345678-1234-1234-1234-123456789012',
67 | 'propertyId': 'abcdef12-3456-7890-abcd-ef1234567890',
68 | 'propertyValues': [
69 | {
70 | 'value': {'doubleValue': 25.5},
71 | 'timestamp': {'timeInSeconds': 1640995200},
72 | 'quality': 'GOOD',
73 | }
74 | ],
75 | }
76 | ]
77 |
78 | # Call the function
79 | result = batch_put_asset_property_value(entries=entries, region='us-east-1')
80 |
81 | # Verify the result
82 | assert result['success'] is True
83 | assert result['error_entries'] == []
84 |
85 | # Verify the client was called correctly
86 | mock_client.batch_put_asset_property_value.assert_called_once_with(entries=entries)
87 |
88 | @patch('awslabs.aws_iot_sitewise_mcp_server.tools.sitewise_data.create_sitewise_client')
89 | def test_get_asset_property_value_success(self, mock_boto_client):
90 | """Test successful property value retrieval."""
91 | # Mock the boto3 client
92 | mock_client = Mock()
93 | mock_boto_client.return_value = mock_client
94 |
95 | # Mock the response
96 | mock_response = {
97 | 'propertyValue': {
98 | 'value': {'doubleValue': 25.5},
99 | 'timestamp': {'timeInSeconds': 1640995200},
100 | 'quality': 'GOOD',
101 | }
102 | }
103 | mock_client.get_asset_property_value.return_value = mock_response
104 |
105 | # Call the function
106 | result = get_asset_property_value(
107 | asset_id='12345678-1234-1234-1234-123456789012',
108 | property_id='abcdef12-3456-7890-abcd-ef1234567890',
109 | region='us-east-1',
110 | )
111 |
112 | # Verify the result
113 | assert result['success'] is True
114 | assert result['value']['doubleValue'] == 25.5
115 | assert result['quality'] == 'GOOD'
116 |
117 | @patch('awslabs.aws_iot_sitewise_mcp_server.tools.sitewise_data.create_sitewise_client')
118 | def test_get_asset_property_value_history_success(self, mock_boto_client):
119 | """Test successful property value history retrieval."""
120 | mock_client = Mock()
121 | mock_boto_client.return_value = mock_client
122 |
123 | mock_response = {
124 | 'assetPropertyValueHistory': [
125 | {
126 | 'value': {'doubleValue': 25.5},
127 | 'timestamp': {'timeInSeconds': 1640995200},
128 | },
129 | {
130 | 'value': {'doubleValue': 26.0},
131 | 'timestamp': {'timeInSeconds': 1640995260},
132 | },
133 | ],
134 | 'nextToken': 'token-123',
135 | }
136 | mock_client.get_asset_property_value_history.return_value = mock_response
137 |
138 | result = get_asset_property_value_history(
139 | asset_id='12345678-1234-1234-1234-123456789012',
140 | property_id='abcdef12-3456-7890-abcd-ef1234567890',
141 | property_alias=None,
142 | start_date=None,
143 | end_date=None,
144 | qualities=None,
145 | time_ordering='ASCENDING',
146 | next_token=None,
147 | max_results=100,
148 | region='us-east-1',
149 | )
150 |
151 | assert result['success'] is True
152 | assert len(result['asset_property_value_history']) == 2
153 |
154 | @patch('awslabs.aws_iot_sitewise_mcp_server.tools.sitewise_data.create_sitewise_client')
155 | def test_get_asset_property_aggregates_success(self, mock_boto_client):
156 | """Test successful property aggregates retrieval."""
157 | mock_client = Mock()
158 | mock_boto_client.return_value = mock_client
159 |
160 | mock_response = {
161 | 'aggregatedValues': [
162 | {
163 | 'timestamp': {'timeInSeconds': 1640995200},
164 | 'value': {'average': 25.5},
165 | },
166 | ],
167 | 'nextToken': 'token-123',
168 | }
169 | mock_client.get_asset_property_aggregates.return_value = mock_response
170 |
171 | result = get_asset_property_aggregates(
172 | asset_id='12345678-1234-1234-1234-123456789012',
173 | property_id='abcdef12-3456-7890-abcd-ef1234567890',
174 | property_alias=None,
175 | aggregate_types=None,
176 | resolution='1h',
177 | start_date=None,
178 | end_date=None,
179 | qualities=None,
180 | time_ordering='ASCENDING',
181 | next_token=None,
182 | max_results=100,
183 | region='us-east-1',
184 | )
185 |
186 | assert result['success'] is True
187 | assert len(result['aggregated_values']) == 1
188 |
189 | @patch('awslabs.aws_iot_sitewise_mcp_server.tools.sitewise_data.create_sitewise_client')
190 | def test_get_interpolated_asset_property_values_success(self, mock_boto_client):
191 | """Test successful interpolated values retrieval."""
192 | mock_client = Mock()
193 | mock_boto_client.return_value = mock_client
194 |
195 | mock_response = {
196 | 'interpolatedAssetPropertyValues': [
197 | {
198 | 'timestamp': {'timeInSeconds': 1640995200},
199 | 'value': {'doubleValue': 25.5},
200 | },
201 | ],
202 | 'nextToken': 'token-123',
203 | }
204 | mock_client.get_interpolated_asset_property_values.return_value = mock_response
205 |
206 | result = get_interpolated_asset_property_values(
207 | asset_id='12345678-1234-1234-1234-123456789012',
208 | property_id='abcdef12-3456-7890-abcd-ef1234567890',
209 | start_time_in_seconds=1640995200,
210 | end_time_in_seconds=1640999000,
211 | region='us-east-1',
212 | )
213 |
214 | assert result['success'] is True
215 | assert len(result['interpolated_asset_property_values']) == 1
216 |
217 | @patch('awslabs.aws_iot_sitewise_mcp_server.tools.sitewise_data.create_sitewise_client')
218 | def test_batch_get_asset_property_value_success(self, mock_boto_client):
219 | """Test successful batch get property values."""
220 | mock_client = Mock()
221 | mock_boto_client.return_value = mock_client
222 |
223 | mock_response = {
224 | 'successEntries': [
225 | {'entryId': 'entry1', 'propertyValue': {'value': {'doubleValue': 25.5}}}
226 | ],
227 | 'skippedEntries': [],
228 | 'errorEntries': [],
229 | 'nextToken': 'token-123',
230 | }
231 | mock_client.batch_get_asset_property_value.return_value = mock_response
232 |
233 | entries = [
234 | {
235 | 'entryId': 'entry1',
236 | 'assetId': '12345678-1234-1234-1234-123456789012',
237 | 'propertyId': 'abcdef12-3456-7890-abcd-ef1234567890',
238 | }
239 | ]
240 | result = batch_get_asset_property_value(entries=entries, region='us-east-1')
241 |
242 | assert result['success'] is True
243 | assert len(result['success_entries']) == 1
244 |
245 | @patch('awslabs.aws_iot_sitewise_mcp_server.tools.sitewise_data.create_sitewise_client')
246 | def test_batch_get_asset_property_value_history_success(self, mock_boto_client):
247 | """Test successful batch get property value history."""
248 | mock_client = Mock()
249 | mock_boto_client.return_value = mock_client
250 |
251 | mock_response = {
252 | 'successEntries': [{'entryId': 'entry1', 'assetPropertyValueHistory': []}],
253 | 'skippedEntries': [],
254 | 'errorEntries': [],
255 | }
256 | mock_client.batch_get_asset_property_value_history.return_value = mock_response
257 |
258 | entries = [
259 | {
260 | 'entryId': 'entry1',
261 | 'assetId': '12345678-1234-1234-1234-123456789012',
262 | 'propertyId': 'abcdef12-3456-7890-abcd-ef1234567890',
263 | }
264 | ]
265 | result = batch_get_asset_property_value_history(entries=entries, region='us-east-1')
266 |
267 | assert result['success'] is True
268 | assert len(result['success_entries']) == 1
269 |
270 | @patch('awslabs.aws_iot_sitewise_mcp_server.tools.sitewise_data.create_sitewise_client')
271 | def test_batch_get_asset_property_aggregates_success(self, mock_boto_client):
272 | """Test successful batch get property aggregates."""
273 | mock_client = Mock()
274 | mock_boto_client.return_value = mock_client
275 |
276 | mock_response = {
277 | 'successEntries': [{'entryId': 'entry1', 'aggregatedValues': []}],
278 | 'skippedEntries': [],
279 | 'errorEntries': [],
280 | }
281 | mock_client.batch_get_asset_property_aggregates.return_value = mock_response
282 |
283 | entries = [
284 | {
285 | 'entryId': 'entry1',
286 | 'assetId': '12345678-1234-1234-1234-123456789012',
287 | 'propertyId': 'abcdef12-3456-7890-abcd-ef1234567890',
288 | }
289 | ]
290 | result = batch_get_asset_property_aggregates(entries=entries, region='us-east-1')
291 |
292 | assert result['success'] is True
293 | assert len(result['success_entries']) == 1
294 |
295 | @patch('awslabs.aws_iot_sitewise_mcp_server.tools.sitewise_data.create_sitewise_client')
296 | def test_execute_query_success(self, mock_boto_client):
297 | """Test successful query execution."""
298 | mock_client = Mock()
299 | mock_boto_client.return_value = mock_client
300 |
301 | mock_response = {
302 | 'columns': [{'name': 'asset_id', 'type': {'scalarType': 'VARCHAR'}}],
303 | 'rows': [{'data': [{'scalarValue': 'asset-123'}]}],
304 | 'nextToken': 'token-123',
305 | 'queryStatistics': {'queryExecutionTime': 100},
306 | 'queryStatus': 'COMPLETED',
307 | }
308 | mock_client.execute_query.return_value = mock_response
309 |
310 | result = execute_query(
311 | query_statement='SELECT asset_id FROM asset',
312 | region='us-east-1',
313 | next_token=None,
314 | max_results=100,
315 | )
316 |
317 | assert result['success'] is True
318 | assert len(result['columns']) == 1
319 | assert len(result['rows']) == 1
320 | assert result['query_status'] == 'COMPLETED'
321 |
322 | @patch('awslabs.aws_iot_sitewise_mcp_server.tools.sitewise_data.create_sitewise_client')
323 | def test_execute_query_validation_errors(self, mock_boto_client):
324 | """Test validation errors in execute_query."""
325 | mock_client = Mock()
326 | mock_boto_client.return_value = mock_client
327 |
328 | # Test empty query
329 | result = execute_query(query_statement='', region='us-east-1')
330 | assert result['success'] is False
331 | assert result['error_code'] == 'ValidationException'
332 |
333 | # Test query too long
334 | result = execute_query(query_statement='a' * 70000, region='us-east-1')
335 | assert result['success'] is False
336 | assert result['error_code'] == 'ValidationException'
337 |
338 | @patch('awslabs.aws_iot_sitewise_mcp_server.tools.sitewise_data.create_sitewise_client')
339 | def test_client_error_handling(self, mock_boto_client):
340 | """Test ClientError handling."""
341 | mock_client = Mock()
342 | mock_boto_client.return_value = mock_client
343 |
344 | error_response = {'Error': {'Code': 'InvalidRequestException', 'Message': 'Invalid query'}}
345 | mock_client.execute_query.side_effect = ClientError(error_response, 'ExecuteQuery')
346 |
347 | result = execute_query(
348 | query_statement='SELECT * FROM invalid_table',
349 | region='us-east-1',
350 | next_token=None,
351 | max_results=100,
352 | )
353 |
354 | assert result['success'] is False
355 | assert result['error_code'] == 'InvalidRequestException'
356 |
357 | @patch('awslabs.aws_iot_sitewise_mcp_server.tools.sitewise_data.create_sitewise_client')
358 | def test_get_asset_property_value_with_all_params(self, mock_boto_client):
359 | """Test get asset property value with all optional parameters."""
360 | mock_client = Mock()
361 | mock_boto_client.return_value = mock_client
362 |
363 | mock_response = {
364 | 'propertyValue': {
365 | 'value': {'doubleValue': 42.5},
366 | 'timestamp': {'timeInSeconds': 1609459200, 'offsetInNanos': 0},
367 | 'quality': 'GOOD',
368 | }
369 | }
370 | mock_client.get_asset_property_value.return_value = mock_response
371 |
372 | # Test with asset_id and property_id
373 | result = get_asset_property_value(
374 | asset_id='12345678-1234-1234-1234-123456789012',
375 | property_id='abcdef12-3456-7890-abcd-ef1234567890',
376 | property_alias=None,
377 | region='us-west-2',
378 | )
379 |
380 | assert result['success'] is True
381 | mock_client.get_asset_property_value.assert_called_once_with(
382 | assetId='12345678-1234-1234-1234-123456789012',
383 | propertyId='abcdef12-3456-7890-abcd-ef1234567890',
384 | )
385 |
386 | # Test with property_alias only
387 | mock_client.reset_mock()
388 | result = get_asset_property_value(
389 | asset_id=None,
390 | property_id=None,
391 | property_alias='/company/plant/temperature',
392 | region='us-east-1',
393 | )
394 |
395 | assert result['success'] is True
396 | mock_client.get_asset_property_value.assert_called_once_with(
397 | propertyAlias='/company/plant/temperature'
398 | )
399 |
400 | # Test with all parameters
401 | mock_client.reset_mock()
402 | result = get_asset_property_value(
403 | asset_id='12345678-1234-1234-1234-123456789012',
404 | property_id='abcdef12-3456-7890-abcd-ef1234567890',
405 | property_alias='/company/plant/temperature',
406 | region='us-west-2',
407 | )
408 |
409 | assert result['success'] is True
410 | mock_client.get_asset_property_value.assert_called_once_with(
411 | assetId='12345678-1234-1234-1234-123456789012',
412 | propertyId='abcdef12-3456-7890-abcd-ef1234567890',
413 | propertyAlias='/company/plant/temperature',
414 | )
415 |
416 | @patch('awslabs.aws_iot_sitewise_mcp_server.tools.sitewise_data.create_sitewise_client')
417 | def test_get_asset_property_value_history_with_all_params(self, mock_boto_client):
418 | """Test get asset property value history with all optional parameters."""
419 | mock_client = Mock()
420 | mock_boto_client.return_value = mock_client
421 |
422 | mock_response = {
423 | 'assetPropertyValueHistory': [
424 | {
425 | 'value': {'doubleValue': 42.5},
426 | 'timestamp': {'timeInSeconds': 1609459200, 'offsetInNanos': 0},
427 | 'quality': 'GOOD',
428 | }
429 | ],
430 | 'nextToken': 'next-token-123',
431 | }
432 | mock_client.get_asset_property_value_history.return_value = mock_response
433 |
434 | result = get_asset_property_value_history(
435 | asset_id='12345678-1234-1234-1234-123456789012',
436 | property_id='abcdef12-3456-7890-abcd-ef1234567890',
437 | property_alias='/company/plant/temperature',
438 | start_date='2021-01-01T00:00:00Z',
439 | end_date='2021-01-02T00:00:00Z',
440 | qualities=['GOOD', 'BAD'],
441 | time_ordering='DESCENDING',
442 | next_token='prev-token',
443 | max_results=200,
444 | region='us-west-2',
445 | )
446 |
447 | assert result['success'] is True
448 | assert len(result['asset_property_value_history']) == 1
449 | assert result['next_token'] == 'next-token-123'
450 |
451 | # Verify datetime parsing and all parameters were passed
452 | call_args = mock_client.get_asset_property_value_history.call_args[1]
453 | assert call_args['assetId'] == '12345678-1234-1234-1234-123456789012'
454 | assert call_args['propertyId'] == 'abcdef12-3456-7890-abcd-ef1234567890'
455 | assert call_args['propertyAlias'] == '/company/plant/temperature'
456 | assert call_args['qualities'] == ['GOOD', 'BAD']
457 | assert call_args['timeOrdering'] == 'DESCENDING'
458 | assert call_args['nextToken'] == 'prev-token'
459 | assert call_args['maxResults'] == 200
460 |
461 | @patch('awslabs.aws_iot_sitewise_mcp_server.tools.sitewise_data.create_sitewise_client')
462 | def test_get_asset_property_aggregates_with_all_params(self, mock_boto_client):
463 | """Test get asset property aggregates with all optional parameters."""
464 | mock_client = Mock()
465 | mock_boto_client.return_value = mock_client
466 |
467 | mock_response = {
468 | 'aggregatedValues': [
469 | {
470 | 'timestamp': {'timeInSeconds': 1609459200, 'offsetInNanos': 0},
471 | 'quality': 'GOOD',
472 | 'value': {'average': 42.5, 'count': 10},
473 | }
474 | ],
475 | 'nextToken': 'next-token-123',
476 | }
477 | mock_client.get_asset_property_aggregates.return_value = mock_response
478 |
479 | # Test with custom aggregate types
480 | result = get_asset_property_aggregates(
481 | asset_id='12345678-1234-1234-1234-123456789012',
482 | property_id='abcdef12-3456-7890-abcd-ef1234567890',
483 | property_alias='/company/plant/temperature',
484 | aggregate_types=['AVERAGE', 'MAXIMUM', 'MINIMUM'],
485 | resolution='15m',
486 | start_date='2021-01-01T00:00:00Z',
487 | end_date='2021-01-02T00:00:00Z',
488 | qualities=['GOOD'],
489 | time_ordering='DESCENDING',
490 | next_token='prev-token',
491 | max_results=500,
492 | region='us-west-2',
493 | )
494 |
495 | assert result['success'] is True
496 | assert len(result['aggregated_values']) == 1
497 |
498 | # Test with default aggregate types (None)
499 | mock_client.reset_mock()
500 | result = get_asset_property_aggregates(
501 | asset_id='12345678-1234-1234-1234-123456789012',
502 | property_id='abcdef12-3456-7890-abcd-ef1234567890',
503 | property_alias=None,
504 | aggregate_types=None, # Should default to ["AVERAGE"]
505 | resolution='1h',
506 | start_date=None,
507 | end_date=None,
508 | qualities=None,
509 | time_ordering='ASCENDING',
510 | next_token=None,
511 | max_results=100,
512 | region='us-east-1',
513 | )
514 |
515 | assert result['success'] is True
516 | call_args = mock_client.get_asset_property_aggregates.call_args[1]
517 | assert call_args['aggregateTypes'] == ['AVERAGE']
518 |
519 | @patch('awslabs.aws_iot_sitewise_mcp_server.tools.sitewise_data.create_sitewise_client')
520 | def test_get_interpolated_asset_property_values_with_all_params(self, mock_boto_client):
521 | """Test get interpolated asset property values with all optional parameters."""
522 | mock_client = Mock()
523 | mock_boto_client.return_value = mock_client
524 |
525 | mock_response = {
526 | 'interpolatedAssetPropertyValues': [
527 | {
528 | 'timestamp': {'timeInSeconds': 1609459200, 'offsetInNanos': 0},
529 | 'value': {'doubleValue': 42.5},
530 | }
531 | ],
532 | 'nextToken': 'next-token-123',
533 | }
534 | mock_client.get_interpolated_asset_property_values.return_value = mock_response
535 |
536 | result = get_interpolated_asset_property_values(
537 | asset_id='12345678-1234-1234-1234-123456789012',
538 | property_id='abcdef12-3456-7890-abcd-ef1234567890',
539 | property_alias='/company/plant/temperature',
540 | start_time_in_seconds=1609459200,
541 | end_time_in_seconds=1609545600,
542 | quality='GOOD',
543 | interval_in_seconds=1800,
544 | next_token='prev-token',
545 | max_results=250,
546 | interpolation_type='LOCF_INTERPOLATION',
547 | interval_window_in_seconds=900,
548 | region='us-west-2',
549 | )
550 |
551 | assert result['success'] is True
552 | assert len(result['interpolated_asset_property_values']) == 1
553 |
554 | # Verify all parameters were passed correctly
555 | call_args = mock_client.get_interpolated_asset_property_values.call_args[1]
556 | assert call_args['assetId'] == '12345678-1234-1234-1234-123456789012'
557 | assert call_args['propertyId'] == 'abcdef12-3456-7890-abcd-ef1234567890'
558 | assert call_args['propertyAlias'] == '/company/plant/temperature'
559 | assert call_args['startTimeInSeconds'] == 1609459200
560 | assert call_args['endTimeInSeconds'] == 1609545600
561 | assert call_args['quality'] == 'GOOD'
562 | assert call_args['intervalInSeconds'] == 1800
563 | assert call_args['nextToken'] == 'prev-token'
564 | assert call_args['maxResults'] == 250
565 | assert call_args['type'] == 'LOCF_INTERPOLATION'
566 | assert call_args['intervalWindowInSeconds'] == 900
567 |
568 | @patch('awslabs.aws_iot_sitewise_mcp_server.tools.sitewise_data.create_sitewise_client')
569 | def test_batch_get_asset_property_value_with_next_token(self, mock_boto_client):
570 | """Test batch get asset property value with next token."""
571 | mock_client = Mock()
572 | mock_boto_client.return_value = mock_client
573 |
574 | mock_response = {
575 | 'successEntries': [{'entryId': 'entry1'}],
576 | 'skippedEntries': [],
577 | 'errorEntries': [],
578 | 'nextToken': 'next-token-123',
579 | }
580 | mock_client.batch_get_asset_property_value.return_value = mock_response
581 |
582 | entries = [
583 | {
584 | 'entryId': 'entry1',
585 | 'assetId': '12345678-1234-1234-1234-123456789012',
586 | 'propertyId': 'abcdef12-3456-7890-abcd-ef1234567890',
587 | }
588 | ]
589 |
590 | # Test with next_token
591 | result = batch_get_asset_property_value(
592 | entries=entries, next_token='prev-token', region='us-west-2'
593 | )
594 |
595 | assert result['success'] is True
596 | mock_client.batch_get_asset_property_value.assert_called_once_with(
597 | entries=entries, nextToken='prev-token'
598 | )
599 |
600 | # Test without next_token
601 | mock_client.reset_mock()
602 | result = batch_get_asset_property_value(
603 | entries=entries,
604 | next_token=None,
605 | region='us-east-1',
606 | )
607 |
608 | assert result['success'] is True
609 | mock_client.batch_get_asset_property_value.assert_called_once_with(entries=entries)
610 |
611 | @patch('awslabs.aws_iot_sitewise_mcp_server.tools.sitewise_data.create_sitewise_client')
612 | def test_batch_get_asset_property_value_history_with_next_token(self, mock_boto_client):
613 | """Test batch get asset property value history with next token."""
614 | mock_client = Mock()
615 | mock_boto_client.return_value = mock_client
616 |
617 | mock_response = {
618 | 'successEntries': [{'entryId': 'entry1'}],
619 | 'skippedEntries': [],
620 | 'errorEntries': [],
621 | 'nextToken': 'next-token-123',
622 | }
623 | mock_client.batch_get_asset_property_value_history.return_value = mock_response
624 |
625 | entries = [
626 | {
627 | 'entryId': 'entry1',
628 | 'assetId': '12345678-1234-1234-1234-123456789012',
629 | 'propertyId': 'abcdef12-3456-7890-abcd-ef1234567890',
630 | }
631 | ]
632 |
633 | # Test with next_token
634 | result = batch_get_asset_property_value_history(
635 | entries=entries,
636 | next_token='prev-token',
637 | max_results=500,
638 | region='us-west-2',
639 | )
640 |
641 | assert result['success'] is True
642 | mock_client.batch_get_asset_property_value_history.assert_called_once_with(
643 | entries=entries, maxResults=500, nextToken='prev-token'
644 | )
645 |
646 | # Test without next_token
647 | mock_client.reset_mock()
648 | result = batch_get_asset_property_value_history(
649 | entries=entries,
650 | next_token=None,
651 | max_results=200,
652 | region='us-east-1',
653 | )
654 |
655 | assert result['success'] is True
656 | mock_client.batch_get_asset_property_value_history.assert_called_once_with(
657 | entries=entries, maxResults=200
658 | )
659 |
660 | @patch('awslabs.aws_iot_sitewise_mcp_server.tools.sitewise_data.create_sitewise_client')
661 | def test_batch_get_asset_property_aggregates_with_next_token(self, mock_boto_client):
662 | """Test batch get asset property aggregates with next token."""
663 | mock_client = Mock()
664 | mock_boto_client.return_value = mock_client
665 |
666 | mock_response = {
667 | 'successEntries': [{'entryId': 'entry1'}],
668 | 'skippedEntries': [],
669 | 'errorEntries': [],
670 | 'nextToken': 'next-token-123',
671 | }
672 | mock_client.batch_get_asset_property_aggregates.return_value = mock_response
673 |
674 | entries = [
675 | {
676 | 'entryId': 'entry1',
677 | 'assetId': '12345678-1234-1234-1234-123456789012',
678 | 'propertyId': 'abcdef12-3456-7890-abcd-ef1234567890',
679 | }
680 | ]
681 |
682 | # Test with next_token
683 | result = batch_get_asset_property_aggregates(
684 | entries=entries,
685 | next_token='prev-token',
686 | max_results=750,
687 | region='us-west-2',
688 | )
689 |
690 | assert result['success'] is True
691 | mock_client.batch_get_asset_property_aggregates.assert_called_once_with(
692 | entries=entries, maxResults=750, nextToken='prev-token'
693 | )
694 |
695 | # Test without next_token
696 | mock_client.reset_mock()
697 | result = batch_get_asset_property_aggregates(
698 | entries=entries,
699 | next_token=None,
700 | max_results=300,
701 | region='us-east-1',
702 | )
703 |
704 | assert result['success'] is True
705 | mock_client.batch_get_asset_property_aggregates.assert_called_once_with(
706 | entries=entries, maxResults=300
707 | )
708 |
709 | def test_execute_query_additional_validation_errors(self):
710 | """Test execute query validation error cases."""
711 | # Test empty query
712 | result = execute_query(
713 | query_statement='',
714 | region='us-east-1',
715 | next_token=None,
716 | max_results=100,
717 | )
718 | assert result['success'] is False
719 | assert 'Query statement cannot be empty' in result['error']
720 |
721 | # Test whitespace-only query
722 | result = execute_query(
723 | query_statement=' ',
724 | region='us-east-1',
725 | next_token=None,
726 | max_results=100,
727 | )
728 | assert result['success'] is False
729 | assert 'Query statement cannot be empty' in result['error']
730 |
731 | # Test query too long (over 64KB)
732 | long_query = "SELECT * FROM asset WHERE asset_name = '" + 'x' * 65537 + "'"
733 | result = execute_query(
734 | query_statement=long_query,
735 | region='us-east-1',
736 | next_token=None,
737 | max_results=100,
738 | )
739 | assert result['success'] is False
740 | assert 'Query statement cannot exceed 64KB' in result['error']
741 |
742 | # Test next token too long
743 | result = execute_query(
744 | query_statement='SELECT asset_id FROM asset',
745 | region='us-east-1',
746 | next_token='x' * 4097, # Exceeds 4096 character limit
747 | max_results=100,
748 | )
749 | assert result['success'] is False
750 | assert 'Next token too long' in result['error']
751 |
752 | @patch('awslabs.aws_iot_sitewise_mcp_server.tools.sitewise_data.create_sitewise_client')
753 | def test_execute_query_with_all_params(self, mock_boto_client):
754 | """Test execute query with all optional parameters."""
755 | mock_client = Mock()
756 | mock_boto_client.return_value = mock_client
757 |
758 | mock_response = {
759 | 'columns': [{'name': 'asset_id', 'type': {'scalarType': 'VARCHAR'}}],
760 | 'rows': [{'data': [{'scalarValue': 'asset-123'}]}],
761 | 'nextToken': 'next-token-123',
762 | 'queryStatistics': {'scannedRows': 100, 'executionTimeInMillis': 250},
763 | 'queryStatus': 'COMPLETED',
764 | }
765 | mock_client.execute_query.return_value = mock_response
766 |
767 | query = "SELECT asset_id, asset_name FROM asset WHERE asset_name LIKE 'Test%'"
768 | result = execute_query(
769 | query_statement=query,
770 | region='us-west-2',
771 | next_token='prev-token',
772 | max_results=2000,
773 | )
774 |
775 | assert result['success'] is True
776 | assert len(result['columns']) == 1
777 | assert len(result['rows']) == 1
778 | assert result['next_token'] == 'next-token-123'
779 | assert result['query_statistics']['scannedRows'] == 100
780 | assert result['query_status'] == 'COMPLETED'
781 |
782 | mock_client.execute_query.assert_called_once_with(
783 | queryStatement=query, maxResults=2000, nextToken='prev-token'
784 | )
785 |
786 | @patch('awslabs.aws_iot_sitewise_mcp_server.tools.sitewise_data.create_sitewise_client')
787 | def test_execute_query_without_optional_params(self, mock_boto_client):
788 | """Test execute query without optional parameters."""
789 | mock_client = Mock()
790 | mock_boto_client.return_value = mock_client
791 |
792 | mock_response = {
793 | 'columns': [],
794 | 'rows': [],
795 | 'queryStatistics': {},
796 | 'queryStatus': 'COMPLETED',
797 | }
798 | mock_client.execute_query.return_value = mock_response
799 |
800 | query = 'SELECT COUNT(*) FROM asset'
801 | result = execute_query(
802 | query_statement=query,
803 | region='us-east-1',
804 | next_token=None,
805 | max_results=100,
806 | )
807 |
808 | assert result['success'] is True
809 |
810 | # Verify only required parameters were passed
811 | mock_client.execute_query.assert_called_once_with(queryStatement=query, maxResults=100)
812 |
813 | @patch('awslabs.aws_iot_sitewise_mcp_server.tools.sitewise_data.create_sitewise_client')
814 | def test_all_functions_client_error_handling(self, mock_boto_client):
815 | """Test that all functions handle ClientError exceptions properly."""
816 | mock_client = Mock()
817 | mock_boto_client.return_value = mock_client
818 |
819 | error_response = {
820 | 'Error': {
821 | 'Code': 'InternalFailureException',
822 | 'Message': 'Internal server error',
823 | }
824 | }
825 |
826 | # Test batch_put_asset_property_value error handling
827 | mock_client.batch_put_asset_property_value.side_effect = ClientError(
828 | error_response, 'BatchPutAssetPropertyValue'
829 | )
830 | result = batch_put_asset_property_value(entries=[{'entryId': 'test'}])
831 | assert result['success'] is False
832 | assert result['error_code'] == 'InternalFailureException'
833 |
834 | # Test get_asset_property_value error handling
835 | mock_client.get_asset_property_value.side_effect = ClientError(
836 | error_response, 'GetAssetPropertyValue'
837 | )
838 | result = get_asset_property_value(
839 | asset_id='12345678-1234-1234-1234-123456789012',
840 | property_id=None,
841 | property_alias=None,
842 | region='us-east-1',
843 | )
844 | assert result['success'] is False
845 | assert result['error_code'] == 'InternalFailureException'
846 |
847 | # Test get_asset_property_value_history error handling
848 | mock_client.get_asset_property_value_history.side_effect = ClientError(
849 | error_response, 'GetAssetPropertyValueHistory'
850 | )
851 | result = get_asset_property_value_history(
852 | asset_id='12345678-1234-1234-1234-123456789012',
853 | property_id=None,
854 | property_alias=None,
855 | start_date=None,
856 | end_date=None,
857 | qualities=None,
858 | time_ordering='ASCENDING',
859 | next_token=None,
860 | max_results=100,
861 | region='us-east-1',
862 | )
863 | assert result['success'] is False
864 | assert result['error_code'] == 'InternalFailureException'
865 |
866 | # Test get_asset_property_aggregates error handling
867 | mock_client.get_asset_property_aggregates.side_effect = ClientError(
868 | error_response, 'GetAssetPropertyAggregates'
869 | )
870 | result = get_asset_property_aggregates(
871 | asset_id='12345678-1234-1234-1234-123456789012',
872 | property_id=None,
873 | property_alias=None,
874 | aggregate_types=None,
875 | resolution='1h',
876 | start_date=None,
877 | end_date=None,
878 | qualities=None,
879 | time_ordering='ASCENDING',
880 | next_token=None,
881 | max_results=100,
882 | region='us-east-1',
883 | )
884 | assert result['success'] is False
885 | assert result['error_code'] == 'InternalFailureException'
886 |
887 | # Test get_interpolated_asset_property_values error handling
888 | mock_client.get_interpolated_asset_property_values.side_effect = ClientError(
889 | error_response, 'GetInterpolatedAssetPropertyValues'
890 | )
891 | result = get_interpolated_asset_property_values(
892 | asset_id='12345678-1234-1234-1234-123456789012',
893 | start_time_in_seconds=1609459200,
894 | end_time_in_seconds=1609545600,
895 | )
896 | assert result['success'] is False
897 | assert result['error_code'] == 'InternalFailureException'
898 |
899 | # Test batch_get_asset_property_value error handling
900 | mock_client.batch_get_asset_property_value.side_effect = ClientError(
901 | error_response, 'BatchGetAssetPropertyValue'
902 | )
903 | result = batch_get_asset_property_value(
904 | entries=[{'entryId': 'test'}],
905 | next_token=None,
906 | region='us-east-1',
907 | )
908 | assert result['success'] is False
909 | assert result['error_code'] == 'InternalFailureException'
910 |
911 | # Test batch_get_asset_property_value_history error handling
912 | mock_client.batch_get_asset_property_value_history.side_effect = ClientError(
913 | error_response, 'BatchGetAssetPropertyValueHistory'
914 | )
915 | result = batch_get_asset_property_value_history(
916 | entries=[{'entryId': 'test'}],
917 | next_token=None,
918 | max_results=100,
919 | region='us-east-1',
920 | )
921 | assert result['success'] is False
922 | assert result['error_code'] == 'InternalFailureException'
923 |
924 | # Test batch_get_asset_property_aggregates error handling
925 | mock_client.batch_get_asset_property_aggregates.side_effect = ClientError(
926 | error_response, 'BatchGetAssetPropertyAggregates'
927 | )
928 | result = batch_get_asset_property_aggregates(
929 | entries=[{'entryId': 'test'}],
930 | next_token=None,
931 | max_results=100,
932 | region='us-east-1',
933 | )
934 | assert result['success'] is False
935 | assert result['error_code'] == 'InternalFailureException'
936 |
937 | # Test execute_query error handling
938 | mock_client.execute_query.side_effect = ClientError(error_response, 'ExecuteQuery')
939 | result = execute_query(
940 | query_statement='SELECT asset_id FROM asset',
941 | region='us-east-1',
942 | next_token=None,
943 | max_results=100,
944 | )
945 | assert result['success'] is False
946 | assert result['error_code'] == 'InternalFailureException'
947 |
948 | @patch('awslabs.aws_iot_sitewise_mcp_server.tools.sitewise_data.create_iam_client')
949 | def test_create_bulk_import_iam_role_success(self, mock_create_iam_client):
950 | """Test successful IAM role creation for bulk import."""
951 | mock_iam_client = Mock()
952 | mock_create_iam_client.return_value = mock_iam_client
953 |
954 | mock_iam_client.create_role.return_value = {
955 | 'Role': {'Arn': 'arn:aws:iam::123456789012:role/TestRole'}
956 | }
957 |
958 | result = create_bulk_import_iam_role(
959 | role_name='TestRole',
960 | data_bucket_names=['test-data-bucket'],
961 | error_bucket_name='test-error-bucket',
962 | region='us-east-1',
963 | )
964 |
965 | assert result['success'] is True
966 | assert result['role_arn'] == 'arn:aws:iam::123456789012:role/TestRole'
967 | assert result['role_name'] == 'TestRole'
968 | mock_iam_client.create_role.assert_called_once()
969 | mock_iam_client.put_role_policy.assert_called_once()
970 |
971 | @patch('awslabs.aws_iot_sitewise_mcp_server.tools.sitewise_data.create_iam_client')
972 | def test_create_bulk_import_iam_role_error(self, mock_create_iam_client):
973 | """Test IAM role creation error handling."""
974 | mock_iam_client = Mock()
975 | mock_create_iam_client.return_value = mock_iam_client
976 |
977 | error_response = {
978 | 'Error': {'Code': 'EntityAlreadyExistsException', 'Message': 'Role already exists'}
979 | }
980 | mock_iam_client.create_role.side_effect = ClientError(error_response, 'CreateRole')
981 |
982 | result = create_bulk_import_iam_role(
983 | role_name='ExistingRole',
984 | data_bucket_names=['test-bucket'],
985 | error_bucket_name='error-bucket',
986 | )
987 |
988 | assert result['success'] is False
989 | assert 'error' in result
990 |
991 | @patch('awslabs.aws_iot_sitewise_mcp_server.tools.sitewise_data.create_sitewise_client')
992 | def test_create_bulk_import_job_success(self, mock_boto_client):
993 | """Test successful bulk import job creation."""
994 | mock_client = Mock()
995 | mock_boto_client.return_value = mock_client
996 |
997 | mock_client.create_bulk_import_job.return_value = {
998 | 'jobId': 'test-job-id',
999 | 'jobName': 'test-job',
1000 | 'jobStatus': 'PENDING',
1001 | }
1002 |
1003 | result = create_bulk_import_job(
1004 | job_name='test-job',
1005 | job_role_arn='arn:aws:iam::123456789012:role/TestRole',
1006 | files=[{'bucket': 'test-bucket', 'key': 'test.csv'}],
1007 | error_report_location={'bucket': 'error-bucket', 'prefix': 'errors/'},
1008 | job_configuration={
1009 | 'fileFormat': {
1010 | 'csv': {'columnNames': ['ALIAS', 'VALUE', 'DATA_TYPE', 'TIMESTAMP_SECONDS']}
1011 | }
1012 | },
1013 | adaptive_ingestion=True,
1014 | )
1015 |
1016 | assert result['success'] is True
1017 | assert result['job_id'] == 'test-job-id'
1018 | assert result['job_name'] == 'test-job'
1019 | mock_client.create_bulk_import_job.assert_called_once()
1020 |
1021 | @patch('awslabs.aws_iot_sitewise_mcp_server.tools.sitewise_data.create_sitewise_client')
1022 | def test_create_buffered_ingestion_job_success(self, mock_boto_client):
1023 | """Test successful buffered ingestion job creation."""
1024 | mock_client = Mock()
1025 | mock_boto_client.return_value = mock_client
1026 |
1027 | mock_client.create_bulk_import_job.return_value = {
1028 | 'jobId': 'buffered-job-id',
1029 | 'jobName': 'buffered-job',
1030 | 'jobStatus': 'PENDING',
1031 | }
1032 |
1033 | result = create_buffered_ingestion_job(
1034 | job_name='buffered-job',
1035 | job_role_arn='arn:aws:iam::123456789012:role/TestRole',
1036 | files=[{'bucket': 'test-bucket', 'key': 'test.csv'}],
1037 | error_report_location={'bucket': 'error-bucket', 'prefix': 'errors/'},
1038 | job_configuration={
1039 | 'fileFormat': {
1040 | 'csv': {'columnNames': ['ALIAS', 'VALUE', 'DATA_TYPE', 'TIMESTAMP_SECONDS']}
1041 | }
1042 | },
1043 | )
1044 |
1045 | assert result['success'] is True
1046 | assert result['job_id'] == 'buffered-job-id'
1047 | mock_client.create_bulk_import_job.assert_called_once()
1048 | # Verify adaptive_ingestion was set to True
1049 | call_args = mock_client.create_bulk_import_job.call_args[1]
1050 | assert call_args['adaptiveIngestion'] is True
1051 |
1052 | @patch('awslabs.aws_iot_sitewise_mcp_server.tools.sitewise_data.create_sitewise_client')
1053 | def test_describe_bulk_import_job_success(self, mock_boto_client):
1054 | """Test successful bulk import job description."""
1055 | mock_client = Mock()
1056 | mock_boto_client.return_value = mock_client
1057 |
1058 | mock_client.describe_bulk_import_job.return_value = {
1059 | 'jobId': '12345678-1234-1234-1234-123456789012',
1060 | 'jobName': 'test-job',
1061 | 'jobStatus': 'COMPLETED',
1062 | 'jobRoleArn': 'arn:aws:iam::123456789012:role/TestRole',
1063 | }
1064 |
1065 | result = describe_bulk_import_job(job_id='12345678-1234-1234-1234-123456789012')
1066 |
1067 | assert result['success'] is True
1068 | assert result['job_id'] == '12345678-1234-1234-1234-123456789012'
1069 | assert result['job_status'] == 'COMPLETED'
1070 | mock_client.describe_bulk_import_job.assert_called_once_with(
1071 | jobId='12345678-1234-1234-1234-123456789012'
1072 | )
1073 |
1074 | @patch('awslabs.aws_iot_sitewise_mcp_server.tools.sitewise_data.create_sitewise_client')
1075 | def test_list_bulk_import_jobs_success(self, mock_boto_client):
1076 | """Test successful bulk import jobs listing."""
1077 | mock_client = Mock()
1078 | mock_boto_client.return_value = mock_client
1079 |
1080 | mock_client.list_bulk_import_jobs.return_value = {
1081 | 'jobSummaries': [
1082 | {'jobId': 'job1', 'jobName': 'test-job-1', 'jobStatus': 'COMPLETED'},
1083 | {'jobId': 'job2', 'jobName': 'test-job-2', 'jobStatus': 'PENDING'},
1084 | ]
1085 | }
1086 |
1087 | result = list_bulk_import_jobs()
1088 |
1089 | assert result['success'] is True
1090 | assert len(result['job_summaries']) == 2
1091 | assert result['job_summaries'][0]['jobId'] == 'job1'
1092 | mock_client.list_bulk_import_jobs.assert_called_once()
1093 |
1094 | @patch('awslabs.aws_iot_sitewise_mcp_server.tools.sitewise_data.create_sitewise_client')
1095 | def test_bulk_import_job_error_handling(self, mock_boto_client):
1096 | """Test bulk import job error handling."""
1097 | mock_client = Mock()
1098 | mock_boto_client.return_value = mock_client
1099 |
1100 | error_response = {'Error': {'Code': 'ValidationException', 'Message': 'Invalid job name'}}
1101 | mock_client.create_bulk_import_job.side_effect = ClientError(
1102 | error_response, 'CreateBulkImportJob'
1103 | )
1104 |
1105 | result = create_bulk_import_job(
1106 | job_name='', # Invalid empty name
1107 | job_role_arn='arn:aws:iam::123456789012:role/TestRole',
1108 | files=[{'bucket': 'test-bucket', 'key': 'test.csv'}],
1109 | error_report_location={'bucket': 'error-bucket', 'prefix': 'errors/'},
1110 | job_configuration={'fileFormat': {'csv': {'columnNames': ['ALIAS', 'VALUE']}}},
1111 | adaptive_ingestion=True,
1112 | )
1113 |
1114 | assert result['success'] is False
1115 | assert result['error_code'] == 'ValidationException'
1116 |
1117 | def test_bulk_import_csv_validation_missing_column_names(self):
1118 | """Test CSV validation fails when columnNames is missing."""
1119 | result = create_bulk_import_job(
1120 | job_name='test-job',
1121 | job_role_arn='arn:aws:iam::123456789012:role/TestRole',
1122 | files=[{'bucket': 'test-bucket', 'key': 'test.csv'}],
1123 | error_report_location={'bucket': 'error-bucket', 'prefix': 'errors/'},
1124 | job_configuration={'fileFormat': {'csv': {}}},
1125 | adaptive_ingestion=True,
1126 | )
1127 | assert result['success'] is False
1128 | assert 'CSV configuration must have "columnNames" field' in result['error']
1129 |
1130 | def test_bulk_import_csv_validation_empty_column_names(self):
1131 | """Test CSV validation fails when columnNames is empty."""
1132 | result = create_bulk_import_job(
1133 | job_name='test-job',
1134 | job_role_arn='arn:aws:iam::123456789012:role/TestRole',
1135 | files=[{'bucket': 'test-bucket', 'key': 'test.csv'}],
1136 | error_report_location={'bucket': 'error-bucket', 'prefix': 'errors/'},
1137 | job_configuration={'fileFormat': {'csv': {'columnNames': []}}},
1138 | adaptive_ingestion=True,
1139 | )
1140 | assert result['success'] is False
1141 | assert 'CSV columnNames must be a non-empty list' in result['error']
1142 |
1143 | def test_bulk_import_csv_validation_invalid_column_name(self):
1144 | """Test CSV validation fails with invalid column name."""
1145 | result = create_bulk_import_job(
1146 | job_name='test-job',
1147 | job_role_arn='arn:aws:iam::123456789012:role/TestRole',
1148 | files=[{'bucket': 'test-bucket', 'key': 'test.csv'}],
1149 | error_report_location={'bucket': 'error-bucket', 'prefix': 'errors/'},
1150 | job_configuration={'fileFormat': {'csv': {'columnNames': ['INVALID_COLUMN']}}},
1151 | adaptive_ingestion=True,
1152 | )
1153 | assert result['success'] is False
1154 | assert 'Invalid column name: INVALID_COLUMN' in result['error']
1155 |
1156 | def test_bulk_import_csv_validation_all_three_identifiers(self):
1157 | """Test CSV validation fails when ASSET_ID, PROPERTY_ID, and ALIAS are all present."""
1158 | result = create_bulk_import_job(
1159 | job_name='test-job',
1160 | job_role_arn='arn:aws:iam::123456789012:role/TestRole',
1161 | files=[{'bucket': 'test-bucket', 'key': 'test.csv'}],
1162 | error_report_location={'bucket': 'error-bucket', 'prefix': 'errors/'},
1163 | job_configuration={
1164 | 'fileFormat': {
1165 | 'csv': {
1166 | 'columnNames': [
1167 | 'ASSET_ID',
1168 | 'PROPERTY_ID',
1169 | 'ALIAS',
1170 | 'TIMESTAMP_SECONDS',
1171 | 'VALUE',
1172 | 'DATA_TYPE',
1173 | ]
1174 | }
1175 | }
1176 | },
1177 | adaptive_ingestion=True,
1178 | )
1179 | assert result['success'] is False
1180 | assert 'CSV cannot include ASSET_ID, PROPERTY_ID, and ALIAS together' in result['error']
1181 |
1182 | def test_bulk_import_csv_validation_asset_id_without_property_id(self):
1183 | """Test CSV validation fails when ASSET_ID is present without PROPERTY_ID."""
1184 | result = create_bulk_import_job(
1185 | job_name='test-job',
1186 | job_role_arn='arn:aws:iam::123456789012:role/TestRole',
1187 | files=[{'bucket': 'test-bucket', 'key': 'test.csv'}],
1188 | error_report_location={'bucket': 'error-bucket', 'prefix': 'errors/'},
1189 | job_configuration={
1190 | 'fileFormat': {
1191 | 'csv': {'columnNames': ['ASSET_ID', 'TIMESTAMP_SECONDS', 'VALUE', 'DATA_TYPE']}
1192 | }
1193 | },
1194 | adaptive_ingestion=True,
1195 | )
1196 | assert result['success'] is False
1197 | assert 'CSV with ASSET_ID must also include PROPERTY_ID' in result['error']
1198 |
1199 | def test_bulk_import_csv_validation_property_id_without_asset_id(self):
1200 | """Test CSV validation fails when PROPERTY_ID is present without ASSET_ID."""
1201 | result = create_bulk_import_job(
1202 | job_name='test-job',
1203 | job_role_arn='arn:aws:iam::123456789012:role/TestRole',
1204 | files=[{'bucket': 'test-bucket', 'key': 'test.csv'}],
1205 | error_report_location={'bucket': 'error-bucket', 'prefix': 'errors/'},
1206 | job_configuration={
1207 | 'fileFormat': {
1208 | 'csv': {
1209 | 'columnNames': ['PROPERTY_ID', 'TIMESTAMP_SECONDS', 'VALUE', 'DATA_TYPE']
1210 | }
1211 | }
1212 | },
1213 | adaptive_ingestion=True,
1214 | )
1215 | assert result['success'] is False
1216 | assert 'CSV with PROPERTY_ID must also include ASSET_ID' in result['error']
1217 |
1218 | def test_bulk_import_csv_validation_no_identifier_columns(self):
1219 | """Test CSV validation fails when no identifier columns are present."""
1220 | result = create_bulk_import_job(
1221 | job_name='test-job',
1222 | job_role_arn='arn:aws:iam::123456789012:role/TestRole',
1223 | files=[{'bucket': 'test-bucket', 'key': 'test.csv'}],
1224 | error_report_location={'bucket': 'error-bucket', 'prefix': 'errors/'},
1225 | job_configuration={
1226 | 'fileFormat': {'csv': {'columnNames': ['TIMESTAMP_SECONDS', 'VALUE', 'DATA_TYPE']}}
1227 | },
1228 | adaptive_ingestion=True,
1229 | )
1230 | assert result['success'] is False
1231 | assert 'CSV must include either ALIAS or both ASSET_ID and PROPERTY_ID' in result['error']
1232 |
1233 | def test_bulk_import_csv_validation_missing_required_columns(self):
1234 | """Test CSV validation fails when required columns are missing."""
1235 | result = create_bulk_import_job(
1236 | job_name='test-job',
1237 | job_role_arn='arn:aws:iam::123456789012:role/TestRole',
1238 | files=[{'bucket': 'test-bucket', 'key': 'test.csv'}],
1239 | error_report_location={'bucket': 'error-bucket', 'prefix': 'errors/'},
1240 | job_configuration={
1241 | 'fileFormat': {'csv': {'columnNames': ['ALIAS', 'TIMESTAMP_SECONDS']}}
1242 | },
1243 | adaptive_ingestion=True,
1244 | )
1245 | assert result['success'] is False
1246 | assert 'CSV missing required columns' in result['error']
1247 |
1248 | def test_bulk_import_invalid_file_format(self):
1249 | """Test validation fails when neither CSV nor Parquet is specified."""
1250 | result = create_bulk_import_job(
1251 | job_name='test-job',
1252 | job_role_arn='arn:aws:iam::123456789012:role/TestRole',
1253 | files=[{'bucket': 'test-bucket', 'key': 'test.txt'}],
1254 | error_report_location={'bucket': 'error-bucket', 'prefix': 'errors/'},
1255 | job_configuration={'fileFormat': {'invalid': {}}},
1256 | adaptive_ingestion=True,
1257 | )
1258 | assert result['success'] is False
1259 | assert 'File format must specify either "csv" or "parquet"' in result['error']
1260 |
1261 | def test_bulk_import_missing_file_format(self):
1262 | """Test validation fails when fileFormat is missing."""
1263 | result = create_bulk_import_job(
1264 | job_name='test-job',
1265 | job_role_arn='arn:aws:iam::123456789012:role/TestRole',
1266 | files=[{'bucket': 'test-bucket', 'key': 'test.csv'}],
1267 | error_report_location={'bucket': 'error-bucket', 'prefix': 'errors/'},
1268 | job_configuration={},
1269 | adaptive_ingestion=True,
1270 | )
1271 | assert result['success'] is False
1272 | assert 'Job configuration must have "fileFormat" field' in result['error']
1273 |
1274 | def test_bulk_import_invalid_file_format_type(self):
1275 | """Test validation fails when fileFormat is not a dictionary."""
1276 | result = create_bulk_import_job(
1277 | job_name='test-job',
1278 | job_role_arn='arn:aws:iam::123456789012:role/TestRole',
1279 | files=[{'bucket': 'test-bucket', 'key': 'test.csv'}],
1280 | error_report_location={'bucket': 'error-bucket', 'prefix': 'errors/'},
1281 | job_configuration={'fileFormat': 'invalid'},
1282 | adaptive_ingestion=True,
1283 | )
1284 | assert result['success'] is False
1285 | assert 'File format must be a dictionary' in result['error']
1286 |
1287 | def test_describe_bulk_import_job_empty_job_id(self):
1288 | """Test validation fails with empty job ID."""
1289 | result = describe_bulk_import_job(job_id='')
1290 | assert result['success'] is False
1291 | assert 'Job ID must be a non-empty string' in result['error']
1292 |
1293 | def test_describe_bulk_import_job_invalid_uuid_length(self):
1294 | """Test validation fails with incorrect UUID length."""
1295 | result = describe_bulk_import_job(job_id='12345678-1234-1234-1234-12345678901') # 35 chars
1296 | assert result['success'] is False
1297 | assert 'Job ID must be in UUID format' in result['error']
1298 |
1299 | def test_describe_bulk_import_job_invalid_uuid_hyphens(self):
1300 | """Test validation fails with incorrect number of hyphens."""
1301 | result = describe_bulk_import_job(
1302 | job_id='123456781234123412341234567890123456'
1303 | ) # 36 chars, no hyphens
1304 | assert result['success'] is False
1305 | assert 'Job ID must be in UUID format' in result['error']
1306 |
1307 | def test_describe_bulk_import_job_invalid_uuid_format(self):
1308 | """Test validation fails with wrong hyphen positions."""
1309 | result = describe_bulk_import_job(
1310 | job_id='1234567-8123-1234-1234-567890123456', # 37 chars - too long
1311 | region='us-east-1',
1312 | )
1313 | assert result['success'] is False
1314 | assert 'Job ID must be in UUID format' in result['error']
1315 |
1316 | @patch('awslabs.aws_iot_sitewise_mcp_server.tools.sitewise_data.create_sitewise_client')
1317 | def test_bulk_import_csv_validation_valid_asset_property_combo(self, mock_boto_client):
1318 | """Test CSV validation passes with valid ASSET_ID + PROPERTY_ID combination."""
1319 | mock_client = Mock()
1320 | mock_boto_client.return_value = mock_client
1321 | mock_client.describe_storage_configuration.return_value = {
1322 | 'storageType': 'SITEWISE_DEFAULT_STORAGE',
1323 | 'warmTier': {'state': 'ENABLED'},
1324 | }
1325 | mock_client.create_bulk_import_job.return_value = {
1326 | 'jobId': 'test-job-id',
1327 | 'jobName': 'test-job',
1328 | 'jobStatus': 'PENDING',
1329 | }
1330 |
1331 | result = create_bulk_import_job(
1332 | job_name='test-job',
1333 | job_role_arn='arn:aws:iam::123456789012:role/TestRole',
1334 | files=[{'bucket': 'test-bucket', 'key': 'test.csv'}],
1335 | error_report_location={'bucket': 'error-bucket', 'prefix': 'errors/'},
1336 | job_configuration={
1337 | 'fileFormat': {
1338 | 'csv': {
1339 | 'columnNames': [
1340 | 'ASSET_ID',
1341 | 'PROPERTY_ID',
1342 | 'TIMESTAMP_SECONDS',
1343 | 'VALUE',
1344 | 'DATA_TYPE',
1345 | ]
1346 | }
1347 | }
1348 | },
1349 | adaptive_ingestion=True,
1350 | )
1351 | assert result['success'] is True
1352 |
1353 | @patch('awslabs.aws_iot_sitewise_mcp_server.tools.sitewise_data.create_sitewise_client')
1354 | def test_bulk_import_parquet_validation_valid(self, mock_boto_client):
1355 | """Test Parquet validation passes with valid configuration."""
1356 | mock_client = Mock()
1357 | mock_boto_client.return_value = mock_client
1358 | mock_client.describe_storage_configuration.return_value = {
1359 | 'storageType': 'SITEWISE_DEFAULT_STORAGE',
1360 | 'warmTier': {'state': 'ENABLED'},
1361 | }
1362 | mock_client.create_bulk_import_job.return_value = {
1363 | 'jobId': 'test-job-id',
1364 | 'jobName': 'test-job',
1365 | 'jobStatus': 'PENDING',
1366 | }
1367 |
1368 | result = create_bulk_import_job(
1369 | job_name='test-job',
1370 | job_role_arn='arn:aws:iam::123456789012:role/TestRole',
1371 | files=[{'bucket': 'test-bucket', 'key': 'test.parquet'}],
1372 | error_report_location={'bucket': 'error-bucket', 'prefix': 'errors/'},
1373 | job_configuration={'fileFormat': {'parquet': {}}},
1374 | adaptive_ingestion=True,
1375 | )
1376 | assert result['success'] is True
1377 |
1378 | def test_buffered_ingestion_job_inherits_csv_validation(self):
1379 | """Test that buffered ingestion job inherits CSV validation from bulk import."""
1380 | result = create_buffered_ingestion_job(
1381 | job_name='test-job',
1382 | job_role_arn='arn:aws:iam::123456789012:role/TestRole',
1383 | files=[{'bucket': 'test-bucket', 'key': 'test.csv'}],
1384 | error_report_location={'bucket': 'error-bucket', 'prefix': 'errors/'},
1385 | job_configuration={'fileFormat': {'csv': {'columnNames': ['INVALID_COLUMN']}}},
1386 | )
1387 | assert result['success'] is False
1388 | assert 'Invalid column name: INVALID_COLUMN' in result['error']
1389 |
1390 | def test_create_bulk_import_job_adaptive_ingestion_not_boolean(self):
1391 | """Test validation fails when adaptive_ingestion is not boolean."""
1392 | result = create_bulk_import_job(
1393 | job_name='test-job',
1394 | job_role_arn='arn:aws:iam::123456789012:role/TestRole',
1395 | files=[{'bucket': 'test-bucket', 'key': 'test.csv'}],
1396 | error_report_location={'bucket': 'error-bucket', 'prefix': 'errors/'},
1397 | job_configuration={
1398 | 'fileFormat': {
1399 | 'csv': {'columnNames': ['ALIAS', 'TIMESTAMP_SECONDS', 'VALUE', 'DATA_TYPE']}
1400 | }
1401 | },
1402 | adaptive_ingestion='not_boolean', # Invalid type
1403 | region='us-east-1',
1404 | )
1405 | assert result['success'] is False
1406 | assert 'Please provide a boolean value for adaptive_ingestion' in result['error']
1407 |
1408 | def test_create_bulk_import_job_control_characters_in_name(self):
1409 | """Test validation fails with control characters in job name."""
1410 | result = create_bulk_import_job(
1411 | job_name='test\x00job', # Contains null character
1412 | job_role_arn='arn:aws:iam::123456789012:role/TestRole',
1413 | files=[{'bucket': 'test-bucket', 'key': 'test.csv'}],
1414 | error_report_location={'bucket': 'error-bucket', 'prefix': 'errors/'},
1415 | job_configuration={
1416 | 'fileFormat': {
1417 | 'csv': {'columnNames': ['ALIAS', 'TIMESTAMP_SECONDS', 'VALUE', 'DATA_TYPE']}
1418 | }
1419 | },
1420 | adaptive_ingestion=True,
1421 | )
1422 | assert result['success'] is False
1423 | assert 'Job name cannot contain control characters' in result['error']
1424 |
1425 | def test_create_bulk_import_job_missing_job_role_arn(self):
1426 | """Test validation fails with missing job role ARN."""
1427 | result = create_bulk_import_job(
1428 | job_name='test-job',
1429 | job_role_arn='', # Empty ARN
1430 | files=[{'bucket': 'test-bucket', 'key': 'test.csv'}],
1431 | error_report_location={'bucket': 'error-bucket', 'prefix': 'errors/'},
1432 | job_configuration={
1433 | 'fileFormat': {'csv': {'columnNames': ['ALIAS', 'TIMESTAMP_SECONDS', 'VALUE']}}
1434 | },
1435 | adaptive_ingestion=True,
1436 | )
1437 | assert result['success'] is False
1438 | assert 'Job role ARN is required' in result['error']
1439 |
1440 | def test_create_bulk_import_job_invalid_arn_format(self):
1441 | """Test validation fails with invalid ARN format."""
1442 | result = create_bulk_import_job(
1443 | job_name='test-job',
1444 | job_role_arn='invalid-arn-format',
1445 | files=[{'bucket': 'test-bucket', 'key': 'test.csv'}],
1446 | error_report_location={'bucket': 'error-bucket', 'prefix': 'errors/'},
1447 | job_configuration={
1448 | 'fileFormat': {'csv': {'columnNames': ['ALIAS', 'TIMESTAMP_SECONDS', 'VALUE']}}
1449 | },
1450 | adaptive_ingestion=True,
1451 | )
1452 | assert result['success'] is False
1453 | assert 'Job role ARN must be a valid AWS ARN' in result['error']
1454 |
1455 | def test_create_bulk_import_job_arn_too_long(self):
1456 | """Test validation fails with ARN too long."""
1457 | result = create_bulk_import_job(
1458 | job_name='test-job',
1459 | job_role_arn='arn:aws:iam::123456789012:role/' + 'a' * 1600, # Too long
1460 | files=[{'bucket': 'test-bucket', 'key': 'test.csv'}],
1461 | error_report_location={'bucket': 'error-bucket', 'prefix': 'errors/'},
1462 | job_configuration={
1463 | 'fileFormat': {'csv': {'columnNames': ['ALIAS', 'TIMESTAMP_SECONDS', 'VALUE']}}
1464 | },
1465 | adaptive_ingestion=True,
1466 | )
1467 | assert result['success'] is False
1468 | assert 'Job role ARN must be between 1 and 1600 characters' in result['error']
1469 |
1470 | def test_create_bulk_import_job_files_not_list(self):
1471 | """Test validation fails when files is not a list."""
1472 | result = create_bulk_import_job(
1473 | job_name='test-job',
1474 | job_role_arn='arn:aws:iam::123456789012:role/TestRole',
1475 | files='not-a-list', # Invalid type
1476 | error_report_location={'bucket': 'error-bucket', 'prefix': 'errors/'},
1477 | job_configuration={
1478 | 'fileFormat': {'csv': {'columnNames': ['ALIAS', 'TIMESTAMP_SECONDS', 'VALUE']}}
1479 | },
1480 | adaptive_ingestion=True,
1481 | )
1482 | assert result['success'] is False
1483 | assert 'Files must be a non-empty list' in result['error']
1484 |
1485 | def test_create_bulk_import_job_file_not_dict(self):
1486 | """Test validation fails when file is not a dictionary."""
1487 | result = create_bulk_import_job(
1488 | job_name='test-job',
1489 | job_role_arn='arn:aws:iam::123456789012:role/TestRole',
1490 | files=['not-a-dict'], # Invalid type
1491 | error_report_location={'bucket': 'error-bucket', 'prefix': 'errors/'},
1492 | job_configuration={
1493 | 'fileFormat': {'csv': {'columnNames': ['ALIAS', 'TIMESTAMP_SECONDS', 'VALUE']}}
1494 | },
1495 | adaptive_ingestion=True,
1496 | )
1497 | assert result['success'] is False
1498 | assert 'Each file must be a dictionary' in result['error']
1499 |
1500 | def test_create_bulk_import_job_file_missing_bucket_key(self):
1501 | """Test validation fails when file missing bucket or key."""
1502 | result = create_bulk_import_job(
1503 | job_name='test-job',
1504 | job_role_arn='arn:aws:iam::123456789012:role/TestRole',
1505 | files=[{'bucket': 'test-bucket'}], # Missing key
1506 | error_report_location={'bucket': 'error-bucket', 'prefix': 'errors/'},
1507 | job_configuration={
1508 | 'fileFormat': {'csv': {'columnNames': ['ALIAS', 'TIMESTAMP_SECONDS', 'VALUE']}}
1509 | },
1510 | adaptive_ingestion=True,
1511 | )
1512 | assert result['success'] is False
1513 | assert 'Each file must have "bucket" and "key" fields' in result['error']
1514 |
1515 | def test_create_bulk_import_job_bucket_name_too_short(self):
1516 | """Test validation fails with bucket name too short."""
1517 | result = create_bulk_import_job(
1518 | job_name='test-job',
1519 | job_role_arn='arn:aws:iam::123456789012:role/TestRole',
1520 | files=[{'bucket': 'ab', 'key': 'test.csv'}], # Too short
1521 | error_report_location={'bucket': 'error-bucket', 'prefix': 'errors/'},
1522 | job_configuration={
1523 | 'fileFormat': {'csv': {'columnNames': ['ALIAS', 'TIMESTAMP_SECONDS', 'VALUE']}}
1524 | },
1525 | adaptive_ingestion=True,
1526 | )
1527 | assert result['success'] is False
1528 | assert 'S3 bucket name must be between 3 and 63 characters' in result['error']
1529 |
1530 | def test_create_bulk_import_job_error_location_not_dict(self):
1531 | """Test validation fails when error report location is not dict."""
1532 | result = create_bulk_import_job(
1533 | job_name='test-job',
1534 | job_role_arn='arn:aws:iam::123456789012:role/TestRole',
1535 | files=[{'bucket': 'test-bucket', 'key': 'test.csv'}],
1536 | error_report_location='not-a-dict', # Invalid type
1537 | job_configuration={
1538 | 'fileFormat': {'csv': {'columnNames': ['ALIAS', 'TIMESTAMP_SECONDS', 'VALUE']}}
1539 | },
1540 | adaptive_ingestion=True,
1541 | )
1542 | assert result['success'] is False
1543 | assert 'Error report location must be a dictionary' in result['error']
1544 |
1545 | def test_create_bulk_import_job_error_location_missing_fields(self):
1546 | """Test validation fails when error location missing fields."""
1547 | result = create_bulk_import_job(
1548 | job_name='test-job',
1549 | job_role_arn='arn:aws:iam::123456789012:role/TestRole',
1550 | files=[{'bucket': 'test-bucket', 'key': 'test.csv'}],
1551 | error_report_location={'bucket': 'error-bucket'}, # Missing prefix
1552 | job_configuration={
1553 | 'fileFormat': {'csv': {'columnNames': ['ALIAS', 'TIMESTAMP_SECONDS', 'VALUE']}}
1554 | },
1555 | adaptive_ingestion=True,
1556 | )
1557 | assert result['success'] is False
1558 | assert 'Error report location must have "bucket" and "prefix" fields' in result['error']
1559 |
1560 | def test_create_bulk_import_job_error_prefix_no_slash(self):
1561 | """Test validation fails when error prefix doesn't end with slash."""
1562 | result = create_bulk_import_job(
1563 | job_name='test-job',
1564 | job_role_arn='arn:aws:iam::123456789012:role/TestRole',
1565 | files=[{'bucket': 'test-bucket', 'key': 'test.csv'}],
1566 | error_report_location={
1567 | 'bucket': 'error-bucket',
1568 | 'prefix': 'errors',
1569 | }, # No trailing slash
1570 | job_configuration={
1571 | 'fileFormat': {'csv': {'columnNames': ['ALIAS', 'TIMESTAMP_SECONDS', 'VALUE']}}
1572 | },
1573 | adaptive_ingestion=True,
1574 | )
1575 | assert result['success'] is False
1576 | assert 'Error report prefix must end with a forward slash (/)' in result['error']
1577 |
1578 | def test_create_bulk_import_job_config_not_dict(self):
1579 | """Test validation fails when job configuration is not dict."""
1580 | result = create_bulk_import_job(
1581 | job_name='test-job',
1582 | job_role_arn='arn:aws:iam::123456789012:role/TestRole',
1583 | files=[{'bucket': 'test-bucket', 'key': 'test.csv'}],
1584 | error_report_location={'bucket': 'error-bucket', 'prefix': 'errors/'},
1585 | job_configuration='not-a-dict', # Invalid type
1586 | adaptive_ingestion=True,
1587 | )
1588 | assert result['success'] is False
1589 | assert 'Job configuration must be a dictionary' in result['error']
1590 |
1591 | @patch('awslabs.aws_iot_sitewise_mcp_server.tools.sitewise_data.create_sitewise_client')
1592 | def test_create_bulk_import_job_client_error(self, mock_create_client):
1593 | """Test handling of AWS client errors."""
1594 | mock_client = Mock()
1595 | mock_create_client.return_value = mock_client
1596 | mock_client.describe_storage_configuration.side_effect = ClientError(
1597 | {'Error': {'Code': 'AccessDenied', 'Message': 'Access denied'}},
1598 | 'DescribeStorageConfiguration',
1599 | )
1600 |
1601 | result = create_bulk_import_job(
1602 | job_name='test-job',
1603 | job_role_arn='arn:aws:iam::123456789012:role/TestRole',
1604 | files=[{'bucket': 'test-bucket', 'key': 'test.csv'}],
1605 | error_report_location={'bucket': 'error-bucket', 'prefix': 'errors/'},
1606 | job_configuration={
1607 | 'fileFormat': {
1608 | 'csv': {'columnNames': ['ALIAS', 'TIMESTAMP_SECONDS', 'VALUE', 'DATA_TYPE']}
1609 | }
1610 | },
1611 | adaptive_ingestion=False, # This will trigger storage config check
1612 | region='us-east-1',
1613 | )
1614 | assert result['success'] is False
1615 | assert 'Failed to validate storage configuration' in result['error']
1616 |
1617 | def test_create_bulk_import_job_error_bucket_too_short(self):
1618 | """Test create_bulk_import_job with error bucket name too short."""
1619 | result = create_bulk_import_job(
1620 | job_name='test-job',
1621 | job_role_arn='arn:aws:iam::123456789012:role/TestRole',
1622 | files=[{'bucket': 'test-bucket', 'key': 'test.csv'}],
1623 | error_report_location={'bucket': 'ab', 'prefix': 'errors/'},
1624 | job_configuration={
1625 | 'fileFormat': {
1626 | 'csv': {'columnNames': ['ALIAS', 'TIMESTAMP_SECONDS', 'VALUE', 'QUALITY']}
1627 | }
1628 | },
1629 | adaptive_ingestion=True,
1630 | )
1631 | assert result['success'] is False
1632 | assert 'Error report bucket name must be between 3 and 63 characters' in result['error']
1633 |
1634 | def test_create_bulk_import_job_prefix_no_slash(self):
1635 | """Test create_bulk_import_job with prefix not ending in slash."""
1636 | result = create_bulk_import_job(
1637 | job_name='test-job',
1638 | job_role_arn='arn:aws:iam::123456789012:role/TestRole',
1639 | files=[{'bucket': 'test-bucket', 'key': 'test.csv'}],
1640 | error_report_location={'bucket': 'test-bucket', 'prefix': 'errors'},
1641 | job_configuration={
1642 | 'fileFormat': {
1643 | 'csv': {'columnNames': ['ALIAS', 'TIMESTAMP_SECONDS', 'VALUE', 'QUALITY']}
1644 | }
1645 | },
1646 | adaptive_ingestion=True,
1647 | )
1648 | assert result['success'] is False
1649 | assert 'Error report prefix must end with a forward slash' in result['error']
1650 |
1651 | def test_list_bulk_import_jobs_invalid_filter(self):
1652 | """Test list_bulk_import_jobs with invalid filter."""
1653 | result = list_bulk_import_jobs(filter='INVALID')
1654 | assert result['success'] is False
1655 | assert 'Invalid filter: INVALID' in result['error']
1656 |
1657 | @patch('awslabs.aws_iot_sitewise_mcp_server.tools.sitewise_data.create_sitewise_client')
1658 | def test_list_bulk_import_jobs_client_error(self, mock_client):
1659 | """Test list_bulk_import_jobs with AWS client error."""
1660 | mock_sitewise = Mock()
1661 | mock_client.return_value = mock_sitewise
1662 | mock_sitewise.list_bulk_import_jobs.side_effect = ClientError(
1663 | {'Error': {'Code': 'AccessDenied', 'Message': 'Access denied'}}, 'ListBulkImportJobs'
1664 | )
1665 |
1666 | result = list_bulk_import_jobs()
1667 |
1668 | assert result['success'] is False
1669 | assert result['error_code'] == 'AccessDenied'
1670 |
1671 | @patch(
1672 | 'awslabs.aws_iot_sitewise_mcp_server.validation.check_storage_configuration_requirements'
1673 | )
1674 | @patch('awslabs.aws_iot_sitewise_mcp_server.tools.sitewise_data.create_sitewise_client')
1675 | def test_create_bulk_import_job_aws_error(self, mock_client, mock_storage):
1676 | """Test create_bulk_import_job AWS ClientError handling."""
1677 | mock_storage.return_value = None
1678 | mock_sitewise = Mock()
1679 | mock_client.return_value = mock_sitewise
1680 | mock_sitewise.create_bulk_import_job.side_effect = ClientError(
1681 | {'Error': {'Code': 'AccessDenied', 'Message': 'Access denied'}}, 'CreateBulkImportJob'
1682 | )
1683 |
1684 | result = create_bulk_import_job(
1685 | job_name='test-job',
1686 | job_role_arn='arn:aws:iam::123456789012:role/TestRole',
1687 | files=[{'bucket': 'test-bucket', 'key': 'test.csv'}],
1688 | error_report_location={'bucket': 'test-bucket', 'prefix': 'errors/'},
1689 | job_configuration={
1690 | 'fileFormat': {
1691 | 'csv': {'columnNames': ['ALIAS', 'TIMESTAMP_SECONDS', 'VALUE', 'DATA_TYPE']}
1692 | }
1693 | },
1694 | adaptive_ingestion=True,
1695 | )
1696 |
1697 | assert result['success'] is False
1698 | assert result['error_code'] == 'AccessDenied'
1699 |
1700 | @patch('awslabs.aws_iot_sitewise_mcp_server.tools.sitewise_data.create_sitewise_client')
1701 | def test_list_bulk_import_jobs_aws_error(self, mock_client):
1702 | """Test list_bulk_import_jobs AWS ClientError handling."""
1703 | mock_sitewise = Mock()
1704 | mock_client.return_value = mock_sitewise
1705 | mock_sitewise.list_bulk_import_jobs.side_effect = ClientError(
1706 | {'Error': {'Code': 'ThrottlingException', 'Message': 'Rate exceeded'}},
1707 | 'ListBulkImportJobs',
1708 | )
1709 |
1710 | result = list_bulk_import_jobs()
1711 |
1712 | assert result['success'] is False
1713 | assert result['error_code'] == 'ThrottlingException'
1714 |
1715 | @patch('awslabs.aws_iot_sitewise_mcp_server.tools.sitewise_data.create_sitewise_client')
1716 | def test_describe_bulk_import_job_aws_error(self, mock_client):
1717 | """Test describe_bulk_import_job AWS ClientError handling."""
1718 | mock_sitewise = Mock()
1719 | mock_client.return_value = mock_sitewise
1720 | mock_sitewise.describe_bulk_import_job.side_effect = ClientError(
1721 | {'Error': {'Code': 'ResourceNotFound', 'Message': 'Job not found'}},
1722 | 'DescribeBulkImportJob',
1723 | )
1724 |
1725 | result = describe_bulk_import_job(job_id='12345678-1234-1234-1234-123456789012')
1726 |
1727 | assert result['success'] is False
1728 | assert result['error_code'] == 'ResourceNotFound'
1729 |
1730 | @patch('awslabs.aws_iot_sitewise_mcp_server.tools.sitewise_data.create_sitewise_client')
1731 | def test_list_bulk_import_jobs_region_validation_workflow(self, mock_client):
1732 | """Test list_bulk_import_jobs region validation in workflow."""
1733 | result = list_bulk_import_jobs(
1734 | filter='ALL', next_token=None, max_results=50, region='invalid_region!'
1735 | )
1736 |
1737 | assert result['success'] is False
1738 | assert result['error_code'] == 'ValidationException'
1739 | assert 'Invalid AWS region format' in result['error']
1740 |
1741 | @patch('awslabs.aws_iot_sitewise_mcp_server.tools.sitewise_data.create_sitewise_client')
1742 | def test_list_bulk_import_jobs_max_results_validation_workflow(self, mock_client):
1743 | """Test list_bulk_import_jobs max_results validation in workflow."""
1744 | result = list_bulk_import_jobs(
1745 | filter='ALL', next_token=None, max_results=0, region='us-east-1'
1746 | )
1747 |
1748 | assert result['success'] is False
1749 | assert result['error_code'] == 'ValidationException'
1750 | assert 'Max results must be at least 1' in result['error']
1751 |
1752 |
1753 | if __name__ == '__main__':
1754 | pytest.main([__file__])
1755 |
```