Enterprise Java

Spring AI MCP Servers OAuth2 Example

The Model Context Protocol (MCP) allows AI models to securely access external data and tools. Let us delve into understanding how to secure Spring AI MCP Servers with OAuth2.

1. What is Spring AI?

Spring AI is an extension of the popular Spring Boot framework that allows developers to integrate large language models (LLMs) and AI capabilities directly into their applications. It simplifies building intelligent features such as chatbots, recommendation engines, and natural language understanding within Spring-based systems.

1.1 What is OAuth2?

OAuth2 is an open-standard authorization framework that allows applications to securely access resources on behalf of a user. In the context of Spring AI MCP servers, OAuth2 ensures that only authorized clients can interact with AI services, protecting sensitive data and AI endpoints.

1.2 What is MCP?

MCP is an open protocol that standardizes how applications connect LLMs to data and tools, like how USB-C connects devices to peripherals. It enables building agents and complex workflows by linking models with the world.

  • Pre-built integrations your LLM can use directly
  • A standard approach to build custom integrations
  • An open protocol anyone can implement
  • Flexibility to switch between apps while keeping your context

Learn more about MCP here.

1.3 Spring Security in MCP

Spring Security is a powerful framework for securing Spring applications. In the context of MCP servers, it ensures that only authorized clients can access AI model endpoints, protecting sensitive data and services. Key features of Spring Security for MCP servers:

  • Authentication: Verify the identity of clients using OAuth2 tokens.
  • Authorization: Control access to resources based on roles or scopes.
  • JWT Support: Integrate JSON Web Tokens for stateless, secure API calls.
  • Integration with Spring Boot: Easily configure security rules using annotations or a SecurityFilterChain.

Using Spring Security, developers can:

  • Secure REST endpoints of the MCP server with minimal configuration.
  • Integrate OAuth2 flows like client_credentials for server-to-server communication.
  • Combine with Spring Boot features such as CORS, CSRF, and session management for robust security.

Overall, Spring Security provides the backbone for safely exposing AI model endpoints, ensuring that only authenticated and authorized clients can interact with the MCP server.

2. Creating MCP Server

2.1 Add Dependencies (pom.xml)

Add these dependencies to your pom.xml:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-authorization-server</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-mcp-server-webmvc-spring-boot-starter</artifactId>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
</dependency>

2.2 Creating a Controller acting as MCP Server

Define a controller that provides realistic stock data in MCP format. In production, you could fetch real stock data from APIs like Alpha Vantage or Yahoo Finance.

@RestController
@RequestMapping("/stocks")
public class StocksController {

    private final Map<String, Double> stockPrices = Map.of(
        "AAPL", 172.45,
        "GOOG", 1350.60,
        "MSFT", 289.30,
        "TSLA", 730.25
    );

    @GetMapping("/{symbol}")
    public Map<String, Object> getStockInfo(@PathVariable String symbol) {
        Double price = stockPrices.get(symbol.toUpperCase());
        if (price == null) {
            throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Stock not found");
        }
        Map<String, Object> stockData = new HashMap<>();
        stockData.put("symbol", symbol.toUpperCase());
        stockData.put("price", price);
        stockData.put("currency", "USD");
        stockData.put("companyName", getCompanyName(symbol.toUpperCase()));
        stockData.put("timestamp", LocalDateTime.now().toString());
        return stockData;
    }

    private String getCompanyName(String symbol) {
        return switch(symbol) {
            case "AAPL" -> "Apple Inc.";
            case "GOOG" -> "Alphabet Inc.";
            case "MSFT" -> "Microsoft Corporation";
            case "TSLA" -> "Tesla, Inc.";
            default -> "Unknown Company";
        };
    }
}

2.2.1 Code Explanation

This Spring Boot controller, annotated with @RestController and @RequestMapping("/stocks"), provides a simple API to fetch stock information. It stores stock symbols and their prices in an immutable Map called stockPrices. The @GetMapping("/{symbol}") method takes a stock symbol as a path variable, looks up the price, and if not found, throws a ResponseStatusException with a 404 status. If the stock exists, it creates a Map containing the symbol, price, currency (“USD”), company name (determined by the private getCompanyName method using a switch expression), and the current timestamp. The resulting map is returned as JSON when the API endpoint is called.

