Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/ecs-mcp-server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ An MCP server for containerizing applications, deploying applications to Amazon
- **Security Best Practices**: Implement AWS security best practices for container deployments
- **Resource Management**: List and explore ECS resources such as task definitions, services, clusters, and tasks
- **ECR Integration**: View repositories and container images in Amazon ECR
- **AWS Knowledge Integration**: Access up-to-date AWS documentation through the integrated AWS Knowledge MCP Server proxy which includes knowledge on ECS and new features released that models may not be aware of

Customers can use the `containerize_app` tool to help them containerize their applications with best practices and deploy them to Amazon ECS. The `create_ecs_infrastructure` tool automates infrastructure deployment using CloudFormation, while `get_deployment_status` returns the status of deployments and provide the URL of the set up Application Load Balancer. When resources are no longer needed, the `delete_ecs_infrastructure` tool allows for easy cleanup and removal of all deployed components.

Expand Down Expand Up @@ -86,6 +87,9 @@ The following operations are read-only and relatively safe for production enviro
| `ecs_troubleshooting_tool` | `fetch_service_events` | ✅ Safe - Read-only |
| `ecs_troubleshooting_tool` | `get_ecs_troubleshooting_guidance` | ✅ Safe - Read-only |
| `get_deployment_status` | Status checking | ✅ Safe - Read-only |
| `aws_knowledge_aws___search_documentation` | AWS documentation search | ✅ Safe - Read-only |
| `aws_knowledge_aws___read_documentation` | AWS documentation reading | ✅ Safe - Read-only |
| `aws_knowledge_aws___recommend` | AWS documentation recommendations | ✅ Safe - Read-only |

The following operations modify resources and should be used with extreme caution in production:

Expand Down Expand Up @@ -298,6 +302,16 @@ This tool provides comprehensive access to Amazon ECS resources to help you moni

The resource management tool enforces permission checks for write operations. Operations that modify resources require the ALLOW_WRITE environment variable to be set to true.

### AWS Documentation Tools

The ECS MCP Server integrates with the AWS Knowledge MCP Server to provide access to up-to-date AWS documentation, including ECS-specific knowledge about new features recently launched that models may not be aware of.

- **aws_knowledge_aws___search_documentation**: Search across all AWS documentation including the latest AWS docs, API references, Blogs posts, Architectural references, and Well-Architected best practices.

- **aws_knowledge_aws___read_documentation**: Fetch and convert AWS documentation pages to markdown format.

- **aws_knowledge_aws___recommend**: Get content recommendations for AWS documentation pages.

## Example Prompts

### Containerization and Deployment
Expand Down Expand Up @@ -330,6 +344,12 @@ The resource management tool enforces permission checks for write operations. Op
- "Run a task in my cluster"
- "Stop a running task"

### AWS Documentation and Knowledge

- "What are the best practices for ECS deployments?"
- "How do I set up blue-green deployments in ECS?"
- "Get recommendations for ECS security best practices"

## Requirements

- Python 3.10+
Expand Down
121 changes: 74 additions & 47 deletions src/ecs-mcp-server/awslabs/ecs_mcp_server/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,13 @@
import logging
import os
import sys
from contextlib import asynccontextmanager
from typing import Any, Dict, Tuple

from fastmcp import FastMCP

from awslabs.ecs_mcp_server.modules import (
aws_knowledge_proxy,
containerize,
delete,
deployment_status,
Expand All @@ -36,42 +39,58 @@
secure_tool,
)

# Configure logging
log_level = os.environ.get("FASTMCP_LOG_LEVEL", "INFO")
log_format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
log_file = os.environ.get("FASTMCP_LOG_FILE")

# Set up basic configuration
logging.basicConfig(
level=log_level,
format=log_format,
)
def _setup_logging() -> logging.Logger:
"""Configure logging for the server."""
log_level = os.environ.get("FASTMCP_LOG_LEVEL", "INFO")
log_format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
log_file = os.environ.get("FASTMCP_LOG_FILE")

# Add file handler if log file path is specified
if log_file:
try:
# Create directory for log file if it doesn't exist
log_dir = os.path.dirname(log_file)
if log_dir and not os.path.exists(log_dir):
os.makedirs(log_dir, exist_ok=True)

