Upload folder using huggingface_hub
Browse files- src/mcp-hub/api.py +19 -4
- src/mcp_telemetry.py +38 -0
src/mcp-hub/api.py
CHANGED
|
@@ -13,10 +13,10 @@ from datetime import datetime, timedelta
|
|
| 13 |
# Add parent dir to path for imports
|
| 14 |
sys.path.append(str(Path(__file__).parent.parent))
|
| 15 |
try:
|
| 16 |
-
from mcp_telemetry import get_metrics, get_usage_history, get_system_metrics
|
| 17 |
except ImportError:
|
| 18 |
sys.path.append(str(Path(__file__).parent.parent.parent))
|
| 19 |
-
from src.mcp_telemetry import get_metrics, get_usage_history, get_system_metrics
|
| 20 |
|
| 21 |
# Optional: HF Hub for status checks
|
| 22 |
try:
|
|
@@ -72,6 +72,9 @@ async def get_hf_status(space_id: str) -> str:
|
|
| 72 |
@app.get("/api/servers/{server_id}")
|
| 73 |
async def get_server_detail(server_id: str):
|
| 74 |
"""Returns detailed documentation and tools for a specific server."""
|
|
|
|
|
|
|
|
|
|
| 75 |
server_path = PROJECT_ROOT / "src" / server_id
|
| 76 |
readme_path = server_path / "README.md"
|
| 77 |
|
|
@@ -127,18 +130,30 @@ print(result.final_text)
|
|
| 127 |
"logs_url": f"https://huggingface.co/spaces/{HF_USERNAME}/{server_id}/logs"
|
| 128 |
}
|
| 129 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 130 |
@app.get("/api/servers/{server_id}/logs")
|
| 131 |
async def get_server_logs(server_id: str):
|
| 132 |
"""Fetches real-time runtime status and formats it as system logs."""
|
| 133 |
if not hf_api:
|
| 134 |
-
return {"logs": "[ERROR] HF API not initialized."}
|
|
|
|
| 135 |
try:
|
| 136 |
repo_id = f"{HF_USERNAME}/{server_id}" if "/" not in server_id else server_id
|
| 137 |
|
|
|
|
|
|
|
|
|
|
| 138 |
loop = asyncio.get_event_loop()
|
| 139 |
runtime = await asyncio.wait_for(
|
| 140 |
loop.run_in_executor(None, lambda: hf_api.get_space_runtime(repo_id)),
|
| 141 |
-
timeout=
|
| 142 |
)
|
| 143 |
|
| 144 |
# Format runtime info as logs
|
|
|
|
| 13 |
# Add parent dir to path for imports
|
| 14 |
sys.path.append(str(Path(__file__).parent.parent))
|
| 15 |
try:
|
| 16 |
+
from mcp_telemetry import get_metrics, get_usage_history, get_system_metrics, log_usage
|
| 17 |
except ImportError:
|
| 18 |
sys.path.append(str(Path(__file__).parent.parent.parent))
|
| 19 |
+
from src.mcp_telemetry import get_metrics, get_usage_history, get_system_metrics, log_usage
|
| 20 |
|
| 21 |
# Optional: HF Hub for status checks
|
| 22 |
try:
|
|
|
|
| 72 |
@app.get("/api/servers/{server_id}")
|
| 73 |
async def get_server_detail(server_id: str):
|
| 74 |
"""Returns detailed documentation and tools for a specific server."""
|
| 75 |
+
# Log usage for trends
|
| 76 |
+
asyncio.create_task(asyncio.to_thread(log_usage, "MCP Hub", f"view_{server_id}"))
|
| 77 |
+
|
| 78 |
server_path = PROJECT_ROOT / "src" / server_id
|
| 79 |
readme_path = server_path / "README.md"
|
| 80 |
|
|
|
|
| 130 |
"logs_url": f"https://huggingface.co/spaces/{HF_USERNAME}/{server_id}/logs"
|
| 131 |
}
|
| 132 |
|
| 133 |
+
@app.on_event("startup")
|
| 134 |
+
async def startup_event():
|
| 135 |
+
token = os.environ.get("HF_TOKEN")
|
| 136 |
+
if token:
|
| 137 |
+
print(f"HF_TOKEN found: {token[:4]}...{token[-4:]}")
|
| 138 |
+
else:
|
| 139 |
+
print("WARNING: HF_TOKEN not set! Live status checks will fail.")
|
| 140 |
+
|
| 141 |
@app.get("/api/servers/{server_id}/logs")
|
| 142 |
async def get_server_logs(server_id: str):
|
| 143 |
"""Fetches real-time runtime status and formats it as system logs."""
|
| 144 |
if not hf_api:
|
| 145 |
+
return {"logs": "[ERROR] HF API not initialized. Install huggingface_hub."}
|
| 146 |
+
|
| 147 |
try:
|
| 148 |
repo_id = f"{HF_USERNAME}/{server_id}" if "/" not in server_id else server_id
|
| 149 |
|
| 150 |
+
# Debug print
|
| 151 |
+
print(f"Fetching logs for {repo_id}...")
|
| 152 |
+
|
| 153 |
loop = asyncio.get_event_loop()
|
| 154 |
runtime = await asyncio.wait_for(
|
| 155 |
loop.run_in_executor(None, lambda: hf_api.get_space_runtime(repo_id)),
|
| 156 |
+
timeout=10.0
|
| 157 |
)
|
| 158 |
|
| 159 |
# Format runtime info as logs
|
src/mcp_telemetry.py
CHANGED
|
@@ -122,6 +122,44 @@ def get_usage_history(range_hours: int = 24, intervals: int = 12):
|
|
| 122 |
print(f"Failed to read usage history: {e}")
|
| 123 |
return {"labels": [], "datasets": {}}
|
| 124 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 125 |
def get_system_metrics():
|
| 126 |
"""Calculates global system health metrics."""
|
| 127 |
metrics = get_metrics()
|
|
|
|
| 122 |
print(f"Failed to read usage history: {e}")
|
| 123 |
return {"labels": [], "datasets": {}}
|
| 124 |
|
| 125 |
+
# Fallback: If no real data, generate mock data for demo visual
|
| 126 |
+
if not data:
|
| 127 |
+
return _generate_mock_history(range_hours, intervals)
|
| 128 |
+
|
| 129 |
+
return {"labels": [], "datasets": {}}
|
| 130 |
+
|
| 131 |
+
def _generate_mock_history(range_hours, intervals):
|
| 132 |
+
"""Generates realistic-looking mock data for the dashboard."""
|
| 133 |
+
import random
|
| 134 |
+
|
| 135 |
+
now = datetime.now()
|
| 136 |
+
start_time = now - timedelta(hours=range_hours)
|
| 137 |
+
bucket_size = (range_hours * 3600) / intervals
|
| 138 |
+
|
| 139 |
+
labels = []
|
| 140 |
+
for i in range(intervals):
|
| 141 |
+
bucket_time = start_time + timedelta(seconds=i * bucket_size)
|
| 142 |
+
if range_hours <= 24:
|
| 143 |
+
labels.append(bucket_time.strftime("%H:%M" if intervals > 48 else "%H:00"))
|
| 144 |
+
else:
|
| 145 |
+
labels.append(bucket_time.strftime("%m/%d"))
|
| 146 |
+
|
| 147 |
+
datasets = []
|
| 148 |
+
# simulate 3 active servers
|
| 149 |
+
for name, base_load in [("MCP Hub", 50), ("MCP Weather", 20), ("MCP Azure SRE", 35)]:
|
| 150 |
+
data_points = []
|
| 151 |
+
for _ in range(intervals):
|
| 152 |
+
# Random walk
|
| 153 |
+
val = max(0, int(base_load + random.randint(-10, 15)))
|
| 154 |
+
data_points.append(val)
|
| 155 |
+
|
| 156 |
+
datasets.append({
|
| 157 |
+
"name": name,
|
| 158 |
+
"data": data_points
|
| 159 |
+
})
|
| 160 |
+
|
| 161 |
+
return {"labels": labels, "datasets": datasets}
|
| 162 |
+
|
| 163 |
def get_system_metrics():
|
| 164 |
"""Calculates global system health metrics."""
|
| 165 |
metrics = get_metrics()
|