Fundamentos, arquitectura limpia y estrategia de testing
Introducción
Model Context Protocol (MCP) está emergiendo como el estándar de facto para conectar agentes de IA con capacidades reales de sistemas: APIs, datos, operaciones.
El problema es que está entrando en proyectos por la puerta equivocada.
Estoy viendo equipos que:
- diseñan directamente “un MCP Server”
- meten lógica dentro de tools
- acoplan dominio a protocolo
- y luego se preguntan por qué no pueden testear ni escalar
Este artículo va a ser claro:
MCP no es tu arquitectura. Es un adaptador.
Y si no lo tratas como tal, vas a construir algo frágil.
1. Qué es MCP (desde el punto de vista arquitectónico)
MCP define un contrato:
- tools (acciones ejecutables)
- resources (datos)
- prompts (plantillas)
- comunicación vía JSON-RPC
Especificación oficial:
https://modelcontextprotocol.io/specification/2025-03-26
En .NET, ya puedes montar servidores MCP sobre ASP.NET Core:
- SDK C#
- integración con HTTP / streaming
- despliegue en Azure
Ejemplo oficial de Microsoft:
https://learn.microsoft.com/en-us/azure/container-apps/tutorial-mcp-server-dotnet
Lo importante
MCP:
- expone capacidades
- no define cómo construirlas
2. El anti-patrón que debes evitar
Este diseño aparece constantemente:
MCP Tool
├── lógica de negocio
├── validaciones
├── llamadas a Azure
├── composición de respuesta
└── retorno al cliente
Problemas:
- acoplamiento extremo
- imposible testear en aislamiento
- difícil evolucionar
- no reutilizable
- sin separación de responsabilidades
Esto no escala.
3. Patrón correcto: Clean Architecture + MCP como adapter
La única forma sostenible es separar:
[MCP Adapter]
│
[Application Layer]
│
[Domain]
│
[Infrastructure]
Regla clave
Cada tool MCP debe ser un wrapper fino sobre un caso de uso.
Ejemplo conceptual en .NET:
public class GetCostTool
{
private readonly IGetCostUseCase _useCase;
public async Task<GetCostResult> Execute(GetCostInput input)
{
return await _useCase.Execute(input);
}
}
Nada de lógica en el tool.
4. Por qué no debes diseñar “directo a MCP”
Hay razones técnicas, no opiniones.
4.1 El protocolo aún está evolucionando
El propio roadmap lo reconoce:
- retos en transporte remoto
- balanceo
- operación stateless
- sesiones
Información adicional: https://modelcontextprotocol.io/development/roadmap
4.2 MCP no cubre necesidades operativas
No resuelve:
- health checks
- observabilidad estándar
- control de errores avanzado
De hecho, Microsoft recomienda endpoints adicionales:
/mcp
/health
4.3 Te ata a un canal de entrada
Si todo está dentro de MCP:
- no puedes exponer REST fácilmente
- no puedes reutilizar lógica
- no puedes integrar otros sistemas
5. Testing: separar lo determinista de lo probabilístico
Aquí está la clave que suele confundirse.
5.1 Qué puedes testear de forma determinista
Dominio y aplicación
- tests unitarios clásicos
- sin MCP
- sin LLM
100% determinista
Adaptador MCP (contrato)
Puedes validar:
- nombre del tool
- schema de entrada/salida
- mapping a casos de uso
- errores
Endpoint MCP
Puedes testear:
- JSON-RPC correcto
- estructura de respuesta
- códigos HTTP
- streaming
El protocolo está definido para permitir esto: https://modelcontextprotocol.io/specification/2025-03-26
5.2 Qué NO es determinista
La respuesta final de un agente:
Usuario → LLM → decide tool → ejecuta → responde
Aquí entran:
- decisiones del modelo
- contexto
- temperatura
Esto no es testing clásico. Es:
- evaluación
- métricas
- observabilidad
5.3 ¿Necesitas una API REST para testear?
No.
Puedes testear directamente MCP:
- llamadas HTTP JSON-RPC
- herramientas como MCP Inspector
https://modelcontextprotocol.io/docs/tools/inspector
REST es útil, pero no obligatorio.
6. Diseño de un MCP Server en .NET
Stack típico:
- ASP.NET Core
ModelContextProtocol.AspNetCore- hosting en Azure
Opciones de despliegue:
- Azure Container Apps
- Azure App Service
- Azure Kubernetes Service
Referencia oficial: https://learn.microsoft.com/en-us/azure/container-apps/tutorial-mcp-server-dotnet
Endpoints recomendados
/mcp → protocolo MCP
/health → health checks
Nunca uses /mcp como health endpoint.
Nota del autor: siento repetir esto, pero cuando lo ves, lo explicas 1 vez, 2 veces, …, pues insistes otra vez.
7. Problemas reales en producción
Cuando sales de local aparecen problemas serios.
7.1 Transporte
- streaming HTTP
- proxies que rompen conexiones
- buffering inesperado
7.2 Escalado
- sesiones implícitas
- balanceadores no preparados
- pérdida de contexto
7.3 Seguridad
- autenticación
- exposición de tools
- ejecución indirecta
7.4 Observabilidad
- correlación entre tool calls
- trazabilidad de decisiones
8. Insight clave
Este es el punto que debes interiorizar:
MCP introduce ejecución remota de capacidades controladas por un modelo.
Eso cambia completamente:
- el modelo de seguridad
- el modelo de testing
- el modelo de arquitectura
9. Patrón recomendado
Estructura de solución
/src
├── Domain
├── Application
├── Infrastructure
├── Adapters.Mcp
└── Adapters.Rest (opcional)
Principios
- MCP = adapter, no core
- dominio independiente
- casos de uso testeables
- infraestructura desacoplada
- tools sin lógica
Para terminar
MCP es una pieza clave en la arquitectura de sistemas con IA.
Pero no es el sistema.
Si diseñas directamente alrededor de MCP:
- pierdes testabilidad
- pierdes control
- pierdes capacidad de evolución
Si lo usas correctamente:
- ganas interoperabilidad con agentes
- mantienes arquitectura sólida
- puedes escalar en Azure
No construyas un MCP Server.
Construye capacidades bien diseñadas y expónlas vía MCP.
Nota del autor
Una observación recurrente en proyectos recientes es que muchas de las malas prácticas en torno a MCP aparecen en desarrollos realizados en Python.
Es importante matizar que esto no es un problema del lenguaje en sí —aunque, como cualquier stack, tiene sus limitaciones—, sino principalmente una cuestión de falta de disciplina arquitectónica.
En muchos casos se detecta:
-
ausencia de separación clara entre dominio, aplicación e infraestructura
-
lógica de negocio incrustada en handlers o tools
-
falta de contratos explícitos
-
baja testabilidad desde el diseño
- falta de testing (derivado de lo anterior)
Python facilita iterar rápido, pero también facilita saltarse estructuras formales si no se imponen desde el inicio. En entornos MCP esto se agrava, porque el protocolo introduce una capa adicional de complejidad (ejecución indirecta, tools, agentes, etc.).
La conclusión no es “evitar Python”, sino:
sin un modelo de arquitectura limpia, cualquier lenguaje deriva rápidamente en sistemas difíciles de mantener, testear y escalar.
En contextos enterprise —especialmente cuando se integran agentes y MCP—, la disciplina arquitectónica deja de ser opcional.





