| """Always-on verification of the top featured MCP servers against the sandbox. |
| |
| This fetches the top entries from the **real** Matrix Hub API (no hardcoded |
| ids) and runs the sandbox-testability verifier on each, so we continuously know |
| which featured servers can be trialed in the no-secrets sandbox and which are |
| tagged "not available" (and why). |
| |
| Run: |
| cd hf && python -m pytest tests/test_featured_sandbox.py -v -s |
| |
| Network: hits https://api.matrixhub.io. If unreachable, network-dependent tests |
| skip (so the suite stays green offline). Set MATRIXLAB_SANDBOX_LIVE=1 and |
| MATRIXLAB_SANDBOX_URL=<worker> to additionally start real sandbox sessions for |
| the testable servers. |
| """ |
| from __future__ import annotations |
|
|
| import os |
| import sys |
| import time |
| from pathlib import Path |
|
|
| import pytest |
|
|
| sys.path.insert(0, str(Path(__file__).resolve().parents[1])) |
| from app.plan import verify, is_testable |
|
|
| try: |
| import requests |
| except Exception: |
| requests = None |
|
|
| HUB = os.environ.get("MATRIX_HUB_BASE", "https://api.matrixhub.io").rstrip("/") |
| TOP_N = int(os.environ.get("FEATURED_TOP_N", "5")) |
|
|
|
|
| def _get(path: str): |
| if requests is None: |
| pytest.skip("requests not installed") |
| try: |
| r = requests.get(HUB + path, timeout=15, headers={"Accept": "application/json"}) |
| r.raise_for_status() |
| return r.json() |
| except Exception as e: |
| pytest.skip(f"Matrix Hub unreachable ({HUB}): {e}") |
|
|
|
|
| def _featured_top(): |
| """Top featured entries from the real catalog (mirrors the homepage feed).""" |
| data = _get(f"/catalog?limit={TOP_N}&sort=quality") |
| items = data.get("items") or data.get("entities") or [] |
| return items[:TOP_N] |
|
|
|
|
| |
|
|
| def test_real_api_returns_featured(): |
| items = _featured_top() |
| assert items, "real Matrix Hub returned no featured items" |
| assert all(it.get("id") for it in items), "featured items missing ids" |
|
|
|
|
| def test_verifier_classifies_top5_featured(): |
| """The verifier must produce a clear testable/not verdict for every one of |
| the live top-5 featured servers (this is the 'tag' the UI shows).""" |
| items = _featured_top() |
| print(f"\nSandbox testability of top {len(items)} featured (live from {HUB}):") |
| for it in items: |
| v = verify(it) |
| tag = "● available" if v["testable"] else "○ not available" |
| print(f" {tag:16} {it.get('name') or it.get('id')}") |
| print(f" id={it.get('id')}") |
| print(f" reason: {v['reason']}") |
| if v["testable"]: |
| print(f" run: {v['start_command']}") |
| |
| assert isinstance(v["testable"], bool) |
| assert v["reason"] |
| if v["testable"]: |
| assert v["start_command"] and v["runtime"] in ("node", "python") |
|
|
|
|
| |
|
|
| @pytest.mark.parametrize("entity,expected", [ |
| ({"id": "mcp.io-github-modelcontextprotocol-servers.filesystem", |
| "name": "Filesystem", "source_url": "https://github.com/modelcontextprotocol/servers"}, True), |
| ({"id": "x", "name": "Time", "source_url": "https://github.com/x/mcp-server-time"}, True), |
| ({"id": "tool.io-github-mindstone-mcp-server-retell-ai.5425b3de29", |
| "name": "Retell AI", "source_url": "https://github.com/mindstone/retell"}, False), |
| ({"id": "tool.x", "name": "Microsoft Office", "source_url": "https://github.com/x/office"}, False), |
| ({"id": "mcp.some-unknown-server", "name": "Unknown", "source_url": "https://github.com/x/y"}, False), |
| ]) |
| def test_verifier_contract(entity, expected): |
| assert is_testable(entity) is expected |
|
|
|
|
| def test_saas_reason_mentions_credentials(): |
| v = verify({"id": "x", "name": "Retell AI", "source_url": ""}) |
| assert v["testable"] is False |
| assert "credential" in v["reason"].lower() |
|
|
|
|
| |
|
|
| @pytest.mark.skipif(os.environ.get("MATRIXLAB_SANDBOX_LIVE") != "1", |
| reason="set MATRIXLAB_SANDBOX_LIVE=1 (+ MATRIXLAB_SANDBOX_URL) to run live") |
| def test_live_sandbox_runs_testable_featured(): |
| base = os.environ.get("MATRIXLAB_SANDBOX_URL", "http://127.0.0.1:7860").rstrip("/") |
| |
| plan = verify({"id": "filesystem", "name": "Filesystem", |
| "source_url": "https://github.com/modelcontextprotocol/servers"}) |
| assert plan["testable"] |
| r = requests.post(f"{base}/mcp/sessions", timeout=30, json={ |
| "entity_id": "test-filesystem", "runtime": plan["runtime"], |
| "start_command": plan["start_command"], "transport": "stdio", "ttl_seconds": 120, |
| }) |
| r.raise_for_status() |
| sid = r.json()["session_id"] |
| try: |
| status = "" |
| for _ in range(40): |
| status = requests.get(f"{base}/mcp/sessions/{sid}", timeout=15).json()["status"] |
| if status in ("running", "failed", "timeout", "install_failed", "start_failed"): |
| break |
| time.sleep(2) |
| assert status == "running", f"sandbox status={status}" |
| tools = requests.get(f"{base}/mcp/sessions/{sid}/tools", timeout=15).json().get("tools", []) |
| assert len(tools) > 0, "no tools discovered" |
| finally: |
| requests.delete(f"{base}/mcp/sessions/{sid}", timeout=15) |
|
|