refactor(mcp): drop fable_ prefix from tool names; rebrand to Scribe
MCP clients see tools namespaced by the server's local name already
(mcp__<server>__<tool>), so the fable_ prefix on every tool name was
redundant and ate tokens in the model's tool list.
Tools renamed (34 total):
fable_search → search
fable_list_notes / get_note / create_note / update_note / delete_note → list_notes / ...
fable_list_tasks / get_task / create_task / update_task / add_task_log → list_tasks / ...
fable_list_projects / get_project / create_project / update_project → list_projects / ...
fable_list_milestones / create_milestone / update_milestone → list_milestones / ...
fable_list_events / create_event / get_event / update_event / delete_event → list_events / ...
fable_list_tags → list_tags
fable_get_recent → get_recent
fable_list_persons / create_person / update_person → list_persons / ...
fable_list_places / create_place / update_place → list_places / ...
fable_list_lists / create_list / update_list → list_lists / ...
Also rebranded in MCP scope:
FastMCP("fable", ...) → FastMCP("scribe", ...)
auth realm "fable-mcp" → "scribe-mcp"
ASGI scope key fable_user_id → scribe_user_id
ContextVar label fable_mcp_user_id → scribe_mcp_user_id
Tool docstrings "in Fable" / "Fable task" → "in Scribe" / "Scribe task"
Server _INSTRUCTIONS prose
Deliberately kept:
- The internal Python package name `fabledassistant` (per project naming
convention — internal stays).
- "Fabled Scribe" as the official product/brand name (page footer,
smtp_from_name default).
- References to the legacy `fable-mcp/` standalone package in docstrings
explaining what we ported from — accurate until that directory is
deleted in Phase 10.
Client impact: existing MCP registrations need
claude mcp remove <name> && claude mcp add ...
once with a freshly-copied snippet from Settings → MCP Access. Claude
Code then re-discovers tools on connect — old conversations that
referenced fable_* tool names will see "tool not found" on those calls
until updated.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5,15 +5,16 @@ from mcp.server.fastmcp import FastMCP
|
||||
from quart import Quart
|
||||
|
||||
_INSTRUCTIONS = """
|
||||
Fabled Scribe is the user's self-hosted second-brain and project-management
|
||||
data store. You (Claude) are the assistant.
|
||||
Scribe is the user's self-hosted second-brain and project-management data
|
||||
store. You (Claude) are the assistant.
|
||||
|
||||
Hierarchy: Project -> Milestone -> Task/Note.
|
||||
|
||||
- Notes and Tasks share a model; tasks are notes with is_task=True.
|
||||
- Use fable_*_note tools for notes, fable_*_task tools for tasks.
|
||||
- Typed entities (person, place, list) are notes with a type field plus
|
||||
type-specific columns; use the dedicated tools for those.
|
||||
- Use the *_note tools for notes, the *_task tools for tasks. Don't mix them.
|
||||
- Typed entities (person, place, list) are notes with a non-default note_type
|
||||
plus type-specific columns; use the dedicated *_person / *_place / *_list
|
||||
tools rather than create_note.
|
||||
- Tags are plain strings (no `#` prefix). Empty list clears tags; omit to leave
|
||||
unchanged on updates.
|
||||
- For optional integer FKs (project_id, milestone_id, parent_id), use 0 to mean
|
||||
@@ -23,7 +24,7 @@ Hierarchy: Project -> Milestone -> Task/Note.
|
||||
|
||||
def build_mcp_server() -> FastMCP:
|
||||
"""Build the FastMCP instance with all tools registered."""
|
||||
mcp = FastMCP("fable", instructions=_INSTRUCTIONS.strip())
|
||||
mcp = FastMCP("scribe", instructions=_INSTRUCTIONS.strip())
|
||||
from fabledassistant.mcp.tools import register_all
|
||||
register_all(mcp)
|
||||
return mcp
|
||||
@@ -34,7 +35,7 @@ def mount_mcp(app: Quart) -> None:
|
||||
|
||||
A small ASGI middleware between Quart and the FastMCP sub-app validates the
|
||||
Bearer token against the api_keys table. Authenticated requests have their
|
||||
user_id attached to the ASGI scope under "fable_user_id" for tool handlers
|
||||
user_id attached to the ASGI scope under "scribe_user_id" for tool handlers
|
||||
to read in later phases.
|
||||
"""
|
||||
from fabledassistant.mcp.auth import resolve_bearer_to_user_id
|
||||
@@ -55,7 +56,7 @@ def mount_mcp(app: Quart) -> None:
|
||||
"status": 401,
|
||||
"headers": [
|
||||
(b"content-type", b"application/json"),
|
||||
(b"www-authenticate", b'Bearer realm="fable-mcp"'),
|
||||
(b"www-authenticate", b'Bearer realm="scribe-mcp"'),
|
||||
],
|
||||
})
|
||||
await send({
|
||||
@@ -63,7 +64,7 @@ def mount_mcp(app: Quart) -> None:
|
||||
"body": b'{"error":"unauthorized"}',
|
||||
})
|
||||
return
|
||||
scope["fable_user_id"] = user_id
|
||||
scope["scribe_user_id"] = user_id
|
||||
from fabledassistant.mcp._context import _user_id_ctx
|
||||
token = _user_id_ctx.set(user_id)
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user