Java SpringAI

Spring AI MCP Server — Build a Model Context Protocol Server with Spring Boot

Spring AI MCP Server — Build a Model Context Protocol Server with Spring Boot

The Model Context Protocol (MCP) is an open standard by Anthropic that defines how AI models communicate with external tools, data sources, and services. Unlike direct function calling (which is tightly coupled to a specific AI application), MCP turns your Spring Boot app into a standalone tool server that any MCP-compatible AI client (Claude Desktop, VS Code Copilot, Spring AI) can connect to.

MCP vs Direct Function Calling

Direct Function Calling:
  AI App → calls your Java @Tool method directly (in-process)
  Tight coupling, can't be reused by other AI clients

MCP Server:
  AI Client (Claude Desktop) ──── MCP Protocol ────→ Your Spring Boot Server
  AI Client (VS Code Copilot) ─── MCP Protocol ────→   (exposes tools/resources/prompts)
  AI Client (Custom App)  ──────── MCP Protocol ────→
  Decoupled, reusable across any MCP-compatible client

Maven Dependencies

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-mcp-server-spring-boot-starter</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

application.properties

spring.ai.mcp.server.name=java9r-tools
spring.ai.mcp.server.version=1.0.0
spring.ai.mcp.server.type=SYNC

# SSE transport for HTTP clients (stdio for CLI tools like Claude Desktop)
# spring.ai.mcp.server.stdio=true   ← enable for Claude Desktop

Main Application

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

MCP Tools — Expose Java Methods to AI Clients

import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.mcp.server.annotation.McpTool;

@Component
public class JavaDocumentationTool {

    @Tool(description = "Search Java class documentation. Returns Javadoc summary and method list.")
    public String searchJavaDoc(String className) {
        // In production: call actual Javadoc API or database
        Map<String, String> docs = Map.of(
            "ArrayList",  "Resizable array implementation of List. Key methods: add, get, remove, size, iterator.",
            "HashMap",    "Hash table based Map implementation. Key methods: put, get, containsKey, keySet, values.",
            "CompletableFuture", "Async computation result. Key methods: supplyAsync, thenApply, thenAccept, join, exceptionally."
        );
        return docs.getOrDefault(className,
                "No documentation found for: " + className + ". Try ArrayList, HashMap, or CompletableFuture.");
    }

    @Tool(description = "Get Spring Boot auto-configuration details for a starter dependency.")
    public String getAutoConfigInfo(String starterName) {
        return switch (starterName) {
            case "spring-boot-starter-data-jpa" ->
                "Auto-configures: DataSource, EntityManagerFactory, JpaTransactionManager. " +
                "Requires: datasource URL, username, password in application.properties.";
            case "spring-boot-starter-security" ->
                "Auto-configures: SecurityFilterChain with basic auth. " +
                "Default user: 'user', password in console. Override with SecurityFilterChain @Bean.";
            default -> "Starter info not available for: " + starterName;
        };
    }
}

Register Tools as Spring Beans

import org.springframework.ai.mcp.server.McpServerFeatures;

@Configuration
public class McpToolConfig {

    // Register tool providers — Spring AI MCP auto-discovers @Tool annotated methods
    @Bean
    public List<ToolCallback> javaTools(JavaDocumentationTool javaDocTool) {
        return ToolCallbacks.from(javaDocTool);
    }
}

MCP Resources — Expose Data to AI Clients

import org.springframework.ai.mcp.server.annotation.McpResource;
import org.springframework.ai.mcp.spec.McpSchema;

@Component
public class JavaCheatSheetResources {

    @Bean
    public List<McpServerFeatures.SyncResourceRegistration> javaResources() {
        var cheatSheet = new McpServerFeatures.SyncResourceRegistration(
                new McpSchema.Resource(
                        "java://cheatsheet/collections",
                        "Java Collections Cheat Sheet",
                        "Complete guide to Java collection types with use cases",
                        "text/plain",
                        null
                ),
                req -> new McpSchema.ReadResourceResult(List.of(
                        new McpSchema.TextResourceContents(
                                req.uri(),
                                "text/plain",
                                getCollectionsCheatSheet()
                        )
                ))
        );

        return List.of(cheatSheet);
    }

    private String getCollectionsCheatSheet() {
        return """
               Java Collections Quick Reference
               =================================
               ArrayList   → Fast random access, O(1). Use when order matters.
               LinkedList  → Fast insert/delete at ends, O(1). Use as Queue/Deque.
               HashSet     → No duplicates, O(1) lookup. Use for membership testing.
               TreeSet     → Sorted, no duplicates, O(log n). Use when sorted order needed.
               HashMap     → Key-value, O(1) avg. Most common Map.
               TreeMap     → Sorted keys, O(log n). Use when key order matters.
               PriorityQueue → Min-heap by default. Use for scheduling/top-K.
               """;
    }
}

MCP Prompts — Pre-defined Prompt Templates for AI Clients

@Bean
public List<McpServerFeatures.SyncPromptRegistration> javaPrompts() {
    var codeReviewPrompt = new McpServerFeatures.SyncPromptRegistration(
            new McpSchema.Prompt(
                    "java-code-review",
                    "Performs a thorough Java code review",
                    List.of(
                            new McpSchema.PromptArgument("code",       "Java code to review", true),
                            new McpSchema.PromptArgument("focus_area", "security|performance|style", false)
                    )
            ),
            req -> {
                String code      = req.arguments().get("code");
                String focus     = req.arguments().getOrDefault("focus_area", "general");
                return new McpSchema.GetPromptResult(
                        "Java code review prompt",
                        List.of(new McpSchema.PromptMessage(
                                McpSchema.Role.USER,
                                new McpSchema.TextContent("Review this Java code for %s issues:\n\n```java\n%s\n```"
                                        .formatted(focus, code))
                        ))
                );
            }
    );

    return List.of(codeReviewPrompt);
}

Testing the MCP Server

# The server exposes SSE endpoint at:
GET http://localhost:8080/sse

# List available tools:
POST http://localhost:8080/mcp
{
  "jsonrpc": "2.0",
  "method": "tools/list",
  "id": 1
}

# Response:
{
  "result": {
    "tools": [
      {
        "name": "searchJavaDoc",
        "description": "Search Java class documentation...",
        "inputSchema": { "type": "object", "properties": { "className": {"type":"string"} } }
      },
      {
        "name": "getAutoConfigInfo",
        "description": "Get Spring Boot auto-configuration details..."
      }
    ]
  }
}

Connect from Claude Desktop

# Add to claude_desktop_config.json:
{
  "mcpServers": {
    "java9r-tools": {
      "command": "java",
      "args": ["-jar", "/path/to/mcp-server.jar"],
      "env": {}
    }
  }
}

Key Points

  • MCP server exposes tools, resources, and prompts — tools are callable, resources are readable data, prompts are templates
  • Set spring.ai.mcp.server.stdio=true for CLI clients like Claude Desktop; use default HTTP/SSE for web-based clients
  • Any Spring bean method annotated with @Tool and registered via ToolCallbacks.from() becomes an MCP tool
  • MCP is provider-agnostic — the same server works with Claude, GPT-4, and any other MCP-compatible client
  • Resources are better than tools for static reference data — they don't consume LLM thinking time for retrieval
Topics: Java SpringAI
← Newer Post Older Post →