🔥 0
0
Lesson 6 of 8 30 min +250 XP

Model Context Protocol (MCP)

In lesson 5 you gave the ShopKart agent tools by wiring @Tool methods directly into the ChatClient. That works beautifully - inside your one Spring Boot app. But what if you wanted Claude Desktop to search the ShopKart catalog? Or an internal IDE assistant to check stock? Or your app to use a shipping-rate tool that another team owns? You would be writing a new custom integration every single time.

The Model Context Protocol (MCP) solves exactly this. It is an open standard - introduced by Anthropic in late 2024 and since adopted across the industry - that defines a common way for AI applications to connect to tools and data. Expose your tools once as an MCP server, and any MCP-compatible client can discover and call them. No bespoke glue.

The N-times-M problem

Without a standard, every AI client needs a custom connector to every tool source. Ten clients and ten tool sources is a hundred integrations. MCP collapses that: each client speaks MCP, each tool source speaks MCP, and they interoperate.

MCP: one protocol, many clients and servers MCP CLIENTS (hosts) ShopKart app (ChatClient) Claude Desktop IDE assistant MCP JSON-RPC 2.0 MCP SERVERS (tools) ShopKart catalog server Shipping-rate server Payments server Every client and server speaks MCP, so any client can use any server - no custom integrations.

How MCP works, briefly

MCP uses a client-server architecture over JSON-RPC 2.0. A server exposes three kinds of capability:

  • Tools - functions the client's model can call (this is what we focus on - it maps directly to your @Tool methods).
  • Resources - read-only data the model can pull in, addressed by URI.
  • Prompts - reusable prompt templates the server offers.

Transports vary by deployment. STDIO is used when the client launches the server as a local subprocess (great for desktop tools). SSE and Streamable HTTP are used when the server runs as a web service that clients connect to over the network - which is what we want for a ShopKart server other apps reach over HTTP.

Exposing ShopKart tools as an MCP server

Here is the elegant part: the @Tool methods you wrote in lesson 5 need no changes. Spring AI's MCP server starter can publish any ToolCallbackProvider as MCP tools. Add the server starter (WebMVC transport, so it serves over HTTP):

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

Configure the server identity in application.properties:

spring.ai.mcp.server.name=shopkart-catalog
spring.ai.mcp.server.version=1.0.0
spring.ai.mcp.server.type=SYNC

Then declare a ToolCallbackProvider bean that wraps your existing ShopKartTools. MethodToolCallbackProvider turns each @Tool method into a callback the MCP server publishes.

package com.shopkart.mcp;

import com.shopkart.agent.ShopKartTools;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.ai.tool.method.MethodToolCallbackProvider;
import org.springframework.context.annotation.*;

@Configuration
public class McpServerConfig {

    @Bean
    public ToolCallbackProvider shopKartToolProvider(ShopKartTools shopKartTools) {
        return MethodToolCallbackProvider.builder()
                .toolObjects(shopKartTools)
                .build();
    }
}

That is it. On startup, Spring AI publishes searchProducts, checkStock, and placeOrder as MCP tools over HTTP. Any MCP client - Claude Desktop, another team's app, an IDE - can now connect, discover those three tools, and call them. You wrote the tools once for your own agent in lesson 5, and now they are shareable infrastructure.

> Newer Spring AI versions also offer a more declarative @McpTool annotation for methods that are MCP-only. For 1.0 GA, wrapping your existing @Tool methods in a ToolCallbackProvider is the standard approach and has the nice property that the same tool object serves both your in-process agent and the MCP server.

Consuming an external MCP server

The other half of MCP is being a client. Say the shipping team runs an MCP server exposing a getDeliveryEstimate(pincode) tool. Your ShopKart agent can use it without you writing any shipping code. Add the MCP client starter:

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

Point it at the remote server in configuration. On the Spring AI 1.0 stack the client uses the SSE transport (matching the WebMVC SSE server you configured above); the connection key names the server and gives its base URL (the client appends the default /sse endpoint).

spring.ai.mcp.client.sse.connections.shipping.url=http://shipping-svc:8090

The client starter connects on startup, discovers the remote tools, and auto-configures them as a ToolCallbackProvider. Attach that provider to your ChatClient and the remote tools join your local ones in the same agent loop:

package com.shopkart.config;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.mcp.SyncMcpToolCallbackProvider;
import org.springframework.context.annotation.*;

@Configuration
public class ChatConfig {

    // This app has TWO ToolCallbackProvider beans - our own MCP-server provider
    // (shopKartToolProvider, a MethodToolCallbackProvider) and the MCP client's
    // auto-configured one. Injecting the generic ToolCallbackProvider type would
    // be ambiguous (NoUniqueBeanDefinitionException), so we inject the client's
    // concrete type, SyncMcpToolCallbackProvider, which resolves it cleanly.
    @Bean
    public ChatClient chatClient(ChatModel chatModel,
                                 com.shopkart.agent.ShopKartTools localTools,
                                 SyncMcpToolCallbackProvider mcpTools) {  // remote tools from MCP client
        return ChatClient.builder(chatModel)
                .defaultSystem(SYSTEM_PROMPT)
                .defaultTools(localTools)          // your @Tool methods
                .defaultToolCallbacks(mcpTools)    // tools from the MCP shipping server
                .build();
    }

    private static final String SYSTEM_PROMPT = "You are the ShopKart shopping assistant...";
}

Now when a customer asks "when will these earbuds reach 560001?", the agent can call the remote getDeliveryEstimate tool - a tool your codebase does not contain - exactly as if it were local. From the model's point of view, local and MCP tools are indistinguishable.

The full ShopKart MCP wiring

Putting both sides together, ShopKart is simultaneously an MCP server (publishing its catalog tools) and an MCP client (consuming the shipping team's tools).

ShopKart as both MCP client and server ShopKart Spring Boot ChatClient (the agent) MCP server MCP client Claude Desktop calls searchProducts MCP over HTTP Shipping MCP server getDeliveryEstimate MCP over HTTP Same @Tool methods serve the local agent AND external MCP clients. Remote MCP tools join the agent loop as if they were local. Write a tool once, share it everywhere - that is the MCP payoff.
On the job

Reach for MCP when a tool needs to be reused across more than one AI application, or when it is owned by another team. For a single app talking to its own database, plain in-process @Tool methods (lesson 5) are simpler - do not add a network hop you do not need. And treat an MCP server like any other public surface: authenticate callers, and be extremely careful about exposing write tools like placeOrder to clients you do not fully control. MCP standardizes access; it does not grant it.

Key takeaways

  • MCP is an open, JSON-RPC-based protocol that standardizes how AI apps connect to tools and data - expose once, consume from any MCP client.
  • MCP servers expose tools, resources, and prompts; transports include STDIO (local subprocess) and SSE / Streamable HTTP (networked).
  • Expose existing @Tool methods as an MCP server by adding spring-ai-starter-mcp-server-webmvc and declaring a ToolCallbackProvider via MethodToolCallbackProvider - no changes to the tools.
  • Consume remote tools by adding spring-ai-starter-mcp-client, configuring the server URL, and attaching the auto-configured ToolCallbackProvider to the ChatClient.
  • Use MCP for reuse across apps and teams; keep single-app tools in-process. Secure any write tools you publish.

Next up: Streaming Responses to React - stream the agent's answer token by token for a live typing effect.

🧠 Quick Quiz

Test your understanding of this lesson.

1

What problem does MCP primarily solve?

2

In Spring AI, how do you expose your existing @Tool methods through an MCP server?

AI Agents with Tool Calling