cd /news/ai-agents/model-context-protocol-with-spring-a… Β· home β€Ί topics β€Ί ai-agents β€Ί article
[ARTICLE Β· art-134409] src=dev.to β†— pub= topic=ai-agents verified=true sentiment=↑ positive

Model Context Protocol with Spring AI, Building MCP Clients and Servers in Java

A developer demonstrated how Java developers can build Model Context Protocol (MCP) clients and servers using Spring AI, which provides Boot starters and APIs for both sides of the architecture. The writeup explains how MCP standardizes AI application communication with external tools, resources, and prompts, replacing bespoke per-service integrations with a common protocol layer. The author frames MCP as a protocol rather than a model, positioning it between the LLM and external systems.

by read15 min views3 publishedSep 19, 2026

In the previous article, we explored how to build AI agents with Spring AI using:

LLMs
 ↓
RAG
 ↓
Tool Calling
 ↓
Memory
 ↓
Agent Workflows

Tool calling gives an AI application the ability to interact with external capabilities.

But another problem appears as AI systems become larger.

Imagine you have:

Customer Service Agent
        ↓
Order APIs
Payment APIs
CRM APIs
Knowledge Base
Email Service

And another application has:

Sales Agent
        ↓
CRM
Calendar
Email
Customer Database

And another has:

Developer Agent
        ↓
Git Repository
Issue Tracker
CI/CD
Documentation

If every AI application implements every integration differently, the architecture quickly becomes difficult to maintain.

This is where Model Context Protocol (MCP) becomes interesting.

MCP provides a standardized way for AI applications to interact with external tools and resources. Spring AI provides support for both building MCP servers and consuming MCP servers from Spring Boot applications.

In this article, we'll build a mental model for MCP and explore how Java developers can use it with Spring AI.

MCP stands for:

Model Context Protocol

At a high level, MCP standardizes how an AI application communicates with external capabilities such as:

Tools
Resources
Prompts

Instead of every AI application inventing its own integration mechanism:

AI Application
 ↓
Custom Tool Integration
 ↓
CRM

we can have:

AI Application
 ↓
MCP Client
 ↓
MCP Protocol
 ↓
MCP Server
 ↓
CRM

The MCP server exposes capabilities through a standardized interface.

The AI application doesn't need to understand every internal implementation detail of the external system.

Suppose you build an AI assistant that needs access to:

GitHub
Slack
PostgreSQL
Google Calendar
Internal APIs
File Systems

Without a standard protocol, your application might contain:

GitHub Integration
Slack Integration
PostgreSQL Integration
Calendar Integration
Internal API Integration

Each integration may have its own:

Authentication
Tool Schema
Request Format
Response Format
Connection Management
Error Handling

Now imagine another AI application needs the same capabilities.

You may end up rebuilding many of the same integrations.

MCP addresses this by creating a common protocol for AI applications and external servers.

Conceptually:

                    AI Application
                         β”‚
                    MCP Client
                         β”‚
                MCP Protocol
                         β”‚
       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
       ↓                 ↓                 ↓
  MCP Server         MCP Server         MCP Server
       ↓                 ↓                 ↓
     CRM              GitHub            Database

This is one of the main ideas behind MCP.

This distinction is important.

MCP is not:

An AI model

It is a protocol for connecting AI applications with capabilities.

Think of the stack like this:

LLM
 ↓
AI Application
 ↓
MCP Client
 ↓
MCP Protocol
 ↓
MCP Server
 ↓
Tools / Resources
 ↓
External System

The LLM performs reasoning.

The MCP layer provides standardized communication.

The external system performs the actual operation.

MCP introduces two important roles.

The MCP client lives inside the AI application.

Its responsibility is to connect to MCP servers and interact with the capabilities they expose.

For example:

Spring Boot AI Application
        ↓
MCP Client
        ↓
Weather MCP Server

The client can discover and use the server's available capabilities.

The MCP server exposes capabilities.

Weather MCP Server

Tools:
getWeather()
getForecast()

Resources:
weather://cities

Prompts:
weather-analysis

The server is responsible for implementing those capabilities.

Spring AI provides Boot starters and APIs for both sides of this architecture.

A simplified architecture looks like:

                    User
                     ↓
                 Spring Boot
                     ↓
                  ChatClient
                     ↓
                  MCP Client
                     ↓
                MCP Protocol
                     ↓
                MCP Server
                     ↓
                   Tool
                     ↓
                External API
