eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Maven – NPI EA (cat = Maven)
announcement - icon

Get Started with Apache Maven:

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

Get started with Spring and Spring Boot, through the Learn Spring course:

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

Get started with Spring Data JPA through the guided reference course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (cat=Spring Boot)
announcement - icon

Refactor Java code safely — and automatically — with OpenRewrite.

Refactoring big codebases by hand is slow, risky, and easy to put off. That’s where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.

Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions — one for newcomers and one for experienced users. You’ll see how recipes work, how to apply them across projects, and how to modernize code with confidence.

Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.

Course – LJB – NPI EA (cat = Core Java)
announcement - icon

Code your way through and build up a solid, practical foundation of Java:

>> Learn Java Basics

Partner – LambdaTest – NPI EA (cat= Testing)
announcement - icon

Distributed systems often come with complex challenges such as service-to-service communication, state management, asynchronous messaging, security, and more.

Dapr (Distributed Application Runtime) provides a set of APIs and building blocks to address these challenges, abstracting away infrastructure so we can focus on business logic.

In this tutorial, we'll focus on Dapr's pub/sub API for message brokering. Using its Spring Boot integration, we'll simplify the creation of a loosely coupled, portable, and easily testable pub/sub messaging system:

>> Flexible Pub/Sub Messaging With Spring Boot and Dapr

1. Overview

The Model Context Protocol (MCP) has emerged as a standard for connecting AI models to external data and tools. Rather than building bespoke integrations for every data source, MCP enables developers to create universal connectors that work across various AI clients.

Spring AI supports this protocol through a dedicated module that introduces a declarative, annotation-based programming model. Instead of manually registering tool callbacks or configuring JSON schemas, we can annotate standard Java methods to expose them as AI capabilities.

In this tutorial, we’ll explore the core MCP annotations in Spring AI: @McpTool, @McpResource, and @McpPrompt.

2. Maven Dependencies 

We use the spring-ai-starter-mcp-server dependency. This starter handles the auto-configuration and component scanning for MCP beans:

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-mcp-server</artifactId>
    <version>1.1.2</version>
</dependency>

3. Server Configuration

MCP servers often communicate via Standard Input/Output (Stdio) when running locally. This means the AI client launches our Java application as a subprocess and “talks” to it via the console.

For this to work, our application must not print any logs to the console, as this corrupts the protocol JSON messages.

We need to configure our application.properties to use Stdio and silence the logs:

spring.application.name=my-spring-calculator

# 1. Use STDIO transport
spring.ai.mcp.server.stdio=true

# 2. CRITICAL: Disable the Banner and Web Server
# Any text printed to console will break the connection
spring.main.banner-mode=off
spring.main.web-application-type=none

# 3. Redirect logs away from Console
logging.pattern.console=

4. Exposing Functionality with @McpTool

The @McpTool annotation is the workhorse of MCP development. It marks a Java method as an executable “tool” that the AI model can call. When the application starts, Spring AI analyzes the method signature to build a tool definition.

4.1. Basic Tool Definition

Let’s create a service that exposes a simple calculator function. We use @McpTool on the method and @McpToolParam on the arguments to provide metadata:

@Service
public class CalculatorService {

    @McpTool(
        name = "calculate_sum", 
        description = "Calculates the sum of two integers. Useful for basic arithmetic."
    )
    public int add(
        @McpToolParam(description = "The first number to add", required = true) int a, 
        @McpToolParam(description = "The second number to add", required = true) int b
    ) {
        return a + b;
    }
}

The description fields are functionally important. The LLM uses them to understand when to call this tool and what the parameters represent. If the name is omitted, the method name is used by default.

4.2. Handling Complex Objects

For more sophisticated tools, we often need to pass structured objects rather than simple primitives. Spring AI supports Java Records (and POJOs), automatically serializing them to JSON schemas. Consider a customer search tool that accepts filter criteria:

public record CustomerSearchCriteria(
    String region, 
    boolean activeOnly, 
    @JsonProperty(required = false) Integer limit
) {}

@Service
public class CustomerService {

    @McpTool(description = "Search for customers using structured criteria")
    public List<String> searchCustomers(
        @McpToolParam(description = "The search filters") CustomerSearchCriteria criteria
    ) {
        // In a real app, this would query a database
        return List.of("Customer A", "Customer B");
    }
}

By using a Record, we group related parameters. The AI client receives a schema indicating that it should send a JSON object containing the region and activeOnly fields.

4.3. Accessing Request Context

Sometimes a tool needs access to the underlying MCP session, for example, to log messages back to the client or track progress. We can inject McpSyncRequestContext as an argument. This parameter is part of the internal infrastructure and is excluded from the generated tool schema visible to the AI.

@McpTool(name = "long_running_process")
public String processData(
        String dataId,
        McpSyncRequestContext context
) {
    context.info("Starting processing for ID: " + dataId);

    // Simulate work and report detailed progress
    // 50% complete (0.5 out of 1.0)
    context.progress(p -> p.progress(0.5).total(1.0).message("Processing records..."));

    return "Processed " + dataId;
}

4.4. Enabling Auto-Completion with @McpComplete

Modern AI clients like Claude support auto-completion when users type arguments for a Prompt. The @McpComplete annotation allows us to provide dynamic suggestions. For example, we can suggest programming languages for our review_code prompt:

