c5498273c3
The MCP was still calling /api/briefing/* endpoints I deleted in the
journal hard-cut. Replaced the briefing tool surface with a journal
equivalent so external MCP clients can inspect and control the journal
the same way they could the briefing.
Changes:
- New fable_mcp/tools/journal.py — helpers for /api/journal/* endpoints
- Delete fable_mcp/tools/briefing.py — RSS endpoints are gone too
- server.py: drop fable_list_rss_feeds, fable_add_rss_feed, fable_remove_rss_feed,
fable_list_briefings, fable_get_today_briefing, fable_get_briefing_messages,
fable_trigger_briefing, fable_reset_today_briefing
- server.py: add fable_get_today_journal, fable_get_journal_day,
fable_list_journal_days, fable_trigger_journal_prep, fable_get_journal_config,
fable_list_moments
- server.py: fable_get_conversation now points at journal.get_conversation
(same /api/chat/conversations/{id} endpoint, just lives under journal helpers)
- Update _INSTRUCTIONS to describe the journal model (replacing the RSS/briefing
section) — explains the daily prep, moments, day payloads
- Update top-line docstring: "Fable Assistant" → "Fable Scribe"
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
97 lines
3.5 KiB
Python
97 lines
3.5 KiB
Python
"""MCP tools for inspecting and controlling the Fable Scribe Journal."""
|
|
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
from fable_mcp.client import FableClient
|
|
|
|
|
|
# ── Day payloads ─────────────────────────────────────────────────────────────
|
|
|
|
|
|
async def get_today_journal(client: FableClient) -> dict[str, Any]:
|
|
"""Fetch today's journal day payload (creates today's conversation + prep if needed)."""
|
|
return await client.get("/api/journal/today")
|
|
|
|
|
|
async def get_journal_day(client: FableClient, *, iso_date: str) -> dict[str, Any]:
|
|
"""Fetch a specific day's journal payload by ISO date (YYYY-MM-DD)."""
|
|
return await client.get(f"/api/journal/day/{iso_date}")
|
|
|
|
|
|
async def list_journal_days(client: FableClient) -> dict[str, Any]:
|
|
"""List dates that have journal content for the current user."""
|
|
return await client.get("/api/journal/days")
|
|
|
|
|
|
# ── Daily prep ───────────────────────────────────────────────────────────────
|
|
|
|
|
|
async def trigger_journal_prep(
|
|
client: FableClient,
|
|
*,
|
|
iso_date: str | None = None,
|
|
) -> dict[str, Any]:
|
|
"""Force-regenerate the daily prep for today (or a specific day)."""
|
|
payload: dict[str, Any] = {}
|
|
if iso_date:
|
|
payload["date"] = iso_date
|
|
return await client.post("/api/journal/trigger-prep", json=payload)
|
|
|
|
|
|
# ── Config ───────────────────────────────────────────────────────────────────
|
|
|
|
|
|
async def get_journal_config(client: FableClient) -> dict[str, Any]:
|
|
"""Fetch the user's journal config (prep schedule, day rollover, locations, etc.)."""
|
|
return await client.get("/api/journal/config")
|
|
|
|
|
|
# ── Moments ──────────────────────────────────────────────────────────────────
|
|
|
|
|
|
async def list_moments(
|
|
client: FableClient,
|
|
*,
|
|
query: str | None = None,
|
|
person_id: int | None = None,
|
|
place_id: int | None = None,
|
|
tag: str | None = None,
|
|
date_from: str | None = None,
|
|
date_to: str | None = None,
|
|
pinned_only: bool = False,
|
|
limit: int = 50,
|
|
) -> dict[str, Any]:
|
|
"""List/search journal moments with optional filters.
|
|
|
|
All params are optional. Returns a dict with a ``moments`` array.
|
|
"""
|
|
params: dict[str, str] = {"limit": str(limit)}
|
|
if query:
|
|
params["query"] = query
|
|
if person_id is not None:
|
|
params["person_id"] = str(person_id)
|
|
if place_id is not None:
|
|
params["place_id"] = str(place_id)
|
|
if tag:
|
|
params["tag"] = tag
|
|
if date_from:
|
|
params["date_from"] = date_from
|
|
if date_to:
|
|
params["date_to"] = date_to
|
|
if pinned_only:
|
|
params["pinned_only"] = "true"
|
|
return await client.get("/api/journal/moments", params=params)
|
|
|
|
|
|
# ── Generic conversation access (still works for journal conversations) ───────
|
|
|
|
|
|
async def get_conversation(
|
|
client: FableClient,
|
|
*,
|
|
conversation_id: int,
|
|
) -> dict[str, Any]:
|
|
"""Fetch any conversation (chat or journal) with its full message list."""
|
|
return await client.get(f"/api/chat/conversations/{conversation_id}")
|