User:
What's the weather in Paris?

The AI application can discover a weather tool exposed by an MCP server.

The flow becomes:

User
 ↓
LLM
 ↓
MCP Tool
 ↓
Weather MCP Server
 ↓
Weather API
 ↓
Tool Result
 ↓
LLM
 ↓
Final Answer

At this point, you might ask:

"Isn't this just tool calling?"

There is an important distinction.

Traditional Spring AI tool calling can expose application methods directly:

@Tool
public String getWeather(String city) {
    return weatherService.getWeather(city);
}

Your application owns the tool.

With MCP:

AI Application
      ↓
MCP Client
      ↓
Remote MCP Server
      ↓
Tool

The tool can live outside the application.

This creates a cleaner separation between:

AI Application

and:

Capability Provider

Spring AI integrates MCP tools into its tool-calling architecture, allowing applications to consume tools exposed by MCP servers.

One of the most important MCP capabilities is the tool.

A tool represents an action that an AI application can invoke.

getWeather()
createTicket()
searchCustomers()
getOrder()
sendEmail()

A weather server might expose:

getTemperature(city)

A CRM server might expose:

findCustomer(email)
createLead(customer)
updateLead(leadId)

A developer server might expose:

searchRepository(query)
getBuildStatus()
createIssue(title)

The MCP client can discover these tools and make them available to the AI application.

MCP is not limited to actions.

It can also expose resources.

A resource represents information that an MCP client can access.

customer://123
order://ORD-10291
file://README.md
database://schema

Think of the distinction as:

Do something

Access something
Tool:
createTicket()

Resource:
customer://123

A server can expose both.

MCP also supports prompts.

A server can provide reusable prompt templates for specific tasks.

Prompt:
analyze-customer

Input:
customerId

Or:

Prompt:
summarize-order

Input:
orderId

This allows prompt templates to become part of the server-provided capabilities rather than being hardcoded independently in every client.

Spring AI's MCP support includes annotations for tools, resources, and prompts.

Let's build a simple MCP server.

Imagine a weather service.

Our application already has:

@Service
public class WeatherService {

    public String getTemperature(String city) {
        return "22Β°C";
    }
}

We can expose this capability through an MCP tool.

With Spring AI's annotation-based MCP support:

@Service
public class WeatherTools {

    @McpTool(description = "Get the current temperature for a city")
    public String getTemperature(
            @McpToolParam(
                description = "City name",
                required = true
            )
            String city) {

        return weatherService.getTemperature(city);
    }
}

The MCP annotation model allows Spring services to expose capabilities as MCP operations.

For a Spring Boot application, Spring AI provides MCP server starters.

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

You can configure the server to use Streamable HTTP:

spring.ai.mcp.server.protocol=STREAMABLE

Spring AI 2.x supports MCP server transports including Streamable HTTP, stateless Streamable HTTP, SSE, and STDIO. Streamable HTTP is the current recommended HTTP transport in Spring AI 2.x, while SSE is deprecated for this use case.

Spring Boot
     ↓
MCP Server
     ↓
Tool Registry
     ↓
@McpTool
     ↓
WeatherService
     ↓
Weather API

The server exposes the tool through the MCP protocol.

The client doesn't need to know how the weather service works internally.

It only needs to understand:

Tool Name
Description
Input Schema

Now let's create the other side.

Suppose our AI application needs to consume the weather MCP server.

Add the MCP client starter:

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-mcp-client</artifactId>
</dependency>

Then configure the MCP server connection.

For example, using Streamable HTTP:

spring:
  ai:
    mcp:
      client:
        streamable-http:
          connections:
            weather-server:
              url: http://localhost:8080

Spring AI can connect to the configured MCP server and discover its tools.

Once the MCP client discovers the server's tools, those tools can be integrated into Spring AI's tool-calling architecture.

@Bean
CommandLineRunner demo(
        ChatClient chatClient,
        ToolCallbackProvider mcpTools) {

    return args -> {

        String response = chatClient
                .prompt("What's the weather in Paris?")
                .tools(mcpTools)
                .call()
                .content();

        System.out.println(response);
    };
}

This is a powerful abstraction.

The application doesn't need to manually implement every weather function.

The MCP server provides the capability.

The MCP client discovers it.

Spring AI makes the discovered tools available to the model.

User
 ↓
