
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:

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.
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:

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:
- 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!
- 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. - 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?
- Dive into the documentation: If you want to learn all the details, the official Spring AI documentation is the best place to keep learning.
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:
