HTML UIs in Spring AI MCP Servers
Modern AI applications are evolving beyond simple text interactions. With the introduction of the Model Context Protocol (MCP), developers can expose tools, resources, and prompts that AI agents can discover and invoke dynamically. While most MCP examples focus on APIs and tool execution, there are scenarios where returning rich HTML interfaces directly from MCP servers provides a much better user experience. In this article, we’ll explore how to build an MCP Server using Spring AI, expose an HTML-based UI through MCP resources, and test the server using MCP-compatible clients.
1. Overview
The Model Context Protocol (MCP) is an open standard that enables AI models to interact with external systems in a structured and secure manner. MCP servers can expose:
- Tools for executing actions
- Resources for retrieving content
- Prompts for reusable AI interactions
One interesting use case is embedding HTML interfaces directly within MCP resources. Instead of returning plain text, the server can provide a complete HTML page that can be rendered by MCP-aware clients, dashboards, or agent platforms. Embedding HTML UIs within MCP resources enhances the user experience by enabling rich visual presentations, interactive dashboards, embedded reports and analytics, AI-generated custom interfaces, and improved usability for enterprise applications, making AI-powered systems more intuitive, engaging, and business-friendly.
2. Introduction to Spring AI and MCP Servers
2.1 What is Spring AI?
Spring AI is the Spring ecosystem’s framework for building AI-powered applications, providing abstractions for Large Language Models (LLMs), embeddings, vector databases, prompt engineering, AI agents, and the Model Context Protocol (MCP). It enables developers to build intelligent applications using familiar Spring Boot programming patterns while maintaining portability and flexibility across multiple AI providers.
2.2 What is an MCP Server?
An MCP (Model Context Protocol) Server exposes tools, resources, and other capabilities that AI models can dynamically discover and invoke through a standardized protocol, eliminating the need for hard-coded integrations. In a typical MCP architecture, an AI Assistant communicates with an MCP Client, which interacts with an MCP Server that provides access to various tools and resources. This architecture enables seamless integration between AI applications and external systems, with the MCP server acting as a bridge that connects AI models to enterprise services, business workflows, and data sources in a consistent and extensible manner.
3. Creating an MCP Server with Spring AI
3.1 Project Dependencies
Add the following Maven dependencies:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
</dependency>
</dependencies>
This Maven configuration adds the core dependencies required to build a Spring AI MCP server. The spring-boot-starter dependency provides the foundational Spring Boot components, including auto-configuration, dependency management, and application startup support, while the spring-ai-starter-mcp-server-webmvc dependency adds Spring AI’s Model Context Protocol (MCP) server capabilities on top of Spring MVC, enabling developers to create MCP-compliant servers that can expose tools, resources, and prompts for discovery and invocation by AI clients and agents.
3.2 Application Configuration
Configure the MCP server:
spring:
application:
name: html-mcp-server
server:
port: 8080
spring:
ai:
mcp:
server:
name: html-ui-server
version: 1.0.0
This configuration defines the basic settings for the Spring Boot MCP server application. The spring.application.name property assigns the application name as html-mcp-server, while the server.port property configures the embedded web server to listen on port 8080. The spring.ai.mcp.server section configures the MCP server metadata by specifying a server name (html-ui-server) and version (1.0.0), allowing MCP clients to identify and interact with the server and its exposed capabilities through the Model Context Protocol.
3.3 Create an HTML Dashboard Resource
The following component exposes an HTML dashboard as an MCP resource.
package com.example.mcp.resource;
import org.springframework.stereotype.Component;
@Component
public class DashboardResource {
public String getDashboardHtml() {
return """
<html>
<head>
<title>AI Dashboard</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
}
.card {
border: 1px solid #ddd;
padding: 20px;
margin: 10px 0;
border-radius: 8px;
width: 250px;
}
.metric {
font-size: 32px;
font-weight: bold;
}
</style>
</head>
<body>
<h1>Welcome to MCP Dashboard</h1>
<div class='card'>
<div>Active Agents</div>
<div class='metric'>24</div>
</div>
<div class='card'>
<div>MCP Requests</div>
<div class='metric'>1204</div>
</div>
</body>
</html>
""";
}
}
This class is responsible for generating the dashboard HTML and acts as the central source of the UI markup. It is annotated with @Component, which makes it a Spring-managed bean, and its getDashboardHtml() method returns the complete HTML page as a Java text block. The returned markup includes the page structure, title, embedded CSS styles, dashboard heading, and metric cards such as Active Agents and MCP Requests. By keeping the HTML generation in this dedicated class, the design separates UI construction from MCP tool logic, making the dashboard easier to maintain, reuse, and update in one place.
3.4 Create an MCP Tool
Spring AI allows MCP tools to be exposed using the @Tool annotation.
package com.example.mcp.tools;
import com.example.mcp.resource.DashboardResource;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.stereotype.Service;
@Service
public class DashboardTools {
private final DashboardResource dashboardResource;
public DashboardTools(DashboardResource dashboardResource) {
this.dashboardResource = dashboardResource;
}
@Tool(description = "Returns an HTML dashboard")
public String getDashboard() {
return """
{
"contentType": "text/html",
"content": %s
}
""".formatted(toJsonString(dashboardResource.getDashboardHtml()));
}
private String toJsonString(String html) {
return "\"" + html
.replace("\\", "\\\\")
.replace("\"", "\\\"")
.replace("\n", "\\n")
.replace("\r", "") + "\"";
}
}
This class is responsible for exposing the dashboard through MCP as a callable tool. It is annotated with @Service and receives DashboardResource through constructor injection, so it does not create the HTML itself. Instead, when the getDashboard() method is invoked by an MCP client, it calls dashboardResource.getDashboardHtml() to fetch the HTML generated in section 3.3, then wraps that HTML inside a JSON response with contentType set to text/html. This makes the flow explicit: section 3.3 is responsible for producing the dashboard HTML, while section 3.4 is responsible for publishing that HTML as an MCP tool response that clients can render directly.
3.5 Register Tool Callback Provider
package com.example.mcp.config;
import com.example.mcp.tools.DashboardTools;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.ai.tool.method.MethodToolCallbackProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ToolConfig {
@Bean
ToolCallbackProvider tools(
DashboardTools dashboardTools) {
return MethodToolCallbackProvider.builder()
.toolObjects(dashboardTools)
.build();
}
}
This configuration class registers the application’s MCP tools with Spring AI so they can be discovered and invoked by MCP clients. The @Configuration annotation marks the class as a source of Spring bean definitions, while the tools() method creates a ToolCallbackProvider bean. Using MethodToolCallbackProvider.builder(), the configuration scans the supplied DashboardTools object for methods annotated with @Tool and automatically exposes them as MCP-compatible tools. This eliminates the need for manual tool registration and allows Spring AI to manage tool discovery, invocation, and metadata generation, making the MCP server’s capabilities available to AI assistants and clients through the Model Context Protocol.
3.6 Main Application
package com.example.mcp;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class HtmlMcpServerApplication {
public static void main(String[] args) {
SpringApplication.run(
HtmlMcpServerApplication.class,
args
);
}
}
This class serves as the entry point for the Spring Boot MCP server application. The @SpringBootApplication annotation combines component scanning, auto-configuration, and configuration support, allowing Spring Boot to automatically discover and configure application components such as MCP tools, resources, and configuration classes. The main() method invokes SpringApplication.run(), which initializes the Spring application context, starts the embedded web server, loads all registered beans, and activates the Spring AI MCP server infrastructure. Once the application starts successfully, MCP clients can connect to the server and access the exposed tools and resources, including the HTML dashboard functionality implemented in the application.
3.7 Testing the MCP Server
After completing the application setup and configuration, the next step is to start the Spring Boot MCP server. Spring Boot provides a simple command-line mechanism for building and launching the application, automatically initializing the embedded web server, loading all configured MCP tools and resources, and registering them with the Spring AI MCP framework.
mvn spring-boot:run
Executing this command compiles the project, resolves the required dependencies, and starts the application. Once the server is running successfully, MCP clients can connect to it, discover the available tools, invoke the HTML dashboard functionality, and interact with the resources exposed by the MCP server.
Started HtmlMcpServerApplication MCP Server Started Server Name: html-ui-server Version: 1.0.0 Listening on port 8080
3.7.1 Verify Tool Discovery
Once the MCP server is running, the first step is to verify that the server is correctly exposing its registered tools. MCP clients can discover available capabilities by sending a tools/list request, which returns metadata about all tools published by the server. This allows clients and AI assistants to understand what functionality is available before invoking specific tools.
// ENDPOINT
http://localhost:8080/mcp
// REQUEST
{
"method": "tools/list"
}
If the tool registration was successful, the server responds with a list of available tools along with their names and descriptions. In this example, the MCP server exposes a single tool named getDashboard, which returns an HTML dashboard.
{
"tools": [
{
"name": "getDashboard",
"description": "Returns an HTML dashboard"
}
]
}
3.7.2 Invoke the Tool
After discovering the available tools, an MCP client can invoke a specific tool using the tools/call method. The request includes the tool name that should be executed by the MCP server.
// ENDPOINT
http://localhost:8080/mcp
// REQUEST
{
"method": "tools/call",
"params": {
"name": "getDashboard"
}
}
When the request is processed, the server executes the corresponding tool method and returns its output. In this case, the response contains HTML content with a MIME type of text/html, allowing MCP-compatible clients to render the dashboard directly instead of displaying plain text.
{
"contentType": "text/html",
"content": "<html>
<head>
<title>AI Dashboard</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
}
.card {
border: 1px solid #ddd;
padding: 20px;
margin: 10px 0;
border-radius: 8px;
width: 250px;
}
.metric {
font-size: 32px;
font-weight: bold;
}
</style>
</head>
<body>
<h1>Welcome to MCP Dashboard</h1>
<div class='card'>
<div>Active Agents</div>
<div class='metric'>24</div>
</div>
<div class='card'>
<div>MCP Requests</div>
<div class='metric'>1204</div>
</div>
</body>
</html>"
}
The response contains HTML markup generated by the getDashboard() tool. Since the content type is set to text/html, MCP-compatible clients can render the response as a web page, displaying dashboard components such as metrics, reports, status indicators, and other visual elements. This demonstrates how MCP tools can return rich user interfaces rather than simple text responses, enabling AI-powered applications to deliver interactive and visually appealing experiences.
4. Conclusion
Spring AI significantly simplifies the development of MCP servers by providing native support for tool registration, resource exposure, and protocol integration within Spring Boot applications. Embedding HTML UIs inside MCP resources enables developers to deliver rich dashboards, reports, analytics views, and interactive business interfaces directly through MCP clients. As MCP adoption grows, combining Spring AI’s developer-friendly programming model with HTML-based interfaces offers a powerful approach for building next-generation AI applications that seamlessly blend conversational intelligence with traditional web experiences.




