300 lines
7.7 KiB
Python
300 lines
7.7 KiB
Python
|
|
"""
|
||
|
|
Aftersale MCP Server - Returns, exchanges, and complaints
|
||
|
|
"""
|
||
|
|
import sys
|
||
|
|
import os
|
||
|
|
from typing import Optional, List
|
||
|
|
|
||
|
|
# Add shared module to path
|
||
|
|
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||
|
|
|
||
|
|
from fastmcp import FastMCP
|
||
|
|
from pydantic_settings import BaseSettings
|
||
|
|
|
||
|
|
|
||
|
|
from pydantic import ConfigDict
|
||
|
|
|
||
|
|
|
||
|
|
class Settings(BaseSettings):
|
||
|
|
"""Server configuration"""
|
||
|
|
hyperf_api_url: str
|
||
|
|
hyperf_api_token: str
|
||
|
|
log_level: str = "INFO"
|
||
|
|
|
||
|
|
model_config = ConfigDict(env_file=".env")
|
||
|
|
|
||
|
|
|
||
|
|
settings = Settings()
|
||
|
|
|
||
|
|
# Create MCP server
|
||
|
|
mcp = FastMCP(
|
||
|
|
"Aftersale Service"
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
# Hyperf client for this server
|
||
|
|
from shared.hyperf_client import HyperfClient
|
||
|
|
hyperf = HyperfClient(settings.hyperf_api_url, settings.hyperf_api_token)
|
||
|
|
|
||
|
|
|
||
|
|
@mcp.tool()
|
||
|
|
async def apply_return(
|
||
|
|
order_id: str,
|
||
|
|
user_id: str,
|
||
|
|
items: List[dict],
|
||
|
|
description: str,
|
||
|
|
images: Optional[List[str]] = None
|
||
|
|
) -> dict:
|
||
|
|
"""Apply for a return
|
||
|
|
|
||
|
|
Args:
|
||
|
|
order_id: Order ID
|
||
|
|
user_id: User identifier
|
||
|
|
items: List of items to return, each with:
|
||
|
|
- item_id: Order item ID
|
||
|
|
- quantity: Quantity to return
|
||
|
|
- reason: Return reason (quality_issue, wrong_item, not_as_described, etc.)
|
||
|
|
description: Detailed description of the issue
|
||
|
|
images: Optional list of image URLs showing the issue
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
Return application result with aftersale ID
|
||
|
|
"""
|
||
|
|
payload = {
|
||
|
|
"order_id": order_id,
|
||
|
|
"user_id": user_id,
|
||
|
|
"items": items,
|
||
|
|
"description": description
|
||
|
|
}
|
||
|
|
|
||
|
|
if images:
|
||
|
|
payload["images"] = images
|
||
|
|
|
||
|
|
try:
|
||
|
|
result = await hyperf.post("/aftersales/return", json=payload)
|
||
|
|
|
||
|
|
return {
|
||
|
|
"success": True,
|
||
|
|
"aftersale_id": result.get("aftersale_id"),
|
||
|
|
"status": result.get("status"),
|
||
|
|
"estimated_refund": result.get("estimated_refund"),
|
||
|
|
"process_steps": result.get("process_steps", []),
|
||
|
|
"message": "Return application submitted successfully"
|
||
|
|
}
|
||
|
|
except Exception as e:
|
||
|
|
return {
|
||
|
|
"success": False,
|
||
|
|
"error": str(e)
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
@mcp.tool()
|
||
|
|
async def apply_exchange(
|
||
|
|
order_id: str,
|
||
|
|
user_id: str,
|
||
|
|
items: List[dict],
|
||
|
|
description: str
|
||
|
|
) -> dict:
|
||
|
|
"""Apply for an exchange
|
||
|
|
|
||
|
|
Args:
|
||
|
|
order_id: Order ID
|
||
|
|
user_id: User identifier
|
||
|
|
items: List of items to exchange, each with:
|
||
|
|
- item_id: Order item ID
|
||
|
|
- reason: Exchange reason
|
||
|
|
- new_specs: Optional new specifications (size, color, etc.)
|
||
|
|
description: Detailed description of the issue
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
Exchange application result with aftersale ID
|
||
|
|
"""
|
||
|
|
try:
|
||
|
|
result = await hyperf.post(
|
||
|
|
"/aftersales/exchange",
|
||
|
|
json={
|
||
|
|
"order_id": order_id,
|
||
|
|
"user_id": user_id,
|
||
|
|
"items": items,
|
||
|
|
"description": description
|
||
|
|
}
|
||
|
|
)
|
||
|
|
|
||
|
|
return {
|
||
|
|
"success": True,
|
||
|
|
"aftersale_id": result.get("aftersale_id"),
|
||
|
|
"status": result.get("status"),
|
||
|
|
"process_steps": result.get("process_steps", []),
|
||
|
|
"message": "Exchange application submitted successfully"
|
||
|
|
}
|
||
|
|
except Exception as e:
|
||
|
|
return {
|
||
|
|
"success": False,
|
||
|
|
"error": str(e)
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
@mcp.tool()
|
||
|
|
async def create_complaint(
|
||
|
|
user_id: str,
|
||
|
|
complaint_type: str,
|
||
|
|
title: str,
|
||
|
|
description: str,
|
||
|
|
related_order_id: Optional[str] = None,
|
||
|
|
attachments: Optional[List[str]] = None
|
||
|
|
) -> dict:
|
||
|
|
"""Create a complaint
|
||
|
|
|
||
|
|
Args:
|
||
|
|
user_id: User identifier
|
||
|
|
complaint_type: Type of complaint:
|
||
|
|
- product_quality: Product quality issues
|
||
|
|
- service: Service attitude or process issues
|
||
|
|
- logistics: Shipping/delivery issues
|
||
|
|
- pricing: Pricing or billing issues
|
||
|
|
- other: Other complaints
|
||
|
|
title: Brief complaint title
|
||
|
|
description: Detailed description
|
||
|
|
related_order_id: Related order ID (optional)
|
||
|
|
attachments: Optional list of attachment URLs
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
Complaint creation result
|
||
|
|
"""
|
||
|
|
payload = {
|
||
|
|
"user_id": user_id,
|
||
|
|
"type": complaint_type,
|
||
|
|
"title": title,
|
||
|
|
"description": description
|
||
|
|
}
|
||
|
|
|
||
|
|
if related_order_id:
|
||
|
|
payload["related_order_id"] = related_order_id
|
||
|
|
if attachments:
|
||
|
|
payload["attachments"] = attachments
|
||
|
|
|
||
|
|
try:
|
||
|
|
result = await hyperf.post("/aftersales/complaint", json=payload)
|
||
|
|
|
||
|
|
return {
|
||
|
|
"success": True,
|
||
|
|
"complaint_id": result.get("complaint_id"),
|
||
|
|
"status": result.get("status"),
|
||
|
|
"assigned_to": result.get("assigned_to"),
|
||
|
|
"expected_response_time": result.get("expected_response_time"),
|
||
|
|
"message": "Complaint submitted successfully"
|
||
|
|
}
|
||
|
|
except Exception as e:
|
||
|
|
return {
|
||
|
|
"success": False,
|
||
|
|
"error": str(e)
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
@mcp.tool()
|
||
|
|
async def create_ticket(
|
||
|
|
user_id: str,
|
||
|
|
category: str,
|
||
|
|
priority: str,
|
||
|
|
title: str,
|
||
|
|
description: str
|
||
|
|
) -> dict:
|
||
|
|
"""Create a support ticket
|
||
|
|
|
||
|
|
Args:
|
||
|
|
user_id: User identifier
|
||
|
|
category: Ticket category (technical_support, account, payment, other)
|
||
|
|
priority: Priority level (low, medium, high, urgent)
|
||
|
|
title: Ticket title
|
||
|
|
description: Detailed description
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
Ticket creation result
|
||
|
|
"""
|
||
|
|
try:
|
||
|
|
result = await hyperf.post(
|
||
|
|
"/aftersales/ticket",
|
||
|
|
json={
|
||
|
|
"user_id": user_id,
|
||
|
|
"category": category,
|
||
|
|
"priority": priority,
|
||
|
|
"title": title,
|
||
|
|
"description": description
|
||
|
|
}
|
||
|
|
)
|
||
|
|
|
||
|
|
return {
|
||
|
|
"success": True,
|
||
|
|
"ticket_id": result.get("ticket_id"),
|
||
|
|
"status": result.get("status"),
|
||
|
|
"assigned_team": result.get("assigned_team"),
|
||
|
|
"message": "Support ticket created successfully"
|
||
|
|
}
|
||
|
|
except Exception as e:
|
||
|
|
return {
|
||
|
|
"success": False,
|
||
|
|
"error": str(e)
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
@mcp.tool()
|
||
|
|
async def query_aftersale_status(
|
||
|
|
user_id: str,
|
||
|
|
aftersale_id: Optional[str] = None
|
||
|
|
) -> dict:
|
||
|
|
"""Query aftersale records and status
|
||
|
|
|
||
|
|
Args:
|
||
|
|
user_id: User identifier
|
||
|
|
aftersale_id: Specific aftersale ID (optional, queries all if not provided)
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
List of aftersale records with progress
|
||
|
|
"""
|
||
|
|
params = {"user_id": user_id}
|
||
|
|
if aftersale_id:
|
||
|
|
params["aftersale_id"] = aftersale_id
|
||
|
|
|
||
|
|
try:
|
||
|
|
result = await hyperf.get("/aftersales/query", params=params)
|
||
|
|
|
||
|
|
return {
|
||
|
|
"success": True,
|
||
|
|
"records": result.get("records", [])
|
||
|
|
}
|
||
|
|
except Exception as e:
|
||
|
|
return {
|
||
|
|
"success": False,
|
||
|
|
"error": str(e),
|
||
|
|
"records": []
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
# Health check endpoint
|
||
|
|
@mcp.tool()
|
||
|
|
async def health_check() -> dict:
|
||
|
|
"""Check server health status"""
|
||
|
|
return {
|
||
|
|
"status": "healthy",
|
||
|
|
"service": "aftersale_mcp",
|
||
|
|
"version": "1.0.0"
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
import uvicorn
|
||
|
|
|
||
|
|
# Create FastAPI app from MCP
|
||
|
|
app = mcp.http_app()
|
||
|
|
|
||
|
|
# Add health endpoint
|
||
|
|
from starlette.responses import JSONResponse
|
||
|
|
async def health_check(request):
|
||
|
|
return JSONResponse({"status": "healthy"})
|
||
|
|
|
||
|
|
# Add the route to the app
|
||
|
|
from starlette.routing import Route
|
||
|
|
app.router.routes.append(Route('/health', health_check, methods=['GET']))
|
||
|
|
|
||
|
|
uvicorn.run(app, host="0.0.0.0", port=8003)
|