ecomcp / scripts /deploy_modal.py
vinhnx90's picture
feat: Add HuggingFace Spaces deployment documentation and refactor Modal deployment script path.
3bf9e7e
"""
EcoMCP Modal Deployment
Deploy MCP server to Modal serverless platform
Run: modal deploy deploy_modal.py
"""
import os
import json
import asyncio
from typing import Dict, Any
try:
import modal
except ImportError:
raise ImportError("Install modal: pip install modal")
# Create Modal app
app = modal.App("ecomcp-server")
# Import the server
from ecomcp_server_refined import EcoMCPServerRefined
# Create server instance
server = None
def get_server():
"""Get or create server instance"""
global server
if server is None:
server = EcoMCPServerRefined()
return server
# ============================================================================
# HTTP API ENDPOINT
# ============================================================================
@app.function(
image=modal.Image.debian_slim().pip_install(
"httpx>=0.25.0",
"python-dotenv>=1.0.0",
"openai>=1.0.0"
),
secrets=[modal.Secret.from_name("openai-api-key")]
)
@modal.web_endpoint(method="POST")
async def process_request(request: Dict[str, Any]) -> Dict:
"""
Process MCP request via HTTP
Example request:
{
"method": "tools/call",
"params": {
"name": "analyze_product",
"arguments": {"name": "Headphones"}
}
}
"""
server = get_server()
# Ensure OPENAI_API_KEY is set from modal secret
if not os.getenv("OPENAI_API_KEY"):
return {"error": "OPENAI_API_KEY not configured"}
try:
# Build JSON-RPC message
message = {
"jsonrpc": "2.0",
"method": request.get("method"),
"params": request.get("params", {}),
"id": 1
}
# Process message
response = await server.process_message(message)
return response
except Exception as e:
return {
"jsonrpc": "2.0",
"error": {"code": -32603, "message": str(e)},
"id": 1
}
# ============================================================================
# INDIVIDUAL TOOL ENDPOINTS
# ============================================================================
@app.function(
image=modal.Image.debian_slim().pip_install(
"httpx>=0.25.0",
"python-dotenv>=1.0.0",
"openai>=1.0.0"
),
secrets=[modal.Secret.from_name("openai-api-key")]
)
@modal.web_endpoint(method="POST")
async def analyze_product(request: Dict[str, Any]) -> Dict:
"""Analyze product endpoint"""
server = get_server()
try:
result = await server.call_tool("analyze_product", request)
return result
except Exception as e:
return {"status": "error", "error": str(e)}
@app.function(
image=modal.Image.debian_slim().pip_install(
"httpx>=0.25.0",
"python-dotenv>=1.0.0",
"openai>=1.0.0"
),
secrets=[modal.Secret.from_name("openai-api-key")]
)
@modal.web_endpoint(method="POST")
async def analyze_reviews(request: Dict[str, Any]) -> Dict:
"""Analyze reviews endpoint"""
server = get_server()
try:
result = await server.call_tool("analyze_reviews", request)
return result
except Exception as e:
return {"status": "error", "error": str(e)}
@app.function(
image=modal.Image.debian_slim().pip_install(
"httpx>=0.25.0",
"python-dotenv>=1.0.0",
"openai>=1.0.0"
),
secrets=[modal.Secret.from_name("openai-api-key")]
)
@modal.web_endpoint(method="POST")
async def generate_listing(request: Dict[str, Any]) -> Dict:
"""Generate listing endpoint"""
server = get_server()
try:
result = await server.call_tool("generate_listing", request)
return result
except Exception as e:
return {"status": "error", "error": str(e)}
@app.function(
image=modal.Image.debian_slim().pip_install(
"httpx>=0.25.0",
"python-dotenv>=1.0.0",
"openai>=1.0.0"
),
secrets=[modal.Secret.from_name("openai-api-key")]
)
@modal.web_endpoint(method="POST")
async def price_recommendation(request: Dict[str, Any]) -> Dict:
"""Price recommendation endpoint"""
server = get_server()
try:
result = await server.call_tool("price_recommendation", request)
return result
except Exception as e:
return {"status": "error", "error": str(e)}
@app.function(
image=modal.Image.debian_slim().pip_install(
"httpx>=0.25.0",
"python-dotenv>=1.0.0",
"openai>=1.0.0"
),
secrets=[modal.Secret.from_name("openai-api-key")]
)
@modal.web_endpoint(method="POST")
async def competitor_analysis(request: Dict[str, Any]) -> Dict:
"""Competitor analysis endpoint"""
server = get_server()
try:
result = await server.call_tool("competitor_analysis", request)
return result
except Exception as e:
return {"status": "error", "error": str(e)}
# ============================================================================
# HEALTH CHECK
# ============================================================================
@app.function(
image=modal.Image.debian_slim().pip_install(
"httpx>=0.25.0",
"python-dotenv>=1.0.0"
)
)
@modal.web_endpoint(method="GET")
async def health() -> Dict:
"""Health check endpoint"""
server = get_server()
return {
"status": "healthy",
"server": "ecomcp-v2.0",
"cache_stats": server.cache.stats(),
"metrics": server.metrics
}
if __name__ == "__main__":
print("""
============================================================
EcoMCP Modal Deployment
============================================================
Deploy to Modal:
$ modal deploy deploy_modal.py
This creates serverless endpoints for:
- /process_request - Main MCP endpoint
- /analyze_product - Product analysis
- /analyze_reviews - Review analysis
- /generate_listing - Listing generation
- /price_recommendation - Pricing strategy
- /competitor_analysis - Competitive analysis
- /health - Health check
Setup:
1. Install Modal: pip install modal
2. Authenticate: modal token new
3. Create secret: modal secret create openai-api-key --value sk-...
4. Deploy: modal deploy deploy_modal.py
============================================================
""")