1212
1313from loguru import logger
1414from mcp .server .fastmcp import FastMCP
15+ from pydantic import BaseModel , Field
1516
1617from swarms .structs .agent import Agent
1718from swarms .structs .omni_agent_types import AgentType
1819from swarms .tools .mcp_client_tools import (
1920 get_tools_for_multiple_mcp_servers ,
2021)
2122
23+ # Optional x402 and Starlette imports
24+ try :
25+ from starlette .middleware .base import BaseHTTPMiddleware
26+ from starlette .requests import Request
27+ from x402 .fastapi .middleware import require_payment
28+
29+ X402_AVAILABLE = True
30+ except ImportError :
31+ X402_AVAILABLE = False
32+
33+
34+ class PaymentConfig (BaseModel ):
35+ """
36+ Configuration for x402 cryptocurrency payment integration.
37+
38+ This enables monetization of AI agent endpoints by requiring payment
39+ before execution. Payments are processed via x402 protocol on Solana blockchain.
40+
41+ Attributes:
42+ pay_to_address: Solana wallet address to receive cryptocurrency payments
43+ price: Cost per agent request (e.g., "$0.01", "$0.05")
44+ network_id: Blockchain network identifier (default: "solana" for Solana mainnet)
45+ description: Optional description of the payment service for users
46+ """
47+
48+ pay_to_address : str = Field (
49+ ...,
50+ description = "Solana wallet address to receive payments" ,
51+ )
52+ price : str = Field (
53+ default = "$0.01" ,
54+ description = "Price per agent request in USD (e.g., '$0.01')" ,
55+ )
56+ network_id : str = Field (
57+ default = "solana" ,
58+ description = "Blockchain network ID (default: 'solana' for mainnet, or 'solana-devnet' for testing)" ,
59+ )
60+ description : Optional [str ] = Field (
61+ None ,
62+ description = "Service description shown to users during payment" ,
63+ )
64+
65+
66+ if X402_AVAILABLE :
67+
68+ class X402PaymentMiddleware (BaseHTTPMiddleware ):
69+ """
70+ Starlette middleware that wraps x402 payment validation.
71+
72+ Intercepts HTTP requests and applies x402 payment requirement
73+ to specified paths (MCP tool execution paths).
74+ """
75+
76+ def __init__ (self , app , payment_config : PaymentConfig ):
77+ """
78+ Initialize x402 payment middleware.
79+
80+ Args:
81+ app: Starlette app instance
82+ payment_config: Payment configuration with wallet, price, network
83+ """
84+ super ().__init__ (app )
85+ self .payment_config = payment_config
86+ # Create x402 payment middleware for MCP path
87+ self .payment_validator = require_payment (
88+ path = "/mcp" , # FastMCP streamable-http path
89+ price = payment_config .price ,
90+ pay_to_address = payment_config .pay_to_address ,
91+ network_id = payment_config .network_id ,
92+ description = payment_config .description
93+ or "AI Agent execution via MCP" ,
94+ input_schema = {
95+ "type" : "object" ,
96+ "properties" : {"task" : {"type" : "string" }},
97+ },
98+ output_schema = {
99+ "type" : "object" ,
100+ "properties" : {"result" : {"type" : "string" }},
101+ },
102+ )
103+
104+ async def dispatch (self , request : Request , call_next ):
105+ """
106+ Intercept requests and apply x402 payment validation.
107+
108+ Args:
109+ request: Incoming HTTP request
110+ call_next: Next middleware in chain
111+
112+ Returns:
113+ Response from payment validator or next middleware
114+ """
115+ # Check if request path requires payment (MCP paths)
116+ if request .url .path .startswith ("/mcp" ):
117+ # Apply x402 payment validation
118+ return await self .payment_validator (request , call_next )
119+
120+ # Other paths don't require payment
121+ return await call_next (request )
122+
22123
23124class TaskStatus (Enum ):
24125 """Status of a task in the queue."""
@@ -597,6 +698,8 @@ def __init__(
597698 max_network_retries : int = 5 ,
598699 network_retry_delay : float = 10.0 ,
599700 network_timeout : float = 30.0 ,
701+ payment : bool = False ,
702+ payment_config : Optional [PaymentConfig ] = None ,
600703 log_level : Literal [
601704 "DEBUG" , "INFO" , "WARNING" , "ERROR" , "CRITICAL"
602705 ] = "INFO" ,
@@ -628,7 +731,22 @@ def __init__(
628731 max_network_retries: Maximum number of network reconnection attempts
629732 network_retry_delay: Delay between network retry attempts in seconds
630733 network_timeout: Network connection timeout in seconds
734+ payment: Enable x402 cryptocurrency payment for agent endpoints
735+ payment_config: Configuration for x402 payment (required if payment=True)
631736 """
737+ # Validate payment configuration
738+ if payment and not payment_config :
739+ raise ValueError (
740+ "payment_config is required when payment=True. "
741+ "Please provide a PaymentConfig instance with pay_to_address."
742+ )
743+
744+ if payment and not X402_AVAILABLE :
745+ raise ImportError (
746+ "x402 package is required for payment functionality. "
747+ "Install it with: pip install x402"
748+ )
749+
632750 self .server_name = server_name
633751 self .description = description
634752 self .verbose = verbose
@@ -648,6 +766,8 @@ def __init__(
648766 self .max_network_retries = max_network_retries
649767 self .network_retry_delay = network_retry_delay
650768 self .network_timeout = network_timeout
769+ self .payment = payment
770+ self .payment_config = payment_config
651771
652772 # Persistence state tracking
653773 self ._restart_count = 0
@@ -671,6 +791,39 @@ def __init__(
671791 ** kwargs ,
672792 )
673793
794+ # Patch streamable_http_app to add x402 payment middleware
795+ if self .payment and self .payment_config :
796+ if X402_AVAILABLE :
797+ # Store original streamable_http_app
798+ original_streamable_http_app = (
799+ self .mcp_server .streamable_http_app
800+ )
801+ payment_config = self .payment_config
802+
803+ # Create patched version that adds middleware
804+ def patched_streamable_http_app ():
805+ app = original_streamable_http_app ()
806+ app .add_middleware (
807+ X402PaymentMiddleware ,
808+ payment_config = payment_config ,
809+ )
810+ return app
811+
812+ # Replace streamable_http_app with patched version
813+ self .mcp_server .streamable_http_app = (
814+ patched_streamable_http_app
815+ )
816+
817+ logger .info (
818+ f"Added x402 payment middleware (Solana): "
819+ f"price={ self .payment_config .price } , "
820+ f"wallet={ self .payment_config .pay_to_address } "
821+ )
822+ else :
823+ logger .error (
824+ "x402 payment enabled but middleware not available"
825+ )
826+
674827 # Configure logger
675828 logger .remove () # Remove default handler
676829 logger .add (
@@ -681,7 +834,7 @@ def __init__(
681834 )
682835
683836 logger .info (
684- f"Initialized AOP with server name: { server_name } , verbose: { verbose } , traceback: { traceback_enabled } , persistence: { persistence } , network_monitoring: { network_monitoring } "
837+ f"Initialized AOP with server name: { server_name } , verbose: { verbose } , traceback: { traceback_enabled } , persistence: { persistence } , network_monitoring: { network_monitoring } , payment: { payment } "
685838 )
686839
687840 # Add initial agents if provided
0 commit comments