ChatClient
 ↓
LLM
 ↓
MCP Tool
 ↓
MCP Client
 ↓
MCP Server
 ↓
Weather API
 ↓
Tool Result
 ↓
LLM
 ↓
Answer

Spring AI's current MCP documentation demonstrates this client pattern using ToolCallbackProvider.

One of the interesting capabilities of MCP is tool discovery.

Instead of hardcoding:

Tool A
Tool B
Tool C

the client can connect to an MCP server and discover what capabilities it provides.

MCP Server
 ↓
tools/list
 ↓
getWeather()
getForecast()
searchAlerts()

The AI application can then make these tools available to the model.

This creates a more modular architecture.

Now imagine our AI assistant needs multiple capabilities.

We could have:

AI Application
      β”‚
      β”œβ”€β”€ MCP Client
      β”‚
      β”œβ”€β”€ Weather Server
      β”‚
      β”œβ”€β”€ CRM Server
      β”‚
      β”œβ”€β”€ GitHub Server
      β”‚
      └── Internal API Server

The architecture becomes:

                         AI Agent
                            β”‚
                        MCP Client
                            β”‚
             β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
             ↓              ↓              ↓
        Weather MCP      CRM MCP       GitHub MCP
             ↓              ↓              ↓
        Weather API       CRM API      GitHub API

The AI application can consume tools from multiple MCP servers.

This is one reason MCP becomes useful as an AI system grows.

Now connect this to the previous article.

We previously had:

Agent
 ↓
Tools
 ↓
APIs

With MCP, we can move the tools outside the application boundary:

Agent
 ↓
MCP Client
 ↓
MCP Servers
 β”œβ”€β”€ CRM
 β”œβ”€β”€ Payments
 β”œβ”€β”€ Search
 └── Internal APIs

The resulting architecture becomes:

                         User
                           ↓
                       Spring Boot
                           ↓
                        ChatClient
                           ↓
                         Agent
                           ↓
                       MCP Client
                           ↓
             β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
             ↓             ↓             ↓
          CRM MCP      Payment MCP    Search MCP
             ↓             ↓             ↓
           CRM API     Payment API   Search API

This creates a modular tool ecosystem.

Let's compare the two approaches.

ChatClient
    ↓
@Tool
    ↓
Service
    ↓
Database

Everything lives inside the application.

ChatClient
    ↓
MCP Client
    ↓
MCP Server
    ↓
Service
    ↓
Database

The capability provider can be separated from the AI application.

This can be useful when:

One useful architectural pattern is:

Business System
       ↓
MCP Server
       ↓
AI Applications
CRM
 ↓
CRM MCP Server
 ↓
 β”œβ”€β”€ Sales Agent
 β”œβ”€β”€ Support Agent
 └── Internal Assistant

Instead of implementing CRM integration separately in every AI application, the MCP server becomes the standardized capability layer.

MCP doesn't replace RAG.

They solve different problems.

RAG:

Retrieve relevant knowledge

MCP:

Connect AI applications to external capabilities

You can combine them:

                       Agent
                         ↓
             β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
             ↓           ↓           ↓
            RAG        MCP Tools    Memory
             ↓           ↓           ↓
        Vector DB    External APIs  Database
User:
Can I refund order ORD-10291?

The agent could:

1. MCP β†’ Get order information
2. RAG β†’ Retrieve refund policy
3. Agent β†’ Compare the two
4. Return answer

This gives the model both:

Live Data
+
Business Knowledge

Memory can also coexist with MCP.

User:
Use my preferred delivery address.

Agent:
Which address?

User:
The one I used last time.

The application may use:

Memory
 ↓
Previous Address

while MCP provides:

Order Service
 ↓
Update Delivery Address

The complete flow becomes:

Agent
 β”œβ”€β”€ Memory
 β”œβ”€β”€ RAG
 └── MCP
       β”œβ”€β”€ Orders
       β”œβ”€β”€ Payments
       └── CRM

This is becoming a much more complete agent architecture.

MCP supports multiple ways for clients and servers to communicate.

Common options include:

STDIO
SSE
Streamable HTTP
Stateless Streamable HTTP

For local process-based integrations:

AI Application
 ↓
STDIO
 ↓
MCP Server Process

For network-based applications:

AI Application
 ↓
HTTP
 ↓
MCP Server

