Artículo

Incorporar interfaces HTML en servidores MCP con Spring AI

Incorporar interfaces HTML en servidores MCP con Spring AI

1. Visión general

Los servidores MCP (Modelo Context Protocol) son la base del manejo y desarrollo de IA modernos. Para ello, saber cómo configurarlo e integrarlo en proyectos puede ser esencial.

En este tutorial, aprenderemos cómo construir un servidor MCP con Spring AI y conectarlo a un harness de IA como Claude Desktop. Para empezar, creamos una herramienta hello-world simple, la probamos usando el MCP Inspector, y luego la registramos con Claude Desktop como un conector personalizado.

Una vez que se tengan los conceptos básicos, llevaremos el proyecto un paso más allá y expondremos una interfaz HTML interactiva y rica: una ruleta de fortuna que elige aleatoriamente el deporte del día. En esa implementación, veremos cómo las anotaciones @McpTool y @McpResource de Spring AI permiten al harness renderizar la página en línea dentro del chat y devolver el resultado a la conversación.

2. Creación de un servidor MCP

El Modelo Context Protocol (MCP) proporciona una forma estandarizada para que asistentes de IA como Claude Code o Claude Desktop invoquen alguna funcionalidad personalizada siempre que el modelo lo considere apropiado. Un servidor MCP es el backend ligero que expone esta funcionalidad a través de herramientas, recursos y indicaciones.

Comencemos creando un servidor MCP hello-world simple. Primero, añadimos la dependencia spring-ai-starter-mcp-server al pom.xml:

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

Además, utilizamos spring-ai-bom para la gestión de versiones:

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.springframework.ai</groupId>
      <artifactId>spring-ai-bom</artifactId>
      <version>2.0.0</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

Luego, configuramos el protocolo de transporte MCP. Spring AI admite tres opciones de transporte:

  • stdio para comunicación basada en procesos locales
  • streamable para el nuevo transporte HTTP streamable que maneja tanto peticiones como respuestas en streaming sobre un único punto final
  • stateless para una variante de Streamable HTTP que descarta el estado de la sesión en el servidor. Se escala horizontalmente de forma trivial a costa de perder las capacidades bidireccionales del protocolo

Aquí, usamos el protocolo stdio. Por lo tanto, lo configuramos en application.properties:

spring.ai.mcp.server.stdio=true
spring.main.banner-mode=off
logging.file.name=./mcp-server.log

Las dos propiedades finales son críticas para stdio: Spring no debe imprimir nada en stdout, ya que ese canal está reservado para JSON-RPC.

Finalmente, añadimos una herramienta que diga hola del servidor al usuario de vuelta:

@SpringBootApplication
class McpUiApplication {

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

    @McpTool(
        title = "Say Hello",
        name = "say-hello",
        description = "A simple tool that returns a greeting message."
    )
    String sayHello() {
        return "Hello from the MCP UI Application!";
    }
}

Como era de esperarse, esta herramienta se expone al agente de IA, y el mensaje de saludo se devuelve al usuario cada vez que el modelo decida invocarla.

3. Probando el servidor MCP

Hay varias formas de conectarse y probar un servidor MCP. Intentemos usar algunas de ellas para eso y activar la herramienta Say Hello.

3.1. Probar con MCP Inspector

Una opción conveniente es el MCP Inspector, una herramienta de desarrollo interactiva diseñada para probar y depurar servidores MCP:

npx @modelcontextprotocol/inspector java -jar target/spring-ai-mcp-0.0.1.jar

Este comando inicia un servidor proxy local junto con una interfaz web que podemos abrir en el navegador para probar el MCP. Usando esta interfaz, podemos realizar diferentes acciones:

  1. conectar a un servidor MCP
  2. ver los recursos, indicaciones y herramientas que expone
  3. activar herramientas

La interfaz es bastante sencilla:
MCP Inspector areas

Como podemos ver, estamos conectados al servidor MCP que creamos con Spring AI, y ejecutamos con éxito su herramienta Say Hello.

3.2. Probar con Claude Desktop

Alternativamente, podemos usar un harness de IA para probar el servidor MCP. Después de todo, el objetivo final es usar el servidor MCP desde una aplicación de escritorio como Claude Desktop.

Primero, necesitamos registrarlo en el archivo claude_desktop_config.json, cuya ubicación varía:

  • en Windows, es %APPDATA%\Claude\claude_desktop_config.json
  • en macOS, es ~/Library/Application Support/Claude/claude_desktop_config.json

Claude Desktop soporta de forma nativa el transporte stdio; podemos apuntarlo directamente al archivo jar:

"mcpServers": {
  "sport-spinner": {
    "command": "java",
    "args": ["-jar", "D:/repos/tutorials/spring-ai-modules/spring-ai-mcp/target/spring-ai-mcp-0.0.1.jar"]
  }
}

Como vemos, también debemos asignar una etiqueta a la aplicación MCP. Llamémosla sport-spinner, ya que la extendemos para recomendar un deporte que el usuario pueda practicar cualquier día.

