Commit Graph
6 Commits
Author SHA1 Message Date
7adc935632 refactor(mcp): use discover_and_filter in main.py; add per-service manifests
- main.py: drops the hard-coded McpService class and MCP_SERVICES list.
  Lifespan now calls discover_and_filter() which does import + env
  filtering. Unset MCP_SERVICES reproduces today's behavior exactly.
- spark_executor/service.py: new file exporting SERVICE = McpService(
  name='spark_executor', app=spark_executor.app, mount_path='/spark-executor-mcp').
- files_mcp/service.py: new file exporting SERVICE = McpService(
  name='files', app=files_mcp.app, mount_path='/files-mcp').

The McpService dataclass itself moved to common/mcp_service.py in the
prior commit. 327 existing tests pass unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-30 11:13:23 +00:00
ClaudeandClaude Fable 5 c17a33152f 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>
2026-06-30 18:15:45 +08:00
ClaudeandClaude Fable 5 8c110329b2 feat(files-mcp): FastAPI app with 9 tool routes and integration tests
Adds files_mcp/server.py (FastAPI title=Files MCP, 9 POST routes, and
3 exception handlers: KeyError->404, ValueError->400, FileExistsError->409).
The third handler is the only one not present in spark_executor.server;
handlers are registered on this app only, so spark_executor is unaffected.

Adds tests/integration/test_files_mcp_routes.py with 12 end-to-end HTTP
tests covering CRUD happy paths, error codes (404/400/409), and
introspection (list_dir, stat, search, move, copy).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-30 18:09:35 +08:00
ClaudeandClaude Fable 5 36da3f7024 feat(files-mcp): business wrappers and Pydantic request models
Adds files_mcp/tools/requests.py with 9 Pydantic body models (one per
tool, since fastapi-mcp passes args as JSON body) and
files_mcp/tools/files.py with 9 thin wrappers that call path_guard
then fs_ops and return model_dump() form. Adds tests/unit/test_files_tool.py
covering happy path, sandbox escape, and KeyError/FileExistsError
propagation for each wrapper.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-30 17:57:02 +08:00
ClaudeandClaude Fable 5 01f5e54a66 feat(files-mcp): add Pydantic models and pure fs_ops layer
Adds files_mcp/models.py (FileEntry, OperationResult) and
files_mcp/core/fs_ops.py with 9 pure file operations on already-resolved
Path objects: create/read/update/delete/list_dir/stat/search/move/copy.

All writes go through tempfile.mkstemp + os.replace for atomicity;
read enforces utf-8 + 1MB cap; create/update enforce strict presence
semantics (create: absent or overwrite; update: present). 39 unit tests
in tests/unit/test_fs_ops.py.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-30 17:52:00 +08:00
ClaudeandClaude Fable 5 d8d541f50d feat(files-mcp): scaffold package + path_guard sandbox
Adds the files_mcp/ sibling package and core/path_guard.py which
resolves arbitrary input paths and rejects any that escape the
FILES_MCP_ROOT sandbox (handles .., ~, symlinks, NUL, empty). Adds
tests/unit/test_path_guard.py covering accept, escape modes,
symlink escape, and _init_root failure paths.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-30 17:39:23 +08:00