In Spring AI 2.x, Streamable HTTP is the current HTTP-oriented approach, while SSE has been deprecated in favor of Streamable HTTP.

A simple way to think about it:

Application
 ↓
Local MCP Process

Useful for local integrations and process-based communication.

Application
 ↓
Network
 ↓
MCP Server

Useful when the MCP server runs as an independent service.

Client
 ↓
Request
 ↓
Server
 ↓
Response

This can be useful for stateless, cloud-native service architectures.

The right transport depends on deployment and communication requirements.

This is extremely important.

An MCP server may expose powerful capabilities:

readCustomer()
createInvoice()
refundPayment()
deleteUser()

Simply exposing those tools does not make them safe.

Spring AI's MCP server starters do not automatically provide authentication or authorization for network-accessible MCP endpoints. The documentation specifically warns that HTTP-based MCP endpoints need a security boundary before being exposed beyond localhost.

A production architecture should look like:

Client
 ↓
Authentication
 ↓
Authorization
 ↓
MCP Server
 ↓
Tool
 ↓
Business Logic

Not:

Internet
 ↓
MCP Server
 ↓
Dangerous Tool

Imagine an MCP server exposes:

getCustomer()
updateCustomer()
deleteCustomer()

Different users should have different capabilities.

READ
 ↓
getCustomer()

WRITE
 ↓
updateCustomer()

DESTRUCTIVE
 ↓
deleteCustomer()

Your security layer should determine whether the caller is allowed to invoke each capability.

The model should never be considered the authorization layer.

The application must enforce it.

MCP becomes particularly interesting in SaaS environments.

Suppose:

Tenant A
 ↓
CRM MCP Server
Tenant B
 ↓
CRM MCP Server

The MCP layer must preserve tenant context.

A request might carry:

tenantId
userId
roles
permissions

The server can then enforce:

Authentication
 ↓
Tenant Resolution
 ↓
Authorization
 ↓
Tool Execution
 ↓
Tenant-Scoped Data

This is especially important for tools such as:

searchCustomers()
getInvoices()
searchDocuments()
createTicket()

A model must never be able to use a tool to cross tenant boundaries.

External tools can fail.

Agent
 ↓
MCP Tool
 ↓
CRM API
 ↓
Timeout

Your application needs controlled failure behavior.

Tool Failure
 ↓
Capture Error
 ↓
Return Structured Result
 ↓
Agent
 ↓
Retry / Alternative Tool / Final Response

The agent might decide:

CRM unavailable.

Try cached customer information.
Unable to retrieve the customer's order.
Please try again later.

The important part is that failures should be observable and controlled.

When MCP is added to an agent architecture, your observability requirements increase.

You may need to track:

MCP Server
MCP Client
Tool Name
Tool Arguments
Request ID
Latency
Status
Errors
Retries
Model Calls
Token Usage

A useful trace could look like:

User Request
    ↓
LLM Call
    ↓
MCP Tool Discovery
    ↓
Tool Call
    ↓
CRM API
    ↓
Tool Result
    ↓
LLM Call
    ↓
Final Response

Without tracing, debugging multi-server agent systems can become difficult.

This is another important principle.

Suppose you have:

public RefundResult refundPayment(
        String orderId,
        BigDecimal amount) {
    ...
}

You shouldn't move all business logic into an MCP handler.

Instead:

MCP Tool
 ↓
Application Service
 ↓
Business Rules
 ↓
Repository
 ↓
Database
@McpTool(description = "Refund an eligible order")
public RefundResult refundOrder(String orderId) {

    return refundService.refund(orderId);
}

The MCP layer becomes an interface.

Your existing business service remains responsible for the actual business rules.

This keeps the architecture clean.

One of the strongest ways to think about MCP is as an integration boundary.

Instead of:

AI
 ↓
Everything

use:

AI
 ↓
MCP
 ↓
Controlled Capabilities

The MCP layer becomes a contract between AI applications and external systems.

AI Application
      ↓
MCP
      ↓
CRM

or:

AI Application
      ↓
MCP
      ↓
Payment System
AI Application
      ↓
MCP
      ↓
Internal Developer Platform

Now combine everything from this series:

                              User
                                ↓
                         Spring Boot API
                                ↓
                           ChatClient
                                ↓
                              Agent
                                ↓
             β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
             ↓                  ↓                  ↓
           Memory              RAG              MCP Client
             ↓                  ↓                  ↓
         PostgreSQL          pgvector        β”Œβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”
                                             ↓     ↓     ↓
                                           CRM  GitHub  Search
                                           MCP    MCP     MCP
                                             ↓     ↓     ↓
                                           APIs  APIs   APIs

