Designing APIs for the AI Era with Spring AI and MCP

Designing APIs for the AI Era with Spring AI and MCP

As backend developers, we've been building robust REST APIs for years. We design them to be consumed by our UIs, mobile apps, or other microservices. It's a paradigm we've mastered. But what if I told you that with minimal effort, that same API could have a second interface—one that allows AI agents to interact with your business logic using natural language?

Today, thinking about artificial intelligence isn't an afterthought; it's a design strategy. It's not just about creating a service that responds to GET or POST requests, but about asking ourselves: how can an AI model consume my service to provide extra value?

For those of us developing with Java, thanks to Spring AI, this idea has shifted from a complex task to a simple extension of what we already do. In this post, we'll explore how incredibly easy it is to add an MCP (Model Context Protocol) Server to an existing Spring Boot application, using a real-world API for managing a product catalog as our example.

The Dual API Paradigm: REST for Machines, MCP for AI 🤖

A REST API is great for structured machine-to-machine communication. But an AI agent doesn't think in terms of JSON or endpoints.

This is where the MCP Server comes in. It acts as a translator, exposing your application's logic in a way that an LLM (Large Language Model) can understand and use. This allows you to have the best of both worlds:

  • Your traditional REST API, stable and reliable for your applications.
  • An MCP Server, offering a native interface for AI integration.

This approach forces you to design from the outset with the functions (Tools), data (Resources), and guides (Prompts) that an intelligent agent would need to operate autonomously within your domain.

What is the Model Context Protocol?

The Model Context Protocol (MCP) is the standard that defines how an AI model can discover and use your application's capabilities in a secure and structured way. It provides the AI with the necessary context about what actions it can perform and what information it can query.

This protocol is built on three pillars: Tools, Resources, and Prompts. If you want to dive deeper into how it works and what each of these concepts means, you can read my more detailed post:

Model Context Protocol Uncovered: The Power of Resources and Prompts Beyond Tools
A practical guide to move beyond ‘function calling’ and build high-value MCP servers with the power of Resources and Prompts. As a developer in the AI world, you’ve surely faced this problem: connecting an LLM with real-world applications and data is a repetitive and fragmented process. Every integration seems like

For this article, the key takeaway is seeing how easy it is to implement these three pillars with Spring AI.

From @RestController to MCP Server

To demonstrate this, I'll use my Product Catalog project.

GitHub - The-Dave-Stack/product-catalog: A comprehensive, enterprise-grade RESTful API for product catalog management using Spring Boot.
A comprehensive, enterprise-grade RESTful API for product catalog management using Spring Boot. - The-Dave-Stack/product-catalog

Step 0: Build Your Traditional Spring Boot Service

I won't spend much time on this point because creating the foundation for a Spring Boot project is almost trivial using https://start.spring.io/. I'll also leave a link to their documentation if you want more details:

Getting Started | Building an Application with Spring Boot
Learn how to build an application with minimal configuration.

Step 1: Configuration is a Breeze

Once you have your Spring Boot service, you just need to add the Spring AI dependency and enable the server. To manage versions centrally, we add the Spring AI "Bill of Materials" (BOM) to the <dependencyManagement> section of your pom.xml:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-bom</artifactId>
            <version>1.0.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

Next, in your <dependencies> section, you only need to add the MCP server starter, which in this case is spring-ai-starter-mcp-server-webmvc:

<dependencies>
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
    </dependency>
</dependencies>

Finally, in your application.properties, you enable and configure the server. It's that simple:

# application.properties

# Activa el servidor MCP
spring.ai.mcp.server.enabled=true
spring.ai.mcp.server.name=product-catalog-mcp-server
spring.ai.mcp.server.version=1.0.0

# Define las instrucciones generales para la IA
spring.ai.mcp.server.instructions=Servidor para la gestión de un catálogo de productos con herramientas, recursos y guías impulsadas por IA.

# Activa las capacidades que quieres exponer
spring.ai.mcp.server.capabilities.tool=true
spring.ai.mcp.server.capabilities.resource=true
spring.ai.mcp.server.capabilities.prompt=true

With just these few lines, your application now has a functional MCP server.

Step 2: Implementing the MCP Features

Now that we have the Spring AI dependencies and the MCP starter, it's time to dive in.

2.1: Expose Your Services as Tools

You already have the business logic in your @Service classes. To expose a method as a tool for the AI, you just need one annotation: @Tool.

@Tool(description = "Creates a new product in the catalog with comprehensive validation and audit logging. Required fields: name, price, category, stockQuantity, minStockLevel. Optional fields: description, SKU (auto-generated if not provided), weight, dimensions, imageUrl. SKU must be globally unique if provided. Automatically creates audit log entry. Throws DuplicateSkuException for duplicate SKUs. Use this for adding new products to the inventory system.")
@Transactional
public Product createProduct(@ToolParam(description = "Product object with required fields: name, price, category, stockQuantity, minStockLevel. Optional: description, sku, weight, dimensions, imageUrl") Product product) {
    ...
}