# Add file handler
file_handler = logging.FileHandler(log_file)
file_handler.setFormatter(logging.Formatter(log_format))
logging.getLogger().addHandler(file_handler)
logging.info(f"Logging to file: {log_file}")
except Exception as e:
logging.error(f"Failed to set up log file {log_file}: {e}")
logging.basicConfig(level=log_level, format=log_format)

if log_file:
try:
log_dir = os.path.dirname(log_file)
if log_dir and not os.path.exists(log_dir):
os.makedirs(log_dir, exist_ok=True)

file_handler = logging.FileHandler(log_file)
file_handler.setFormatter(logging.Formatter(log_format))
logging.getLogger().addHandler(file_handler)
logging.info(f"Logging to file: {log_file}")
except Exception as e:
logging.error(f"Failed to set up log file {log_file}: {e}")

return logging.getLogger("ecs-mcp-server")


@asynccontextmanager
async def server_lifespan(server):
"""
Server lifespan context manager for initialization and cleanup.

logger = logging.getLogger("ecs-mcp-server")
Provides safe access to async server methods during startup for
operations like tool transformations.
"""
logger = logging.getLogger("ecs-mcp-server")
logger.info("Server initializing")

# Load configuration
config = get_config()
# Safe async operations can be performed here
await aws_knowledge_proxy.apply_tool_transformations(server)

