|
|
""" |
|
|
FleetMind MCP Server - Hugging Face Space Entry Point (Track 1) |
|
|
|
|
|
This file serves as the entry point for HuggingFace Space deployment. |
|
|
Exposes 29 MCP tools via Server-Sent Events (SSE) endpoint for AI clients. |
|
|
|
|
|
Architecture: |
|
|
User β MCP Client (Claude Desktop, Continue, etc.) |
|
|
β SSE Endpoint (this file) |
|
|
β FleetMind MCP Server (server.py) |
|
|
β Tools (chat/tools.py) |
|
|
β Database (PostgreSQL) |
|
|
|
|
|
For Track 1: Building MCP Servers - Enterprise Category |
|
|
https://huggingface.co/MCP-1st-Birthday |
|
|
|
|
|
Compatible with: |
|
|
- Claude Desktop (via SSE transport) |
|
|
- Continue.dev (VS Code extension) |
|
|
- Cline (VS Code extension) |
|
|
- Any MCP client supporting SSE protocol |
|
|
""" |
|
|
|
|
|
import os |
|
|
import sys |
|
|
import logging |
|
|
from pathlib import Path |
|
|
|
|
|
|
|
|
sys.path.insert(0, str(Path(__file__).parent)) |
|
|
|
|
|
|
|
|
logging.basicConfig( |
|
|
level=logging.INFO, |
|
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', |
|
|
handlers=[logging.StreamHandler()] |
|
|
) |
|
|
logger = logging.getLogger(__name__) |
|
|
|
|
|
|
|
|
from server import mcp |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
HF_SPACE_PORT = int(os.getenv("PORT", 7861)) |
|
|
HF_SPACE_HOST = os.getenv("HOST", "0.0.0.0") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
logger.info("=" * 70) |
|
|
logger.info("FleetMind MCP Server - HuggingFace Space (Track 1)") |
|
|
logger.info("=" * 70) |
|
|
logger.info("MCP Server: FleetMind Dispatch Coordinator v1.0.0") |
|
|
logger.info("Protocol: Model Context Protocol (MCP)") |
|
|
logger.info("Transport: Server-Sent Events (SSE)") |
|
|
logger.info(f"SSE Endpoint: https://mcp-1st-birthday-fleetmind-dispatch-ai.hf.space/sse") |
|
|
logger.info("=" * 70) |
|
|
logger.info("Features:") |
|
|
logger.info(" β 29 AI Tools (Order + Driver + Assignment Management)") |
|
|
logger.info(" β 2 Real-Time Resources (orders://all, drivers://all)") |
|
|
logger.info(" β Gemini 2.0 Flash AI - Intelligent Assignment") |
|
|
logger.info(" β Google Maps API Integration (Routes + Geocoding)") |
|
|
logger.info(" β Weather-Aware Routing (OpenWeatherMap)") |
|
|
logger.info(" β PostgreSQL Database (Neon)") |
|
|
logger.info("=" * 70) |
|
|
logger.info("Compatible Clients:") |
|
|
logger.info(" β’ Claude Desktop") |
|
|
logger.info(" β’ Continue.dev (VS Code)") |
|
|
logger.info(" β’ Cline (VS Code)") |
|
|
logger.info(" β’ Any MCP-compatible client") |
|
|
logger.info("=" * 70) |
|
|
logger.info("How to Connect (Claude Desktop):") |
|
|
logger.info(' Add to claude_desktop_config.json:') |
|
|
logger.info(' {') |
|
|
logger.info(' "mcpServers": {') |
|
|
logger.info(' "fleetmind": {') |
|
|
logger.info(' "command": "npx",') |
|
|
logger.info(' "args": [') |
|
|
logger.info(' "mcp-remote",') |
|
|
logger.info(' "https://mcp-1st-birthday-fleetmind-dispatch-ai.hf.space/sse"') |
|
|
logger.info(' ]') |
|
|
logger.info(' }') |
|
|
logger.info(' }') |
|
|
logger.info(' }') |
|
|
logger.info("=" * 70) |
|
|
logger.info(f"Starting SSE server on {HF_SPACE_HOST}:{HF_SPACE_PORT}...") |
|
|
logger.info("Waiting for MCP client connections...") |
|
|
logger.info("=" * 70) |
|
|
|
|
|
try: |
|
|
|
|
|
from starlette.responses import HTMLResponse, JSONResponse |
|
|
from starlette.requests import Request |
|
|
from database.api_keys import generate_api_key as db_generate_api_key |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
logger.info("[Auth] Using proxy-based authentication") |
|
|
logger.info("[Auth] Proxy captures API keys and injects into tool requests") |
|
|
|
|
|
@mcp.custom_route("/", methods=["GET"]) |
|
|
async def landing_page(request): |
|
|
"""Landing page with MCP connection information""" |
|
|
return HTMLResponse(""" |
|
|
<!DOCTYPE html> |
|
|
<html> |
|
|
<head> |
|
|
<title>FleetMind MCP Server</title> |
|
|
<style> |
|
|
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Arial, sans-serif; max-width: 1000px; margin: 50px auto; padding: 20px; background: #0f172a; color: #e2e8f0; } |
|
|
.container { background: #1e293b; padding: 40px; border-radius: 12px; box-shadow: 0 8px 16px rgba(0,0,0,0.4); } |
|
|
h1 { color: #f1f5f9; margin-top: 0; } |
|
|
h2 { color: #e2e8f0; border-bottom: 2px solid #334155; padding-bottom: 10px; } |
|
|
h3 { color: #cbd5e1; } |
|
|
code { background: #334155; color: #60a5fa; padding: 3px 8px; border-radius: 4px; font-family: 'Courier New', monospace; } |
|
|
pre { background: #0f172a; color: #f1f5f9; padding: 20px; border-radius: 8px; overflow-x: auto; border: 1px solid #334155; } |
|
|
.endpoint { background: #1e3a5f; padding: 15px; margin: 15px 0; border-left: 4px solid #3b82f6; border-radius: 4px; } |
|
|
.feature { background: #134e4a; padding: 15px; margin: 10px 0; border-left: 4px solid #10b981; border-radius: 4px; } |
|
|
.badge { display: inline-block; background: #3b82f6; color: white; padding: 4px 12px; border-radius: 12px; font-size: 12px; margin: 5px; } |
|
|
a { color: #60a5fa; text-decoration: none; } |
|
|
a:hover { text-decoration: underline; color: #93c5fd; } |
|
|
ol { line-height: 1.8; } |
|
|
ul { line-height: 1.8; } |
|
|
p { color: #cbd5e1; } |
|
|
</style> |
|
|
</head> |
|
|
<body> |
|
|
<div class="container"> |
|
|
<h1>π FleetMind MCP Server</h1> |
|
|
<p><strong>Enterprise Model Context Protocol Server for AI-Powered Delivery Dispatch</strong></p> |
|
|
<p><span class="badge">MCP 1st Birthday Hackathon</span> <span class="badge">Track 1: Building MCP</span> <span class="badge">Enterprise Category</span></p> |
|
|
|
|
|
<hr style="margin: 30px 0; border: none; border-top: 1px solid #e5e7eb;"> |
|
|
|
|
|
<h2>π MCP Server Connection</h2> |
|
|
|
|
|
<div class="endpoint"> |
|
|
<strong>SSE Endpoint URL:</strong><br> |
|
|
<code>https://mcp-1st-birthday-fleetmind-dispatch-ai.hf.space/sse</code> |
|
|
</div> |
|
|
|
|
|
<h3>π Step 1: Get Your API Key</h3> |
|
|
<p style="text-align: center; margin: 20px 0;"> |
|
|
<a href="/generate-key" style="display: inline-block; background: #3b82f6; color: white; padding: 15px 30px; border-radius: 8px; text-decoration: none; font-weight: bold; font-size: 18px;"> |
|
|
Generate API Key β |
|
|
</a> |
|
|
</p> |
|
|
<p>Click the button above to generate your unique API key. You'll need this to authenticate with the server.</p> |
|
|
|
|
|
<h3>βοΈ Step 2: Configure Claude Desktop</h3> |
|
|
<p>Add this to your <code>claude_desktop_config.json</code> file:</p> |
|
|
<pre>{ |
|
|
"mcpServers": { |
|
|
"fleetmind": { |
|
|
"command": "npx", |
|
|
"args": [ |
|
|
"mcp-remote", |
|
|
"https://mcp-1st-birthday-fleetmind-dispatch-ai.hf.space/sse<strong style="color: #60a5fa;">?api_key=fm_your_api_key_here</strong>" |
|
|
] |
|
|
} |
|
|
} |
|
|
}</pre> |
|
|
<p style="background: #1e3a5f; padding: 10px; border-radius: 6px; margin: 10px 0; border-left: 4px solid #3b82f6;"> |
|
|
π‘ <strong>Important:</strong> Add your API key as a query parameter (<code>?api_key=...</code>) in the URL, not in the <code>env</code> section! |
|
|
</p> |
|
|
|
|
|
<h3>π Step 3: Connect</h3> |
|
|
<ol> |
|
|
<li><strong>Generate your API key</strong> using the button above</li> |
|
|
<li>Install <a href="https://claude.ai/download" target="_blank">Claude Desktop</a></li> |
|
|
<li>Locate your <code>claude_desktop_config.json</code> file</li> |
|
|
<li>Add the configuration, replacing <code>fm_your_api_key_here</code> with your actual API key <strong>in the URL</strong></li> |
|
|
<li>Restart Claude Desktop</li> |
|
|
<li>Look for "FleetMind" in the π tools menu</li> |
|
|
</ol> |
|
|
|
|
|
<hr style="margin: 30px 0; border: none; border-top: 1px solid #e5e7eb;"> |
|
|
|
|
|
<h2>π οΈ Available Tools (29 Total)</h2> |
|
|
|
|
|
<div class="feature"> |
|
|
<strong>π Geocoding & Routing (3 tools):</strong><br> |
|
|
geocode_address, calculate_route, calculate_intelligent_route |
|
|
</div> |
|
|
|
|
|
<div class="feature"> |
|
|
<strong>π¦ Order Management (8 tools):</strong><br> |
|
|
create_order, count_orders, fetch_orders, get_order_details, search_orders, get_incomplete_orders, update_order, delete_order |
|
|
</div> |
|
|
|
|
|
<div class="feature"> |
|
|
<strong>π₯ Driver Management (8 tools):</strong><br> |
|
|
create_driver, count_drivers, fetch_drivers, get_driver_details, search_drivers, get_available_drivers, update_driver, delete_driver |
|
|
</div> |
|
|
|
|
|
<div class="feature"> |
|
|
<strong>π Assignment Management (8 tools):</strong><br> |
|
|
create_assignment, <strong>auto_assign_order</strong>, <strong>intelligent_assign_order</strong>, get_assignment_details, update_assignment, unassign_order, complete_delivery, fail_delivery |
|
|
</div> |
|
|
|
|
|
<div class="feature"> |
|
|
<strong>ποΈ Bulk Operations (2 tools):</strong><br> |
|
|
delete_all_orders, delete_all_drivers |
|
|
</div> |
|
|
|
|
|
<hr style="margin: 30px 0; border: none; border-top: 1px solid #e5e7eb;"> |
|
|
|
|
|
<h2>β Key Features</h2> |
|
|
<ul> |
|
|
<li><strong>π API Key Authentication</strong> - Secure multi-tenant access with personal API keys (URL-based)</li> |
|
|
<li><strong>π₯ Multi-Tenant Isolation</strong> - Complete data separation via user_id (deterministic from email)</li> |
|
|
<li><strong>π§ Gemini 2.0 Flash AI</strong> - Intelligent order assignment with detailed reasoning</li> |
|
|
<li><strong>π¦οΈ Weather-Aware Routing</strong> - Safety-first delivery planning with OpenWeatherMap</li> |
|
|
<li><strong>π¦ Real-Time Traffic</strong> - Google Routes API integration with live traffic data</li> |
|
|
<li><strong>π SLA Tracking</strong> - Automatic on-time performance monitoring</li> |
|
|
<li><strong>ποΈ PostgreSQL Database</strong> - Production-grade data storage with user_id filtering (Neon)</li> |
|
|
<li><strong>π Multi-Client Support</strong> - Works with Claude Desktop, Continue, Cline, any MCP client</li> |
|
|
</ul> |
|
|
|
|
|
<h2>π Authentication & Security</h2> |
|
|
<div class="feature"> |
|
|
<strong>How Authentication Works:</strong><br> |
|
|
1. Generate API key via <a href="/generate-key">/generate-key</a><br> |
|
|
2. API key hashed (SHA-256) before storage<br> |
|
|
3. User ID generated: <code>user_{MD5(email)[:12]}</code><br> |
|
|
4. Add key to URL: <code>?api_key=fm_...</code><br> |
|
|
5. Server validates on each SSE connection<br> |
|
|
6. All queries filter by user_id for isolation |
|
|
</div> |
|
|
<div class="feature"> |
|
|
<strong>Security Features:</strong><br> |
|
|
β
One-Time Display (keys shown once)<br> |
|
|
β
Hashed Storage (SHA-256, never plaintext)<br> |
|
|
β
Database-Level Isolation (all tables have user_id)<br> |
|
|
β
Deterministic User IDs (same email β same user_id)<br> |
|
|
β
Production Safeguards (ENV-based SKIP_AUTH protection) |
|
|
</div> |
|
|
|
|
|
<hr style="margin: 30px 0; border: none; border-top: 1px solid #e5e7eb;"> |
|
|
|
|
|
<h2>π Resources</h2> |
|
|
<ul> |
|
|
<li><strong>GitHub:</strong> <a href="https://github.com/mashrur-rahman-fahim/fleetmind-mcp" target="_blank">mashrur-rahman-fahim/fleetmind-mcp</a></li> |
|
|
<li><strong>HuggingFace Space:</strong> <a href="https://huggingface.co/spaces/MCP-1st-Birthday/fleetmind-dispatch-ai" target="_blank">MCP-1st-Birthday/fleetmind-dispatch-ai</a></li> |
|
|
<li><strong>MCP Protocol Docs:</strong> <a href="https://modelcontextprotocol.io" target="_blank">modelcontextprotocol.io</a></li> |
|
|
</ul> |
|
|
|
|
|
<hr style="margin: 30px 0; border: none; border-top: 1px solid #e5e7eb;"> |
|
|
|
|
|
<p style="text-align: center; color: #6b7280; font-size: 14px;"> |
|
|
FleetMind v1.0 - Built for MCP 1st Birthday Hackathon<br> |
|
|
29 AI Tools | 2 Real-Time Resources | Enterprise-Ready |
|
|
</p> |
|
|
</div> |
|
|
</body> |
|
|
</html> |
|
|
""") |
|
|
|
|
|
@mcp.custom_route("/generate-key", methods=["GET", "POST"]) |
|
|
async def generate_key_page(request): |
|
|
"""API Key generation page""" |
|
|
if request.method == "GET": |
|
|
return HTMLResponse(""" |
|
|
<!DOCTYPE html> |
|
|
<html> |
|
|
<head> |
|
|
<title>Generate FleetMind API Key</title> |
|
|
<style> |
|
|
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Arial, sans-serif; max-width: 600px; margin: 50px auto; padding: 20px; background: #0f172a; color: #e2e8f0; } |
|
|
.container { background: #1e293b; padding: 40px; border-radius: 12px; box-shadow: 0 8px 16px rgba(0,0,0,0.4); } |
|
|
h1 { color: #f1f5f9; } |
|
|
input { width: 100%; padding: 12px; margin: 10px 0; border-radius: 6px; border: 1px solid #334155; background: #0f172a; color: #e2e8f0; font-size: 16px; } |
|
|
button { background: #3b82f6; color: white; border: none; padding: 12px 24px; border-radius: 6px; font-size: 16px; cursor: pointer; width: 100%; } |
|
|
button:hover { background: #2563eb; } |
|
|
button:disabled { background: #64748b; cursor: not-allowed; opacity: 0.6; } |
|
|
.info { background: #1e3a5f; padding: 15px; border-radius: 6px; margin: 15px 0; border-left: 4px solid #3b82f6; } |
|
|
</style> |
|
|
<script> |
|
|
function handleGenerateKey(event) { |
|
|
const button = event.target.querySelector('button'); |
|
|
button.textContent = 'Generating...'; |
|
|
button.disabled = true; |
|
|
} |
|
|
</script> |
|
|
</head> |
|
|
<body> |
|
|
<div class="container"> |
|
|
<h1>π Generate API Key</h1> |
|
|
<p>Create your FleetMind MCP Server API key</p> |
|
|
|
|
|
<div class="info"> |
|
|
<strong>π What you'll need:</strong><br> |
|
|
β’ Your email address (used to generate your unique user_id)<br> |
|
|
β’ Your name (optional)<br> |
|
|
<br> |
|
|
<strong>π What you'll get:</strong><br> |
|
|
β’ API Key: <code>fm_xxxxx...</code> (show once, copy immediately!)<br> |
|
|
β’ User ID: <code>user_xxxxx</code> (deterministic from your email)<br> |
|
|
β’ All your data (orders/drivers/assignments) will be isolated by this user_id |
|
|
</div> |
|
|
|
|
|
<form method="POST" onsubmit="handleGenerateKey(event)"> |
|
|
<input type="email" name="email" placeholder="Your email address" required> |
|
|
<input type="text" name="name" placeholder="Your name (optional)"> |
|
|
<button type="submit">Generate API Key</button> |
|
|
</form> |
|
|
|
|
|
<p style="text-align: center; margin-top: 20px;"> |
|
|
<a href="/" style="color: #60a5fa; text-decoration: none;">β Back to Home</a> |
|
|
</p> |
|
|
</div> |
|
|
</body> |
|
|
</html> |
|
|
""") |
|
|
|
|
|
|
|
|
else: |
|
|
try: |
|
|
form_data = await request.form() |
|
|
email = form_data.get("email") |
|
|
name = form_data.get("name") or None |
|
|
|
|
|
if not email: |
|
|
return HTMLResponse("<h1>Error: Email is required</h1>", status_code=400) |
|
|
|
|
|
result = db_generate_api_key(email, name) |
|
|
|
|
|
if not result['success']: |
|
|
return HTMLResponse(f"<h1>Error: {result['error']}</h1>", status_code=400) |
|
|
|
|
|
|
|
|
return HTMLResponse(f""" |
|
|
<!DOCTYPE html> |
|
|
<html> |
|
|
<head> |
|
|
<title>Your FleetMind API Key</title> |
|
|
<style> |
|
|
body {{ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Arial, sans-serif; max-width: 800px; margin: 50px auto; padding: 20px; background: #0f172a; color: #e2e8f0; }} |
|
|
.container {{ background: #1e293b; padding: 40px; border-radius: 12px; box-shadow: 0 8px 16px rgba(0,0,0,0.4); }} |
|
|
h1 {{ color: #f1f5f9; }} |
|
|
.success {{ background: #10b981; padding: 15px; border-radius: 6px; margin: 15px 0; }} |
|
|
.warning {{ background: #ef4444; padding: 15px; border-radius: 6px; margin: 15px 0; }} |
|
|
code {{ background: #334155; color: #60a5fa; padding: 3px 8px; border-radius: 4px; font-family: 'Courier New', monospace; display: block; margin: 10px 0; word-wrap: break-word; font-size: 14px; }} |
|
|
pre {{ background: #0f172a; color: #f1f5f9; padding: 20px; border-radius: 8px; overflow-x: auto; border: 1px solid #334155; }} |
|
|
button {{ background: #3b82f6; color: white; border: none; padding: 12px 24px; border-radius: 6px; font-size: 16px; cursor: pointer; margin: 10px 5px; }} |
|
|
button:hover {{ background: #2563eb; }} |
|
|
</style> |
|
|
<script> |
|
|
function copyKey() {{ |
|
|
navigator.clipboard.writeText('{result["api_key"]}'); |
|
|
alert('API key copied to clipboard!'); |
|
|
}} |
|
|
</script> |
|
|
</head> |
|
|
<body> |
|
|
<div class="container"> |
|
|
<h1>β
API Key Generated!</h1> |
|
|
|
|
|
<div class="success"> |
|
|
<strong>Your API key has been created successfully</strong> |
|
|
</div> |
|
|
|
|
|
<p><strong>π§ Email:</strong> {result["email"]}</p> |
|
|
<p><strong>π€ Name:</strong> {result["name"]}</p> |
|
|
<p><strong>π User ID:</strong> <code>{result["user_id"]}</code></p> |
|
|
|
|
|
<div class="warning"> |
|
|
<strong>β οΈ SAVE THIS KEY NOW - IT WON'T BE SHOWN AGAIN!</strong> |
|
|
</div> |
|
|
|
|
|
<h2>π Your API Key:</h2> |
|
|
<code>{result["api_key"]}</code> |
|
|
<button onclick="copyKey()">π Copy Key</button> |
|
|
|
|
|
<h2>π₯ Multi-Tenant Isolation</h2> |
|
|
<p style="background: #1e3a5f; padding: 15px; border-radius: 6px; margin: 10px 0; border-left: 4px solid #3b82f6;"> |
|
|
<strong>Your user_id (<code>{result["user_id"]}</code>) ensures complete data isolation:</strong><br> |
|
|
β
You will only see your own orders, drivers, and assignments<br> |
|
|
β
All database operations automatically filter by your user_id<br> |
|
|
β
Your user_id is deterministic - same email always gets same ID<br> |
|
|
β
Even if you regenerate your API key, your user_id stays the same |
|
|
</p> |
|
|
|
|
|
<h2>π Claude Desktop Setup:</h2> |
|
|
<p>Add this to your <code>claude_desktop_config.json</code>:</p> |
|
|
<pre>{{ |
|
|
"mcpServers": {{ |
|
|
"fleetmind": {{ |
|
|
"command": "npx", |
|
|
"args": [ |
|
|
"mcp-remote", |
|
|
"https://mcp-1st-birthday-fleetmind-dispatch-ai.hf.space/sse?api_key={result["api_key"]}" |
|
|
] |
|
|
}} |
|
|
}} |
|
|
}}</pre> |
|
|
<p style="background: #1e3a5f; padding: 10px; border-radius: 6px; margin: 10px 0; border-left: 4px solid #3b82f6;"> |
|
|
π‘ <strong>Important:</strong> The API key is included in the URL as a query parameter (<code>?api_key=...</code>) |
|
|
</p> |
|
|
|
|
|
<h2>π Next Steps:</h2> |
|
|
<ol> |
|
|
<li>Copy your API key (click the button above)</li> |
|
|
<li>Add it to your Claude Desktop config</li> |
|
|
<li>Restart Claude Desktop</li> |
|
|
<li>Start using FleetMind tools!</li> |
|
|
</ol> |
|
|
|
|
|
<h2>π How Authentication Works:</h2> |
|
|
<div style="background: #134e4a; padding: 15px; border-radius: 6px; margin: 10px 0; border-left: 4px solid #10b981;"> |
|
|
<strong>Authentication Flow:</strong><br><br> |
|
|
1οΈβ£ <strong>Connection:</strong> Claude Desktop connects to SSE endpoint with your API key in URL<br> |
|
|
2οΈβ£ <strong>Validation:</strong> Server hashes your key (SHA-256) and looks it up in database<br> |
|
|
3οΈβ£ <strong>User Extraction:</strong> Server retrieves your user_id: <code>{result["user_id"]}</code><br> |
|
|
4οΈβ£ <strong>Data Isolation:</strong> All tool calls automatically filter by your user_id<br> |
|
|
5οΈβ£ <strong>Security:</strong> You can only access data associated with your user_id<br> |
|
|
</div> |
|
|
|
|
|
<p style="text-align: center; margin-top: 30px;"> |
|
|
<a href="/" style="color: #60a5fa; text-decoration: none;">β Back to Home</a> |
|
|
</p> |
|
|
</div> |
|
|
</body> |
|
|
</html> |
|
|
""") |
|
|
|
|
|
except Exception as e: |
|
|
return HTMLResponse(f"<h1>Error: {str(e)}</h1>", status_code=500) |
|
|
|
|
|
logger.info("[OK] Landing page added at / route") |
|
|
logger.info("[OK] API key generation page added at /generate-key") |
|
|
logger.info("[OK] MCP SSE endpoint available at /sse") |
|
|
logger.info("[OK] Authentication handled by proxy.py (port 7860)") |
|
|
|
|
|
|
|
|
|
|
|
mcp.run( |
|
|
transport="sse", |
|
|
host=HF_SPACE_HOST, |
|
|
port=HF_SPACE_PORT |
|
|
) |
|
|
|
|
|
except Exception as e: |
|
|
logger.error(f"Failed to start server: {e}") |
|
|
logger.error("Check that:") |
|
|
logger.error(" 1. Database connection is configured (DB_HOST, DB_USER, etc.)") |
|
|
logger.error(" 2. Google Maps API key is set (GOOGLE_MAPS_API_KEY)") |
|
|
logger.error(" 3. Port 7860 is available") |
|
|
raise |
|
|
|