awslabs.nova-canvas-mcp-server 0.1.10233__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.
@@ -0,0 +1,59 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ build/
8
+ develop-eggs/
9
+ dist/
10
+ downloads/
11
+ eggs/
12
+ .eggs/
13
+ lib/
14
+ lib64/
15
+ parts/
16
+ sdist/
17
+ var/
18
+ wheels/
19
+ share/python-wheels/
20
+ *.egg-info/
21
+ .installed.cfg
22
+ *.egg
23
+ MANIFEST
24
+
25
+ # Virtual environments
26
+ .venv
27
+ env/
28
+ venv/
29
+ ENV/
30
+
31
+ # IDE
32
+ .idea/
33
+ .vscode/
34
+ *.swp
35
+ *.swo
36
+
37
+ # Testing
38
+ .tox/
39
+ .coverage
40
+ .coverage.*
41
+ htmlcov/
42
+ .pytest_cache/
43
+
44
+ # Ruff
45
+ .ruff_cache/
46
+
47
+ # Build
48
+ *.manifest
49
+ *.spec
50
+ .pybuilder/
51
+ target/
52
+
53
+ # Environments
54
+ .env
55
+ .env.local
56
+ .env.*.local
57
+
58
+ # PyPI
59
+ .pypirc
@@ -0,0 +1,14 @@
1
+ repos:
2
+ - repo: https://github.com/astral-sh/ruff-pre-commit
3
+ rev: v0.9.6
4
+ hooks:
5
+ - id: ruff
6
+ args: [--fix]
7
+ - id: ruff-format
8
+
9
+ - repo: https://github.com/commitizen-tools/commitizen
10
+ rev: v3.13.0
11
+ hooks:
12
+ - id: commitizen
13
+ - id: commitizen-branch
14
+ stages: [push]
@@ -0,0 +1,58 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## v0.1.6 (2025-03-30)
9
+
10
+ ### Fix
11
+
12
+ - update __version__ format to remove v prefix
13
+
14
+ ## v0.1.5 (2025-03-30)
15
+
16
+ ### Fix
17
+
18
+ - __version__
19
+
20
+ ## v0.1.4 (2025-03-30)
21
+
22
+ ### Fix
23
+
24
+ - __version__
25
+
26
+ ## v0.1.3 (2025-03-30)
27
+
28
+ ### Fix
29
+
30
+ - pyproject.toml
31
+
32
+ ## v0.1.2 (2025-03-30)
33
+
34
+ ### Fix
35
+
36
+ - uv package
37
+ - release
38
+
39
+ ## v0.1.1 (2025-03-30)
40
+
41
+ ### Fix
42
+
43
+ - release
44
+
45
+ ## v0.1.0 (2025-03-30)
46
+
47
+ ### Feat
48
+
49
+ - MCP server for generating images with Amazon Nova Canvas
50
+ - **doc**: material mkdocs (#5)
51
+ - **doc**: initial documentation (#4)
52
+ - **security**: add CODEOWNERS (#2)
53
+ - **cicd**: add github workflows (#1)
54
+
55
+ ### Fix
56
+
57
+ - pyright errors on overrides
58
+ - optional fields
@@ -0,0 +1,74 @@
1
+ Metadata-Version: 2.4
2
+ Name: awslabs.nova-canvas-mcp-server
3
+ Version: 0.1.10233
4
+ Summary: An AWS Labs Model Context Protocol (MCP) server for Amazon Nova Canvas
5
+ Requires-Python: >=3.13
6
+ Requires-Dist: boto3>=1.37.24
7
+ Requires-Dist: loguru>=0.7.3
8
+ Requires-Dist: mcp[cli]>=1.6.0
9
+ Requires-Dist: pydantic>=2.11.1
10
+ Description-Content-Type: text/markdown
11
+
12
+ # awslabs MCP Nova Canvas Server
13
+
14
+ MCP server for generating images using Amazon Nova Canvas
15
+
16
+ ## Features
17
+
18
+ - **Text-based image generation** - Create images from text prompts with `generate_image`
19
+ - Customizable dimensions (320-4096px), quality options, and negative prompting
20
+ - Supports multiple image generation (1-5) in single request
21
+ - Adjustable parameters like cfg_scale (1.1-10.0) and seeded generation
22
+
23
+ - **Color-guided image generation** - Generate images with specific color palettes using `generate_image_with_colors`
24
+ - Define up to 10 hex color values to influence the image style and mood
25
+ - Same customization options as text-based generation
26
+
27
+ - **Workspace integration** - Images saved to user-specified workspace directories with automatic folder creation
28
+
29
+ - **AWS authentication** - Uses AWS profiles for secure access to Amazon Nova Canvas services
30
+
31
+ ## Prerequisites
32
+
33
+ 1. Install `uv` from [Astral](https://docs.astral.sh/uv/getting-started/installation/) or the [GitHub README](https://github.com/astral-sh/uv#installation)
34
+ 2. Install Python using `uv python install 3.13`
35
+ 3. Set up AWS credentials with access to Amazon Bedrock and Nova Canvas
36
+ - You need an AWS account with Amazon Bedrock and Amazon Nova Canvas enabled
37
+ - Configure AWS credentials with `aws configure` or environment variables
38
+ - Ensure your IAM role/user has permissions to use Amazon Bedrock and Nova Canvas
39
+
40
+ ## Installation
41
+
42
+ Install the MCP server:
43
+
44
+ Add the server to your MCP client config (e.g. for Amazon Q CLI MCP, `~/.aws/amazonq/mcp.json`):
45
+
46
+ ```json
47
+ {
48
+ "mcpServers": {
49
+ "awslabs.nova-canvas-mcp-server": {
50
+ "command": "uvx",
51
+ "args": ["awslabs.nova-canvas-mcp-server@latest"],
52
+ "env": {
53
+ "AWS_PROFILE": "your-aws-profile", // Optional: specify AWS profile
54
+ "AWS_REGION": "us-east-1" // Required: region where Bedrock is available
55
+ },
56
+ "disabled": false,
57
+ "autoApprove": []
58
+ }
59
+ }
60
+ }
61
+ ```
62
+
63
+ ### AWS Authentication
64
+
65
+ The MCP server uses the AWS profile specified in the `AWS_PROFILE` environment variable. If not provided, it defaults to the "default" profile in your AWS configuration file.
66
+
67
+ ```json
68
+ "env": {
69
+ "AWS_PROFILE": "your-aws-profile", // Specify which AWS profile to use
70
+ "AWS_REGION": "us-east-1" // Region where Bedrock is available
71
+ }
72
+ ```
73
+
74
+ Make sure the AWS profile has permissions to access Amazon Bedrock and Amazon Nova Canvas. The MCP server creates a boto3 session using the specified profile to authenticate with AWS services. Your AWS IAM credentials remain on your local machine and are strictly used for using the Amazon Bedrock model APIs.
@@ -0,0 +1,63 @@
1
+ # awslabs MCP Nova Canvas Server
2
+
3
+ MCP server for generating images using Amazon Nova Canvas
4
+
5
+ ## Features
6
+
7
+ - **Text-based image generation** - Create images from text prompts with `generate_image`
8
+ - Customizable dimensions (320-4096px), quality options, and negative prompting
9
+ - Supports multiple image generation (1-5) in single request
10
+ - Adjustable parameters like cfg_scale (1.1-10.0) and seeded generation
11
+
12
+ - **Color-guided image generation** - Generate images with specific color palettes using `generate_image_with_colors`
13
+ - Define up to 10 hex color values to influence the image style and mood
14
+ - Same customization options as text-based generation
15
+
16
+ - **Workspace integration** - Images saved to user-specified workspace directories with automatic folder creation
17
+
18
+ - **AWS authentication** - Uses AWS profiles for secure access to Amazon Nova Canvas services
19
+
20
+ ## Prerequisites
21
+
22
+ 1. Install `uv` from [Astral](https://docs.astral.sh/uv/getting-started/installation/) or the [GitHub README](https://github.com/astral-sh/uv#installation)
23
+ 2. Install Python using `uv python install 3.13`
24
+ 3. Set up AWS credentials with access to Amazon Bedrock and Nova Canvas
25
+ - You need an AWS account with Amazon Bedrock and Amazon Nova Canvas enabled
26
+ - Configure AWS credentials with `aws configure` or environment variables
27
+ - Ensure your IAM role/user has permissions to use Amazon Bedrock and Nova Canvas
28
+
29
+ ## Installation
30
+
31
+ Install the MCP server:
32
+
33
+ Add the server to your MCP client config (e.g. for Amazon Q CLI MCP, `~/.aws/amazonq/mcp.json`):
34
+
35
+ ```json
36
+ {
37
+ "mcpServers": {
38
+ "awslabs.nova-canvas-mcp-server": {
39
+ "command": "uvx",
40
+ "args": ["awslabs.nova-canvas-mcp-server@latest"],
41
+ "env": {
42
+ "AWS_PROFILE": "your-aws-profile", // Optional: specify AWS profile
43
+ "AWS_REGION": "us-east-1" // Required: region where Bedrock is available
44
+ },
45
+ "disabled": false,
46
+ "autoApprove": []
47
+ }
48
+ }
49
+ }
50
+ ```
51
+
52
+ ### AWS Authentication
53
+
54
+ The MCP server uses the AWS profile specified in the `AWS_PROFILE` environment variable. If not provided, it defaults to the "default" profile in your AWS configuration file.
55
+
56
+ ```json
57
+ "env": {
58
+ "AWS_PROFILE": "your-aws-profile", // Specify which AWS profile to use
59
+ "AWS_REGION": "us-east-1" // Region where Bedrock is available
60
+ }
61
+ ```
62
+
63
+ Make sure the AWS profile has permissions to access Amazon Bedrock and Amazon Nova Canvas. The MCP server creates a boto3 session using the specified profile to authenticate with AWS services. Your AWS IAM credentials remain on your local machine and are strictly used for using the Amazon Bedrock model APIs.
@@ -0,0 +1,2 @@
1
+ # This file is part of the awslabs namespace.
2
+ # It is intentionally minimal to support PEP 420 namespace packages.
@@ -0,0 +1,3 @@
1
+ """awslabs.nova-canvas-mcp-server"""
2
+
3
+ __version__ = '0.1.6'
@@ -0,0 +1,61 @@
1
+ # Constants
2
+ NOVA_CANVAS_MODEL_ID = 'amazon.nova-canvas-v1:0'
3
+ DEFAULT_WIDTH = 1024
4
+ DEFAULT_HEIGHT = 1024
5
+ DEFAULT_QUALITY = 'standard'
6
+ DEFAULT_CFG_SCALE = 6.5
7
+ DEFAULT_NUMBER_OF_IMAGES = 1
8
+ DEFAULT_OUTPUT_DIR = 'output' # Default directory inside workspace_dir
9
+
10
+
11
+ # Nova Canvas Prompt Best Practices
12
+ PROMPT_INSTRUCTIONS = """
13
+ # Amazon Nova Canvas Prompting Best Practices
14
+
15
+ ## General Guidelines
16
+
17
+ - Prompts must be no longer than 1024 characters. For very long prompts, place the least important details near the end.
18
+ - Do not use negation words like "no", "not", "without" in your prompt. The model doesn't understand negation and will result in the opposite of what you intend.
19
+ - Use negative prompts (via the `negative_prompt` parameter) to specify objects or characteristics to exclude from the image.
20
+ - Omit negation words from your negative prompts as well.
21
+
22
+ ## Effective Prompt Structure
23
+
24
+ An effective prompt often includes short descriptions of:
25
+
26
+ 1. The subject
27
+ 2. The environment
28
+ 3. (optional) The position or pose of the subject
29
+ 4. (optional) Lighting description
30
+ 5. (optional) Camera position/framing
31
+ 6. (optional) The visual style or medium ("photo", "illustration", "painting", etc.)
32
+
33
+ ## Refining Results
34
+
35
+ When the output is close to what you want but not perfect:
36
+
37
+ 1. Use a consistent `seed` value and make small changes to your prompt or negative prompt.
38
+ 2. Once the prompt is refined, generate more variations using the same prompt but different `seed` values.
39
+
40
+ ## Examples
41
+
42
+ ### Example 1: Stock Photo
43
+ **Prompt:** "realistic editorial photo of female teacher standing at a blackboard with a warm smile"
44
+ **Negative Prompt:** "crossed arms"
45
+
46
+ ### Example 2: Story Illustration
47
+ **Prompt:** "whimsical and ethereal soft-shaded story illustration: A woman in a large hat stands at the ship's railing looking out across the ocean"
48
+ **Negative Prompt:** "clouds, waves"
49
+
50
+ ### Example 3: Pre-visualization for TV/Film
51
+ **Prompt:** "drone view of a dark river winding through a stark Iceland landscape, cinematic quality"
52
+
53
+ ### Example 4: Fashion/Editorial Content
54
+ **Prompt:** "A cool looking stylish man in an orange jacket, dark skin, wearing reflective glasses. Shot from slightly low angle, face and chest in view, aqua blue sleek building shapes in background."
55
+
56
+ ## Using Negative Prompts
57
+
58
+ Negative prompts can be surprisingly useful. Use them to exclude objects or style characteristics that might otherwise naturally occur as a result of your main prompt.
59
+
60
+ For example, adding "waves, clouds" as a negative prompt to a ship scene will result in a cleaner, more minimal composition.
61
+ """
@@ -0,0 +1,287 @@
1
+ """Pydantic models for Amazon Nova Canvas image generation."""
2
+
3
+ import random
4
+ import re
5
+ from enum import Enum
6
+ from pydantic import BaseModel, Field, field_validator, model_validator
7
+ from typing import Any, Dict, List, Literal, Optional
8
+
9
+
10
+ class Quality(str, Enum):
11
+ """Quality options for image generation.
12
+
13
+ Attributes:
14
+ STANDARD: Standard quality image generation.
15
+ PREMIUM: Premium quality image generation with enhanced details.
16
+ """
17
+
18
+ STANDARD = 'standard'
19
+ PREMIUM = 'premium'
20
+
21
+
22
+ class TaskType(str, Enum):
23
+ """Task types for image generation.
24
+
25
+ Attributes:
26
+ TEXT_IMAGE: Generate an image from text description.
27
+ COLOR_GUIDED_GENERATION: Generate an image guided by both text and color palette.
28
+ """
29
+
30
+ TEXT_IMAGE = 'TEXT_IMAGE'
31
+ COLOR_GUIDED_GENERATION = 'COLOR_GUIDED_GENERATION'
32
+
33
+
34
+ class ImageGenerationConfig(BaseModel):
35
+ """Configuration for image generation.
36
+
37
+ This model defines the parameters that control the image generation process,
38
+ including dimensions, quality, and generation settings.
39
+
40
+ Attributes:
41
+ width: Width of the generated image (320-4096, must be divisible by 16).
42
+ height: Height of the generated image (320-4096, must be divisible by 16).
43
+ quality: Quality level of the generated image (standard or premium).
44
+ cfgScale: How strongly the image adheres to the prompt (1.1-10.0).
45
+ seed: Seed for reproducible generation (0-858993459).
46
+ numberOfImages: Number of images to generate (1-5).
47
+ """
48
+
49
+ width: int = Field(default=1024, ge=320, le=4096)
50
+ height: int = Field(default=1024, ge=320, le=4096)
51
+ quality: Quality = Quality.STANDARD
52
+ cfgScale: float = Field(default=6.5, ge=1.1, le=10.0)
53
+ seed: int = Field(default_factory=lambda: random.randint(0, 858993459), ge=0, le=858993459)
54
+ numberOfImages: int = Field(default=1, ge=1, le=5)
55
+
56
+ @field_validator('width', 'height')
57
+ @classmethod
58
+ def must_be_divisible_by_16(cls, v: int) -> int:
59
+ """Validate that width and height are divisible by 16.
60
+
61
+ Args:
62
+ v: The width or height value to validate.
63
+
64
+ Returns:
65
+ The validated value if it passes.
66
+
67
+ Raises:
68
+ ValueError: If the value is not divisible by 16.
69
+ """
70
+ if v % 16 != 0:
71
+ raise ValueError('Value must be divisible by 16')
72
+ return v
73
+
74
+ @model_validator(mode='after')
75
+ def validate_aspect_ratio_and_total_pixels(self):
76
+ """Validate aspect ratio and total pixel count.
77
+
78
+ Ensures that:
79
+ 1. The aspect ratio is between 1:4 and 4:1
80
+ 2. The total pixel count is less than 4,194,304
81
+
82
+ Returns:
83
+ The validated model if it passes.
84
+
85
+ Raises:
86
+ ValueError: If the aspect ratio or total pixel count is invalid.
87
+ """
88
+ width = self.width
89
+ height = self.height
90
+
91
+ # Check aspect ratio between 1:4 and 4:1
92
+ aspect_ratio = width / height
93
+ if aspect_ratio < 0.25 or aspect_ratio > 4.0:
94
+ raise ValueError('Aspect ratio must be between 1:4 and 4:1')
95
+
96
+ # Check total pixel count
97
+ total_pixels = width * height
98
+ if total_pixels >= 4194304:
99
+ raise ValueError('Total pixel count must be less than 4,194,304')
100
+
101
+ return self
102
+
103
+
104
+ class TextToImageParams(BaseModel):
105
+ """Parameters for text-to-image generation.
106
+
107
+ This model defines the text prompts used to generate images.
108
+
109
+ Attributes:
110
+ text: The text description of the image to generate (1-1024 characters).
111
+ negativeText: Optional text to define what not to include in the image (1-1024 characters).
112
+ """
113
+
114
+ text: str = Field(..., min_length=1, max_length=1024)
115
+ negativeText: Optional[str] = Field(default=None, min_length=1, max_length=1024)
116
+
117
+
118
+ class ColorGuidedGenerationParams(BaseModel):
119
+ """Parameters for color-guided generation.
120
+
121
+ This model defines the text prompts and color palette used to generate images.
122
+
123
+ Attributes:
124
+ colors: List of hexadecimal color values (e.g., "#FF9800") to guide the image generation.
125
+ text: The text description of the image to generate (1-1024 characters).
126
+ negativeText: Optional text to define what not to include in the image (1-1024 characters).
127
+ """
128
+
129
+ colors: List[str] = Field(..., max_length=10)
130
+ text: str = Field(..., min_length=1, max_length=1024)
131
+ negativeText: Optional[str] = Field(default=None, min_length=1, max_length=1024)
132
+
133
+ @field_validator('colors')
134
+ @classmethod
135
+ def validate_hex_colors(cls, v: List[str]) -> List[str]:
136
+ """Validate that colors are in the correct hexadecimal format.
137
+
138
+ Args:
139
+ v: List of color strings to validate.
140
+
141
+ Returns:
142
+ The validated list if all colors pass.
143
+
144
+ Raises:
145
+ ValueError: If any color is not a valid hexadecimal color in the format '#RRGGBB'.
146
+ """
147
+ hex_pattern = re.compile(r'^#[0-9A-Fa-f]{6}$')
148
+ for color in v:
149
+ if not hex_pattern.match(color):
150
+ raise ValueError(
151
+ f"Color '{color}' is not a valid hexadecimal color in the format '#RRGGBB'"
152
+ )
153
+ return v
154
+
155
+
156
+ class TextImageRequest(BaseModel):
157
+ """Request model for text-to-image generation.
158
+
159
+ This model combines the task type, text parameters, and generation configuration
160
+ for a complete text-to-image request.
161
+
162
+ Attributes:
163
+ taskType: The type of task (TEXT_IMAGE).
164
+ textToImageParams: Parameters for text-to-image generation.
165
+ imageGenerationConfig: Configuration for image generation.
166
+ """
167
+
168
+ taskType: Literal[TaskType.TEXT_IMAGE] = TaskType.TEXT_IMAGE
169
+ textToImageParams: TextToImageParams
170
+ imageGenerationConfig: Optional[ImageGenerationConfig] = Field(
171
+ default_factory=ImageGenerationConfig
172
+ )
173
+
174
+ # instead of overriding model_dump, we add a post-model_dump extension method
175
+ def to_api_dict(self) -> Dict[str, Any]:
176
+ """Convert model to dictionary suitable for API requests.
177
+
178
+ Returns:
179
+ A dictionary representation of the model suitable for API requests.
180
+ """
181
+ text_to_image_params = self.textToImageParams.model_dump()
182
+ # Remove negativeText if it's None
183
+ if text_to_image_params.get('negativeText') is None:
184
+ text_to_image_params.pop('negativeText', None)
185
+
186
+ return {
187
+ 'taskType': self.taskType,
188
+ 'textToImageParams': text_to_image_params,
189
+ 'imageGenerationConfig': self.imageGenerationConfig.model_dump()
190
+ if self.imageGenerationConfig
191
+ else None,
192
+ }
193
+
194
+
195
+ class ColorGuidedRequest(BaseModel):
196
+ """Request model for color-guided generation.
197
+
198
+ This model combines the task type, color-guided parameters, and generation configuration
199
+ for a complete color-guided generation request.
200
+
201
+ Attributes:
202
+ taskType: The type of task (COLOR_GUIDED_GENERATION).
203
+ colorGuidedGenerationParams: Parameters for color-guided generation.
204
+ imageGenerationConfig: Configuration for image generation.
205
+ """
206
+
207
+ taskType: Literal[TaskType.COLOR_GUIDED_GENERATION] = TaskType.COLOR_GUIDED_GENERATION
208
+ colorGuidedGenerationParams: ColorGuidedGenerationParams
209
+ imageGenerationConfig: Optional[ImageGenerationConfig] = Field(
210
+ default_factory=ImageGenerationConfig
211
+ )
212
+
213
+ # instead of overriding model_dump, we add a post-model_dump extension method
214
+ def to_api_dict(self) -> Dict[str, Any]:
215
+ """Convert model to dictionary suitable for API requests.
216
+
217
+ Returns:
218
+ A dictionary representation of the model suitable for API requests.
219
+ """
220
+ color_guided_params = self.colorGuidedGenerationParams.model_dump()
221
+ # Remove negativeText if it's None
222
+ if color_guided_params.get('negativeText') is None:
223
+ color_guided_params.pop('negativeText', None)
224
+
225
+ return {
226
+ 'taskType': self.taskType,
227
+ 'colorGuidedGenerationParams': color_guided_params,
228
+ 'imageGenerationConfig': self.imageGenerationConfig.model_dump()
229
+ if self.imageGenerationConfig
230
+ else None,
231
+ }
232
+
233
+
234
+ class McpImageGenerationResponse(BaseModel):
235
+ """Response from image generation API.
236
+
237
+ This model represents the response from the Amazon Nova Canvas API
238
+ for both text-to-image and color-guided image generation.
239
+ """
240
+
241
+ status: str
242
+ paths: List[str]
243
+
244
+
245
+ class ImageGenerationResponse(BaseModel):
246
+ """Response from image generation API.
247
+
248
+ This model represents the response from the Amazon Nova Canvas API
249
+ for both text-to-image and color-guided image generation.
250
+
251
+ Attributes:
252
+ status: Status of the image generation request ('success' or 'error').
253
+ message: Message describing the result or error.
254
+ paths: List of paths to the generated image files.
255
+ images: List of PIL Image objects.
256
+ prompt: The text prompt used to generate the images.
257
+ negative_prompt: The negative prompt used to generate the images, if any.
258
+ colors: The colors used to guide the image generation, if any.
259
+ """
260
+
261
+ status: str
262
+ message: str
263
+ paths: List[str]
264
+ prompt: str
265
+ negative_prompt: Optional[str] = None
266
+ colors: Optional[List[str]] = None
267
+
268
+ class Config:
269
+ """Pydantic configuration."""
270
+
271
+ arbitrary_types_allowed = True # Allow PIL.Image.Image type
272
+
273
+ def __getitem__(self, key: str) -> Any:
274
+ """Support dictionary-style access for backward compatibility.
275
+
276
+ Args:
277
+ key: The attribute name to access.
278
+
279
+ Returns:
280
+ The value of the attribute.
281
+
282
+ Raises:
283
+ KeyError: If the attribute does not exist.
284
+ """
285
+ if hasattr(self, key):
286
+ return getattr(self, key)
287
+ raise KeyError(f"'{key}' not found in ImageGenerationResponse")