[KongchangAI]
· 3 min read· 1,602 words

Spring AI + MCP in Practice: Building Production-Grade AI Agents with Java

Spring AI + MCP in Practice: Building Production-Grade AI Agents with Java

Build production-grade AI Agents in Java that connect to real enterprise data using Spring AI and MCP.

This article systematically covers how to build a production-grade AI Agent in the Java ecosystem using Spring AI and MCP (Model Context Protocol). It clarifies the key distinction between AI Agents and LLMs, explains MCP's role as a standardized intermediary for connecting to databases, REST APIs, and Kafka, breaks down the Controller/Service/Tool layered architecture with ChatClient and ToolContext, and addresses critical deployment security concerns including environment-specific config, secret management, Dockerization, and least-privilege access control. The stack requires Java 21, Maven 3.9, and a valid OpenAI API Key.

Building AI Agents capable of autonomous work within the Java ecosystem is becoming an essential skill for backend and full-stack developers. This article — based on a YouTube technical tutorial — walks through how to use Spring AI + MCP (Model Context Protocol) to build a production-ready AI Agent, covering core concepts, architecture design, key code patterns, and deployment security best practices.

What Exactly Is an AI Agent?

Many people confuse AI Agents with LLMs (Large Language Models), but their responsibilities are fundamentally different. An LLM's job is to generate answers, while an AI Agent uses an LLM to make decisions and execute actions — it understands goals, determines what steps to take, observes results, and keeps working until the objective is complete.

In other words, an Agent is more like a "digital colleague." You hand it a task, and it drives it forward autonomously. A recurring example from the tutorial: when you ask "Why did order 12345 fail?", a regular chatbot can only answer based on the LLM's existing knowledge — and the LLM has no awareness of that order's actual state in your internal system. It will either give an irrelevant answer or pull something unrelated from the internet.

Order query scenario: if order data only lives internally, the Agent cannot provide an accurate answer without external access

For an Agent to give an accurate answer, it must be able to connect to external systems — databases, logs, business APIs — retrieve real data, and then analyze it. This is exactly where MCP comes into play.

MCP vs. Traditional REST APIs

The tutorial offers a clear contrast: REST APIs solve application-to-application communication, while MCP is a standardized protocol specifically designed to let AI applications discover and use tools and context, which in turn connect to external databases or APIs.

The MCP architecture has several key roles:

  • MCP Client: The side that initiates requests
  • Tool / Resource / Template: Capability units the Agent can invoke
  • MCP Server (intermediary): The central hub, responsible for translating the LLM's decisions into actual calls to external systems

The AI model itself never directly communicates with databases, logs, or APIs — there must always be an intermediary, the MCP Server.

After the LLM generates a decision, MCP handles the actual calls to external systems

The full flow looks like this: User asks "Why did order 12345 fail?" → LLM determines it can't answer on its own → Hands off to the MCP protocol → MCP Server queries the database, scans logs, calls API endpoints → Aggregates results → Returns a well-reasoned explanation of the failure. The entire process is transparent to the user, but under the hood it's Spring AI and MCP working in concert.

MCP (Model Context Protocol) was proposed and open-sourced by Anthropic in late 2024, with the goal of providing AI applications with a unified "tool invocation" specification — similar to how USB standardizes hardware peripherals. Regardless of whether the underlying system is a database, file system, or third-party API, AI models interact with these capabilities through the same protocol. Before MCP, every AI application had to implement its own integration logic for external systems, with different formats, authentication schemes, and error handling that couldn't be reused. MCP abstracts these capabilities into three standard object types: Tool (executable functions/actions), Resource (readable data sources), and Prompt Template (predefined prompt templates), and defines a JSON-RPC-based communication format between Client and Server. This means the same MCP Server can be reused by different AI applications, and a single AI application can mount multiple MCP Servers to expand its capability boundaries. Spring AI has built-in MCP Client support since version 1.0 — developers simply add the corresponding dependency and configure the endpoint to enable a Spring Boot application to communicate with any spec-compliant MCP Server.

Production-Grade Architecture Design

Moving from a single-machine demo to production requires a more complete architecture. The typical topology described in the tutorial is:

User → Spring Boot AI Agent → Spring AI + LLM → MCP Server → MCP Tool → External Systems

MCP Tools (essentially annotated Java methods) can connect to different targets based on configuration:

  • Connect to a database and execute queries
  • Call external REST APIs (with security features)
  • Interface with a Kafka Server to analyze streaming data and generate reports

Which systems to connect to is entirely determined by your MCP configuration. This "configuration-driven" design allows the Agent's capability boundaries to be flexibly extended.

Key Code Walkthrough

Controller Layer

