File size: 6,693 Bytes
2be6245 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | """
HTTP Transport wrapper for the PrestaShop MCP Server
This allows the MCP server to be called via HTTP requests (like the old PHP version)
"""
import asyncio
import json
import logging
from typing import Any, Dict
from fastapi import FastAPI, HTTPException, Request
from fastapi.responses import JSONResponse
from pydantic import BaseModel
import uvicorn
from .server import PrestaShopMCPServer
logger = logging.getLogger(__name__)
class MCPRequest(BaseModel):
jsonrpc: str = "2.0"
method: str
params: Dict[str, Any] = {}
id: str
class MCPHTTPWrapper:
"""HTTP wrapper for MCP server to maintain compatibility with existing integrations"""
def __init__(self, api_base: str = None):
self.mcp_server = PrestaShopMCPServer(api_base) if api_base else PrestaShopMCPServer()
self.app = FastAPI(title="PrestaShop MCP HTTP Server")
self.setup_routes()
def setup_routes(self):
"""Setup HTTP routes"""
@self.app.post("/")
async def handle_mcp_request(request: MCPRequest):
"""Handle MCP requests over HTTP"""
try:
if request.method == "tools/list":
# Get available tools
tools = await self._get_tools()
return {
"jsonrpc": "2.0",
"result": {"tools": tools},
"id": request.id
}
elif request.method == "tools/call":
# Call a tool
tool_name = request.params.get("name")
arguments = request.params.get("arguments", {})
result = await self._call_tool(tool_name, arguments)
return {
"jsonrpc": "2.0",
"result": {
"content": [
{
"type": "text",
"text": result
}
]
},
"id": request.id
}
else:
raise HTTPException(
status_code=400,
detail=f"Unknown method: {request.method}"
)
except Exception as e:
logger.error(f"Error handling request: {e}")
return {
"jsonrpc": "2.0",
"error": {
"code": -32603,
"message": "Internal error",
"data": str(e)
},
"id": request.id
}
@self.app.get("/health")
async def health_check():
"""Health check endpoint"""
return {"status": "healthy", "service": "prestashop-mcp-server"}
async def _get_tools(self):
"""Get list of available tools"""
# Simulate the tools/list call
tools = [
{
"name": "get_product_details",
"description": "Get detailed information about a PrestaShop product",
"inputSchema": {
"type": "object",
"properties": {
"product_id": {"type": "integer", "description": "Product ID"},
"lang_id": {"type": "integer", "description": "Language ID", "default": 1}
},
"required": ["product_id"]
}
},
{
"name": "get_product_features",
"description": "Get product features from PrestaShop",
"inputSchema": {
"type": "object",
"properties": {
"product_id": {"type": "integer", "description": "Product ID"}
},
"required": ["product_id"]
}
},
{
"name": "get_product_images",
"description": "Get product images from PrestaShop",
"inputSchema": {
"type": "object",
"properties": {
"product_id": {"type": "integer", "description": "Product ID"}
},
"required": ["product_id"]
}
},
{
"name": "search_products",
"description": "Search for products in PrestaShop catalog",
"inputSchema": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "Search query"},
"limit": {"type": "integer", "description": "Max results", "default": 10}
},
"required": ["query"]
}
}
]
return tools
async def _call_tool(self, tool_name: str, arguments: Dict[str, Any]) -> str:
"""Call a tool and return the result as text"""
try:
if tool_name == "get_product_details":
result = await self.mcp_server._get_product_details(arguments)
elif tool_name == "get_product_features":
result = await self.mcp_server._get_product_features(arguments)
elif tool_name == "get_product_images":
result = await self.mcp_server._get_product_images(arguments)
elif tool_name == "search_products":
result = await self.mcp_server._search_products(arguments)
else:
return f"Unknown tool: {tool_name}"
# Extract text from TextContent result
if result and len(result) > 0:
return result[0].text
else:
return "No result returned"
except Exception as e:
return f"Error calling tool {tool_name}: {str(e)}"
def create_app(api_base: str = None) -> FastAPI:
"""Create FastAPI app instance"""
wrapper = MCPHTTPWrapper(api_base)
return wrapper.app
def start_server(host="0.0.0.0", port=8081):
"""Start the HTTP server for MCP"""
print(f"Starting MCP HTTP server on {host}:{port}")
app = create_app()
uvicorn.run(app, host=host, port=port)
def main():
"""Main entry point for the server"""
start_server()
if __name__ == "__main__":
main()
|