# Create the MCP server
mcp = FastMCP(
name="AWS ECS MCP Server",
instructions="""Use this server to containerize and deploy web applications to AWS ECS.
logger.info("Server ready")
yield
logger.info("Server shutting down")


def _create_ecs_mcp_server() -> Tuple[FastMCP, Dict[str, Any]]:
"""Create and configure the MCP server."""
config = get_config()

mcp = FastMCP(
name="AWS ECS MCP Server",
lifespan=server_lifespan,
instructions="""Use this server to containerize and deploy web applications to AWS ECS.

WORKFLOW:
1. containerize_app:
Expand All @@ -97,30 +116,38 @@
- Set ALLOW_WRITE=true to enable infrastructure creation and deletion
- Set ALLOW_SENSITIVE_DATA=true to enable access to logs and detailed resource information
""",
)
)

# Apply security wrappers to API functions
# Write operations
infrastructure.create_infrastructure = secure_tool(
config, PERMISSION_WRITE, "create_ecs_infrastructure"
)(infrastructure.create_infrastructure)
delete.delete_infrastructure = secure_tool(config, PERMISSION_WRITE, "delete_ecs_infrastructure")(
delete.delete_infrastructure
)
# Apply security wrappers to API functions
# Write operations
infrastructure.create_infrastructure = secure_tool(
config, PERMISSION_WRITE, "create_ecs_infrastructure"
)(infrastructure.create_infrastructure)
delete.delete_infrastructure = secure_tool(
config, PERMISSION_WRITE, "delete_ecs_infrastructure"
)(delete.delete_infrastructure)

# Register all modules
containerize.register_module(mcp)
infrastructure.register_module(mcp)
deployment_status.register_module(mcp)
resource_management.register_module(mcp)
troubleshooting.register_module(mcp)
delete.register_module(mcp)

# Register all modules
containerize.register_module(mcp)
infrastructure.register_module(mcp)
deployment_status.register_module(mcp)
resource_management.register_module(mcp)
troubleshooting.register_module(mcp)
delete.register_module(mcp)
# Register all proxies
aws_knowledge_proxy.register_proxy(mcp)

return mcp, config


def main() -> None:
"""Main entry point for the ECS MCP Server."""
try:
# Start the server
mcp, config = _create_ecs_mcp_server()
logger = _setup_logging()

logger.info("Server started")
logger.info(f"Write operations enabled: {config.get('allow-write', False)}")
logger.info(f"Sensitive data access enabled: {config.get('allow-sensitive-data', False)}")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
AWS Knowledge Proxy module for ECS MCP Server.
This module handles the setup and configuration of the AWS Knowledge MCP Server proxy integration.
"""

import logging
from typing import Optional

from fastmcp import FastMCP
from fastmcp.server.proxy import ProxyClient
from fastmcp.tools.tool_transform import ToolTransformConfig

# Guidance to append to tool descriptions
# ruff: noqa: E501
ECS_TOOL_GUIDANCE = """

## ECS DOCUMENTATION GUIDANCE:
This tool provides up-to-date ECS documentation and implementation guidance, including new ECS features beyond standard LLM training data.

New ECS features include:
- ECS Native Blue-Green Deployments (different from CodeDeploy blue-green, launched 2025)
"""

logger = logging.getLogger(__name__)


def register_proxy(mcp: FastMCP) -> Optional[bool]:
"""
Sets up the AWS Knowledge MCP Server proxy integration.

Args:
mcp: The FastMCP server instance to mount the proxy on

Returns:
bool: True if setup was successful, False otherwise
"""
try:
logger.info("Setting up AWS Knowledge MCP Server proxy")
proxy_config = {
"mcpServers": {
"aws-knowledge-mcp-server": {
"command": "uvx",
"args": [
"mcp-proxy",
"--transport",
"streamablehttp",
"https://knowledge-mcp.global.api.aws",
],
}
}
}

# Create and mount the proxy
aws_knowledge_proxy = FastMCP.as_proxy(ProxyClient(proxy_config))
mcp.mount(aws_knowledge_proxy, prefix="aws_knowledge")

# Add prompt patterns for blue-green deployments
register_ecs_prompts(mcp)

logger.info("Successfully mounted AWS Knowledge MCP Server")
return True

except Exception as e:
logger.error(f"Failed to setup AWS Knowledge MCP Server proxy: {e}")
return False


async def apply_tool_transformations(mcp: FastMCP) -> None:
"""
Apply tool transformations to the AWS Knowledge proxy tools.

Args:
mcp: The FastMCP server instance to apply transformations to
"""
logger.info("Applying tool transformations...")
await _add_ecs_guidance_to_knowledge_tools(mcp)


async def _add_ecs_guidance_to_knowledge_tools(mcp: FastMCP) -> None:
"""Add ECS documentation guidance to specific tools if they exist."""
try:
tools = await mcp.get_tools()

knowledge_tools = [
"aws_knowledge_aws___search_documentation",
"aws_knowledge_aws___read_documentation",
"aws_knowledge_aws___recommend",
]

for tool_name in knowledge_tools:
if tool_name not in tools:
logger.warning(f"Tool {tool_name} not found in MCP tools")
continue

original_desc = tools[tool_name].description or ""
config = ToolTransformConfig(
name=tool_name, description=original_desc + ECS_TOOL_GUIDANCE
)
mcp.add_tool_transformation(tool_name, config)

logger.debug("Added ECS guidance to AWS Knowledge tools")
except Exception as e:
logger.error(f"Error applying tool transformations: {e}")
raise


def register_ecs_prompts(mcp: FastMCP) -> None:
"""
Register ECS-related prompt patterns with AWS Knowledge proxy tools.

Covers blue-green deployments, new ECS features, and comparisons based on ECS_TOOL_GUIDANCE.

Args:
mcp: The FastMCP server instance to register prompts with
"""

prompts = [
{
"patterns": [
"what are blue green deployments",
"what are b/g deployments",
"native ecs blue green",
"native ecs b/g",
"ecs native blue green deployments",
"difference between codedeploy and native blue green",
"how to setup blue green",
"setup ecs blue green",
"configure ecs blue green deployments",
"configure blue green",
"configure b/g",
"create blue green deployment",
],
"response": [
{
"name": "aws_knowledge_aws___search_documentation",
}
],
},
{
"patterns": [
"ecs best practices",
"ecs implementation guide",
"ecs guidance",
"ecs recommendations",
"how to use ecs effectively",
"new ecs feature",
"latest ecs feature",
],
"response": [
{
"name": "aws_knowledge_aws___search_documentation",
}
],
},
]

# Register all prompt patterns using loops
total_patterns = 0
for prompt_group in prompts:
patterns = prompt_group["patterns"]
response = prompt_group["response"]

for pattern in patterns:

def create_prompt_handler(response_data):
def prompt_handler():
return response_data

return prompt_handler

handler = create_prompt_handler(response)
mcp.prompt(pattern)(handler)
total_patterns += 1

logger.info(
f"Registered {total_patterns} ECS-related prompt patterns with AWS Knowledge proxy tools"
)
Loading