@McpComplete(prompt = "review_code")
public List<String> completeLanguage(McpSchema.CompleteRequest.CompleteArgument argument) {
    if (!"language".equals(argument.name())) {
        return List.of();
    }

    String token = argument.value();
    return List.of("Java", "Python", "TypeScript", "Go").stream()
      .filter(lang -> lang.toLowerCase().startsWith(token.toLowerCase()))
      .toList();
}

Spring AI links this method to the review_code prompt. When the user selects that prompt and starts typing in the language field, this method filters the suggestions.

5. Exposing Data with @McpResource

While tools represent actions, resources represent data. The @McpResource annotation exposes data to the AI in a read-only form, similar to how the AI would read a file. Each resource is assigned a URI.

5.1. URI Templates

We can use URI templates to create dynamic resources. Spring AI extracts variables from the URI template and maps them to method parameters:

@Service
public class SystemLogService {

    @McpResource(
        uri = "logs://{serviceName}/{date}", 
        name = "System Logs", 
        description = "Read logs for a specific service and date"
    )
    public String readLog(
        @McpToolParam(description = "Service Name") String serviceName, 
        @McpToolParam(description = "Date YYYY-MM-DD") String date
    ) {
        return "Logs for " + serviceName + " on " + date + ": No errors found.";
    }
}

When an AI client requests logs://payment-service/2023-12-01, this method is invoked with the extracted values.

5.2. Returning Binary Data

Resources can include more than just text. To serve binary data (like images or PDFs), the method should return a ReadResourceResult. This allows us to set the MIME type explicitly:

@McpResource(uri = "diagrams://{id}", name = "System Architecture Diagram")
public ReadResourceResult getDiagram(String id) {
    String base64Image = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=";
    
    return new ReadResourceResult(List.of(
        new BlobResourceContents(
            "diagrams://" + id, 
            "image/png", 
            base64Image
        )
    ));
}

6. Standardizing Prompts with @McpPrompt

The @McpPrompt annotation allows the server to define reusable prompt templates. This is useful for sharing standardized instructions or “best practices” for interacting with the server’s data:

@Service
public class CodeReviewPrompts {

    @McpPrompt(
        name = "review_code", 
        description = "Generates a standard code review request"
    )
    public GetPromptResult generateReviewPrompt(
        @McpArg(name = "language", description = "The programming language", required = true) String language,
        @McpArg(name = "code", description = "The code snippet", required = true) String code
    ) {
        String template = """
            Please review the following %s code. 
            Focus on thread safety and performance:
            
            %s
            """;
            
        String content = String.format(template, language, code);
        
        return new GetPromptResult(
            "Code Review", 
            List.of(new PromptMessage(Role.USER, new TextContent(content)))
        );
    }
}

Here, the @McpArg annotation works similarly to @McpToolParam, defining the variables the client must provide to populate the template.

7. Connecting to Claude Desktop

The Claude Desktop App acts as an MCP Client. To connect it to our Spring Boot server, we must configure it to launch our JAR file directly.

7.1. Building the Application

Because we are using the Stdio transport, we need a runnable JAR file. We’ll build the application using Maven:

./mvnw clean package

Verify that the JAR file exists in your target/ directory (e.g., target/mcp-demo-0.0.1-SNAPSHOT.jar).

7.2. Configuring Claude Desktop

To configure the MCP connection, we need to open the claude_desktop_config.json file. We can access this file easily through the Claude UI by navigating to Settings > Developer and clicking Edit Config. Alternatively, we can locate the file directly at these paths:

  • Windows: %APPDATA%\Claude\claude_desktop_config.json
  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json

Once opened, we need to add our server configuration:

{
  "mcpServers": {
    "my-spring-calculator": {
      "command": "java",
      "args": [
        "-jar",
        "C:\Users\yourname\projects\mcp-demo\target\mcp-demo-0.0.1-SNAPSHOT.jar"
      ]
    }
  }
}

If we are on Windows, we must escape our backslashes. For example, if your real path is C:\Users\me\app.jar, you must write it as C:\\Users\\me\\app.jar inside the JSON file.

After saving the file, we must restart the Claude Desktop App completely to pick up the changes. When we jump back in, we look for the Connectors (plug icon) in the input bar, and we should see my-spring-calculator with a green active status.

8. Conclusion

In this article, we discussed the Spring AI MCP annotations that significantly lower the barrier to entry for building agentic AI systems.

By leveraging familiar concepts like @Service and @McpTool, developers can expose existing business logic to AI models with minimal friction. We explored how @McpTool converts methods into AI-callable actions, how @McpResource creates virtual file systems for AI context, and how @McpPrompt standardizes interactions. Furthermore, because these components remain POJOs, they are easily testable using standard Java practices.

Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Course – LS – NPI EA (cat=REST)

announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (tag=Refactoring)
announcement - icon

Modern Java teams move fast — but codebases don’t always keep up. Frameworks change, dependencies drift, and tech debt builds until it starts to drag on delivery. OpenRewrite was built to fix that: an open-source refactoring engine that automates repetitive code changes while keeping developer intent intact.

The monthly training series, led by the creators and maintainers of OpenRewrite at Moderne, walks through real-world migrations and modernization patterns. Whether you’re new to recipes or ready to write your own, you’ll learn practical ways to refactor safely and at scale.

If you’ve ever wished refactoring felt as natural — and as fast — as writing code, this is a good place to start.

eBook Jackson – NPI EA – 3 (cat = Jackson)