KeelFramework

Keel Framework / Java / Implementación de Referencia

Implementación de Referencia

mcp-petstore-sample — Aplicación real que implementa el stack completo de la Arquitectura Keel MCP, pensada como referencia para developers y arquitectos que construyen servidores MCP con Spring AI. El repositorio materializa los principios arquitectónicos, capas, componentes y convenciones definidos por Keel MCP en una implementación funcional.

Qué demuestra este proyecto

  • ✅ 3 Tools MCP que invocan una API REST externa real (findPet, listPets, registerPet)
  • ✅ 2 Prompts MCP que guían al LLM en flujos habituales (consulta por ID, recolección guiada de datos)
  • ✅ 1 Resource MCP que documenta las tools disponibles para el LLM
  • ✅ Autenticación JWT (Streamable HTTP), validada contra un IdP OIDC público de demo
  • ✅ Logging JSON estructurado (técnico, funcional, seguridad) vía Keel Observability
  • ✅ Deserialización JSON resiliente frente a un backend públicamente editable con años de datos inconsistentes

Sin Keycloak, sin API keys, sin registro — todo funciona contra servicios públicos de demostración.

Requisitos previos

  • Java 25
  • Maven 3.8+
  • Conexión a internet (ambos backends usados son servicios públicos alojados)

Backends utilizados (públicos, sin configuración necesaria)

PropósitoServicioURL
Datos RESTAPI de demo Swagger Petstorehttps://petstore3.swagger.io/api/v3
JWT / OIDCDemo pública de Duende IdentityServerhttps://demo.duendesoftware.com

Ambos son servicios de demo públicos y compartidos. No los uses para nada más allá de probar este proyecto — los datos pueden reiniciarse, y los datos de prueba de otras personas (con formas inconsistentes) son justamente el motivo por el que los DTOs de este proyecto están escritos de forma defensiva (ver más abajo).

Ejecución en local

git clone https://github.com/Keel-Framework/keel-mcp-petstore-sample.git
cd keel-mcp-petstore-sample/petstore-sample-boot
mvn clean install
mvn spring-boot:run

El servidor arranca en http://localhost:8080, con el endpoint MCP en POST /mcp.

Obtener un JWT para autenticar las peticiones

Este proyecto valida los JWT contra el IdP público de demo de Duende, usando el grant client_credentials (máquina-a-máquina, sin necesidad de login de usuario):

curl -X POST "https://demo.duendesoftware.com/connect/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "client_id=m2m&client_secret=secret&grant_type=client_credentials&scope=api"

Copia el access_token de la respuesta y úsalo como token Bearer en el header Authorization de cada petición a /mcp.

Conectar con MCP Inspector (recomendado)

npx @modelcontextprotocol/inspector@latest

En la interfaz de Inspector:

  1. Transport Type: Streamable HTTP
  2. URL: http://localhost:8080/mcp
  3. Authorization header: Bearer <tu-token>
  4. Clic en Connect

Deberías ver 3 tools, 2 prompts y 1 resource listados.

Tools

ToolDescripciónLlamada al backend
findPet(petId)Busca una mascota por su ID numéricoGET /pet/{petId}
listPets(status)Lista mascotas filtrando por estado (available, pending, sold)GET /pet/findByStatus?status=...
registerPet(name, category, status)Registra una nueva mascotaPOST /pet

Prompts

PromptPropósito
petstore-find-petPlantilla para buscar una mascota por ID
petstore-register-petGuía al modelo para recolectar name, category y status antes de invocar registerPet, mediante un ejemplo de dos mensajes (USER + ASSISTANT)

Resources

ResourceURIPropósito
Guía de toolspetstore://tools-guideGuía en texto plano describiendo cuándo y cómo usar cada tool

Manejo de datos públicos inconsistentes

petstore3.swagger.io es una demo públicamente editable, usada por incontables developers a lo largo de los años. Algunas entradas existentes tienen formas de datos que no coinciden exactamente con el esquema OpenAPI (por ejemplo, una entrada de tags que es un string simple en vez de {"id": ..., "name": ...}). Los DTOs de este proyecto manejan esto correctamente:

@JsonCreator(mode = JsonCreator.Mode.DELEGATING)
public static Tag fromString(String name) {
    return new Tag(null, name);
}

Si estás construyendo contra tu propio backend con datos limpios y controlados, probablemente no necesites este tipo de deserialización defensiva — se incluye aquí específicamente porque este proyecto apunta a un sandbox público y compartido.

Estructura del proyecto

petstore-sample/
├── petstore-sample-model/     # DTOs (PetstoreDTO), constantes de mensajes de error
├── petstore-sample-mcp/       # Tools, Prompts, Resources
└── petstore-sample-boot/      # Aplicación Spring Boot, configuración

Configuración

La configuración local vive en petstore-sample-boot/src/main/resources/application-local.yml:

keel:
  adapters:
    rest-client:
      services:
        petstore:
          base-url: https://petstore3.swagger.io/api/v3
          log-requests: true
  mcp:
    transport:
      auth:
        enabled: true
        jwt:
          issuer: https://demo.duendesoftware.com
          jwks-uri: https://demo.duendesoftware.com/.well-known/openid-configuration/jwks

Construido con Keel Framework

Este proyecto de ejemplo funciona sobre Keel Framework — una arquitectura para construir MCP Servers listos para producción sobre Spring AI, con autenticación JWT, gestión de sesión, observabilidad y adaptadores REST ya resueltos por ti.

Licencia

Apache License 2.0 — ver LICENSE.