feat(files-mcp): mount at /files-mcp via MCP_SERVICES registry
- main.py: import files_app, append McpService entry to MCP_SERVICES. Lifespan already iterates the list, so no edit to the lifespan function. - tests/conftest.py: autouse fixture rebinds files_mcp.core.path_guard._ROOT to a per-test tmp_path so the sandbox is fresh for every test. - files_mcp/__init__.py: drop the try/except around the server import now that server.py exists, restoring fail-fast on a missing/corrupt server module in production. The _init_root() try/except stays, since pytest collection can import the package before FILES_MCP_ROOT is set. Verified via uv run pytest: 327 tests pass, no regressions. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -16,13 +16,12 @@ try:
|
|||||||
except RuntimeError:
|
except RuntimeError:
|
||||||
_ROOT = None
|
_ROOT = None
|
||||||
|
|
||||||
# Re-export the FastAPI app once the sandbox root has been initialized.
|
# Re-export the FastAPI app. server.py now exists, so this import is
|
||||||
# server.py is created in a later task; importing it lazily keeps this
|
# unconditional — a missing/corrupt server.py fails loud at import time
|
||||||
# package importable (and unit-testable) before that task lands.
|
# (production-correct behavior). The sandbox root is only needed by the
|
||||||
try: # pragma: no cover - exercised once server.py exists
|
# tool routes at request time, not at import, so this stays safe to import
|
||||||
from files_mcp.server import app # noqa: E402
|
# even when FILES_MCP_ROOT is unset (e.g. during pytest collection).
|
||||||
except ImportError:
|
from files_mcp.server import app # noqa: E402
|
||||||
app = None # type: ignore[assignment]
|
|
||||||
|
|
||||||
ROOT: Path | None = _ROOT
|
ROOT: Path | None = _ROOT
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ from fastapi import FastAPI
|
|||||||
|
|
||||||
from common.factory import init_mcp_server
|
from common.factory import init_mcp_server
|
||||||
from common.logging import logger
|
from common.logging import logger
|
||||||
|
from files_mcp import app as files_app
|
||||||
from spark_executor import app as spark_executor_app
|
from spark_executor import app as spark_executor_app
|
||||||
|
|
||||||
|
|
||||||
@@ -39,6 +40,11 @@ MCP_SERVICES: list[McpService] = [
|
|||||||
app=spark_executor_app,
|
app=spark_executor_app,
|
||||||
mount_path="/spark-executor-mcp",
|
mount_path="/spark-executor-mcp",
|
||||||
),
|
),
|
||||||
|
McpService(
|
||||||
|
name="files",
|
||||||
|
app=files_app,
|
||||||
|
mount_path="/files-mcp",
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -6,3 +6,20 @@ from pathlib import Path
|
|||||||
ROOT = Path(__file__).resolve().parents[1]
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
if str(ROOT) not in sys.path:
|
if str(ROOT) not in sys.path:
|
||||||
sys.path.insert(0, str(ROOT))
|
sys.path.insert(0, str(ROOT))
|
||||||
|
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def _isolate_files_mcp_root(tmp_path, monkeypatch):
|
||||||
|
"""Point files_mcp at a fresh tmp_path for every test.
|
||||||
|
|
||||||
|
Sets FILES_MCP_ROOT and rebinds files_mcp.core.path_guard's module-level
|
||||||
|
_ROOT, so each test starts with an empty sandbox. Spark_executor tests
|
||||||
|
are unaffected by this fixture — they don't touch the files_mcp sandbox.
|
||||||
|
"""
|
||||||
|
monkeypatch.setenv("FILES_MCP_ROOT", str(tmp_path))
|
||||||
|
from files_mcp.core import path_guard
|
||||||
|
path_guard.set_root_for_testing(tmp_path.resolve())
|
||||||
|
yield
|
||||||
|
|||||||
Reference in New Issue
Block a user