Skip to main content
Glama
renaisanci

mcp-clean-architecture

by renaisanci

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 API

Regla 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 UI

Por ejemplo:

MCP Tool
   |
   v
GetProductUseCase
   |
   v
ProductRepository
   ^
   |
DummyJsonProductRepository
   |
   v
DummyJSON REST API

GetProductUseCase conoce la abstracción ProductRepository.

No sabe que los productos se obtienen usando HTTP o DummyJSON.

Esto permite que:

DummyJSON

pueda ser reemplazado posteriormente por:

SQL Server
PostgreSQL
MongoDB
another REST API
mock repository

sin 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.md

Las 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
GetCartUseCase

Un 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:

ProductRepository

Infraestructura

Contiene implementaciones de aspectos técnicos externos.

Ejemplos:

HTTP clients
REST APIs
repositories
databases
cache
environment configuration
external service adapters

Por ejemplo:

ProductRepository
        ^
        |
DummyJsonProductRepository

La 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 Apps

Una herramienta MCP debe permanecer ligera.

Su responsabilidad principalmente es:

MCP Request
     |
     v
Validate / map input
     |
     v
Use Case
     |
     v
Map result
     |
     v
MCP Response

La 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 MCP

La aplicación usa MCP sobre HTTP Streamable.

MCP Host
   |
   | Streamable HTTP
   v
http://localhost:8000/mcp
   |
   v
FastMCP Server

El 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_cart

Conceptualmente:

LLM
 |
 | tool call
 v
MCP Tool
 |
 v
Use Case

Recursos

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
CartRepository

La 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_HTTP

Ejemplo:

$env:MCP_SERVER_PORT="9000"

El flujo de configuración es:

Operating System / Container
           |
           | Environment Variables
           v
EnvironmentSettings
           |
           v
server.py
           |
           v
FastMCP

Esto permite que el mismo código de aplicación se ejecute en:

Local
Development
Test
Staging
Production
Docker
Kubernetes
Cloud environments

con 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 EnvironmentSettings

en lugar de:

from infrastructure.config.environment import EnvironmentSettings

Esto reduce el acoplamiento a la estructura interna del fichero.

Conceptualmente, es similar a un TypeScript:

index.ts

usado 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#

str

string

int

int

float

double

bool

bool

None

null

list[T]

List<T>

dict[K, V]

Dictionary<K, V>

tuple[T1, T2]

Tema (T1, T2) / tupla

self

this

ABC

abstract class

@abstractmethod

abstract method

Repositorio ABC

a menudo utilizado de manera similar a IRepository

Product | None

aproximadamente Product?

Exception

Exception

raise

throw

try / except

try / catch

__init__

constructor

__init__.py

inicialización de paquete / propósito similar a los barrel exports

Pydantic BaseModel

modelo tipado + validación/serialización

@deportador

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 generation

Patró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:
        pass

Para 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
        ^
        |
DummyJsonProductRepository

APIs 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
DummyJSON

Esto 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 failures

mientras se proporciona un contrato común de error estructurado.


Jerarquía de errores

AppError
|
|-- DomainError
|   |
|   |-- ProductNotFoundError
|   `-- CartError
|
|-- ValidationError
|
`-- InfrastructureError
    |
    |-- ExternalAPIError
    `-- ExternalAPITimeoutError

Todos los errores de aplicación conocidos provienen de:

AppError

Error 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 rule

Ejemplo:

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 operation

Estos 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 unavailable

Por 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 / Presentation

en lugar de:

httpx.TimeoutException
        |
        +---------------------> MCP Host

Traducció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
ExternalAPIError

Esto 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 / Repository

Los 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 details

Esto 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                       catch

Errores 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

  1. No expongas excepciones de infraestructura en crudo directamente a los clientes MCP.

  2. No dupliques bloques try/except en cada herramienta MCP.

  3. Usa errores de dominio específicos para fallos de negocio esperados.

  4. Usa errores de validación para entradas inválidas y restricciones incumplidas.

  5. Traduce fallos técnicos externos a errores específicos de la aplicación.

  6. Conserva el contexto estructurado útil a través de details.

  7. Registra excepciones inesperadas en el límite de la aplicación.

  8. Nunca expongas secretos, tokens, stack traces, ni detalles de infraestructura sensibles a los clientes MCP.

  9. Mantén estables los códigos de error para que los clientes y pruebas automatizadas puedan confiar en ellos.

  10. 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 Tool

La 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 UI

Por ejemplo:

Unit Test
   |
   v
GetProductUseCase
   |
   v
FakeProductRepository

Esto hace que el caso de uso sea independientemente testeable.

Pruebas unitarias

Las pruebas unitarias deben centrarse en:

Domain behavior
Use Cases
Validation
Error handling

usando 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 API

y:

MCP Client
    |
    v
FastMCP Server

Esta 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+
uv

Instala/sincroniza dependencias:

uv sync

Runs the MCP server:

http://localhost:8000/mcp

Default endpoint:

http://localhost:8000/mcp

Virtual 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.
F
license - not found
Not graded
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

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

  • F
    license
    Not graded
    quality
    D
    maintenance
    A 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.
  • F
    license
    Not graded
    quality
    B
    maintenance
    A 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
  • A
    license
    Not graded
    quality
    C
    maintenance
    A production-ready template for developing Model Context Protocol (MCP) servers using Python and FastMCP.
    Apache 2.0

View all related MCP servers

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.

View all MCP Connectors

Latest Blog Posts

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