553c38200a
- Dockerfile: build fable-mcp wheel into /app/dist/ during image build - routes/fable_mcp_dist.py: GET /api/fable-mcp/info + /download endpoints - app.py: register fable_mcp_dist_bp - fable_mcp/tools/admin.py: get_app_logs() hitting /api/admin/logs - fable_mcp/server.py: fable_get_app_logs MCP tool - SettingsView: "Fable MCP" section in API Keys tab with download button and install instructions - client.ts: getFableMcpInfo() helper - ci.yml: add fable-mcp/** to trigger paths Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
43 lines
1.3 KiB
Python
43 lines
1.3 KiB
Python
"""Serve the fable-mcp distribution wheel built into the Docker image."""
|
|
import logging
|
|
import os
|
|
from pathlib import Path
|
|
|
|
from quart import Blueprint, jsonify, send_file
|
|
|
|
from fabledassistant.auth import login_required
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
fable_mcp_dist_bp = Blueprint("fable_mcp_dist", __name__, url_prefix="/api/fable-mcp")
|
|
|
|
# Wheel is built into the image at this path (see Dockerfile)
|
|
_DIST_DIR = Path(os.environ.get("FABLE_MCP_DIST_DIR", "/app/dist"))
|
|
|
|
|
|
def _find_wheel() -> Path | None:
|
|
"""Return the newest fable_mcp wheel in the dist dir, or None."""
|
|
wheels = sorted(_DIST_DIR.glob("fable_mcp-*.whl"), reverse=True)
|
|
return wheels[0] if wheels else None
|
|
|
|
|
|
@fable_mcp_dist_bp.route("/info", methods=["GET"])
|
|
@login_required
|
|
async def fable_mcp_info():
|
|
"""Return availability and filename of the bundled fable-mcp wheel."""
|
|
wheel = _find_wheel()
|
|
return jsonify({
|
|
"available": wheel is not None,
|
|
"filename": wheel.name if wheel else None,
|
|
})
|
|
|
|
|
|
@fable_mcp_dist_bp.route("/download", methods=["GET"])
|
|
@login_required
|
|
async def download_fable_mcp():
|
|
"""Serve the fable-mcp wheel file as a download."""
|
|
wheel = _find_wheel()
|
|
if wheel is None:
|
|
return jsonify({"error": "Package not built into this image"}), 404
|
|
return await send_file(wheel, as_attachment=True)
|