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.
Files changed (51) hide show
  1. {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/Dockerfile +3 -3
  2. {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/PKG-INFO +2 -2
  3. {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/README.md +1 -1
  4. {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
  5. {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/pyproject.toml +1 -1
  6. awslabs_cdk_mcp_server-1.0.2/tests/data/test_solutions_constructs_parser.py +832 -0
  7. awslabs_cdk_mcp_server-1.0.1/.pre-commit-config.yaml +0 -14
  8. awslabs_cdk_mcp_server-1.0.1/tests/data/test_solutions_constructs_parser.py +0 -214
  9. {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/.gitignore +0 -0
  10. {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/.python-version +0 -0
  11. {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/CHANGELOG.md +0 -0
  12. {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/LICENSE +0 -0
  13. {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/NOTICE +0 -0
  14. {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/awslabs/__init__.py +0 -0
  15. {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/awslabs/cdk_mcp_server/__init__.py +0 -0
  16. {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/awslabs/cdk_mcp_server/core/__init__.py +0 -0
  17. {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/awslabs/cdk_mcp_server/core/resources.py +0 -0
  18. {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/awslabs/cdk_mcp_server/core/search_utils.py +0 -0
  19. {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/awslabs/cdk_mcp_server/core/server.py +0 -0
  20. {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/awslabs/cdk_mcp_server/core/tools.py +0 -0
  21. {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/awslabs/cdk_mcp_server/data/__init__.py +0 -0
  22. {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
  23. {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/awslabs/cdk_mcp_server/data/construct_descriptions.py +0 -0
  24. {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
  25. {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
  26. {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
  27. {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/awslabs/cdk_mcp_server/data/schema_generator.py +0 -0
  28. {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/awslabs/cdk_mcp_server/server.py +0 -0
  29. {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
  30. {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
  31. {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/awslabs/cdk_mcp_server/static/__init__.py +0 -0
  32. {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
  33. {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
  34. {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
  35. {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
  36. {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
  37. {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
  38. {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
  39. {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
  40. {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/docker-healthcheck.sh +0 -0
  41. {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/tests/__init__.py +0 -0
  42. {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/tests/core/test_resources.py +0 -0
  43. {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/tests/core/test_resources_enhanced.py +0 -0
  44. {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/tests/core/test_search_utils.py +0 -0
  45. {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/tests/core/test_server.py +0 -0
  46. {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/tests/core/test_tools.py +0 -0
  47. {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/tests/data/test_cdk_nag_parser.py +0 -0
  48. {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/tests/data/test_genai_cdk_loader.py +0 -0
  49. {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/tests/data/test_lambda_powertools_loader.py +0 -0
  50. {awslabs_cdk_mcp_server-1.0.1 → awslabs_cdk_mcp_server-1.0.2}/tests/data/test_schema_generator.py +0 -0
  51. {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:e78695db10ca8cb129e59e30f7dc9789b0dbd0181dba195d68419c72bac51ac1 AS uv
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:e78695db10ca8cb129e59e30f7dc9789b0dbd0181dba195d68419c72bac51ac1
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.1
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
- Here are some ways you can work with MCP across AWS, and we'll be adding support to more products including Amazon Q Developer CLI soon: (e.g. for Amazon Q Developer CLI MCP, `~/.aws/amazonq/mcp.json`):
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
- Here are some ways you can work with MCP across AWS, and we'll be adding support to more products including Amazon Q Developer CLI soon: (e.g. for Amazon Q Developer CLI MCP, `~/.aws/amazonq/mcp.json`):
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
- # Fetch README.md content
152
+ # Try to fetch README.adoc first (preferred)
119
153
  async with httpx.AsyncClient() as client:
120
- readme_url = f'{GITHUB_RAW_CONTENT_URL}/{REPO_OWNER}/{REPO_NAME}/main/{PATTERNS_PATH}/{pattern_name}/README.md'
121
- logger.info(f'Fetching README from {readme_url}')
122
- response = await client.get(readme_url)
123
-
124
- if response.status_code != 200:
125
- logger.warning(
126
- f'Failed to fetch README for {pattern_name}: HTTP {response.status_code}'
127
- )
128
- return {
129
- 'error': f'Pattern {pattern_name} not found or README.md not available',
130
- 'status_code': response.status_code,
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
- readme_content = response.text
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.md content.
360
+ """Extract the pattern description from README content.
317
361
 
318
362
  Args:
319
- content: README.md content
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(r'## Description\s*\n+(.*?)(?=\n##|\Z)', content, re.DOTALL)
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(r'## Overview\s*\n+(.*?)(?=\n##|\Z)', content, re.DOTALL)
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(r'^(.*?)(?=\n\n|\Z)', overview, re.DOTALL)
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(r'# [^\n]*\n\n(.*?)(?=\n\n|\n##|\Z)', content, re.DOTALL)
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(r'\n\n(.*?)(?=\n##|\Z)', content, re.DOTALL)
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(r'# ([^\n]+)', content)
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.1"
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"