mcp-clean-architecture
FastMCP Clean Architecture — MCP App UI Template
Una plantilla orientada a producción para construir servidores MCP y aplicaciones MCP con Python y FastMCP, siguiendo Arquitectura Limpia, Inversión de Dependencias, separación de responsabilidades y prácticas modernas de Python.
El proyecto también pretende servir como referencia de aprendizaje para desarrolladores que vienen de C# / .NET.
El objetivo no es solo construir un servidor MCP que funcione, sino construir uno que siga siendo mantenible, testeable, extensible e independiente de frameworks y servicios externos.
Objetivos
Esta plantilla demuestra cómo construir una aplicación MCP con:
Python
FastMCP
Transporte Streamable HTTP
HTTP sin estado
Herramientas MCP
Recursos MCP
Prompts MCP
Aplicaciones MCP / Interfaz de la app
Arquitectura Limpia
Inversión de dependencias
Patrón Repositorio
Casos de uso
Modelos Pydantic
Integraciones con API REST externas
Configuración basada en el entorno
Comunicación HTTP asíncrona
Inyección de dependencias / Composición
Manejo centralizado de errores
Errores de aplicación estructurados
Logging
Pruebas unitarias
Pruebas de integración
El dominio de ejemplo es una aplicación de comercio electrónico.
Los productos se obtienen de una API externa pública y se exponen a través de MCP.
La aplicación evolucionará para admitir acciones como:
Buscar productos
Ver los detalles de un producto
Añadir productos al carrito
Ver el carrito
Eliminar productos del carrito
Una MCP App UI proporcionará una experiencia interactiva dentro de hosts MCP compatibles.
Arquitectura
El proyecto sigue los principios de la Arquitectura Limpia.
MCP HOST
Claude / Copilot / etc.
|
| MCP over HTTP
v
+---------------------------------------------------------+
| PRESENTATION |
| |
| FastMCP Server |
| MCP Tools |
| MCP Resources |
| MCP Prompts |
| MCP App UI |
| Error Boundary |
+---------------------------+-----------------------------+
|
v
+---------------------------------------------------------+
| APPLICATION |
| |
| Use Cases |
| |
| GetProductUseCase |
| SearchProductsUseCase |
| AddProductToCartUseCase |
| GetCartUseCase |
+---------------------------+-----------------------------+
|
v
+---------------------------------------------------------+
| DOMAIN |
| |
| Entities / Models |
| |
| Product |
| Cart |
| |
| Repository Contracts |
| |
| ProductRepository |
| CartRepository |
| |
| Domain Errors |
+---------------------------+-----------------------------+
^
|
+---------------------------+-----------------------------+
| INFRASTRUCTURE |
| |
| External API implementations |
| HTTP clients |
| Configuration |
| Persistence adapters |
| |
| DummyJsonProductRepository |
| DummyJsonCartRepository |
+---------------------------+-----------------------------+
|
v
External REST APIRegla de dependencia
La regla más importante es:
Presentation ---> Application ---> Domain
^
|
Infrastructure ----------+Las dependencias apuntan hacia el núcleo de la aplicación.
El Dominio nunca debe depender de:
FastMCP
HTTP libraries
Uvicorn
DummyJSON
Claude
Copilot
databases
environment variables
MCP App UIPor ejemplo:
MCP Tool
|
v
GetProductUseCase
|
v
ProductRepository
^
|
DummyJsonProductRepository
|
v
DummyJSON REST APIGetProductUseCase conoce la abstracción ProductRepository.
No sabe que los productos se obtienen usando HTTP o DummyJSON.
Esto permite que:
DummyJSONpueda ser reemplazado posteriormente por:
SQL Server
PostgreSQL
MongoDB
another REST API
mock repositorysin cambiar el caso de uso de la aplicación.
Estructura del proyecto
El proyecto evolucionará hacia la siguiente estructura:
mcp-clean-architecture/
|
|-- src/
| |
| |-- domain/
| | |
| | |-- entities/
| | | |-- __init__.py
| | | |-- product.py
| | | `-- cart.py
| | |
| | |-- repositories/
| | | |-- __init__.py
| | | |-- product_repository.py
| | | `-- cart_repository.py
| | |
| | `-- errors/
| | |-- __init__.py
| | `-- domain_errors.py
| |
| |-- application/
| | |
| | |-- use_cases/
| | | |-- __init__.py
| | | |-- get_product.py
| | | |-- search_products.py
| | | |-- add_product_to_cart.py
| | | `-- get_cart.py
| | |
| | `-- errors/
| | |-- __init__.py
| | `-- application_errors.py
| |
| |-- infrastructure/
| | |
| | |-- config/
| | | |-- __init__.py
| | | `-- environment.py
| | |
| | |-- http/
| | |
| | |-- repositories/
| | | |-- __init__.py
| | | |-- dummy_json_product_repository.py
| | | `-- dummy_json_cart_repository.py
| | |
| | `-- errors/
| | |-- __init__.py
| | `-- infrastructure_errors.py
| |
| `-- presentation/
| |
| `-- mcp/
| |-- __init__.py
| |-- server.py
| |
| |-- tools/
| |
| |-- resources/
| |
| |-- prompts/
| |
| `-- apps/
|
|-- tests/
| |
| |-- unit/
| `-- integration/
|
|-- .env.example
|-- .gitignore
|-- .python-version
|-- pyproject.toml
|-- uv.lock
`-- README.mdLas carpetas deben introducirse cuando tienen una responsabilidad real.
La plantilla no debe crear abstracciones solo para tener más capas.
Responsabilidades de las capas
Related MCP server: NitroStack
Dominio
Contiene los conceptos y contratos de negocio centrales.
Ejemplos:
G8
El Dominio debe contener conceptos de negocio sin saber cómo se comunica el mundo exterior con la aplicación.
Aplicación
Contiene flujos de trabajo y casos de uso específicos de la aplicación.
Ejemplos:
GetProductUseCase
SearchProductsUseCase
AddProductToCartUseCase
GetCartUseCaseUn caso de uso coordina las abstracciones del dominio.
No debe llamar directamente a una API externa.
Incorrecto
class GetProductUseCase:
def execute(self, product_id: int):
requests.get(
f"https://external-api/products/{product_id}"
)El caso de uso ahora sabe:
que existe HTTP
qué biblioteca HTTP se utiliza
qué proveedor externo se usa
cómo funciona la URL del proveedor
Preferido
class GetProductUseCase:
def __init__(self, repository: ProductRepository):
self.repository = repository
def execute(self, product_id: int) -> Product:
return self.repository.get_by_id(product_id)Ahora el caso de uso solo conoce el contrato:
ProductRepositoryInfraestructura
Contiene implementaciones de aspectos técnicos externos.
Ejemplos:
HTTP clients
REST APIs
repositories
databases
cache
environment configuration
external service adaptersPor ejemplo:
ProductRepository
^
|
DummyJsonProductRepositoryLa infraestructura implementa abstracciones del dominio.
El dominio no depende de la infraestructura.
Presentación
Contiene los puntos de entrada específicos de MCP.
Ejemplos:
FastMCP Server
MCP Tools
MCP Resources
MCP Prompts
MCP AppsUna herramienta MCP debe permanecer ligera.
Su responsabilidad principalmente es:
MCP Request
|
v
Validate / map input
|
v
Use Case
|
v
Map result
|
v
MCP ResponseLa lógica de negocio no debe vivir dentro de los decoradores de MCP.
Arquitectura MCP
MCP y FastMCP son conceptos diferentes.
MCP
|
`-- Protocol
FastMCP
|
`-- Python framework implementing MCPLa aplicación usa MCP sobre HTTP Streamable.
MCP Host
|
| Streamable HTTP
v
http://localhost:8000/mcp
|
v
FastMCP ServerEl servidor está configurado por defecto para ejecutar HTTP sin estado.
Componentes MCP
Herramientas
Acciones que el modelo puede ejecutar.
Ejemplos:
get_product
search_products
add_product_to_cart
get_cart
remove_product_from_cartConceptualmente:
LLM
|
| tool call
v
MCP Tool
|
v
Use CaseRecursos
Los recursos exponen datos o contexto que un host MCP puede leer.
No deben convertirse en un reemplazo de la lógica de negocio de la aplicación.
Los prompts proporcionan plantillas de prompts reutilizables a través de MCP.
Pertenecen al límite de MCP / Presentación.
MCP App UI
Las MCP Apps permiten que los hosts MCP compatibles muestren una interfaz interactiva asociada con la funcionalidad de MCP.
Nuestro ejemplo de comercio electrónico eventualmente renderizará algo conceptualmente similar a:
[ Add to cart ]La regla arquitectónica importante es:
La MCP App UI es una preocupación de Presentación.
La UI no debe implementar reglas de negocio.
Por ejemplo, hacer clic en:
[ Add to cart ]debería resultar en:
MCP App UI
|
v
MCP Tool
|
v
AddProductToCartUseCase
|
v
CartRepositoryLa UI no manipula la infraestructura directamente.
Configuración del entorno
La configuración en tiempo de ejecución debe provenir de variables de entorno en lugar de estar codificada.
Variables actuales:
MCP_SERVER_TRANSPORT
MCP_SERVER_HOST
MCP_SERVER_PORT
MCP_STATELESS_HTTPEjemplo:
$env:MCP_SERVER_PORT="9000"El flujo de configuración es:
Operating System / Container
|
| Environment Variables
v
EnvironmentSettings
|
v
server.py
|
v
FastMCPEsto permite que el mismo código de aplicación se ejecute en:
Local
Development
Test
Staging
Production
Docker
Kubernetes
Cloud environmentscon diferente configuración.
Los secretos nunca deben confirmarse en Git.
Convenciones de paquetes de Python
__init__.py puede ser utilizado para definir la API pública de un paquete de Python.
Por ejemplo:
from infrastructure.config.environment import EnvironmentSettings
__all__ = [
"EnvironmentSettings",
]Los consumidores pueden usar:
from infrastructure.config import EnvironmentSettingsen lugar de:
from infrastructure.config.environment import EnvironmentSettingsEsto reduce el acoplamiento a la estructura interna del fichero.
Conceptualmente, es similar a un TypeScript:
index.tsusado como exportación de barrel (barrel file).
__all__ define la API pública prevista.
No es un modificador de acceso como public o private en C#.
Referencia Python / C#
Este proyecto también está pensado para ayudar a los desarrolladores .NET a aprender Python.
Python | Concepto de C# |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| Tema (T1, T2) / tupla |
|
|
|
|
|
|
Repositorio | a menudo utilizado de manera similar a |
| aproximadamente |
|
|
|
|
|
|
| constructor |
| inicialización de paquete / propósito similar a los barrel exports |
Pydantic | modelo tipado + validación/serialización |
| conceptualmente similar a atributos/comportamiento de middleware según el uso |
Cuando se introduzcan nuevos conceptos de Python, se deben documentar sus equivalentes en C# cuando sea útil.
Modelos de Dominio
Los modelos estructurados usan Pydantic cuando la validación y la serialización son útiles.
Ejemplo:
from typing import Annotated
from pydantic import BaseModel
class Product(BaseModel):
id: Annotated[int, "Product identifier"]
title: Annotated[str, "Product title"]
description: Annotated[str, "Product description"]
price: Annotated[float, "Product price"]
thumbnail: Annotated[str, "Product thumbnail URL"]Pydantic proporciona:
validation
type coercion
serialization
JSON-compatible output
JSON Schema generationPatrón Repositorio
Los repositorios representan abstracciones sobre datos o sistemas externos.
Ejemplo:
from abc import ABC, abstractmethod
from domain.entities import Product
class ProductRepository(ABC):
@abstractmethod
def get_by_id(self, product_id: int) -> Product:
passPara un desarrollador de C#, esto es conceptualmente similar a:
public interface IProductRepository
{
Product GetById(int productId);
}Una implementación concreta de Infrastructure puede entonces proporcionar el comportamiento real:
ProductRepository
^
|
DummyJsonProductRepositoryAPIs externas
Las APIs externas deben ser accedidas desde la infraestructura.
La implementación inicial usa la API Pública de DummyJSON para el ejemplo de e-commerce.
La arquitectura previene que los casos de uso dependan directamente de DummyJSON.
Application
|
v
ProductRepository
^
|
Infrastructure implementation
|
v
DummyJSONEsto permite reemplazar el proveedor externo sin reescribir la aplicación o las capas de dominio.
Estrategia de manejo de errores
El proyecto usa una jerarquía de excepciones centralizada inspirada en Arquitectura Limpia y patrones comunes de .NET para el manejo de errores.
El objetivo es distinguir:
expected business failures
vs
technical/infrastructure failuresmientras se proporciona un contrato común de error estructurado.
Jerarquía de errores
AppError
|
|-- DomainError
| |
| |-- ProductNotFoundError
| `-- CartError
|
|-- ValidationError
|
`-- InfrastructureError
|
|-- ExternalAPIError
`-- ExternalAPITimeoutErrorTodos los errores de aplicación conocidos provienen de:
AppErrorError base de la aplicación
from typing import Any
class AppError(Exception):
error_code: str = "UNKNOWN_ERROR"
def __init__(
self,
message: str,
details: dict[str, Any] | None = None,
):
self.message = message
self.details = details or {}
super().__init__(message)
def to_dict(self) -> dict:
return {
"error_code": self.error_code,
"error_type": self.__class__.__name__,
"message": self.message,
"details": self.details,
}Conceptualmente, esto es similar a:
public abstract class AppException : Exception
{
public string ErrorCode { get; }
protected AppException(
string message,
string errorCode)
: base(message)
{
ErrorCode = errorCode;
}
}Errores de dominio
Los errores de dominio representan fallos de negocio esperados.
Ejemplos:
Product does not exist
Cart is empty
Product cannot be added to the cart
Requested quantity violates a business ruleEjemplo:
class DomainError(AppError):
error_code = "DOMAIN_ERROR"
class ProductNotFoundError(DomainError):
error_code = "PRODUCT_NOT_FOUND"
def __init__(self, product_id: int):
super().__init__(
message=f"Product '{product_id}' was not found.",
details={
"product_id": product_id,
},
)Conceptualmente similar a:
public class ProductNotFoundException : DomainException
{
public int ProductId { get; }
public ProductNotFoundException(int productId)
: base($"Product '{productId}' was not found.")
{
ProductId = productId;
}
}Errores de validación
Los errores de validación representan entrada de aplicación inválida o restricciones incumplidas.
Ejemplos:
Invalid product ID
Quantity must be greater than zero
Missing required input
Invalid cart operationEstos son fallos esperados.
Deben proporcionar suficiente información estructurada para que el host MCP o LLM entienda que se debe corregir.
Errores de infraestructura
Los errores de infraestructura representan fallos que involucran dependencias técnicas.
Ejemplos:
External API unavailable
HTTP timeout
Connection failure
Unexpected downstream response
Database unavailablePor ejemplo:
class InfrastructureError(AppError):
error_code = "INFRASTRUCTURE_ERROR"
class ExternalAPIError(InfrastructureError):
error_code = "EXTERNAL_API_ERROR"El dominio no debe depender de excepciones de infraestructura.
Las excepciones crudas de bibliotecas no deben filtrarse por toda la aplicación.
Por ejemplo:
httpx.TimeoutException
|
v
ExternalAPITimeoutError
|
v
Application / Presentationen lugar de:
httpx.TimeoutException
|
+---------------------> MCP HostTraducción de errores
La infraestructura es responsable de traducir las fallas técnicas de bajo nivel cuando sea apropiado.
Por ejemplo:
HTTP 404 from product provider
|
v
ProductNotFoundError
HTTP timeout
|
v
ExternalAPITimeoutError
HTTP 500
|
v
ExternalAPIErrorEsto evita que el resto de la aplicación no se apoye en un biblioteca HTTP particular.
Límite de errores de presentación
Las herramientas MCP no deben contener duplicación en manejo de errores.
Evita:
@mcp.tool
def tool_one():
try:
...
except AppError:
...
@mcp.tool
def tool_two():
try:
...
except AppError:
...
@mcp.tool
def tool_three():
try:
...
except AppError:
...La arquitectura deseada es:
MCP Host
|
v
Presentation Error Boundary
|
v
MCP Tool
|
v
Use Case
|
v
Domain / RepositoryLos errores conocidos de la aplicación pueden convertirse en errores estructurados compatibles con MCP.
Las excepciones inesperadas deben ser:
logged
|
v
converted to generic internal error
|
v
returned without sensitive detailsEsto es conceptualmente similar a ASP.NET Core:
Python / MCP ASP.NET Core
AppError AppException
DomainError DomainException
InfrastructureError InfrastructureException
central error boundary IExceptionHandler / Middleware
raise throw
except catchErrores estructurados
Los errores deben contener información estructurada cuando sea útil.
Ejemplo:
{
"error_code": "PRODUCT_NOT_FOUND",
"error_type": "ProductNotFoundError",
"message": "Product '123' was not found.",
"details": {
"product_id": 123
}
}Los errores estructurados mejoran:
el comportamiento del cliente MCP
el razonamiento del LLM
logging
observabilidad
pruebas automáticas
depuración
Reglas de manejo de errores
No expongas excepciones de infraestructura en crudo directamente a los clientes MCP.
No dupliques bloques
try/excepten cada herramienta MCP.Usa errores de dominio específicos para fallos de negocio esperados.
Usa errores de validación para entradas inválidas y restricciones incumplidas.
Traduce fallos técnicos externos a errores específicos de la aplicación.
Conserva el contexto estructurado útil a través de
details.Registra excepciones inesperadas en el límite de la aplicación.
Nunca expongas secretos, tokens, stack traces, ni detalles de infraestructura sensibles a los clientes MCP.
Mantén estables los códigos de error para que los clientes y pruebas automatizadas puedan confiar en ellos.
La presentación es responsable de traducir los errores de aplicación en respuestas compatibles con MCP.
Inyección de dependencias y composición
Las dependencias deben ser explícitas.
Por ejemplo:
DummyJsonProductRepository
|
v
GetProductUseCase
|
v
MCP ToolLa composición / cableado raíz pertenece cerca del punto de entrada de la aplicación, no dentro del dominio.
El proyecto debe evitar dependencias globales ocultas cuando sea posible.
Esto se introducirá incrementalmente a medida que crezca la aplicación.
Estrategia de pruebas
La arquitectura debe permitir probar el comportamiento de negocio sin:
starting FastMCP
calling DummyJSON
opening an HTTP port
running MCP App UIPor ejemplo:
Unit Test
|
v
GetProductUseCase
|
v
FakeProductRepositoryEsto hace que el caso de uso sea independientemente testeable.
Pruebas unitarias
Las pruebas unitarias deben centrarse en:
Domain behavior
Use Cases
Validation
Error handlingusando dependencias falsas o de simulación o mocks.
Integrated Tests
Las pruebas de integración pueden validar límites de integración por separado:
Infrastructure
|
v
DummyJSON APIy:
MCP Client
|
v
FastMCP ServerEsta separación evita que el comportamiento de la API externa vuelva poco confiable a todas las pruebas de negocio.
Construcción del entorno de desarrollo
Requisitos:
Python 3.12+
uvInstala/sincroniza dependencias:
uv syncRuns the MCP server:
http://localhost:8000/mcpDefault endpoint:
http://localhost:8000/mcpVirtual Environment
The project uses:
.venv/for isolated Python dependencies.
uv manages the project environment automatically.
Wait, I notice I made a mistake: in line "GXP18" repeated twice because I lost count. Need be extremely careful to include all GXP tokens exactly once and in order. I need go through and map.
Let's list GXP tokens:
1 GXP1
2 GXP2
3 GXP3
4 GXP4
5 GXP5
6 GXP6
7 GXP7
8 GXP8
9 GXP9
10 GXP10
11 GXP11
12 GXP12
13 GXP13
14 GXP14
15 GXP15
16 GXP16
17 GXP17
18 GXP18
19 GXP19
20 GXP20
21 GXP21
22 GXP22
23 GXP23
24 GXP24
25 GXP25
26 GXP26
27 GXP27
28 GXP28
29 GXP29
30 GXP30
31 GXP31
32 GXP32
33 GXP33
34 GXP34
35 GXP35
36 GXP36
37 GXP37
38 GXP38
39 GXP39
40 GXP40
41 GXP41
42 GXP42
43 GXP43
44 GXP44
45 GXP45
46 GXP46
47 GXP47
48 GXP48
49 GXP49
50 GXP50
51 GXP51
52 GXP52
53 GXP53
54 GXP54
55 GXP55
56 GXP56
57 GXP57
58 GXP58
59 GXP59
60 GXP60
61 GXP61
62 GXP62
63 GXP63
64 GXP64
65 GXP65
66 GXP66
67 GXP67
Need ensure each appears exactly once and order. My draft might have errors: I used "G (missing)???", "GXP12" etc. Need now craft final response carefully. Since this platform doesn't let me preview actual output? I will write final answer as a single block. I'll need to not accidentally repeat or omit.
Let's create a clean sequence from input, replicating with translations. I'll use a mental checklist. You can in final output maintain the GXP tokens. Let's go through the input segments in order:
1. Title
2. Paragraph
3.
4. ## Goals
5. bullet list
6. paragraph "The sample domain ..."
7. paragraph "Products are retrieved ..."
8. paragraph "The application will evolve..."
9. list (Search products etc)
10. paragraph "An MCP App UI..."
11. # Architecture
12. paragraph "The project follows"
13. GXP1
14. ***
15. # Dependency Rule
16. paragraph "The most important rule is:"
17. GXP2
18. paragraph "Dependencies point..."
19. paragraph "The **Domain must never depend on**:"
20. GXP3
21. paragraph "For example:"
22. GXP4
23. paragraph "`GetProductUseCase` knows..."
24. paragraph "It does **not** know..."
25. paragraph "This allows:"
26. tx, GXP5
27. paragraph "to later be replaced with:"
28. GXP6
29. paragraph "without changing..."
30. ***
31. # Project Structure
32. paragraph "The project will evolve..."
33. GXP7
34. paragraph "Folders should be introduced..."
35. paragraph "The template should not create..."
36. ***
37. # Layer Responsibilities
38. ## Domain
39. paragraph... Wait original has "## Domain" and then text "Contains..." etc. We need include all.
40. ## Application
41. ### Bad
42. GXP10
43. text then bullet list
44. ### Preferred
45. GXP11...
46. etc.
We need make sure GXP8, GXP9 included. Let's go recursively.
I'll now rewrite final translation from scratch, ensuring all GXP tokens are in sequence.
Let's also address previous "GXP1" appears after # Architecture. Good.
I'll begin final# FastMCP Clean Architecture — MCP App UI Template
Una plantilla orientada a producción para construir **servidores MCP y aplicaciones MCP con Python y FastMCP**, siguiendo los principios de **Clean Architecture**, Inversión de Dependencias, separación de responsabilidades y prácticas modernas de Python.
El proyecto también pretende servir como referencia de aprendizaje para desarrolladores que provienen de **C# / .NET**.
> El objetivo no es solo construir un servidor MCP que funcione, sino construir uno que siga siendo mantenible, testeable, extensible e independiente de los framework y servicios externos.
***
## Objetivos
Esta plantilla muestra cómo construir una aplicación MCP con:
* Python
* FastMCP
* Transporte HTTP Streamable
* HTTP sin estado
* Herramientas MCP
* Recursos MCP
* Prompts MCP
* Aplicaciones MCP / Interfaz de la app
* Arquitectura limpia
* Inversión de dependencias
* Patrón de repositorio
* Casos de uso
* Modelos Pydantic
* Integraciones con APIs REST externas
* Configuración basada en el entorno
* Comunicación HTTP asíncrona
* Inyección de dependencias / composición
* Manejo centralizado de errores
* Errores de aplicación estructurados
* Logging
* Pruebas unitarias
* Pruebas de integración
El dominio de ejemplo es una **aplicación de comercio electrónico**.
Los productos se obtienen desde una API externa pública y se exponen a través de MCP.
La aplicación se ampliará para admitir acciones como:
* Buscar productos
* Ver los detalles de un producto
* Añadir productos al carrito
* Ver el carrito
* Eliminar productos del carrito
Una **MCP App UI** ofrecerá una experiencia interactiva dentro de hosts MCP compatibles.
***
# Arquitectura
El proyecto sigue los principios de la arquitectura limpia.
GXP1
***
# Regla de dependencia
La regla más importante es:
GXP2
Las dependencias apuntan hacia el núcleo de la aplicación.
El **Dominio no debe depender nunca de**:
GXP3
Por ejemplo:
GXP4
`GetProductUseCase` conoce la abstracción `ProductRepository`.
No **sabe** que los productos se obtienen usando HTTP o DummyJSON.
Esto permite que:
GXP5
se reemplace más tarde por:
GXP6
sin cambiar el caso de uso de la aplicación.
***
# Estructura del proyecto
El proyecto evolucionará hacia la siguiente estructura:
GXP7
Las carpetas deben introducirse cuando tienen una responsabilidad real.
La plantilla no debe crear abstracciones solo por tener más capas.
***
# Responsabilidades de las capas
## Dominio
Contiene los conceptos y contratos de negocio fundamentales.
Ejemplos:
GXP8
El dominio debe contener conceptos de negocio sin saber cómo el mundo exterior se comunica con la aplicación.
***
## Aplicación
Contiene los flujos de trabajo y los casos de uso específicos de la aplicación.
Ejemplos:
GXP9
Un caso de uso coordina abstracciones de dominio.
No debe llamar directamente a una API externa.
### Incorrecto
GXP10
El caso de uso ahora sabe:
* que HTTP existe
* cuál biblioteca HTTP se usa
* qué proveedor externo se usa
* qué proveedor habe URL del proveedor
### Preferido
GXP11
Ahora, el caso de uso solo conoce el contrato:
GXP12
***
## Infraestructura
Contiene las implementaciones para las preocupaciones técnicas externas.
Ejemplos:
GXP13
Por ejemplo:
GXP14
La infraestructura implementa las abstracciones del dominio.
El dominio no depende de la infraestructura.
***
## Presentación
Contiene los puntos de entrada específicos de MCP.
Ejemplos:
GXP15
Una herramienta MCP debe mantenerse ligera.
Su responsabilidad es principalmente:
GXP16
La lógica de negocio no debe vivir dentro de los decoradores de MCP.
***
# Arquitectura MCP
MCP y FastMCP son conceptos diferentes.
GXP17
La aplicación utiliza MCP sobre **Streamable HTTP**.
GXP18
El servidor está configurado por defecto para ejecutarse con HTTP sin estado.
***
# Componentes MCP
## Herramientas
Acciones que el modelo puede ejecutar.
Ejemplos:
GXP19
Conceptualmente:
GXP20
***
## Recursos
Los recursos exponen datos que un host MCP puede leer.
No deberían convertirse en un reemplazo de la lógica de negocio de la aplicación.
***
## Prompts
Los prompts proporcionan plantillas de prompts reutilizables a través de MCP.
Pertenecen al límite de MCP / Presentación.
***
# Interfaz de la app MCP
Las *MCP Apps* permiten a los hosts MCP compatibles mostrar una interfaz de usuario interactiva asociada a la funcionalidad MCP.
Nuestro ejemplo de comercio electrónico terminará representando algo conceptualmente similar a:
GXP21
La regla arquitectónica clave es:
> La interfaz de la app MCP es una preocupación de presentación.
La interfaz no debe implementar reglas de negocio.
Por ejemplo, al hacer clic en:
GXP22
debería resultar en:
GXP23
La interfaz no manipula la infraestructura directamente.
***
# Configuración del entorno
La configuración en tiempo de ejecución debe venir de las variables de entorno en lugar de estar escrita en el código.
Variables actuales:
GXP24
Ejemplo:
GXP25
El flujo de configuración es:
GXP26
Esto permite que el mismo código de la aplicación se ejecute en:
GXP27
con diferente configuración.
Los secretos no deben verse nunca en Git.
***
# Convenciones de paquetes Python
El archivo `__init__.py` puede usarse o definir la API pública de un paquete Python.
Por ejemplo:
GXP28
Los consumidores pueden entonces usar:
GXP29
en lugar de:
GXP30
Este reduce el acoplamiento a la estructura interna de archivos.
Conceptualmente es similar a un TypeScript:
GXP31
utilizado como exportación de barril (barrel export).
`__all__` hace referencia a la API pública prevista.
No es un modificador de acceso como `public` o `private` en C#.
***
# Referencia Python / C#
Este proyecto también está pensado para ayudar a los programadores .NET a aprender Python.
| Python | Concepto de C# |
| ---------------------- | --------------------------------------------------------------------------------------- |
| `str` | `string` |
| `int` | `int` |
| `float` | `double` |
| `bool` | `bool` |
| `None` | `null` |
| `list[T]` | `List<T>` |
| `dict[K, V]` | `Dictionary<K, V>` |
| `tuple[T1, T2]` | aproximadamente `(T1, T2)` / tupla |
| `self` | `this` |
| `ABC` | `abstract class` |
| `@abstractmethod` | `método abstracto` |
| Repositorio `ABC` | a menudo se usa de manera similar a `IRepository` |
| `Product \| None` | aproximadamente `Product?` |
| `Exception` | `Exception` |
| `raise` | `throw` |
| `try / QoS` | `try / catch` |
| `__init__` | constructor |
| `__init__.py` | inicialización del paquete / similar a los barrel exports |
| Pydantic `BaseModel` | modelo con tipos + validación/serialización |
| `@decorator` | similar a `attributes` / middleware según el uso |
Cuando se introduzcan nuevos conceptos de Python, se deben documentar sus equivalentes en C# cuando sea útil.
***
# Modelo de dominio
Los modelos estructurados usan Pydantic cuando la validación y la serialización son útiles.
Ejemplo:
GXP32
Pydantic proporciona:
GXP33
***
# Patrón de repositorio
Los repositorios representan abstracciones sobre los datos o los sistemas externos.
Ejemplo:
GXP34
Para un desarrollador de C#, es conceptualmente similar a:
GXP35
Una implementación concreta en Infrastructure puede proporcionarse menos tarde el comportamiento real:
GXP36
***
# APIs externas
El acceso a las APIs externas debe realizarse desde la infraestructura.
La primera implementación usa la API pública de **DummyJSON** para el ejemplo de e-commerce.
La arquitectura evita que los casos de uso dependan directamente de DummyJSON.
GXP37
Esto permite que el proveedor externo se reemplace posteriormente sin reescribir las capas de Aplicación o Dominio.
***
# Estrategia de manejo de errores
El proyecto usa una jerarquía de excepciones centralizada inspirada en Clean Architecture y en los patrones comunes de manejo de excepciones en .NET.
El objetivo es distinguir:
GXP38
mientras se proporciona un contrato de error estructurado común.
***
## jerarquía de errores
GXP39
Todos los errores de aplicación conocidos finalmente derivan de:
GXP40
***
## Error base de la aplicación
GXP41
Esto es conceptualmente similar a C#:
GXP42
***
## Errores de dominio
Los errores de dominio representan fallos de negocio esperados.
Ejemplos:
GXP43
Ejemplo:
GXP44
## Similar a:
GXP45
***
## Errores de validación
Los errores de validación representan entrada inválida de la aplicación o restricciones violadas.
Ejemplos:
GXP46
Estos son fallos esperados.
Deben proporcionar suficiente información estructurada para que el host MCP o el LLM comprenden lo que se podemos corregir.
***
## Errores de infraestructura
Los errores de infraestructura representan fallos que implica las dependencias técnicas.
Ejemplos:
GXP47
Por ejemplo:
GXP48
El dominio no debe depender de las excepciones de infraestructura.
Las excepciones crudas de las biblioteca no deben filtrarse por toda la aplicación.
Por ejemplo:
GXP49
en lugar de:
GXP50
***
# Traducción de errores
La infraestructura tiene la responsabilidad de traducir los fallos técnicos de bajo level cuando sea apropiado.
Por ejemplo:
GXP51
Esto evita que el resto de la aplicación quede acoplado a una biblioteca HTTP específica.
***
# Límite de errores en la presentación
Las herramientas MCP no deben contener manejo de errores duplicado.
Evita:
GXP52
La arquitectura deseada es:
GXP53
Los errores de aplicación conocidos pueden convertirse en errores estructurados amigables con MCP.
Las excepciones inesperadas deben ser:
GXP54
Esto es conceptualmente similar a ASP.NET Core:
GXP55
***
# Errores estructurados
Los errores deben contener información estructurada cuando sea útil.
Ejemplo:
GXP56
Los errores estructurados mejoran:
* el comportamiento del cliente MCP
* el razonamiento del LLM
* un log
* la observabilidad
* las pruebas automáticas
* la depuración
***
# Reglas de manejo de errores
1. No debes exponer excepciones de infraestructura sin procesar directamente a los clientes MCP.
2. No dupliques los bloques `try/except` en cada herramienta MCP.
3. Usa los errores de dominio específicos para los fallos de negocio esperado.
4. Usa errores de validación para entradas no validables y restricciones incumplidas.
5. Traduce los fallos técnicos externos en errores específicos de la aplicación.
6. Preserva contexto estructurado útil mediante `details`.
7. Registra las excepciones inesperadas el límite de la aplicación.
8. Nunca expongas secretos, tokens, stack traces, ni detalles sensibles de infraestructura a los clientes MCP.
9. Mantén estables los códigos de error para que los clientes y las pruebas automáticas puedan confiar en ellos.
10. La presentación es responsable de traducir los errores de la aplicación en respuestas compatibles con MCP.
***
# Inyección y composición de dependencias
Las dependencias deben ser explícitas.
Por ejemplo:
GXP57
La configuración de la raíz/composición se encuentra cerca del punto de entrada de la aplicación, no en el dominio.
El proyecto debe evitar dependencias globales ocultas cuando sea práctico.
Esto se introducirá de forma incremental a medida que la aplicación crezca.
***
# Estrategia de testing
La arquitectura debe permitir probar el comportamiento de negocio sin depender de:
GXP58
Por ejemplo:
GXP59
Esto hace que el caso de uso sea independientemente testeable.
***
## Pruebas unitarias
Las pruebas unitarias deben enfocarse en:
GXP60
con dependencias falsas o simulacros (mock).
***
## Pruebas de integración
Las pruebas de integración
pueden validar límites por separado:
GXP61
y:
GXP62
Esta separación evita que el comportamiento de una API externa haga que cada prueba de negocio sea poco fiable.
***
# Configuración de desarrollo
Requisitos:
GXP63
Instale o sincronice las dependencias:
GXP64
Ejecute el servidor MCP:
GXP65
Endpoint por defecto:
GXP66
***
# Entorno virtual
El proyecto usa:
GXP67
para las dependencias aisladas de Python.
`uv` administra el entorno del proyecto automáticamente.
Los comandos generalmente deben ejecutarse usando:
GXP68
Por ejemplo:
GXP69
Esto evita depender de dependencias del proyecto instaladas globalmente.
***
# Principios de Desarrollo
Al extender esta plantilla:
1. Mantén el código específico de MCP en la capa de Presentación.
2. Mantén los flujos de trabajo de negocio en la capa de Aplicación.
3. Mantén los modelos de negocio y contratos independientes de los frameworks cuando sea práctico.
4. Mantén las integraciones externas en la capa de Infraestructura.
5. Depende de abstracciones en lugar de implementaciones concretas de Infraestructura.
6. Mantén las herramientas MCP delgadas.
7. No codifiques de forma fija la configuración específica del entorno.
8. No subas secretos al repositorio.
9. Prefiere Python tipado.
10. Valida los datos externos en los límites del sistema.
11. Mantén los DTOs de API externa separados de los modelos de Dominio cuando sus estructuras divergen.
12. Haz que los Casos de Uso sean probables de forma independiente.
13. Prefiere dependencias explícitas sobre estado global oculto.
14. Añade abstracciones cuando resuelvan un problema arquitectónico real.
15. Mantén el Dominio independiente de FastMCP.
16. Traduce los fallos de Infraestructura antes de exponerlos fuera de su límite.
17. Usa códigos de error estructurados y estables.
18. Mantén la UI de la App MCP enfocada en la presentación e interacción.
19. No pongas lógica de negocio dentro de los decoradores de MCP.
20. Mantén la API externa reemplazable.
***
# Flujo de Aprendizaje Planificado
La plantilla se está construyendo de forma incremental.
GXP70
***
# Objetivo Final
El proyecto final debe demostrar el flujo completo:
GXP71
con los errores fluyendo de forma segura en la dirección opuesta:
GXP72
***
# Propósito
Este repositorio está destinado a convertirse en una **plantilla y referencia de aprendizaje reutilizable para crear servidores FastMCP y Apps MCP de calidad de producción utilizando Arquitectura Limpia**.
El proyecto demuestra cómo MCP puede tratarse como un límite de aplicación en lugar de permitir que las preocupaciones específicas de MCP se extiendan por todo el código base.
La lógica de negocio central debe permanecer independiente de:
GXP73
Esto hace que la aplicación sea más fácil de:
GXP74
mientras se preservan límites arquitectónicos claros.This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceA Model Context Protocol server that enables AI assistants to interact with a complete e-commerce application, providing authentication, product browsing, and shopping cart management through standardized MCP tools.

NitroStackofficial
FlicenseNot gradedqualityBmaintenanceA Python framework for building MCP servers with modular architecture, dependency injection, and built-in authentication. Enables creating scalable, testable MCP services with features like pipeline interceptors and background tasks.3- AlicenseNot gradedqualityCmaintenanceA production-ready template for developing Model Context Protocol (MCP) servers using Python and FastMCP.Apache 2.0
- FlicenseNot gradedqualityCmaintenanceThis enterprise MCP server template provides a production-ready, architecture-first foundation for building MCP servers in Python, with capability registry, dependency injection, and Docker support.
Related MCP Connectors
FastMCP commerce server starter: product catalog, search, and checkout. Deploy to Vercel in 5 min.
Hosted Amazon Seller and Vendor MCP server for Claude, ChatGPT, Cursor, Codex, Gemini, Copilot.
MCP Server for Slima - AI Writing IDE for Novel Authors with AI Beta Reader.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/renaisanci/mcp-clean-architecture'
If you have feedback or need assistance with the MCP directory API, please join our Discord server