Resolved

Architectural Refactoring: Separating Payment Logic from HTTP Infrastructure

Python
FastAPI
FastMCP
Architecture
Microservices
Webhooks
Stripe
Clean Code

Payment business logic was incorrectly placed in FastAPI's HTTP layer, violating clean architecture principles. Refactored to separate business logic into domain-specific FastMCP servers, improving testability and maintainability.

Issue

Payment business logic was incorrectly implemented in the HTTP infrastructure layer (main.py) rather than in a domain-specific FastMCP server. This violated the intended three-layer architecture by mixing:

  • HTTP layer: Handling signature verification and routing.
  • Business logic: Payment processing logic, which should reside in a dedicated domain-specific server.

The tight coupling led to:

  • Duplicate logic: Payment logic was repeated across main.py and payment_mcp_server.py.
  • Testing challenges: Full HTTP stack was required to test payment logic.
  • Security risks: Stripe API keys and webhook secrets were exposed in the HTTP layer.

Culprit

The architectural misunderstanding stemmed from treating FastMCP as a secondary component rather than the primary owner of business logic. Key issues included:

  1. Improper Server Composition: The mount() pattern in FastMCP was not fully utilized, preventing proper delegation of payment logic to a dedicated domain server.
  2. Missing Domain Tool: The payment_mcp_server.py did not include a dedicated tool for handling Stripe webhooks, leading to direct processing in the HTTP layer.
  3. Direct Processing: The HTTP layer processed Stripe events directly instead of delegating to the payment domain, creating unnecessary complexity.
  4. Configuration Leak: Sensitive Stripe API keys and secrets were accessible in the HTTP layer rather than being encapsulated within the payment domain.

Solution

Domain-Specific Tool Implementation

A dedicated tool for handling Stripe webhooks was implemented in the payment domain server (payment_mcp_server.py). This tool encapsulates all payment business logic and returns structured responses:

  • Tool Design: The handle_stripe_webhook tool processes different Stripe event types (e.g., payment_intent.succeeded) and returns domain-specific actions.

Thin HTTP Infrastructure Layer

The HTTP layer (main.py) was refactored to focus exclusively on:

  1. Signature Verification: Ensuring the integrity of incoming Stripe webhooks.
  2. Deduplication: Preventing duplicate processing of events.
  3. Delegation: Routing events to the FastMCP orchestrator for domain-specific processing.

The HTTP layer delegates all payment logic to the FastMCP orchestrator, ensuring clean separation of concerns:

async with Client("/app/src/main_mcp_server.py") as mcp_client:
    result = await mcp_client.call_tool(
        "payment_handle_stripe_webhook",
        event_type=event_type,
        event_data=event_data
    )

Orchestrator Configuration

The FastMCP orchestrator was configured to properly mount the payment server, enabling namespace-based routing:

main_mcp.mount(payment_mcp, prefix="payment")  # Routes payment_* calls

Key Technical Improvements

  • 100% Business Logic Removal: Eliminated redundant payment logic from the HTTP layer.
  • Automatic Routing: Tools are now accessible via payment_handle_stripe_webhook through mounting.
  • Isolated Testing: The payment domain can be tested independently without requiring the HTTP stack.
  • Encapsulated Configuration: Stripe secrets and API keys are now fully encapsulated within the payment domain.
  • Structured Responses: Tools return standardized responses for downstream processing.

Architecture Benefits

The refactored architecture ensures:

  • FastAPI: Handles only HTTP-related concerns (e.g., routing, security).
  • FastMCP Orchestrator: Routes calls to domain-specific servers using namespace prefixes.
  • Domain Servers: Contain all business logic, improving maintainability and testability.

This approach adheres to the FastMCP 2.0 server composition pattern, where domain-specific logic is isolated and accessible through a clean, prefixed routing mechanism.