awslabs.cdk-mcp-server 1.0.1__tar.gz → 1.0.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/Dockerfile +3 -3
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/PKG-INFO +2 -2
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/README.md +1 -1
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/awslabs/cdk_mcp_server/data/solutions_constructs_parser.py +94 -22
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/pyproject.toml +1 -1
- awslabs_cdk_mcp_server-1.0.2/tests/data/test_solutions_constructs_parser.py +832 -0
- awslabs_cdk_mcp_server-1.0.1/.pre-commit-config.yaml +0 -14
- awslabs_cdk_mcp_server-1.0.1/tests/data/test_solutions_constructs_parser.py +0 -214
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/.gitignore +0 -0
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/.python-version +0 -0
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/CHANGELOG.md +0 -0
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/LICENSE +0 -0
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/NOTICE +0 -0
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/awslabs/__init__.py +0 -0
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/awslabs/cdk_mcp_server/__init__.py +0 -0
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/awslabs/cdk_mcp_server/core/__init__.py +0 -0
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/awslabs/cdk_mcp_server/core/resources.py +0 -0
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/awslabs/cdk_mcp_server/core/search_utils.py +0 -0
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/awslabs/cdk_mcp_server/core/server.py +0 -0
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/awslabs/cdk_mcp_server/core/tools.py +0 -0
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/awslabs/cdk_mcp_server/data/__init__.py +0 -0
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/awslabs/cdk_mcp_server/data/cdk_nag_parser.py +0 -0
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/awslabs/cdk_mcp_server/data/construct_descriptions.py +0 -0
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/awslabs/cdk_mcp_server/data/genai_cdk_loader.py +0 -0
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/awslabs/cdk_mcp_server/data/lambda_layer_parser.py +0 -0
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/awslabs/cdk_mcp_server/data/lambda_powertools_loader.py +0 -0
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/awslabs/cdk_mcp_server/data/schema_generator.py +0 -0
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/awslabs/cdk_mcp_server/server.py +0 -0
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/awslabs/cdk_mcp_server/static/CDK_GENERAL_GUIDANCE.md +0 -0
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/awslabs/cdk_mcp_server/static/CDK_NAG_GUIDANCE.md +0 -0
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/awslabs/cdk_mcp_server/static/__init__.py +0 -0
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/awslabs/cdk_mcp_server/static/lambda_powertools/bedrock.md +0 -0
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/awslabs/cdk_mcp_server/static/lambda_powertools/cdk.md +0 -0
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/awslabs/cdk_mcp_server/static/lambda_powertools/dependencies.md +0 -0
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/awslabs/cdk_mcp_server/static/lambda_powertools/index.md +0 -0
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/awslabs/cdk_mcp_server/static/lambda_powertools/insights.md +0 -0
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/awslabs/cdk_mcp_server/static/lambda_powertools/logging.md +0 -0
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/awslabs/cdk_mcp_server/static/lambda_powertools/metrics.md +0 -0
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/awslabs/cdk_mcp_server/static/lambda_powertools/tracing.md +0 -0
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/docker-healthcheck.sh +0 -0
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/tests/__init__.py +0 -0
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/tests/core/test_resources.py +0 -0
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/tests/core/test_resources_enhanced.py +0 -0
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/tests/core/test_search_utils.py +0 -0
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/tests/core/test_server.py +0 -0
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/tests/core/test_tools.py +0 -0
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/tests/data/test_cdk_nag_parser.py +0 -0
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/tests/data/test_genai_cdk_loader.py +0 -0
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/tests/data/test_lambda_powertools_loader.py +0 -0
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/tests/data/test_schema_generator.py +0 -0
- {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/uv.lock +0 -0
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
#FROM public.ecr.aws/sam/build-python3.10:1.137.1-20250411084548
|
|
16
|
-
FROM public.ecr.aws/sam/build-python3.10@sha256:
|
|
16
|
+
FROM public.ecr.aws/sam/build-python3.10@sha256:d821662474d65f3cf2fc97dba2fa807a3adb580d02895fc4545527812550ea65 AS uv
|
|
17
17
|
|
|
18
18
|
# Install the project into `/app`
|
|
19
19
|
WORKDIR /app
|
|
@@ -35,7 +35,7 @@ COPY pyproject.toml uv.lock ./
|
|
|
35
35
|
|
|
36
36
|
# Install the project's dependencies using the lockfile and settings
|
|
37
37
|
RUN --mount=type=cache,target=/root/.cache/uv \
|
|
38
|
-
pip install uv && \
|
|
38
|
+
pip install uv==0.7.11 && \
|
|
39
39
|
uv sync --frozen --no-install-project --no-dev --no-editable
|
|
40
40
|
|
|
41
41
|
# Then, add the rest of the project source code and install it
|
|
@@ -47,7 +47,7 @@ RUN --mount=type=cache,target=/root/.cache/uv \
|
|
|
47
47
|
# Make the directory just in case it doesn't exist
|
|
48
48
|
RUN mkdir -p /root/.local
|
|
49
49
|
|
|
50
|
-
FROM public.ecr.aws/sam/build-python3.10@sha256:
|
|
50
|
+
FROM public.ecr.aws/sam/build-python3.10@sha256:d821662474d65f3cf2fc97dba2fa807a3adb580d02895fc4545527812550ea65
|
|
51
51
|
|
|
52
52
|
# Place executables in the environment at the front of the path and include other binaries
|
|
53
53
|
ENV PATH="/app/.venv/bin:$PATH:/usr/sbin"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: awslabs.cdk-mcp-server
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.2
|
|
4
4
|
Summary: An AWS CDK MCP server that provides guidance on AWS Cloud Development Kit best practices, infrastructure as code patterns, and security compliance with CDK Nag. This server offers tools to validate infrastructure designs, explain CDK Nag rules, analyze suppressions, generate Bedrock Agent schemas, and discover Solutions Constructs patterns.
|
|
5
5
|
Project-URL: Homepage, https://awslabs.github.io/mcp/
|
|
6
6
|
Project-URL: Documentation, https://awslabs.github.io/mcp/servers/cdk-mcp-server/
|
|
@@ -168,7 +168,7 @@ graph TD
|
|
|
168
168
|
|
|
169
169
|
## Installation
|
|
170
170
|
|
|
171
|
-
|
|
171
|
+
Configure the MCP server in your MCP client configuration (e.g., for Amazon Q Developer CLI, edit `~/.aws/amazonq/mcp.json`):
|
|
172
172
|
|
|
173
173
|
```json
|
|
174
174
|
{
|
|
@@ -138,7 +138,7 @@ graph TD
|
|
|
138
138
|
|
|
139
139
|
## Installation
|
|
140
140
|
|
|
141
|
-
|
|
141
|
+
Configure the MCP server in your MCP client configuration (e.g., for Amazon Q Developer CLI, edit `~/.aws/amazonq/mcp.json`):
|
|
142
142
|
|
|
143
143
|
```json
|
|
144
144
|
{
|
|
@@ -23,6 +23,40 @@ from datetime import datetime, timedelta
|
|
|
23
23
|
from typing import Any, Dict, List
|
|
24
24
|
|
|
25
25
|
|
|
26
|
+
# Regular expression patterns for parsing documentation
|
|
27
|
+
# AsciiDoc patterns
|
|
28
|
+
# Matches a Description section in AsciiDoc format: "= Description" followed by text until the next section or end
|
|
29
|
+
ADOC_DESCRIPTION_SECTION_PATTERN = r'= Description\s*\n+(.*?)(?=\n=|\Z)'
|
|
30
|
+
|
|
31
|
+
# Matches an Overview section in AsciiDoc format: "= Overview" followed by text until the next section or end
|
|
32
|
+
ADOC_OVERVIEW_SECTION_PATTERN = r'= Overview\s*\n+(.*?)(?=\n=|\Z)'
|
|
33
|
+
|
|
34
|
+
# Matches the first paragraph in a section: start of text until first blank line or end
|
|
35
|
+
FIRST_PARAGRAPH_PATTERN = r'^(.*?)(?=\n\n|\Z)'
|
|
36
|
+
|
|
37
|
+
# Matches a title and the following paragraph in AsciiDoc: "= Title" followed by blank line and text
|
|
38
|
+
ADOC_TITLE_AND_PARAGRAPH_PATTERN = r'= ([^\n]+)\s*\n\n(.*?)(?=\n\n|\n=|\Z)'
|
|
39
|
+
|
|
40
|
+
# Markdown patterns
|
|
41
|
+
# Matches a Description section in Markdown: "## Description" followed by text until the next section or end
|
|
42
|
+
MD_DESCRIPTION_SECTION_PATTERN = r'## Description\s*\n+(.*?)(?=\n##|\Z)'
|
|
43
|
+
|
|
44
|
+
# Matches an Overview section in Markdown: "## Overview" followed by text until the next section or end
|
|
45
|
+
MD_OVERVIEW_SECTION_PATTERN = r'## Overview\s*\n+(.*?)(?=\n##|\Z)'
|
|
46
|
+
|
|
47
|
+
# Matches the first paragraph after a title in Markdown: "# Title" followed by blank line and text
|
|
48
|
+
MD_TITLE_AND_PARAGRAPH_PATTERN = r'# [^\n]*\n\n(.*?)(?=\n\n|\n##|\Z)'
|
|
49
|
+
|
|
50
|
+
# Matches any text before the first ## heading
|
|
51
|
+
MD_TEXT_BEFORE_FIRST_HEADING_PATTERN = r'\n\n(.*?)(?=\n##|\Z)'
|
|
52
|
+
|
|
53
|
+
# Matches a title in Markdown: "# Title"
|
|
54
|
+
MD_TITLE_PATTERN = r'# ([^\n]+)'
|
|
55
|
+
|
|
56
|
+
# Pattern to replace multiple whitespace characters with a single space
|
|
57
|
+
WHITESPACE_CLEANUP_PATTERN = r'\s+'
|
|
58
|
+
|
|
59
|
+
|
|
26
60
|
# Set up logging
|
|
27
61
|
logging.basicConfig(level=logging.INFO)
|
|
28
62
|
logger = logging.getLogger(__name__)
|
|
@@ -115,22 +149,32 @@ async def get_pattern_info(pattern_name: str) -> Dict[str, Any]:
|
|
|
115
149
|
logger.info(f'Using cached info for {pattern_name}')
|
|
116
150
|
return _pattern_details_cache[pattern_name]['data']
|
|
117
151
|
|
|
118
|
-
#
|
|
152
|
+
# Try to fetch README.adoc first (preferred)
|
|
119
153
|
async with httpx.AsyncClient() as client:
|
|
120
|
-
|
|
121
|
-
logger.info(f'Fetching README from {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
if
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
154
|
+
readme_adoc_url = f'{GITHUB_RAW_CONTENT_URL}/{REPO_OWNER}/{REPO_NAME}/main/{PATTERNS_PATH}/{pattern_name}/README.adoc'
|
|
155
|
+
logger.info(f'Fetching README.adoc from {readme_adoc_url}')
|
|
156
|
+
adoc_response = await client.get(readme_adoc_url)
|
|
157
|
+
|
|
158
|
+
if adoc_response.status_code == 200:
|
|
159
|
+
readme_content = adoc_response.text
|
|
160
|
+
logger.info(f'Successfully fetched README.adoc for {pattern_name}')
|
|
161
|
+
else:
|
|
162
|
+
# Fall back to README.md (if README.adoc is not available)
|
|
163
|
+
readme_md_url = f'{GITHUB_RAW_CONTENT_URL}/{REPO_OWNER}/{REPO_NAME}/main/{PATTERNS_PATH}/{pattern_name}/README.md'
|
|
164
|
+
logger.info(f'README.adoc not found, trying README.md from {readme_md_url}')
|
|
165
|
+
md_response = await client.get(readme_md_url)
|
|
166
|
+
|
|
167
|
+
if md_response.status_code != 200:
|
|
168
|
+
logger.warning(
|
|
169
|
+
f'Failed to fetch README for {pattern_name}: HTTP {md_response.status_code}'
|
|
170
|
+
)
|
|
171
|
+
return {
|
|
172
|
+
'error': f'Pattern {pattern_name} not found or README not available',
|
|
173
|
+
'status_code': md_response.status_code,
|
|
174
|
+
}
|
|
132
175
|
|
|
133
|
-
|
|
176
|
+
readme_content = md_response.text
|
|
177
|
+
logger.info(f'Successfully fetched README.md for {pattern_name}')
|
|
134
178
|
|
|
135
179
|
# Extract only metadata
|
|
136
180
|
services = extract_services_from_pattern_name(pattern_name)
|
|
@@ -313,41 +357,69 @@ def extract_services_from_pattern_name(pattern_name: str) -> List[str]:
|
|
|
313
357
|
|
|
314
358
|
|
|
315
359
|
def extract_description(content: str) -> str:
|
|
316
|
-
"""Extract the pattern description from README
|
|
360
|
+
"""Extract the pattern description from README content.
|
|
317
361
|
|
|
318
362
|
Args:
|
|
319
|
-
content: README.md
|
|
363
|
+
content: README content (can be .md or .adoc format)
|
|
320
364
|
|
|
321
365
|
Returns:
|
|
322
366
|
Pattern description
|
|
323
367
|
"""
|
|
368
|
+
# Check if this is an AsciiDoc (.adoc) file
|
|
369
|
+
if any(marker in content for marker in ['= Overview', '= Description']):
|
|
370
|
+
# First, try to find a dedicated Description section in AsciiDoc
|
|
371
|
+
desc_section_match = re.search(ADOC_DESCRIPTION_SECTION_PATTERN, content, re.DOTALL)
|
|
372
|
+
if desc_section_match:
|
|
373
|
+
desc_text = desc_section_match.group(1).strip()
|
|
374
|
+
# Replace newlines with spaces to ensure a single line description
|
|
375
|
+
return re.sub(WHITESPACE_CLEANUP_PATTERN, ' ', desc_text)
|
|
376
|
+
|
|
377
|
+
# Next, try to find an Overview section in AsciiDoc
|
|
378
|
+
overview_section_match = re.search(ADOC_OVERVIEW_SECTION_PATTERN, content, re.DOTALL)
|
|
379
|
+
if overview_section_match:
|
|
380
|
+
# Take the first paragraph of the overview
|
|
381
|
+
overview = overview_section_match.group(1).strip()
|
|
382
|
+
first_para_match = re.search(FIRST_PARAGRAPH_PATTERN, overview, re.DOTALL)
|
|
383
|
+
if first_para_match:
|
|
384
|
+
# Replace newlines with spaces to ensure a single line description
|
|
385
|
+
return re.sub(WHITESPACE_CLEANUP_PATTERN, ' ', first_para_match.group(1).strip())
|
|
386
|
+
# Replace newlines with spaces to ensure a single line description
|
|
387
|
+
return re.sub(WHITESPACE_CLEANUP_PATTERN, ' ', overview)
|
|
388
|
+
|
|
389
|
+
# Try to find the first paragraph after a title in AsciiDoc format
|
|
390
|
+
title_match = re.search(ADOC_TITLE_AND_PARAGRAPH_PATTERN, content, re.DOTALL)
|
|
391
|
+
if title_match:
|
|
392
|
+
# Replace newlines with spaces to ensure a single line description
|
|
393
|
+
return re.sub(WHITESPACE_CLEANUP_PATTERN, ' ', title_match.group(2).strip())
|
|
394
|
+
|
|
395
|
+
# For Markdown format
|
|
324
396
|
# First, try to find a dedicated Description section
|
|
325
|
-
desc_section_match = re.search(
|
|
397
|
+
desc_section_match = re.search(MD_DESCRIPTION_SECTION_PATTERN, content, re.DOTALL)
|
|
326
398
|
if desc_section_match:
|
|
327
399
|
return desc_section_match.group(1).strip()
|
|
328
400
|
|
|
329
401
|
# Next, try to find an Overview section
|
|
330
|
-
overview_section_match = re.search(
|
|
402
|
+
overview_section_match = re.search(MD_OVERVIEW_SECTION_PATTERN, content, re.DOTALL)
|
|
331
403
|
if overview_section_match:
|
|
332
404
|
# Take the first paragraph of the overview
|
|
333
405
|
overview = overview_section_match.group(1).strip()
|
|
334
|
-
first_para_match = re.search(
|
|
406
|
+
first_para_match = re.search(FIRST_PARAGRAPH_PATTERN, overview, re.DOTALL)
|
|
335
407
|
if first_para_match:
|
|
336
408
|
return first_para_match.group(1).strip()
|
|
337
409
|
return overview
|
|
338
410
|
|
|
339
411
|
# Try to find the first paragraph after the title
|
|
340
|
-
match = re.search(
|
|
412
|
+
match = re.search(MD_TITLE_AND_PARAGRAPH_PATTERN, content, re.DOTALL)
|
|
341
413
|
if match:
|
|
342
414
|
return match.group(1).strip()
|
|
343
415
|
|
|
344
416
|
# Fallback: Try to find any text before the first ## heading
|
|
345
|
-
match = re.search(
|
|
417
|
+
match = re.search(MD_TEXT_BEFORE_FIRST_HEADING_PATTERN, content, re.DOTALL)
|
|
346
418
|
if match:
|
|
347
419
|
return match.group(1).strip()
|
|
348
420
|
|
|
349
421
|
# If all else fails, extract the title as a fallback
|
|
350
|
-
title_match = re.search(
|
|
422
|
+
title_match = re.search(MD_TITLE_PATTERN, content)
|
|
351
423
|
if title_match:
|
|
352
424
|
pattern_name = title_match.group(1).strip()
|
|
353
425
|
return f'A pattern for integrating {pattern_name} services'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "awslabs.cdk-mcp-server"
|
|
3
|
-
version = "1.0.
|
|
3
|
+
version = "1.0.2"
|
|
4
4
|
description = "An AWS CDK MCP server that provides guidance on AWS Cloud Development Kit best practices, infrastructure as code patterns, and security compliance with CDK Nag. This server offers tools to validate infrastructure designs, explain CDK Nag rules, analyze suppressions, generate Bedrock Agent schemas, and discover Solutions Constructs patterns."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.10"
|