The AgentController in the tutorial uses @RequestMapping to define the AI Agent's entry point with produces = application/json, and accepts an AgentRequest body via @PostMapping("/chat"). The request body carries two key pieces of information: a conversation ID and the service connection details.

Service Layer

AgentService injects ChatClient and Clock (UTC clock). The processing logic roughly follows these steps:

  1. Extract conversationId from the request; generate a random UUID if absent
  2. Build a Map as ToolContext, populated with the conversationId and request context
  3. Call chatClient.prompt(userMessage).toolContext(...) to initiate the request
  4. Return a response containing the conversationId, answer, and creation timestamp

Using a Map to carry context is critical here: the context can include API URLs, user IDs, passwords, headers, and any other information the Tool needs to connect to a specific external API and analyze its data.

After aggregating data from external systems, the Agent returns a structured response with a conversationId

Configuration and Tools

The configuration section registers tools via ToolCallbackProvider, sets the system prompt, and configures request timeouts via McpClientCustomizer — for example, if no response is received within 30 seconds, the MCP Server automatically disconnects.

The tutorial also demonstrates a RuntimeTool example that returns runtime health information such as the current UTC server time, available processor count, and memory in bytes. Following this pattern, you can write dedicated Tools for database queries, API health checks, and other scenarios.

Using the AI Agent to monitor server and system health

ChatClient is Spring AI's unified abstraction layer over LLM providers (OpenAI, Anthropic, Azure OpenAI, etc.), similar to how Spring Data abstracts away database differences. Developers construct an instance via ChatClient.Builder and chain system prompts, tool callbacks (ToolCallbackProvider), and context (ToolContext) onto the call, ultimately receiving the LLM's response in either streaming or blocking mode. ToolContext is a key-value container shared across the lifecycle of a single request — Tool methods can inject it directly as a method parameter to read runtime dynamic values like URLs and tokens, without hardcoding sensitive information into configuration files. This design allows the same Tool code to serve different users' different backend systems in multi-tenant scenarios — simply by switching context content in the request body — significantly improving code reusability and security.

Deployment and Security Best Practices

Several things must be done right before going to production:

Environment-specific configuration: In application.yml, separate MCP endpoint URLs for local and production environments; use local.yaml for local development and the appropriate profile for production.

Model and API keys: The tutorial uses an OpenAI model (GPT-4.1 mini) with temperature set to 0.2 for stable responses. API Keys must never be written into application.yaml — they should be stored in a secrets management service.

Dockerization: Write a Dockerfile to package the fat jar, with configurable memory percentage; pom.xml should include starter-web, starter-model-openai, starter-mcp-client-webflux, and other dependencies, along with Actuator for health monitoring (exportable to Prometheus).

Principle of least privilege: Restrict the MCP Server to the minimum necessary filesystem, network, and account permissions; review tool behavior before connecting; strictly limit accessible ports and APIs.

This last point is especially important — if you're building a general-purpose Agent, MCP could potentially be manipulated into querying sensitive data belonging to other users. Access controls and permission boundaries must therefore be built into the implementation.

Prompt Injection is one of the most critical security threats to watch out for in production AI Agent deployments. Attackers can embed malicious instructions in user input or external data sources (such as database fields or API responses) to trick the LLM into bypassing its preset system prompt and performing unauthorized actions — such as querying another user's orders or calling internal endpoints that shouldn't be exposed. In an MCP architecture, this risk is amplified: because Tools have real system access, once an LLM is "convinced" to invoke the wrong Tool or pass in incorrect parameters, the consequences can be far more severe than a chatbot giving a wrong answer. Mitigations include: validating parameter legitimacy inside Tools (rather than relying solely on the LLM's judgment), scoping each Tool's accessible resources, recording complete invocation audit logs at the MCP Server level, and introducing Human-in-the-loop confirmation for sensitive operations. This is an extension of the same logic as the "principle of least privilege" mentioned above.

Runtime Requirements

Following the tutorial, the baseline requirements to run this Spring AI + MCP Agent are:

  • Java 21
  • Maven 3.9
  • A valid OpenAI API Key

Once running, invoke it via a REST POST to /ai-agent/chat, passing a message and the tool context you want to use in the request body.

Summary

The core value of combining Spring AI + MCP lies in bridging the LLM's reasoning capabilities with real enterprise data. The LLM handles understanding and decision-making; MCP acts as the standardized intermediary that translates those decisions into actual operations against databases, APIs, and message queues. For developers working at the intersection of Java and AI, mastering the layered Controller/Service/Tool pattern, configuration-driven tool registration, and production-environment secrets and permission management are the critical steps to taking a demo all the way to production.

#Spring AI#MCP#Model Context Protocol#AI Agent#Java AI Agent#Spring Boot AI#LLM Java#production AI agent#tool calling#ChatClient
Share:

Related articles