Finalmente, si reiniciamos Claude Desktop, deberíamos poder ver el servidor MCP como un conector personalizado:

Enable connector

Por lo tanto, el modelo ahora puede decidir invocar las herramientas expuestas por el servidor MCP: Example of usage

Parece que logramos conectarnos a la aplicación MCP y devolver una String que el Harness de IA puede usar o mostrar al usuario. Ahora, actualicemos la aplicación para devolver HTML que pueda ser renderizado en Claude Desktop.

4. Insertar HTML

Hasta ahora, el servidor MCP solo devuelve texto plano. Sin embargo, los harness de IA modernos como Claude Desktop también pueden renderizar interfaces de usuario ricas e interactivas que el servidor expone como recursos HTML. En este caso, podemos aprovechar estas funciones combinando una @McpTool que desencadene la UI con una @McpResource que sirva el HTML real.

Mejoramos sport-spinner para mostrar una ruleta de fortuna real que elija el deporte del día. Primero, añadimos un archivo HTML bajo src/main/resources/static/sport-spinner.html, que contiene el HTML, CSS y JavaScript que anima la ruleta.

4.1. Exponer el HTML como un recurso MCP

Creamos un nuevo bean de Spring que cargue el archivo HTML y lo exponga mediante la anotación @McpResource:

@Component
class SportSpinnerUI {

    @Value("classpath:/static/sport-spinner.html")
    private Resource sportSpinnerResource;

    @McpResource(
        name = "Sport Spinner App Resource",
        uri = "ui://sport/sport-spinner.html",
        mimeType = "text/html;profile=mcp-app",
        metaProvider = CspMetaProvider.class)
    public String getSportSpinnerResource() throws IOException {
        return sportSpinnerResource.getContentAsString(StandardCharsets.UTF_8);
    }
}

Algunas cosas que vale la pena destacar aquí:

  • el uri identifica de manera única el recurso dentro del servidor MCP
  • el mimeType utiliza el perfil text/html;profile=mcp-app — señalando al cliente que este HTML debe renderizarse como una aplicación MCP interactiva en lugar de mostrarse como texto sin formato
  • el metaProvider adjunta metadatos adicionales al recurso — en este caso, una Política de Seguridad de Contenido que permite unpkg.com para que la página pueda cargar scripts externos desde ese CDN

Echemos un vistazo al CspMetaProvider:

class CspMetaProvider implements MetaProvider {
    @Override
    public Map<String, Object> getMeta() {
        return Map.of("ui",
            Map.of("csp",
                Map.of("resourceDomains", List.of("https://unpkg.com"))));
    }
}

En este punto, deberíamos estar listos para conectar la UI con la herramienta.

4.2. Vincular la herramienta al recurso UI

Finalmente, añadimos una herramienta MCP que indique al harness que abra la ruleta:

@McpTool(
    title = "Spin Sport Wheel",
    name = "spin-sport-wheel",
    description = "Opens a fortune wheel that spins and randomly picks today's sport.",
    metaProvider = SportSpinnerToolMetaProvider.class)
public String spinSportWheel() {
    return "Opening the sport spinner wheel.";
}

El elemento clave aquí es metaProvider, que vincula esta herramienta al recurso HTML que definimos anteriormente:

class SportSpinnerToolMetaProvider implements MetaProvider {
    @Override
    public Map<String, Object> getMeta() {
        return Map.of("ui",
            Map.of("resourceUri", "ui://sport/sport-spinner.html"));
    }
}

Cuando el modelo invoque spin-sport-wheel, el harness leerá este metadato, obtendrá el recurso en ui://sport/sport-spinner.html y lo renderizará en línea dentro del chat, ofreciendo al usuario una ruleta completamente interactiva en lugar de una respuesta de texto plano.

Reiniciemos Claude Desktop y preguntémosle qué deporte deberíamos practicar hoy: Fortune Wheel spin UI

Como era de esperar, el HTML de la aplicación Spring Boot ahora se renderiza directamente dentro del chat de Claude Desktop. En este punto, podemos girar la ruleta para que elija el deporte del día, con el resultado devuelto a la conversación para que el modelo pueda reaccionar.

5. Conclusión

En este tutorial, aprendimos cómo construir un servidor MCP con Spring AI y conectarlo a un harness de IA como Claude Desktop.

Específicamente, comenzamos con una herramienta hello-world simple y la probamos usando el MCP Inspector y Claude Desktop. Luego, llevamos el proyecto un paso más allá exponiendo una interfaz HTML interactiva y rica mediante las anotaciones @McpTool y @McpResource de Spring AI. Como resultado, hicimos que el harness renderizara una ruleta de fortuna dentro del chat y devolviera el resultado a la conversación.

Como siempre, el código fuente completo está disponible en GitHub.

Newsletter Semanal de Java

Cada viernes recibe lo más nuevo del ecosistema Java: frameworks, herramientas y mejores prácticas.

Sin spam. Cancela cuando quieras.

Compartir artículo