Skip to content

Commit e9962b1

Browse files
authored
Merge branch 'awslabs:main' into main
2 parents 3e5cdd6 + e6c4675 commit e9962b1

File tree

30 files changed

+607
-73
lines changed

30 files changed

+607
-73
lines changed

.github/CODEOWNERS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ NOTICE @awslabs/mcp-admins
3333
/src/aws-bedrock-data-automation-mcp-server @awslabs/mcp-admins @awslabs/mcp-maintainers @krokoko @theagenticguy @alexa-perlov # @ayush987goyal
3434
/src/aws-dataprocessing-mcp-server @awslabs/mcp-admins @awslabs/mcp-maintainers @naikvaib @LiyuanLD @ckha2000 @raghav1397 @chappidim @yuxiaorun
3535
/src/aws-diagram-mcp-server @awslabs/mcp-admins @awslabs/mcp-maintainers @MichaelWalker-git
36-
/src/aws-documentation-mcp-server @awslabs/mcp-admins @awslabs/mcp-maintainers @Lavoiedavidw @JonLim @tuanknguyen
36+
/src/aws-documentation-mcp-server @awslabs/mcp-admins @awslabs/mcp-maintainers @Lavoiedavidw @JonLim @tuanknguyen @AadityaBhoota @artb30 @alexisareyn
3737
/src/document-loader-mcp-server @awslabs/mcp-admins @awslabs/mcp-maintainers @andywidjaja @hvital @HaoOliv
3838
/src/aws-healthomics-mcp-server @awslabs/mcp-admins @awslabs/mcp-maintainers @markjschreiber @WIIASD @a-li @alxawan
3939
/src/aws-iac-mcp-server @awslabs/mcp-admins @awslabs/mcp-maintainers @kdbrogan @vishaalmehrishi @aemada-aws @kumvprat

src/aws-api-mcp-server/CHANGELOG.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## Unreleased
99