And that's it! Your createProduct method is now a tool that any AI agent can invoke.

2.2: Expose Live Data with Resources

A Resource acts as a live data feed for the AI. Instead of having static data in a prompt, you can expose information that changes within your application, like a list of product categories.

To do this, we define a URI (e.g., categories://overview/all) and associate it with a function that returns the data.

public List<McpServerFeatures.SyncResourceSpecification> getResourceSpecifications() {
        return List.of(
                // All categories overview resource
                new McpServerFeatures.SyncResourceSpecification(
                        new McpSchema.Resource(
                                "categories://overview/all",
                                "All Categories Overview",
                                "Complete overview of all product categories with descriptions and guidelines",
                                "application/json",
                                null),
                        this::getAllCategoriesResource),
                ...
                );
}

private McpSchema.ReadResourceResult getAllCategoriesResource(
            McpSyncServerExchange exchange, McpSchema.ReadResourceRequest request) {
        try {
            List<Map<String, Object>> categoriesInfo =
                    Arrays.stream(Category.values())
                            .map(this::createCategoryOverview)
                            .collect(Collectors.toList());

            String jsonContent =
                    objectMapper.writeValueAsString(
                            Map.of(
                                    "totalCategories",
                                    Category.values().length,
                                    "categories",
                                    categoriesInfo,
                                    "description",
                                    "Complete catalog of product categories with their descriptions and key characteristics",
                                    "lastUpdated",
                                    Instant.now().toString()));

            return new McpSchema.ReadResourceResult(
                    List.of(
                            new McpSchema.TextResourceContents(
                                    request.uri(), "application/json", jsonContent)));
        } catch (Exception e) {
            log.error("Failed to get all categories resource", e);
            throw new RuntimeException("Failed to retrieve categories overview", e);
        }
}    

2.3: Expose Your Workflows with Prompts

Prompts are structured guides that teach the AI how to perform complex, multi-step tasks. They are like pre-designed prompt templates that you can invoke, combining instructions, data from Resources, and Tools.

Imagine you want a guide for analyzing inventory. You could create a Prompt named inventory-analysis that instructs the AI to first fetch low-stock products (using a Tool) and then generate a report.

public List<McpServerFeatures.SyncPromptSpecification> getPromptSpecifications() {
        return List.of(
                ...

                // Inventory analysis prompt
                new McpServerFeatures.SyncPromptSpecification(
                        new McpSchema.Prompt(
                                "inventory-analysis",
                                "Inventory Analysis and Recommendations",
                                List.of(
                                        new McpSchema.PromptArgument(
                                                "analysisType",
                                                "Type of analysis (stock-health/reorder/turnover)",
                                                true),
                                        new McpSchema.PromptArgument(
                                                "category", "Focus on specific category", false))),
                        this::createInventoryAnalysisPrompt),
                
                ...
                );
}

private McpSchema.GetPromptResult createInventoryAnalysisPrompt(
            McpSyncServerExchange exchange, McpSchema.GetPromptRequest request) {
        try {
            String analysisType = (String) request.arguments().get("analysisType");
            String category = (String) request.arguments().getOrDefault("category", "ALL");

            String promptText = createInventoryAnalysisPromptText(analysisType, category);

            McpSchema.PromptMessage promptMessage =
                    new McpSchema.PromptMessage(
                            McpSchema.Role.ASSISTANT, new McpSchema.TextContent(promptText));

            return new McpSchema.GetPromptResult(
                    "Inventory analysis guidance for " + analysisType + " analysis",
                    List.of(promptMessage));
        } catch (Exception e) {
            log.error("Failed to create inventory analysis prompt", e);
            throw new RuntimeException("Failed to generate inventory analysis prompt", e);
        }
}

private String createInventoryAnalysisPromptText(String analysisType, String category) {
        return switch (analysisType) {
            case "stock-health" -> """
                You are an inventory management specialist conducting a stock health analysis%s.

                ## Stock Health Analysis Framework

                ### Key Metrics to Evaluate:
                1. **Out of Stock Items** - Immediate attention required
                2. **Low Stock Warnings** - Items below minimum levels
                3. **Overstock Situations** - Items with excessive inventory
                4. **Stock Turnover Rates** - How quickly inventory moves
                5. **Dead Stock** - Items with no recent sales

                ### Analysis Process:
                1. Retrieve current inventory levels using available tools
                2. Compare against minimum stock thresholds
                3. Identify critical alerts requiring immediate action
                4. Calculate stock health scores by category
                5. Generate actionable recommendations

                ### Recommended Actions:
                - **Critical**: Immediate reorders for out-of-stock items
                - **Warning**: Schedule reorders for low-stock items
                - **Optimization**: Review slow-moving inventory for discounts
                - **Planning**: Adjust minimum stock levels based on trends

                Please conduct a comprehensive stock health analysis and provide prioritized recommendations.
                """
                    .formatted(category.equals("ALL") ? "" : " for " + category + " category");

            case "reorder" -> """
                You are a procurement specialist developing reorder recommendations%s.

                ## Reorder Analysis Framework

                ### Reorder Triggers:
                1. Current stock ≤ minimum stock level
                2. Projected stockouts based on demand trends
                3. Lead time considerations
                4. Economic order quantities
                5. Seasonal demand adjustments

                ### Analysis Steps:
                1. Identify products below reorder points
                2. Calculate optimal order quantities
                3. Consider supplier minimums and volume discounts
                4. Factor in lead times and safety stock
                5. Prioritize based on sales velocity and margin

                ### Reorder Recommendations:
                - High priority: Fast-moving items near stockout
                - Medium priority: Steady sellers below minimum
                - Low priority: Slow movers with adequate runway

                Please generate a prioritized reorder plan with specific quantities and timing.
                """
                    .formatted(category.equals("ALL") ? "" : " for " + category + " category");

            case "turnover" -> """
                You are a financial analyst evaluating inventory turnover performance%s.

                ## Inventory Turnover Analysis

                ### Key Calculations:
                1. **Turnover Ratio** = Cost of Goods Sold / Average Inventory Value
                2. **Days Sales Inventory** = 365 / Turnover Ratio
                3. **Stock Velocity** = Units Sold / Average Units in Stock
                4. **Carrying Cost Impact** = Average Inventory × Carrying Cost Rate

                ### Performance Benchmarks:
                - Electronics: 8-12 turns/year (Fast-moving technology)
                - Books: 3-5 turns/year (Diverse demand patterns)
                - Clothing: 4-6 turns/year (Seasonal collections)
                - General: 6-8 turns/year (Standard retail)

                ### Analysis Focus:
                1. Compare actual vs. target turnover rates
                2. Identify slow-moving inventory
                3. Calculate carrying cost implications
                4. Recommend optimization strategies

                Please analyze turnover performance and suggest improvements for capital efficiency.
                """
                    .formatted(category.equals("ALL") ? "" : " for " + category + " category");

            default -> "Please specify analysis type: stock-health, reorder, or turnover.";
        };
}

Step 3: Configure the Beans to Expose Everything

Once you have all the pieces, exposing Tools, Resources, and Prompts is as simple as creating Spring Beans for them.

@SpringBootApplication
public class ProductCatalogSpringApplication {

    public static void main(String[] args) {
        SpringApplication.run(ProductCatalogSpringApplication.class, args);
    }

    @Bean
    public ToolCallbackProvider productCatalogTools(ProductService productService) {
        return MethodToolCallbackProvider.builder().toolObjects(productService).build();
    }

    @Bean
    public List<McpServerFeatures.SyncResourceSpecification> productCatalogResources() {
        List<McpServerFeatures.SyncResourceSpecification> productCatalogResources = new ArrayList<>();
        ...
        return productCatalogResources;
    }

    @Bean
    public List<McpServerFeatures.SyncPromptSpecification> productCatalogPrompts(ProductManagementPromptProvider productManagementPromptProvider) {
        return productManagementPromptProvider.getPromptSpecifications();
    }

}

With these simple steps, you've built a direct and secure bridge between your business logic and the world of AI.

Conclusion: The Next Natural Step for Your APIs

As we've seen, adding an MCP Server to your Spring Boot application isn't a Herculean task. It's the next logical step in the evolution of our services. Spring AI abstracts away all the complexity, allowing us to reuse the code we already have to open our applications to a universe of new possibilities with artificial intelligence.

Designing with AI in mind from the start is no longer an option—it's a competitive advantage.

What's Next? Your Turn to Act 🚀

I hope this post has inspired you to look at your APIs from a new perspective. Here are a few ideas to get you started:

  1. Explore the source code: All the code from this example is available in my Product Catalog API GitHub repository. Clone it, run it with Docker, and experiment for yourself. The best way to learn is by doing!
  2. Start small: You don't need a complex architecture. Pick a key method from one of your current Spring Boot applications and try exposing it as a @Tool. You'll see how simple it is.
  3. Join the conversation: What do you think of this approach to AI-native APIs? What other use cases can you think of for an MCP Server in your projects?
  4. Dive into the documentation: If you want to learn all the details, the official Spring AI documentation is the best place to keep learning.
Model Context Protocol (MCP) :: Spring AI Reference

Further Reading

The internet is full of articles that can also help you learn more about the world of Spring AI and MCP. Here are a couple I've found very interesting:

Dynamic Tool Updates in Spring AI’s Model Context Protocol
Level up your Java code and explore what Spring can do for you.
You've successfully subscribed to The Dave Stack
Great! Next, complete checkout for full access to The Dave Stack
Welcome back! You've successfully signed in.
Success! Your account is fully activated, you now have access to all content.
Success! Your billing info is updated.
Billing info update failed.