Around the system:

Authentication
Authorization
Tenant Isolation
Observability
Audit Logging
Rate Limiting
Guardrails
Human Approval

This is a strong foundation for production-oriented AI applications.

MCP becomes particularly useful when you have:

Multiple AI applications
        ↓
Shared tools
        ↓
Shared integrations
Sales Agent
Support Agent
Developer Agent
Internal Assistant

all need access to:

CRM
GitHub
Internal APIs
Documentation

Instead of implementing each integration separately:

Agent A β†’ CRM Integration
Agent B β†’ CRM Integration
Agent C β†’ CRM Integration

you can create:

CRM MCP Server

and allow multiple AI applications to consume it.

MCP isn't automatically required for every AI application.

If your application has:

One Agent
 ↓
One Tool
 ↓
One Internal Service

direct Spring AI tool calling may be simpler.

ChatClient
 ↓
@Tool
 ↓
OrderService

Introducing an MCP server could add unnecessary infrastructure.

A useful rule is:

Use MCP when standardization, reuse, separation, or interoperability provides real value.

Don't introduce another protocol simply because it is popular.

A simple comparison:

Approach Best suited for
Spring AI @Tool Local application capabilities
MCP Shared/external capabilities
RAG Knowledge retrieval
Memory Conversation context
Agent Dynamic decision-making

They are not mutually exclusive.

A production system may use all of them:

Agent
 β”œβ”€β”€ Local Spring AI Tools
 β”œβ”€β”€ MCP Tools
 β”œβ”€β”€ RAG
 └── Memory

Our AI architecture has evolved throughout this series.

We started with:

LLM
 ↓
Response

Then:

LLM
 ↓
RAG
 ↓
Knowledge
LLM
 ↓
Tools
 ↓
Actions
LLM
 ↓
Tools
 ↓
Memory
 ↓
Agent

And now:

Agent
 ↓
MCP
 ↓
External Capabilities

The architecture is becoming increasingly modular.

Remember it this way:

Reason

Retrieve Knowledge

Remember Context

Invoke Capabilities

Standardize Capability Access

Business Application

Coordinate Decisions

Together:

LLM
+
RAG
+
Memory
+
Tools
+
MCP
+
Production AI Application

MCP gives AI applications a standardized way to interact with external tools and resources.

The key ideas are:

The architecture can now look like:

                         User
                           ↓
                        Agent
                           ↓
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
        ↓                  ↓                  ↓
      Memory              RAG             MCP Client
        ↓                  ↓                  ↓
    Conversation       Vector DB       MCP Servers
                                             ↓
                              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                              ↓              ↓              ↓
                             CRM          GitHub         Internal APIs

The important shift is this:

Before:

AI Application
 ↓
Custom Integrations
 ↓
External Systems
AI Application
 ↓
MCP Client
 ↓
Standardized Protocol
 ↓
MCP Servers
 ↓
External Capabilities

MCP doesn't make your AI application automatically intelligent.

It gives your AI application a standardized way to connect to capabilities.

And when you combine MCP with Spring AI's:

ChatClient
+
Tool Calling
+
RAG
+
Memory
+
Agents

you get a powerful foundation for building modular AI applications in Java.

We've now connected our AI agent to external capabilities.

But another challenge appears:

One Agent
      ↓
Multiple MCP Servers
      ↓
Multiple Tools
      ↓
Multiple Decisions

How do we control which tools an agent can access?

How do we handle permissions?

How do we observe agent behavior?

How do we evaluate whether an agent is making the right decisions?

And how do we build reliable AI workflows instead of simply hoping the model does the right thing?

That takes us into the next stage of AI engineering:

Building Production-Ready AI Agents with Spring AI β€” Guardrails, Evaluation, Observability, and Human-in-the-Loop Workflows.

── more in #ai-agents 4 stories Β· sorted by recency
── more on @model context protocol 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain β€” perfect for shipping the agent you just read about.

$git push zahid main
β†’ Live at https://your-agent.zahid.host βœ“
Get free account β†’ Pricing
from €0/mo Β· no card required
LIVE [news/model-context-protoc…] indexed:0 read:15min 2026-09-19 Β· β€”