We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/sandraschi/robotics-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server
import logging
import os
import sys
from pathlib import Path
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from typing import List, Dict, Any
import httpx
# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("sota-backend")
# Path Alignment
_current_file = Path(__file__).resolve()
project_root = _current_file.parent.parent.parent # D:\Dev\repos\robotics-mcp
docs_path = project_root / "docs"
src_path = project_root / "src"
if src_path.exists():
sys.path.insert(0, str(src_path))
os.environ["PYTHONPATH"] = str(src_path)
logger.info(f"Added {src_path} to sys.path")
app = FastAPI(title="Robotics MCP SOTA Backend", version="2.1.0")
# SOTA CORS Configuration
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.get("/api/health")
async def health():
return {"status": "healthy", "service": "robotics-mcp-backend"}
# --- Documentation API ---
@app.get("/api/v1/docs")
async def list_docs():
"""List all documentation files organized by category."""
if not docs_path.exists():
return {"categories": {}}
docs = {}
for category_dir in docs_path.iterdir():
if category_dir.is_dir():
category_name = category_dir.name
files = []
for doc_file in category_dir.glob("*.md"):
files.append(
{
"name": doc_file.stem.replace("_", " ").title(),
"filename": doc_file.name,
"path": f"{category_name}/{doc_file.name}",
}
)
if files:
docs[category_name] = sorted(files, key=lambda x: x["name"])
return {"categories": docs}
@app.get("/api/v1/docs/{category}/{filename}")
async def get_doc(category: str, filename: str):
"""Get the content of a specific documentation file."""
file_path = docs_path / category / filename
if not file_path.exists() or not file_path.is_file():
raise HTTPException(status_code=404, detail="Document not found")
try:
content = file_path.read_text(encoding="utf-8")
return {
"title": filename.replace("_", " ").replace(".md", "").title(),
"content": content,
"category": category,
}
except Exception as e:
logger.error(f"Error reading doc {file_path}: {e}")
raise HTTPException(status_code=500, detail="Error reading document")
# --- MCP Help API ---
@app.get("/api/v1/help")
async def get_mcp_help():
"""Proxy call to the MCP robotics_system(operation='help') tool."""
# We call our own MCP endpoint
# Note: In production, we'd use a more robust way to find the internal port
mcp_url = "http://127.0.0.1:10707/mcp/tools/call"
payload = {"name": "robotics_system", "arguments": {"operation": "help"}}
try:
async with httpx.AsyncClient() as client:
response = await client.post(mcp_url, json=payload, timeout=10.0)
if response.status_code == 200:
result = response.json()
# Unpack the FastMCP response structure
if "content" in result and len(result["content"]) > 0:
import json
# FastMCP returns text in content[0].text
help_data_raw = result["content"][0].get("text", "{}")
try:
help_data = json.loads(help_data_raw)
return help_data
except json.JSONDecodeError:
return {"text": help_data_raw}
return result
else:
logger.error(f"MCP Help call failed: {response.status_code} - {response.text}")
return {"error": "Failed to fetch system help from MCP server"}
except Exception as e:
logger.error(f"Exception during MCP Help call: {e}")
return {"error": f"Connection error: {str(e)}"}
# Dynamic FastMCP HTTP Mount
try:
# Standard SOTA pattern: server.py must have create_app()
# In robotics-mcp, we check src/robotics_mcp/server.py
from robotics_mcp.server import create_app
mcp_app = create_app()
if mcp_app:
app.mount("/mcp", mcp_app)
logger.info("FastMCP HTTP app mounted successfully at /mcp")
except ImportError as e:
logger.warning(f"Could not import create_app from robotics_mcp.server: {e}")
except Exception as e:
logger.error(f"Failed to mount FastMCP app: {e}")
if __name__ == "__main__":
import uvicorn
# Backend runs on port 10707 (Frontend is 10706)
uvicorn.run(app, host="127.0.0.1", port=10707)