10-
### Fixed
10+
### Changed
11+
12+
- Updated default AWS API connect and read timeout (#1876)
13+
- Upgrade AWS CLI to v1.43.10 (#1891)
14+
- Support `aws login` (#1873)
15+
- AWS CLI operations 'help' command support (#1858)
1116

17+
## [1.1.8] - 2025-11-28
18+
19+
### Fixed
1220
- Origin header parsing (#1851)
1321

1422
## [1.1.7] - 2025-11-20

src/aws-api-mcp-server/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ This server acts as a bridge between AI assistants and AWS services, allowing yo
1717

1818
Choose the installation method that best fits your workflow and get started with your favorite assistant with MCP support, like Q CLI, Cursor or Cline.
1919

20-
| Cursor | VS Code |
21-
|:------:|:-------:|
22-
| [![Install MCP Server](https://cursor.com/deeplink/mcp-install-light.svg)](https://cursor.com/en/install-mcp?name=awslabs.aws-api-mcp-server&config=eyJjb21tYW5kIjoidXZ4IGF3c2xhYnMuYXdzLWFwaS1tY3Atc2VydmVyQGxhdGVzdCIsImVudiI6eyJBV1NfUkVHSU9OIjoidXMtZWFzdC0xIn0sImRpc2FibGVkIjpmYWxzZSwiYXV0b0FwcHJvdmUiOltdfQ%3D%3D) | [![Install on VS Code](https://img.shields.io/badge/Install_on-VS_Code-FF9900?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=AWS%20API%20MCP%20Server&config=%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22awslabs.aws-api-mcp-server%40latest%22%5D%2C%22env%22%3A%7B%22AWS_REGION%22%3A%22us-east-1%22%7D%2C%22type%22%3A%22stdio%22%7D) |
20+
| Cursor | VS Code | Kiro |
21+
|:------:|:-------:|:----:|
22+
| [![Install MCP Server](https://cursor.com/deeplink/mcp-install-light.svg)](https://cursor.com/en/install-mcp?name=awslabs.aws-api-mcp-server&config=eyJjb21tYW5kIjoidXZ4IGF3c2xhYnMuYXdzLWFwaS1tY3Atc2VydmVyQGxhdGVzdCIsImVudiI6eyJBV1NfUkVHSU9OIjoidXMtZWFzdC0xIn0sImRpc2FibGVkIjpmYWxzZSwiYXV0b0FwcHJvdmUiOltdfQ%3D%3D) | [![Install on VS Code](https://img.shields.io/badge/Install_on-VS_Code-FF9900?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=AWS%20API%20MCP%20Server&config=%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22awslabs.aws-api-mcp-server%40latest%22%5D%2C%22env%22%3A%7B%22AWS_REGION%22%3A%22us-east-1%22%7D%2C%22type%22%3A%22stdio%22%7D) | [![Add to Kiro](https://kiro.dev/images/add-to-kiro.svg)](https://kiro.dev/launch/mcp/add?name=awslabs.aws-api-mcp-server&config=%7B%22command%22%3A%20%22uvx%22%2C%20%22args%22%3A%20%5B%22awslabs.aws-api-mcp-server%40latest%22%5D%2C%20%22disabled%22%3A%20false%2C%20%22autoApprove%22%3A%20%5B%5D%7D) |
2323

2424

2525

src/aws-api-mcp-server/awslabs/aws_api_mcp_server/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@
1414

1515
"""awslabs.aws-api-mcp-server"""
1616

17-
__version__ = '1.1.8'
17+
__version__ = '1.2.0'

src/aws-api-mcp-server/awslabs/aws_api_mcp_server/core/aws/service.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from ..aws.services import get_awscli_driver
1717
from ..common.config import AWS_API_MCP_PROFILE_NAME, DEFAULT_REGION
1818
from ..common.errors import AwsApiMcpError, Failure
19+
from ..common.help_command import generate_help_document
1920
from ..common.models import (
2021
AwsCliAliasResponse,
2122
Consent,
@@ -36,7 +37,7 @@
3637
from ..security.policy import PolicyDecision, SecurityPolicy
3738
from .driver import interpret_command as _interpret_command
3839
from awslabs.aws_api_mcp_server.core.common.command import IRCommand
39-
from awslabs.aws_api_mcp_server.core.common.helpers import operation_timer
40+
from awslabs.aws_api_mcp_server.core.common.helpers import as_json, operation_timer
4041
from fastmcp import Context
4142
from fastmcp.server.elicitation import AcceptedElicitation
4243
from io import StringIO
@@ -124,6 +125,24 @@ def validate(ir: IRTranslation) -> ProgramValidationResponse:
124125
)
125126

126127

128+
async def get_help_document(
129+
cli_command: str,
130+
ctx: Context,
131+
) -> ProgramInterpretationResponse:
132+
"""Get help command response."""
133+
args = split_cli_command(cli_command)[1:]
134+
service_name = args[0]
135+
operation_name = args[1]
136+
help_document = generate_help_document(service_name, operation_name)
137+
if help_document is None:
138+
error_message = 'Failed to generate help document'
139+
await ctx.error(error_message)
140+
raise AwsApiMcpError(error_message)
141+
return ProgramInterpretationResponse(
142+
response=InterpretationResponse(json=as_json(help_document), status_code=200, error=None)
143+
)
144+
145+
127146
def execute_awscli_customization(
128147
cli_command: str,
129148
ir_command: IRCommand,

src/aws-api-mcp-server/awslabs/aws_api_mcp_server/core/common/command.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class IRCommand:
4545
profile: str | None = None
4646
client_side_filter: ParsedResult | None = None
4747
is_awscli_customization: bool = False
48+
is_help_operation: bool = False
4849
output_file: OutputFile | None = None
4950
endpoint_url: str | None = None
5051

src/aws-api-mcp-server/awslabs/aws_api_mcp_server/core/common/config.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ def get_user_agent_extra() -> str:
117117

118118
if client_params := ctx.session.client_params:
119119
user_agent_extra += (
120-
f' MCPClient/{client_params.clientInfo.name}-{client_params.clientInfo.version}'
120+
f' MCPClient/{client_params.clientInfo.name}#{client_params.clientInfo.version}'
121121
)
122122
except RuntimeError:
123123
pass # get_context throws a RuntimeError when called outside of a server request, we can safely ingore that
@@ -150,3 +150,5 @@ def get_user_agent_extra() -> str:
150150
ENDPOINT_SUGGEST_AWS_COMMANDS = os.getenv(
151151
'ENDPOINT_SUGGEST_AWS_COMMANDS', 'https://api-mcp.global.api.aws/suggest-aws-commands'
152152
)
153+
CONNECT_TIMEOUT_SECONDS = 10
154+
READ_TIMEOUT_SECONDS = 60
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
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+
import re
16+
from ..parser.parser import driver
17+
from awscli.bcdoc.restdoc import ReSTDocument
18+
from awscli.clidriver import ServiceCommand
19+
from awscli.customizations.commands import BasicCommand
20+
from loguru import logger
21+
from typing import Any
22+
23+
24+
IGNORED_ARGUMENTS = frozenset({'cli-input-json', 'generate-cli-skeleton'})
25+
26+
27+
def _clean_text(text: str) -> str:
28+
text = re.sub(r'\s+', ' ', text) # Normalize whitespace
29+
return text.strip()
30+
31+
32+
def _clean_description(description: str) -> str:
33+
"""This removes the section title added by the help event handlers."""
34+
description = re.sub(r'=+\s*Description\s*=+\s', '', description)
35+
return _clean_text(description)
36+
37+
38+
def generate_help_document(service_name: str, operation_name: str) -> dict[str, Any] | None:
39+
"""Generate a document for a single AWS API operation."""
40+
command = driver._get_command_table()[service_name]
41+
if isinstance(command, BasicCommand):
42+
command_table = command.subcommand_table
43+
elif isinstance(command, ServiceCommand):
44+
command_table = command._get_command_table()
45+
else:
46+
logger.warning(f'Unknown command type {service_name} {command}')
47+
return None
48+
49+
operation = command_table[operation_name]
50+
51+
help_command = operation.create_help_command()
52+
event_handler = help_command.EventHandlerClass(help_command)
53+
54+
# Get description
55+
event_handler.doc_description(help_command)
56+
description = _clean_description(help_command.doc.getvalue().decode('utf-8')).strip()
57+
58+
# Get parameters
59+
params = {}
60+
seen_arg_groups = set()
61+
for arg_name, arg in help_command.arg_table.items():
62+
if getattr(arg, '_UNDOCUMENTED', False) or arg_name in IGNORED_ARGUMENTS:
63+
continue
64+
if arg.group_name in seen_arg_groups:
65+
continue
66+
help_command.doc = ReSTDocument()
67+
if hasattr(event_handler, 'doc'):
68+
event_handler.doc = help_command.doc
69+
event_handler.doc_option(help_command=help_command, arg_name=arg_name)
70+
key = arg.group_name if arg.group_name else arg_name
71+
params[key] = _clean_text(help_command.doc.getvalue().decode('utf-8').strip())
72+
params[key] = params[key][:500] if len(params[key]) > 500 else params[key]
73+
if arg.group_name:
74+
# To avoid adding arguments like --disable-rollback and --no-disable-rollback separately
75+
# we need to make sure a group name is only processed once
76+
# event_handler.doc_option takes care of mentioning all arguments in a group
77+
# so we can safely skip the remaining arguments in the group
78+
seen_arg_groups.add(arg.group_name)
79+
80+
return {
81+
'command': f'aws {service_name} {operation_name}',
82+
'description': description,
83+
'parameters': params,
84+
}

src/aws-api-mcp-server/awslabs/aws_api_mcp_server/core/common/helpers.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@ def expand_user_home_directory(args: list[str]) -> list[str]:
6565
return [os.path.expanduser(arg) for arg in args]
6666

6767

68+
def is_help_operation(args: list[Any]) -> bool:
69+
"""Check if the command is a help operation."""
70+
return any(str(arg).lower() in ['help', '--help'] for arg in args)
71+
72+
6873
def validate_aws_region(region: str):
6974
"""Checks if provided region is a valid AWS Region."""
7075
aws_region_pattern = '^(\\w{1,10})-(\\w{1,10}-)?(\\w{1,10})-\\d{1,2}$'

src/aws-api-mcp-server/awslabs/aws_api_mcp_server/core/parser/interpretation.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
extract_pagination_config,
1919
)
2020
from ..common.command import IRCommand, OutputFile
21-
from ..common.config import get_user_agent_extra
21+
from ..common.config import CONNECT_TIMEOUT_SECONDS, READ_TIMEOUT_SECONDS, get_user_agent_extra
2222
from ..common.file_system_controls import validate_file_path
2323
from ..common.helpers import operation_timer
2424
from botocore.config import Config
@@ -51,8 +51,8 @@ def interpret(
5151

5252
config = Config(
5353
region_name=region,
54-
connect_timeout=TIMEOUT_AFTER_SECONDS,
55-
read_timeout=TIMEOUT_AFTER_SECONDS,
54+
connect_timeout=CONNECT_TIMEOUT_SECONDS,
55+
read_timeout=READ_TIMEOUT_SECONDS,
5656
retries={'max_attempts': 3, 'mode': 'adaptive'},
5757
user_agent_extra=get_user_agent_extra(),
5858
)

0 commit comments

Comments
 (0)