2.3 Adding the Security Configuration

Enable OAuth2 security for your MCP server:

@Configuration
public class SecurityConfiguration {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .cors().and()
            .authorizeRequests()
                .antMatchers("/stocks/**").authenticated()
            .and()
            .oauth2ResourceServer().jwt();
        return http.build();
    }
}

2.3.1 Code Explanation

This Spring configuration class, annotated with @Configuration, sets up security for the application using Spring Security. It defines a SecurityFilterChain bean that customizes HTTP security. CSRF protection is disabled with csrf().disable() and CORS support is enabled using cors(). The configuration requires that any request to endpoints under /stocks/** must be authenticated. Finally, it configures the application as an OAuth2 resource server using JWT tokens (oauth2ResourceServer().jwt()), ensuring that only requests with valid JWTs can access the secured stock endpoints.

2.4 Configure OAuth2 client in application.properties

To enable your MCP server to authenticate and authorize clients using OAuth2, you need to configure a client in application.properties. This configuration registers a client with the authorization server, specifying the client ID, secret, authentication method, and allowed grant types.

spring.security.oauth2.authorizationserver.client.oidc-client.registration.client-id=stocks-client
spring.security.oauth2.authorizationserver.client.oidc-client.registration.client-secret={noop}supersecret
spring.security.oauth2.authorizationserver.client.oidc-client.registration.client-authentication-methods=client_secret_basic
spring.security.oauth2.authorizationserver.client.oidc-client.registration.authorization-grant-types=client_credentials

2.4.1 Code Explanation

  • client-id: The unique identifier for the client application (e.g., “stocks-client”).
  • client-secret: The secret key used to authenticate the client. {noop} indicates no encoding is applied.
  • client-authentication-methods: Specifies how the client authenticates with the authorization server. client_secret_basic uses HTTP Basic authentication.
  • authorization-grant-types: Defines which OAuth2 flows the client can use. client_credentials is suitable for server-to-server communication without user context.

With this configuration, your MCP server can request JWT tokens from the authorization server and include them in requests to secured endpoints. This setup ensures that only authorized clients can access your stock data API. For this tutorial, we will use Keycloak as the authorization server to register the client. The focus is on the MCP server, so Keycloak setup is not covered here.

Note: Before configuring the OAuth2 client, you need to register your MCP server as a client in Keycloak. Create a new client, set the client ID (e.g., stocks-client), configure the client secret, and enable the client_credentials grant type. This allows your MCP server to obtain access tokens to secure its endpoints.

2.5 Code Run

After adding the dependencies, creating the controller, and configuring security, you can run your MCP server as a standard Spring Boot application. Use your IDE or execute mvn spring-boot:run from the command line in the project directory. Once the application starts, it will listen on the default port 8080.

curl -X GET "http://localhost:8080/stocks/AAPL" \
     -H "Authorization: Bearer <your-token>" \
     -H "Accept: application/json"

2.6 Test the Secured MCP Server

Obtain an access token using the client_credentials grant:

curl -X POST https://auth-server.example.com/oauth2/token \
     -d "grant_type=client_credentials" \
     -d "client_id=stocks-client" \
     -d "client_secret=supersecret"

Use the token to query stock information. Please note localhost:8080 will act as the mcp.example.com.

curl -X GET "http://mcp.example.com/stocks/AAPL" \
     -H "Authorization: Bearer <your-token>" \
     -H "Accept: application/json"

The server will return a JSON response like:

{
  "symbol": "AAPL",
  "price": 172.45,
  "currency": "USD",
  "companyName": "Apple Inc.",
  "timestamp": "2025-08-18T21:30:45"
}

Unauthorized requests will be rejected with a 401 error. This setup ensures that only authenticated clients can access stock data, making the MCP server production-ready and secure.

3. Conclusion

We created a Stocks Info MCP Server with Spring AI and secured it using OAuth2. The server returns stock data only to authorized clients, ensuring secure access while keeping the setup simple and easy to use.

Yatin Batra

An experience full-stack engineer well versed with Core Java, Spring/Springboot, MVC, Security, AOP, Frontend (Angular & React), and cloud technologies (such as AWS, GCP, Jenkins, Docker, K8).
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Back to top button