# Directory Structure
```
├── .github
│ └── workflows
│ └── npm-publish.yml
├── .gitignore
├── example-client
│ ├── package-lock.json
│ ├── package.json
│ ├── README.md
│ ├── src
│ │ └── index.ts
│ └── tsconfig.json
├── LICENSE
├── package-lock.json
├── package.json
├── README.md
├── src
│ └── index.ts
└── tsconfig.json
```
# Files
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
```
1 | node_modules/
2 | build/
3 | *.log
4 | .env*
5 | .vscode/
6 |
```
--------------------------------------------------------------------------------
/example-client/README.md:
--------------------------------------------------------------------------------
```markdown
1 | ## Example client to call the `generate_image` tool
2 |
3 | This example demonstrates how to call the `generate_image` tool from terminal.
4 |
5 | ### Prerequisites
6 |
7 | - build the MCP server
8 | ```bash
9 | cd mcp-server-amazon-bedrock
10 | npm install
11 | npm run build
12 | ```
13 |
14 | ### Usage
15 |
16 | ```bash
17 | cd example-client
18 | npm install
19 | npm run build
20 | node build/index.js
21 | ```
```
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
```markdown
1 | [](https://mseep.ai/app/zxkane-mcp-server-amazon-bedrock)
2 |
3 | # Amazon Bedrock MCP Server
4 |
5 | A Model Control Protocol (MCP) server that integrates with Amazon Bedrock's Nova Canvas model for AI image generation.
6 |
7 | <a href="https://glama.ai/mcp/servers/9qw7dwpvj9"><img width="380" height="200" src="https://glama.ai/mcp/servers/9qw7dwpvj9/badge" alt="Amazon Bedrock Server MCP server" /></a>
8 |
9 | ## Features
10 |
11 | - High-quality image generation from text descriptions using Amazon's Nova Canvas model
12 | - Advanced control through negative prompts to refine image composition
13 | - Flexible configuration options for image dimensions and quality
14 | - Deterministic image generation with seed control
15 | - Robust input validation and error handling
16 |
17 | ## Prerequisites
18 |
19 | 1. Active AWS account with Amazon Bedrock and Nova Canvas model access
20 | 2. Properly configured AWS credentials with required permissions
21 | 3. Node.js version 18 or later
22 |
23 | ## Installation
24 |
25 | ### AWS Credentials Configuration
26 |
27 | The server requires AWS credentials with appropriate Amazon Bedrock permissions. Configure these using one of the following methods:
28 |
29 | 1. Environment variables:
30 | ```bash
31 | export AWS_ACCESS_KEY_ID=your_access_key
32 | export AWS_SECRET_ACCESS_KEY=your_secret_key
33 | export AWS_REGION=us-east-1 # or your preferred region
34 | ```
35 |
36 | 2. AWS credentials file (`~/.aws/credentials`):
37 | ```ini
38 | [the_profile_name]
39 | aws_access_key_id = your_access_key
40 | aws_secret_access_key = your_secret_key
41 | ```
42 | Environment variable for active profile:
43 | ```bash
44 | export AWS_PROFILE=the_profile_name
45 | ```
46 |
47 | 3. IAM role (when deployed on AWS infrastructure)
48 |
49 | ### Claude Desktop Integration
50 |
51 | To integrate with Claude Desktop, add the following configuration to your settings file:
52 |
53 | MacOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
54 | Windows: `%APPDATA%/Claude/claude_desktop_config.json`
55 |
56 | ```json
57 | {
58 | "mcpServers": {
59 | "amazon-bedrock": {
60 | "command": "npx",
61 | "args": [
62 | "-y",
63 | "@zxkane/mcp-server-amazon-bedrock"
64 | ],
65 | "env": {
66 | "AWS_PROFILE": "your_profile_name", // Optional, only if you want to use a specific profile
67 | "AWS_ACCESS_KEY_ID": "your_access_key", // Optional if using AWS credentials file or IAM role
68 | "AWS_SECRET_ACCESS_KEY": "your_secret_key", // Optional if using AWS credentials file or IAM role
69 | "AWS_REGION": "us-east-1" // Optional, defaults to 'us-east-1'
70 | }
71 | }
72 | }
73 | }
74 | ```
75 |
76 | ## Available Tools
77 |
78 | ### generate_image
79 |
80 | Creates images from text descriptions using Amazon Bedrock's Nova Canvas model.
81 |
82 | #### Parameters
83 |
84 | - `prompt` (required): Descriptive text for the desired image (1-1024 characters)
85 | - `negativePrompt` (optional): Elements to exclude from the image (1-1024 characters)
86 | - `width` (optional): Image width in pixels (default: 1024)
87 | - `height` (optional): Image height in pixels (default: 1024)
88 | - `quality` (optional): Image quality level - "standard" or "premium" (default: "standard")
89 | - `cfg_scale` (optional): Prompt adherence strength (1.1-10, default: 6.5)
90 | - `seed` (optional): Generation seed for reproducibility (0-858993459, default: 12)
91 | - `numberOfImages` (optional): Batch size for generation (1-5, default: 1)
92 |
93 | #### Example Implementation
94 |
95 | ```typescript
96 | const result = await callTool('generate_image', {
97 | prompt: "A serene mountain landscape at sunset",
98 | negativePrompt: "people, buildings, vehicles",
99 | quality: "premium",
100 | cfg_scale: 8,
101 | numberOfImages: 2
102 | });
103 | ```
104 |
105 | #### Prompt Guidelines
106 |
107 | For optimal results, avoid negative phrasing ("no", "not", "without") in the main prompt. Instead, move these elements to the `negativePrompt` parameter. For example, rather than using "a landscape without buildings" in the prompt, use "buildings" in the `negativePrompt`.
108 |
109 | For detailed usage guidelines, refer to the [Nova Canvas documentation][nova-canvas-doc].
110 |
111 | ## Development
112 |
113 | To set up and run the server in a local environment:
114 |
115 | ```bash
116 | git clone https://github.com/zxkane/mcp-server-amazon-bedrock.git
117 | cd mcp-server-amazon-bedrock
118 | npm install
119 | npm run build
120 | ```
121 |
122 | ### Performance Considerations
123 |
124 | Generation time is influenced by resolution (`width` and `height`), `numberOfImages`, and `quality` settings. When using higher values, be mindful of potential timeout implications in your implementation.
125 |
126 | ## License
127 |
128 | This project is licensed under the MIT License - see the LICENSE file for details.
129 |
130 | [nova-canvas-doc]: https://docs.aws.amazon.com/nova/latest/userguide/image-gen-access.html
131 |
```
--------------------------------------------------------------------------------
/example-client/package.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "name": "example-client",
3 | "version": "1.0.0",
4 | "type": "module",
5 | "scripts": {
6 | "build": "tsc",
7 | "start": "node build/index.js"
8 | },
9 | "dependencies": {
10 | "@modelcontextprotocol/sdk": "^1.0.0",
11 | "terminal-image": "^3.0.0",
12 | "typescript": "^5.0.0"
13 | }
14 | }
15 |
```
--------------------------------------------------------------------------------
/example-client/tsconfig.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "compilerOptions": {
3 | "target": "ES2020",
4 | "module": "ES2020",
5 | "moduleResolution": "node",
6 | "esModuleInterop": true,
7 | "strict": true,
8 | "outDir": "build",
9 | "skipLibCheck": true,
10 | "forceConsistentCasingInFileNames": true
11 | },
12 | "include": ["src/**/*"],
13 | "exclude": ["node_modules"]
14 | }
15 |
```
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "compilerOptions": {
3 | "target": "ES2022",
4 | "module": "Node16",
5 | "moduleResolution": "Node16",
6 | "outDir": "./build",
7 | "rootDir": "./src",
8 | "strict": true,
9 | "esModuleInterop": true,
10 | "skipLibCheck": true,
11 | "forceConsistentCasingInFileNames": true
12 | },
13 | "include": ["src/**/*"],
14 | "exclude": ["node_modules"]
15 | }
16 |
```
--------------------------------------------------------------------------------
/.github/workflows/npm-publish.yml:
--------------------------------------------------------------------------------
```yaml
1 | name: Publish to NPM
2 |
3 | on:
4 | release:
5 | types: [created]
6 |
7 | jobs:
8 | publish:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - uses: actions/checkout@v4
12 |
13 | - name: Setup Node.js
14 | uses: actions/setup-node@v4
15 | with:
16 | node-version: '20'
17 | registry-url: 'https://registry.npmjs.org'
18 |
19 | - name: Install dependencies
20 | run: npm ci
21 |
22 | - name: Build
23 | run: npm run build
24 |
25 | - name: Publish to NPM
26 | run: npm publish
27 | env:
28 | NODE_AUTH_TOKEN: ${{ secrets.npm_token }}
```
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "name": "@zxkane/mcp-server-amazon-bedrock",
3 | "version": "0.1.1",
4 | "description": "Use Amazon Bedrock Nova models to generate image.",
5 | "author": "Kane Zhu",
6 | "type": "module",
7 | "bin": {
8 | "mcp-server-amazon-bedrock": "./build/index.js"
9 | },
10 | "files": [
11 | "build"
12 | ],
13 | "publishConfig": {
14 | "access": "public"
15 | },
16 | "scripts": {
17 | "build": "tsc && node -e \"require('fs').chmodSync('build/index.js', '755')\"",
18 | "prepare": "npm run build",
19 | "watch": "tsc --watch",
20 | "inspector": "npx @modelcontextprotocol/inspector build/index.js"
21 | },
22 | "dependencies": {
23 | "@aws-sdk/client-bedrock-runtime": "^3.716.0",
24 | "@aws-sdk/credential-providers": "^3.716.0",
25 | "@modelcontextprotocol/sdk": "0.6.0",
26 | "zod": "^3.24.1"
27 | },
28 | "devDependencies": {
29 | "@types/node": "^20.11.24",
30 | "typescript": "^5.3.3"
31 | },
32 | "keywords": [
33 | "mcp",
34 | "amazon",
35 | "bedrock",
36 | "ai",
37 | "image-generation"
38 | ],
39 | "license": "MIT"
40 | }
41 |
```
--------------------------------------------------------------------------------
/example-client/src/index.ts:
--------------------------------------------------------------------------------
```typescript
1 | import path from 'path';
2 | import { fileURLToPath } from 'url';
3 | import { Client } from "@modelcontextprotocol/sdk/client/index.js";
4 | import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
5 | import {
6 | ListToolsResultSchema,
7 | CallToolResultSchema
8 | } from "@modelcontextprotocol/sdk/types.js";
9 | import terminalImage from "terminal-image";
10 |
11 | async function main() {
12 | // Get the current file's directory
13 | const __filename = fileURLToPath(import.meta.url);
14 | const __dirname = path.dirname(__filename);
15 |
16 | // Initialize the client
17 | const client = new Client(
18 | {
19 | name: "example-bedrock-client",
20 | version: "1.0.0",
21 | },
22 | {
23 | capabilities: {},
24 | }
25 | );
26 |
27 | try {
28 | // Use path.resolve to get the correct path to the server script
29 | const transport = new StdioClientTransport({
30 | command: path.resolve(__dirname, "../../build/index.js"),
31 | env: {
32 | ...process.env, // Pass all environment variables
33 | NODE_ENV: process.env.NODE_ENV || 'development',
34 | }
35 | });
36 | await client.connect(transport);
37 | console.log("Connected to Amazon Bedrock MCP server");
38 |
39 | // List available tools
40 | const tools = await client.request(
41 | { method: "tools/list" },
42 | ListToolsResultSchema
43 | );
44 | console.log("Available tools:", tools);
45 |
46 | // Log start time
47 | const startTime = new Date();
48 | console.log(`Image Generation Request started at: ${startTime.toISOString()}`);
49 |
50 | // Example: Generate an image using the generate_image tool
51 | const imageResult = await client.request(
52 | {
53 | method: "tools/call",
54 | params: {
55 | name: "generate_image",
56 | arguments: {
57 | prompt: "A serene landscape with mountains and a lake at sunset",
58 | width: 1024,
59 | height: 1024,
60 | quality: "standard",
61 | cfg_scale: 7,
62 | seed: 42,
63 | numberOfImages: 2,
64 | },
65 | },
66 | },
67 | CallToolResultSchema
68 | );
69 | // Log end time and duration
70 | const endTime = new Date();
71 | const duration = endTime.getTime() - startTime.getTime();
72 |
73 | if (imageResult.content && imageResult.content.length > 0) {
74 | for (const content of imageResult.content) {
75 | if (content.type === "image") {
76 | console.log("Image generated successfully!");
77 | try {
78 | const buffer = Buffer.from(content.data, 'base64');
79 | console.log(await terminalImage.buffer(buffer));
80 | } catch (err) {
81 | console.error('Error displaying image:', err);
82 | }
83 | } else if (content.type === "text") {
84 | console.log("Text generated:", content.text);
85 | }
86 | }
87 | }
88 |
89 | console.log(`Request completed at: ${endTime.toISOString()}`);
90 | console.log(`Total duration: ${duration}ms`);
91 |
92 | // Clean up
93 | await client.close();
94 | } catch (error) {
95 | console.error("Error:", error);
96 | process.exit(1);
97 | }
98 | }
99 |
100 | // Handle interrupts
101 | process.on("SIGINT", () => {
102 | console.log("Interrupted, exiting...");
103 | process.exit(0);
104 | });
105 |
106 | main().catch(console.error);
107 |
```
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
```typescript
1 | #!/usr/bin/env node
2 |
3 | import { Server } from "@modelcontextprotocol/sdk/server/index.js";
4 | import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5 | import {
6 | CallToolRequestSchema,
7 | ErrorCode,
8 | ListToolsRequestSchema,
9 | McpError,
10 | } from "@modelcontextprotocol/sdk/types.js";
11 | import { BedrockRuntimeClient, InvokeModelCommand } from "@aws-sdk/client-bedrock-runtime";
12 | import { NodeHttpHandler } from "@smithy/node-http-handler";
13 | import { fromNodeProviderChain, fromIni } from "@aws-sdk/credential-providers";
14 | import { z } from "zod";
15 |
16 | const AWS_REGION = process.env.AWS_REGION || process.env.AWS_DEFAULT_REGION || 'us-east-1';
17 | const AWS_PROFILE = process.env.AWS_PROFILE || 'default';
18 |
19 | // Log AWS configuration for debugging
20 | console.error('AWS Configuration:', {
21 | region: AWS_REGION,
22 | profile: AWS_PROFILE,
23 | hasAccessKeyId: !!process.env.AWS_ACCESS_KEY_ID,
24 | hasSecretKey: !!process.env.AWS_SECRET_ACCESS_KEY,
25 | hasSessionToken: !!process.env.AWS_SESSION_TOKEN
26 | });
27 |
28 | // Initialize Bedrock client with comprehensive configuration including credentials and timeouts
29 | const bedrock = new BedrockRuntimeClient({
30 | region: AWS_REGION,
31 | maxAttempts: 3,
32 | // Try explicit profile credentials first, then fall back to provider chain
33 | credentials: async () => {
34 | try {
35 | // First try loading from profile
36 | const profileCreds = await fromIni({ profile: AWS_PROFILE })();
37 | console.error('Successfully loaded credentials from profile');
38 | return profileCreds;
39 | } catch (error) {
40 | console.error('Failed to load profile credentials, falling back to provider chain:', error);
41 | try {
42 | // Fall back to provider chain
43 | const chainCreds = await fromNodeProviderChain()();
44 | console.error('Successfully loaded credentials from provider chain');
45 | return chainCreds;
46 | } catch (error) {
47 | console.error('Failed to load credentials from provider chain:', error);
48 | throw error;
49 | }
50 | }
51 | },
52 | requestHandler: new NodeHttpHandler({
53 | connectionTimeout: 10000, // 10 seconds connection timeout
54 | requestTimeout: 300000, // 5 minutes request timeout
55 | })
56 | });
57 |
58 | // Log Bedrock client initialization
59 | console.error('Bedrock client initialized');
60 |
61 | // Constants
62 | const NOVA_MODEL_ID = 'amazon.nova-canvas-v1:0';
63 |
64 | // Input validation schemas based on AWS Nova documentation
65 | const GenerateImageSchema = z.object({
66 | prompt: z.string().min(1).max(1024, "Prompt must be 1-1024 characters"),
67 | negativePrompt: z.string().min(1).max(1024, "Negative prompt must be 1-1024 characters").optional(),
68 | width: z.number().int()
69 | .min(320, "Width must be at least 320 pixels")
70 | .max(4096, "Width must be at most 4096 pixels")
71 | .refine(val => val % 16 === 0, "Width must be divisible by 16")
72 | .default(1024),
73 | height: z.number().int()
74 | .min(320, "Height must be at least 320 pixels")
75 | .max(4096, "Height must be at most 4096 pixels")
76 | .refine(val => val % 16 === 0, "Height must be divisible by 16")
77 | .default(1024),
78 | quality: z.enum(["standard", "premium"]).default("standard"),
79 | cfg_scale: z.number().min(1.1).max(10).default(6.5),
80 | seed: z.number().int().min(0).max(858993459).default(12),
81 | numberOfImages: z.number().int().min(1).max(5).default(1)
82 | }).refine(
83 | (data) => {
84 | // Check aspect ratio between 1:4 and 4:1
85 | const ratio = data.width / data.height;
86 | return ratio >= 0.25 && ratio <= 4;
87 | },
88 | "Aspect ratio must be between 1:4 and 4:1"
89 | ).refine(
90 | (data) => {
91 | // Check total pixel count
92 | return data.width * data.height < 4194304;
93 | },
94 | "Total pixel count must be less than 4,194,304"
95 | );
96 |
97 | type GenerateImageInput = z.infer<typeof GenerateImageSchema>;
98 |
99 | // Constants for image generation
100 | const GENERATION_TYPES = {
101 | TEXT_TO_IMAGE: "TEXT_IMAGE",
102 | };
103 |
104 | /**
105 | * Create an MCP server for Amazon Bedrock image generation
106 | */
107 | const server = new Server(
108 | {
109 | name: "mcp-server-amazon-bedrock",
110 | version: "0.1.0",
111 | },
112 | {
113 | capabilities: {
114 | tools: {},
115 | logging: {},
116 | },
117 | }
118 | );
119 |
120 | /**
121 | * Handler that lists available tools.
122 | * Exposes a single "generate_image" tool that generates images using Amazon Bedrock.
123 | */
124 | server.setRequestHandler(ListToolsRequestSchema, async () => {
125 | return {
126 | tools: [
127 | {
128 | name: "generate_image",
129 | description: "Generate image(s) using Amazon Nova Canvas model. The returned data is Base64-encoded string that represent each image that was generated.",
130 | inputSchema: {
131 | type: "object",
132 | properties: {
133 | prompt: {
134 | type: "string",
135 | description: "Text description of the image to generate (1-1024 characters)",
136 | },
137 | negativePrompt: {
138 | type: "string",
139 | description: "Optional text description of what to avoid in the image (1-1024 characters)",
140 | },
141 | width: {
142 | type: "number",
143 | description: "Width of the generated image (default: 1024)",
144 | },
145 | height: {
146 | type: "number",
147 | description: "Height of the generated image (default: 1024)",
148 | },
149 | quality: {
150 | type: "string",
151 | enum: ["standard", "premium"],
152 | description: "Quality of the generated image (default: standard)",
153 | },
154 | cfg_scale: {
155 | type: "number",
156 | description: "How closely to follow the prompt (1.1-10, default: 6.5)",
157 | },
158 | seed: {
159 | type: "number",
160 | description: "Seed for reproducible generation (0-858993459, default: 12)",
161 | },
162 | numberOfImages: {
163 | type: "number",
164 | description: "Number of images to generate (1-5, default: 1)",
165 | },
166 | },
167 | required: ["prompt"],
168 | },
169 | },
170 | ],
171 | };
172 | });
173 |
174 | interface BedrockResponse {
175 | images: string[];
176 | error?: string;
177 | }
178 | /**
179 | * Handler for the generate_image tool.
180 | * Uses Amazon Bedrock to generate an image based on the provided parameters.
181 | */
182 | server.setRequestHandler(CallToolRequestSchema, async (request) => {
183 | if (request.params.name !== "generate_image") {
184 | throw new McpError(
185 | ErrorCode.MethodNotFound,
186 | `Unknown tool: ${request.params.name}`
187 | );
188 | }
189 |
190 | try {
191 | // Validate and parse input
192 | const args = GenerateImageSchema.parse(request.params.arguments);
193 |
194 | server.sendLoggingMessage({
195 | level: "info",
196 | data: `Configuration: ${JSON.stringify({
197 | width: args.width,
198 | height: args.height,
199 | quality: args.quality,
200 | numberOfImages: args.numberOfImages,
201 | cfgScale: args.cfg_scale,
202 | seed: args.seed
203 | })}`,
204 | });
205 |
206 | const progressToken = request.params._meta?.progressToken;
207 |
208 | server.sendLoggingMessage({
209 | level: "info",
210 | data: "Sending request to Bedrock API...",
211 | });
212 |
213 | const response = await bedrock.send(new InvokeModelCommand({
214 | modelId: NOVA_MODEL_ID,
215 | contentType: "application/json",
216 | accept: "application/json",
217 | body: JSON.stringify({
218 | taskType: GENERATION_TYPES.TEXT_TO_IMAGE,
219 | textToImageParams: {
220 | text: args.prompt,
221 | negativeText: args.negativePrompt || undefined,
222 | },
223 | imageGenerationConfig: {
224 | numberOfImages: args.numberOfImages,
225 | height: args.height,
226 | width: args.width,
227 | quality: args.quality,
228 | cfgScale: args.cfg_scale,
229 | seed: args.seed
230 | },
231 | }),
232 | }));
233 |
234 | server.sendLoggingMessage({
235 | level: "info",
236 | data: "Received response from Bedrock API",
237 | });
238 |
239 | if (!response.body) {
240 | server.sendLoggingMessage({
241 | level: "error",
242 | data: "No response body received from Bedrock",
243 | });
244 | throw new McpError(
245 | ErrorCode.InternalError,
246 | "No response body received from Bedrock"
247 | );
248 | }
249 |
250 | const responseBody = JSON.parse(new TextDecoder().decode(response.body)) as BedrockResponse;
251 |
252 | if (!responseBody.images || responseBody.images.length === 0) {
253 | server.sendLoggingMessage({
254 | level: "error",
255 | data: "No image data in response",
256 | });
257 | throw new McpError(
258 | ErrorCode.InternalError,
259 | `No image data in response due to ${responseBody.error}.`
260 | );
261 | }
262 |
263 | server.sendLoggingMessage({
264 | level: "info",
265 | data: "Successfully generated image",
266 | });
267 |
268 | // Return the response in the correct MCP format
269 | return {
270 | content: [
271 | {
272 | type: "text",
273 | text: `This is the image generated for your request '${args.prompt}'.`,
274 | },
275 | ...responseBody.images.map(image => ({
276 | type: "image",
277 | data: image as string,
278 | mimeType: "image/png",
279 | })),
280 | {
281 | type: "text",
282 | text: "This is the end of the image generation.",
283 | }
284 | ],
285 | };
286 | } catch (error) {
287 | console.error('Error:', error);
288 |
289 | // Handle Zod validation errors
290 | if (error instanceof z.ZodError) {
291 | throw new McpError(
292 | ErrorCode.InvalidParams,
293 | `Invalid parameters: ${error.errors.map(e => e.message).join(", ")}`
294 | );
295 | }
296 |
297 | // Handle AWS Bedrock errors
298 | if (error instanceof Error) {
299 | throw new McpError(
300 | ErrorCode.InternalError,
301 | `Failed to generate image: ${error.message}`
302 | );
303 | }
304 |
305 | // Handle unknown errors
306 | throw new McpError(
307 | ErrorCode.InternalError,
308 | "An unexpected error occurred"
309 | );
310 | }
311 | });
312 |
313 | /**
314 | * Start the server using stdio transport.
315 | */
316 | async function main() {
317 | try {
318 | const transport = new StdioServerTransport();
319 | await server.connect(transport);
320 | console.error('Amazon Bedrock MCP server running on stdio');
321 | } catch (error) {
322 | console.error('Failed to start MCP server:', error);
323 | throw error;
324 | }
325 | }
326 |
327 | // Error handling
328 | server.onerror = (error) => console.error('[MCP Error]', error);
329 | process.on('SIGINT', async () => {
330 | await server.close();
331 | process.exit(0);
332 | });
333 |
334 | main().catch((error) => {
335 | console.error("Server error:", error);
336 | process.exit(1);
337 | });
338 |
```