diff --git a/examples/spring-ai-mcp-client/Dockerfile b/examples/spring-ai-mcp-client/Dockerfile new file mode 100644 index 0000000..9382e54 --- /dev/null +++ b/examples/spring-ai-mcp-client/Dockerfile @@ -0,0 +1,26 @@ +FROM --platform=linux/arm64 amazoncorretto:21-alpine + +# Install Python and uv for MCP server support +RUN apk add --no-cache python3 py3-pip curl bash wget + +# Install uv (Python package manager) +RUN curl -LsSf https://astral.sh/uv/install.sh | sh +ENV PATH="/root/.local/bin:${PATH}" + +# Verify uvx is available +RUN uvx --version + +WORKDIR /app + +# Copy the application JAR +COPY target/*.jar app.jar + +# Expose port +EXPOSE 8080 + +# Health check +HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \ + CMD wget --no-verbose --tries=1 --spider http://localhost:8080/ping || exit 1 + +# Run the application +ENTRYPOINT ["java", "-jar", "app.jar"] diff --git a/examples/spring-ai-mcp-client/README.md b/examples/spring-ai-mcp-client/README.md new file mode 100644 index 0000000..540944f --- /dev/null +++ b/examples/spring-ai-mcp-client/README.md @@ -0,0 +1,236 @@ +# Spring AI MCP Client Agent + +A Spring Boot application demonstrating integration with Model Context Protocol (MCP) servers. This example connects to the AWS Documentation MCP Server over stdio to provide AI-powered AWS documentation assistance. + +## Features + +- **MCP Client Integration**: Connects to MCP servers over stdio transport +- **AWS Documentation Tools**: + - Search AWS documentation + - Read full documentation pages + - Get related documentation recommendations +- **AgentCore Integration**: Uses `@AgentCoreInvocation` for automatic endpoint setup +- **Amazon Bedrock**: Integration with Claude 3 Sonnet model +- **Tool Wrapping**: Wraps MCP server tools as Spring AI tools + +## Prerequisites + +- Java 21 +- Maven +- AWS account with access to Amazon Bedrock +- AWS credentials configured locally +- Python with `uv` and `uvx` installed (for MCP server) + +### Installing uv/uvx + +The MCP server runs via `uvx`, which requires `uv` to be installed: + +**macOS/Linux:** +```bash +curl -LsSf https://astral.sh/uv/install.sh | sh +``` + +**Or with Homebrew:** +```bash +brew install uv +``` + +**Or with pip:** +```bash +pip install uv +``` + +After installation, `uvx` will be available automatically. + +## Architecture + +``` +┌─────────────────────────────────────────────────────────────┐ +│ Spring Boot Application │ +│ │ +│ ┌──────────────┐ ┌─────────────────┐ │ +│ │ ChatClient │─────▶│ AwsDocsMcpTools │ │ +│ │ (Spring AI) │ │ (Tool Wrapper) │ │ +│ └──────────────┘ └────────┬────────┘ │ +│ │ │ +│ ┌────────▼────────┐ │ +│ │ McpStdioClient │ │ +│ │ (MCP Client) │ │ +│ └────────┬────────┘ │ +└──────────────────────────────────┼──────────────────────────┘ + │ stdio + ┌─────────▼──────────┐ + │ uvx process │ + │ AWS Docs MCP │ + │ Server │ + └────────────────────┘ +``` + +## Configuration + +The MCP client connects to the AWS Documentation server with these settings: + +```java +command: "uvx" +args: ["awslabs.aws-documentation-mcp-server@latest"] +env: + FASTMCP_LOG_LEVEL: "ERROR" + AWS_DOCUMENTATION_PARTITION: "aws" +``` + +## Building and Running + +```bash +mvn clean package +java -jar target/mcp-client-agent-0.0.1-SNAPSHOT.jar +``` + +Or use Maven directly: + +```bash +mvn spring-boot:run +``` + +The application starts on port 8080. + +## API Endpoints + +### AWS Documentation Query Endpoint + +```bash +# Ask about AWS services +curl -X POST http://localhost:8080/invocations \ + -H "Content-Type: application/json" \ + -d '{"prompt":"What is Amazon S3?"}' + +# Ask about specific features +curl -X POST http://localhost:8080/invocations \ + -H "Content-Type: application/json" \ + -d '{"prompt":"How do I configure S3 bucket versioning?"}' + +# Ask about best practices +curl -X POST http://localhost:8080/invocations \ + -H "Content-Type: application/json" \ + -d '{"prompt":"What are the best practices for Lambda function configuration?"}' + +# Compare services +curl -X POST http://localhost:8080/invocations \ + -H "Content-Type: application/json" \ + -d '{"prompt":"What is the difference between ECS and EKS?"}' +``` + +### Health Endpoints + +```bash +# AgentCore health check +curl http://localhost:8080/ping + +# Actuator health check +curl http://localhost:8080/actuator/health +``` + +## How It Works + +1. **MCP Client Initialization**: On startup, `McpStdioClient` connects to the AWS Documentation MCP server via stdio +2. **Tool Discovery**: The client lists available tools from the MCP server +3. **Tool Wrapping**: `AwsDocsMcpTools` wraps MCP tools as Spring AI `@Tool` methods +4. **AI Processing**: When a user asks about AWS: + - The AI model analyzes the query + - Determines which MCP tool(s) to call + - Calls the tools via the MCP client + - Synthesizes a response with documentation + +## Available MCP Tools + +### search_documentation +Search AWS documentation for specific topics. + +**Parameters:** +- `search_phrase` (required): Search query +- `limit` (optional): Max results (default: 5) + +### read_documentation +Read full content of an AWS documentation page. + +**Parameters:** +- `url` (required): Documentation URL +- `max_length` (optional): Max content length (default: 5000) +- `start_index` (optional): Starting position (default: 0) + +### recommend +Get related documentation recommendations. + +**Parameters:** +- `url` (required): Documentation URL to get recommendations for + +## Example Interactions + +**User**: "What is Amazon S3?" +**Agent**: Searches AWS docs, reads relevant pages, provides comprehensive answer with links + +**User**: "How do I enable S3 versioning?" +**Agent**: Searches for versioning docs, reads the guide, provides step-by-step instructions + +**User**: "What's the difference between ECS and EKS?" +**Agent**: Searches for both services, compares features, provides clear explanation + +## Project Structure + +``` +src/main/java/com/unicorn/mcp/ +├── McpClientApplication.java # Main application +├── McpController.java # AgentCore controller +├── McpStdioClient.java # MCP client (stdio transport) +├── AwsDocsMcpTools.java # Tool wrappers for Spring AI +└── PromptRequest.java # Request model +``` + +## Troubleshooting + +### MCP Server Connection Issues + +If the MCP server fails to start: + +1. Verify `uvx` is installed: `uvx --version` +2. Test the MCP server manually: + ```bash + uvx awslabs.aws-documentation-mcp-server@latest + ``` +3. Check logs in the application output + +### Tool Call Failures + +If tools fail to execute: +- Check the MCP server logs (set `FASTMCP_LOG_LEVEL=DEBUG`) +- Verify the tool arguments match the expected schema +- Ensure network connectivity for documentation fetching + +## Deployment to AWS + +This example can be deployed to Amazon Bedrock AgentCore Runtime. See: + +- **[QUICKSTART.md](QUICKSTART.md)** - 5-minute deployment guide +- **[DEPLOYMENT.md](DEPLOYMENT.md)** - Comprehensive deployment documentation + +Quick deploy: + +```bash +./deploy.sh +``` + +Or manually: + +```bash +cd ../terraform +./build-and-push.sh spring-ai-mcp-client +terraform apply +./invoke-iam.sh "test" "What is Amazon S3?" +``` + +## Notes + +- The MCP server is started automatically by the Java application +- The stdio transport provides reliable communication between Java and Python +- Tool calls are synchronous and may take a few seconds for documentation fetching +- The AI model automatically determines when to use MCP tools vs. its own knowledge +- The container includes Python and uv for running MCP servers diff --git a/examples/spring-ai-mcp-client/pom.xml b/examples/spring-ai-mcp-client/pom.xml new file mode 100644 index 0000000..11e5259 --- /dev/null +++ b/examples/spring-ai-mcp-client/pom.xml @@ -0,0 +1,74 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.4.5 + + + com.unicorn + mcp-client-agent + 0.0.1-SNAPSHOT + mcp-client-agent + Spring AI Agent with MCP Client for AWS Documentation + + 21 + 1.0.0 + + + + org.springframework.ai + spring-ai-starter-model-bedrock-converse + + + + org.springframework.boot + spring-boot-starter-actuator + + + + org.springaicommunity + spring-ai-bedrock-agentcore-starter + 1.0.0-SNAPSHOT + + + + org.springframework.boot + spring-boot-starter-web + + + + + com.fasterxml.jackson.core + jackson-databind + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + org.springframework.ai + spring-ai-bom + ${spring-ai.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/examples/spring-ai-mcp-client/src/main/java/com/unicorn/mcp/AwsDocsMcpTools.java b/examples/spring-ai-mcp-client/src/main/java/com/unicorn/mcp/AwsDocsMcpTools.java new file mode 100644 index 0000000..4d7ad34 --- /dev/null +++ b/examples/spring-ai-mcp-client/src/main/java/com/unicorn/mcp/AwsDocsMcpTools.java @@ -0,0 +1,79 @@ +package com.unicorn.mcp; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyDescription; +import org.springframework.ai.tool.annotation.Tool; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; + +/** + * Spring AI Tools that wrap MCP server calls for AWS Documentation. + */ +@Component +public class AwsDocsMcpTools { + + private final McpStdioClient mcpClient; + + public AwsDocsMcpTools(McpStdioClient mcpClient) { + this.mcpClient = mcpClient; + } + + public record SearchRequest( + @JsonProperty(required = true) + @JsonPropertyDescription("The search query for AWS documentation") + String query, + + @JsonProperty(required = false) + @JsonPropertyDescription("Maximum number of results to return (default: 5)") + Integer limit + ) {} + + public record ReadDocRequest( + @JsonProperty(required = true) + @JsonPropertyDescription("The URL of the AWS documentation page to read") + String url, + + @JsonProperty(required = false) + @JsonPropertyDescription("Maximum length of content to return (default: 5000)") + Integer maxLength, + + @JsonProperty(required = false) + @JsonPropertyDescription("Starting index for content (default: 0)") + Integer startIndex + ) {} + + @Tool(description = "Search AWS documentation for information about AWS services, features, and best practices. Returns relevant documentation URLs and snippets.") + public String searchAwsDocs(SearchRequest request) { + Map args = new HashMap<>(); + args.put("search_phrase", request.query); + if (request.limit != null) { + args.put("limit", request.limit); + } + + return mcpClient.callTool("search_documentation", args); + } + + @Tool(description = "Read the full content of an AWS documentation page. Useful after searching to get detailed information from a specific documentation URL.") + public String readAwsDoc(ReadDocRequest request) { + Map args = new HashMap<>(); + args.put("url", request.url); + if (request.maxLength != null) { + args.put("max_length", request.maxLength); + } + if (request.startIndex != null) { + args.put("start_index", request.startIndex); + } + + return mcpClient.callTool("read_documentation", args); + } + + @Tool(description = "Get recommendations for related AWS documentation pages based on a given documentation URL. Helps discover additional relevant content.") + public String getAwsDocsRecommendations(String url) { + Map args = new HashMap<>(); + args.put("url", url); + + return mcpClient.callTool("recommend", args); + } +} diff --git a/examples/spring-ai-mcp-client/src/main/java/com/unicorn/mcp/McpClientApplication.java b/examples/spring-ai-mcp-client/src/main/java/com/unicorn/mcp/McpClientApplication.java new file mode 100644 index 0000000..352ce2f --- /dev/null +++ b/examples/spring-ai-mcp-client/src/main/java/com/unicorn/mcp/McpClientApplication.java @@ -0,0 +1,12 @@ +package com.unicorn.mcp; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class McpClientApplication { + + public static void main(String[] args) { + SpringApplication.run(McpClientApplication.class, args); + } +} diff --git a/examples/spring-ai-mcp-client/src/main/java/com/unicorn/mcp/McpController.java b/examples/spring-ai-mcp-client/src/main/java/com/unicorn/mcp/McpController.java new file mode 100644 index 0000000..29ff93d --- /dev/null +++ b/examples/spring-ai-mcp-client/src/main/java/com/unicorn/mcp/McpController.java @@ -0,0 +1,42 @@ +package com.unicorn.mcp; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springaicommunity.agentcore.annotation.AgentCoreInvocation; +import org.springaicommunity.agentcore.context.AgentCoreContext; +import org.springaicommunity.agentcore.context.AgentCoreHeaders; +import org.springframework.ai.chat.client.ChatClient; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class McpController { + + private final ChatClient chatClient; + private static final Logger logger = LoggerFactory.getLogger(McpController.class); + + public McpController( + ChatClient.Builder chatClientBuilder, + AwsDocsMcpTools awsDocsMcpTools, + @Value("${agent.system.prompt}") String systemPrompt) { + this.chatClient = chatClientBuilder + .defaultTools(awsDocsMcpTools) + .defaultSystem(systemPrompt) + .build(); + } + + @AgentCoreInvocation + public String handleAwsQuery(PromptRequest promptRequest, AgentCoreContext agentCoreContext) { + String sessionId = agentCoreContext.getHeader(AgentCoreHeaders.SESSION_ID); + logger.info("Processing AWS documentation query for session: {}", sessionId); + logger.info("User prompt: {}", promptRequest.prompt()); + + String response = chatClient.prompt() + .user(promptRequest.prompt()) + .call() + .content(); + + logger.info("Response generated successfully"); + return response; + } +} diff --git a/examples/spring-ai-mcp-client/src/main/java/com/unicorn/mcp/McpStdioClient.java b/examples/spring-ai-mcp-client/src/main/java/com/unicorn/mcp/McpStdioClient.java new file mode 100644 index 0000000..7f0d768 --- /dev/null +++ b/examples/spring-ai-mcp-client/src/main/java/com/unicorn/mcp/McpStdioClient.java @@ -0,0 +1,216 @@ +package com.unicorn.mcp; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import jakarta.annotation.PostConstruct; +import jakarta.annotation.PreDestroy; +import java.io.*; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * MCP Client that connects to MCP Server over stdio using JSON-RPC. + */ +@Component +public class McpStdioClient { + + private static final Logger logger = LoggerFactory.getLogger(McpStdioClient.class); + + @Value("${mcp.server.command:uvx}") + private String mcpCommand; + + @Value("${mcp.server.package}") + private String mcpPackage; + + @Value("${mcp.server.env.FASTMCP_LOG_LEVEL:ERROR}") + private String logLevel; + + @Value("${mcp.server.env.AWS_DOCUMENTATION_PARTITION:aws}") + private String awsPartition; + + private Process mcpProcess; + private BufferedWriter processInput; + private BufferedReader processOutput; + private final ObjectMapper objectMapper = new ObjectMapper(); + private final AtomicInteger requestId = new AtomicInteger(1); + private List> availableTools; + + @PostConstruct + public void initialize() { + try { + logger.info("Initializing MCP client connection..."); + logger.info("MCP Server: {} {}", mcpCommand, mcpPackage); + + // Build environment variables + Map env = new HashMap<>(System.getenv()); + env.put("FASTMCP_LOG_LEVEL", logLevel); + env.put("AWS_DOCUMENTATION_PARTITION", awsPartition); + + // Start the MCP server process + ProcessBuilder pb = new ProcessBuilder( + mcpCommand, + mcpPackage + ); + pb.environment().putAll(env); + pb.redirectError(ProcessBuilder.Redirect.INHERIT); + + mcpProcess = pb.start(); + processInput = new BufferedWriter(new OutputStreamWriter(mcpProcess.getOutputStream())); + processOutput = new BufferedReader(new InputStreamReader(mcpProcess.getInputStream())); + + logger.info("MCP server process started"); + + // Initialize the connection + sendInitialize(); + + // List available tools + listTools(); + + logger.info("Successfully connected to MCP server with {} tools", + availableTools != null ? availableTools.size() : 0); + + } catch (Exception e) { + logger.error("Failed to initialize MCP client", e); + throw new RuntimeException("Failed to initialize MCP client", e); + } + } + + private void sendInitialize() throws IOException { + ObjectNode request = objectMapper.createObjectNode(); + request.put("jsonrpc", "2.0"); + request.put("id", requestId.getAndIncrement()); + request.put("method", "initialize"); + + ObjectNode params = objectMapper.createObjectNode(); + params.put("protocolVersion", "2024-11-05"); + + ObjectNode clientInfo = objectMapper.createObjectNode(); + clientInfo.put("name", "spring-ai-mcp-client"); + clientInfo.put("version", "1.0.0"); + params.set("clientInfo", clientInfo); + + ObjectNode capabilities = objectMapper.createObjectNode(); + params.set("capabilities", capabilities); + + request.set("params", params); + + sendRequest(request); + JsonNode response = readResponse(); + logger.info("Initialize response: {}", response); + + // Send initialized notification + ObjectNode notification = objectMapper.createObjectNode(); + notification.put("jsonrpc", "2.0"); + notification.put("method", "notifications/initialized"); + sendRequest(notification); + } + + private void listTools() throws IOException { + ObjectNode request = objectMapper.createObjectNode(); + request.put("jsonrpc", "2.0"); + request.put("id", requestId.getAndIncrement()); + request.put("method", "tools/list"); + request.set("params", objectMapper.createObjectNode()); + + sendRequest(request); + JsonNode response = readResponse(); + + if (response.has("result") && response.get("result").has("tools")) { + availableTools = new ArrayList<>(); + response.get("result").get("tools").forEach(tool -> { + Map toolMap = objectMapper.convertValue(tool, Map.class); + availableTools.add(toolMap); + logger.info(" - Tool: {} - {}", + toolMap.get("name"), + toolMap.get("description")); + }); + } + } + + /** + * Call an MCP tool with the given name and arguments. + */ + public String callTool(String toolName, Map arguments) { + try { + logger.info("Calling MCP tool: {} with args: {}", toolName, arguments); + + ObjectNode request = objectMapper.createObjectNode(); + request.put("jsonrpc", "2.0"); + request.put("id", requestId.getAndIncrement()); + request.put("method", "tools/call"); + + ObjectNode params = objectMapper.createObjectNode(); + params.put("name", toolName); + params.set("arguments", objectMapper.valueToTree(arguments)); + request.set("params", params); + + sendRequest(request); + JsonNode response = readResponse(); + + if (response.has("result") && response.get("result").has("content")) { + JsonNode content = response.get("result").get("content"); + if (content.isArray() && content.size() > 0) { + JsonNode firstContent = content.get(0); + if (firstContent.has("text")) { + return firstContent.get("text").asText(); + } + } + } + + if (response.has("error")) { + return "Error: " + response.get("error").toString(); + } + + return "No content returned from tool"; + + } catch (Exception e) { + logger.error("Error calling MCP tool: {}", toolName, e); + return "Error calling tool: " + e.getMessage(); + } + } + + private void sendRequest(ObjectNode request) throws IOException { + String requestStr = objectMapper.writeValueAsString(request); + logger.debug("Sending request: {}", requestStr); + processInput.write(requestStr); + processInput.newLine(); + processInput.flush(); + } + + private JsonNode readResponse() throws IOException { + String line = processOutput.readLine(); + if (line == null) { + throw new IOException("MCP server closed connection"); + } + logger.debug("Received response: {}", line); + return objectMapper.readTree(line); + } + + /** + * Get list of available tools from the MCP server. + */ + public List> getAvailableTools() { + return availableTools; + } + + @PreDestroy + public void cleanup() { + try { + if (mcpProcess != null && mcpProcess.isAlive()) { + logger.info("Closing MCP client connection..."); + processInput.close(); + processOutput.close(); + mcpProcess.destroy(); + mcpProcess.waitFor(); + } + } catch (Exception e) { + logger.error("Error closing MCP client", e); + } + } +} diff --git a/examples/spring-ai-mcp-client/src/main/java/com/unicorn/mcp/PromptRequest.java b/examples/spring-ai-mcp-client/src/main/java/com/unicorn/mcp/PromptRequest.java new file mode 100644 index 0000000..cbf916f --- /dev/null +++ b/examples/spring-ai-mcp-client/src/main/java/com/unicorn/mcp/PromptRequest.java @@ -0,0 +1,4 @@ +package com.unicorn.mcp; + +public record PromptRequest(String prompt) { +} diff --git a/examples/spring-ai-mcp-client/src/main/resources/application.properties b/examples/spring-ai-mcp-client/src/main/resources/application.properties new file mode 100644 index 0000000..852f07f --- /dev/null +++ b/examples/spring-ai-mcp-client/src/main/resources/application.properties @@ -0,0 +1,28 @@ +spring.application.name=mcp-client-agent +spring.ai.bedrock.aws.region=eu-central-1 +spring.ai.bedrock.converse.chat.options.model=global.anthropic.claude-sonnet-4-5-20250929-v1:0 + +# Agent System Prompt +agent.system.prompt=You are an AWS documentation assistant. You have access to tools that can: \ + 1. Search AWS documentation for specific topics \ + 2. Read full AWS documentation pages \ + 3. Get recommendations for related documentation \ + \ + When users ask about AWS services, features, or best practices: \ + - First search for relevant documentation \ + - If needed, read specific documentation pages for detailed information \ + - Provide clear, accurate answers based on the official AWS documentation \ + - Include documentation URLs when relevant \ + \ + Always cite your sources and be helpful in explaining AWS concepts. + +# MCP Server Configuration +mcp.server.command=uvx +mcp.server.package=awslabs.aws-documentation-mcp-server@latest +mcp.server.env.FASTMCP_LOG_LEVEL=ERROR +mcp.server.env.AWS_DOCUMENTATION_PARTITION=aws + +# Logging +logging.level.com.unicorn.mcp=INFO +logging.level.org.springframework.ai=INFO +logging.level.io.modelcontextprotocol=INFO diff --git a/examples/spring-ai-mcp-client/test_requests.http b/examples/spring-ai-mcp-client/test_requests.http new file mode 100644 index 0000000..0e87584 --- /dev/null +++ b/examples/spring-ai-mcp-client/test_requests.http @@ -0,0 +1,58 @@ +### Ask about AWS service + +POST http://localhost:8080/invocations +Content-Type: application/json + +{ "prompt" : "What is Amazon S3?"} + + +### Ask about specific feature + +POST http://localhost:8080/invocations +Content-Type: application/json + +{ "prompt" : "How do I configure S3 bucket versioning?"} + + +### Ask about best practices + +POST http://localhost:8080/invocations +Content-Type: application/json + +{ "prompt" : "What are the best practices for Lambda function configuration?"} + + +### Compare AWS services + +POST http://localhost:8080/invocations +Content-Type: application/json + +{ "prompt" : "What is the difference between ECS and EKS?"} + + +### Ask about pricing + +POST http://localhost:8080/invocations +Content-Type: application/json + +{ "prompt" : "How does S3 pricing work?"} + + +### Ask about security + +POST http://localhost:8080/invocations +Content-Type: application/json + +{ "prompt" : "What are the security best practices for S3 buckets?"} + + +### Ping endpoint + +GET http://localhost:8080/ping +Content-Type: application/json + + +### Actuator health endpoint + +GET http://localhost:8080/actuator/health +Content-Type: application/json diff --git a/examples/terraform/build-and-push.sh b/examples/terraform/build-and-push.sh index 7314076..03b6013 100755 --- a/examples/terraform/build-and-push.sh +++ b/examples/terraform/build-and-push.sh @@ -7,7 +7,7 @@ AWS_REGION=$(grep 'region' terraform.tfvars | cut -d'"' -f2) AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text) # Available examples -VALID_APPS=("simple-spring-boot-app" "spring-ai-sse-chat-client" "spring-ai-simple-chat-client") +VALID_APPS=("simple-spring-boot-app" "spring-ai-sse-chat-client" "spring-ai-simple-chat-client" "spring-ai-mcp-client") # Interactive selection if no argument provided if [ $# -eq 0 ]; then @@ -54,12 +54,7 @@ echo "📦 Creating ECR repository if needed..." aws ecr create-repository --repository-name "$ECR_REPO_NAME" --region "$AWS_REGION" 2>/dev/null || echo "Repository already exists" echo "🔨 Building application..." -# Check if we're in the monorepo (starter source available) -if [ -f "../../pom.xml" ] && grep -q "spring-ai-bedrock-agentcore-starter" "../../pom.xml"; then - echo "📦 Building starter from source..." - cd ../.. && mvn clean install -DskipTests -q && cd examples/terraform -fi - +cd ../.. && mvn clean install -DskipTests -q && cd examples/terraform cd "../$EXAMPLE_APP" && mvn clean package -DskipTests -q && cd ../terraform echo "🐳 Building container image..."