Demo de Interfaz Dual con MCP
Demostración de arquitectura de interfaz dual donde la misma lógica de negocio sirve tanto a una aplicación web tradicional como a un servidor MCP para herramientas de IA.
La idea
La mayoría de los equipos construyen aplicaciones para humanos y luego, cuando quieren integrar IA, crean una capa separada encima: wrappers, adaptadores, APIs intermedias. Esto genera acoplamiento, duplicación y puntos de fallo en cascada.
Este experimento explora una alternativa: construir desde el inicio con dos interfaces que comparten la misma lógica de negocio. Una interfaz para humanos (web app) y otra para agentes de IA (servidor MCP), ambas accediendo directamente a la misma capa de datos.
¿Por qué importa?
El Model Context Protocol (MCP) es un estándar abierto que permite a los LLMs interactuar con herramientas externas de forma estructurada. En lugar de que un agente de IA tenga que navegar una UI o parsear HTML, el servidor MCP expone operaciones como herramientas tipadas que el modelo puede invocar directamente.
La pregunta clave que este experimento responde es: ¿se puede diseñar una aplicación donde la interfaz humana y la interfaz de IA sean ciudadanos de primera clase desde el día uno, sin que una sea un parche sobre la otra?
Arquitectura
Los principios clave de la arquitectura:
- Acoplamiento débil: cada servicio accede a DynamoDB directamente, sin depender del otro
- Código compartido: la lógica de negocio vive en un módulo
shared/que ambas interfaces importan - Escalamiento independiente: la API REST y el servidor MCP pueden escalar por separado
- Sin fallos en cascada: si la API REST cae, el servidor MCP sigue funcionando y viceversa
Stack técnico
| Componente | Tecnología |
|---|---|
| API REST | FastAPI + Python 3.11 |
| Servidor MCP | Python MCP SDK (transporte stdio) |
| Frontend | React 19 + TypeScript + Vite + Tailwind CSS |
| Base de datos | DynamoDB Local |
| Lógica compartida | Módulo Python (shared/) |
| Orquestación | Docker Compose |
¿Cómo funciona?
El módulo shared/todo_service.py contiene toda la lógica de negocio: crear, listar, actualizar y eliminar tareas. Tanto la API REST (backend/main.py) como el servidor MCP (mcp-server/server.py) instancian TodoService con la misma tabla de DynamoDB.
La API REST expone endpoints HTTP convencionales:
POST /todos → crear tarea
GET /todos → listar tareas
GET /todos/{id} → obtener tarea
PATCH /todos/{id} → actualizar tarea
DELETE /todos/{id} → eliminar tarea
El servidor MCP expone las mismas operaciones como herramientas tipadas que un LLM puede invocar:
create_todo → crear tarea
list_todos → listar tareas
get_todo → obtener tarea
update_todo → actualizar tarea
delete_todo → eliminar tarea
Ambas interfaces ejecutan exactamente la misma lógica. No hay duplicación de reglas de negocio.
Mapeo a AWS
La arquitectura local se traduce directamente a servicios de AWS para producción:
| Local | AWS |
|---|---|
| DynamoDB Local | DynamoDB |
| FastAPI | Lambda + API Gateway o ECS/Fargate |
| Servidor MCP | Lambda o ECS Task |
| React Frontend | S3 + CloudFront o Amplify |
| Módulo compartido | Lambda Layer o paquete compartido |
Lecciones aprendidas
-
El transporte stdio es simple pero limitante: funciona bien para desarrollo local con Kiro CLI, pero para producción se necesitaría SSE o WebSocket para soportar múltiples clientes concurrentes.
-
La capa compartida es el patrón más valioso: separar la lógica de negocio en un módulo independiente de la interfaz es lo que hace posible la arquitectura dual sin duplicación.
-
DynamoDB simplifica el acceso directo: al no necesitar un ORM complejo ni migraciones, ambos servicios pueden acceder a la misma tabla con configuración mínima.
Referencias
- Repositorio en GitHub — Código fuente del experimento.
- Model Context Protocol — Especificación — Anthropic. Especificación oficial del protocolo.
- Python MCP SDK — Anthropic. Implementación de referencia en Python.
- FastAPI — Tiangolo. Framework web usado para la interfaz REST.