feat(fable-mcp): build wheel in Docker image, serve download, add admin log tool, and Settings install UI

- 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>
This commit is contained in:
2026-03-24 17:26:05 -04:00
parent 6564a03c0e
commit 553c38200a
8 changed files with 202 additions and 3 deletions
+26 -1
View File
@@ -5,7 +5,7 @@ from mcp.server.fastmcp import FastMCP
from dotenv import load_dotenv
from fable_mcp.client import FableClient
from fable_mcp.tools import notes, tasks, projects, milestones, search, chat
from fable_mcp.tools import notes, tasks, projects, milestones, search, chat, admin
load_dotenv()
@@ -341,6 +341,31 @@ async def fable_send_message(
)
# ---------------------------------------------------------------------------
# Admin / observability
# ---------------------------------------------------------------------------
@mcp.tool()
async def fable_get_app_logs(
category: str = "error",
limit: int = 20,
search: str = "",
) -> dict:
"""Fetch Fable application logs. Requires an admin API key.
category: "error" (default) | "audit" | "usage"
search: optional keyword filter applied to action, endpoint, username, and details
"""
async with FableClient() as client:
return await admin.get_app_logs(
client,
category=category,
limit=limit,
search=search or None,
)
# ---------------------------------------------------------------------------
# Entry point
# ---------------------------------------------------------------------------
+20
View File
@@ -0,0 +1,20 @@
"""Admin tools: application log access (requires admin API key)."""
from __future__ import annotations
from fable_mcp.client import FableClient
async def get_app_logs(
client: FableClient,
category: str = "error",
limit: int = 20,
search: str | None = None,
) -> dict:
"""Fetch application logs from Fable. Requires an admin-scoped API key.
category: "error" | "audit" | "usage" (default: "error")
"""
params: dict = {"category": category, "limit": limit}
if search:
params["search"] = search
return await client.get("/api/admin/logs", params=params)