diff --git a/docs/api-keys-and-mcp.md b/docs/api-keys-and-mcp.md index 61f058e..35b89ea 100644 --- a/docs/api-keys-and-mcp.md +++ b/docs/api-keys-and-mcp.md @@ -1,4 +1,4 @@ -# API Keys and Fable MCP +# API Keys and Scribe MCP ## API Keys @@ -19,11 +19,10 @@ Admin-level operations (log access, user management) require a `write`-scoped ke 2. Enter a name (e.g. "Claude MCP", "Home Server") 3. Choose scope 4. Click **Generate Key** -5. Copy the key immediately — it is shown only once +5. Copy the key immediately — it is shown only once (the token is `fmcp_`-prefixed) -After creation you can download: -- **`.env` file** — `FABLE_URL` + `FABLE_API_KEY` ready to paste -- **Claude config JSON** — `mcpServers` block ready to merge into `~/.claude.json` +Paste the key into the `Authorization: Bearer ` header of your MCP client +config (see **Scribe MCP Server** below). ### Revoking a Key @@ -31,73 +30,35 @@ Click **Revoke** next to the key in the API Keys table and confirm. Revoked keys --- -## Fable MCP Server +## Scribe MCP Server -The Fable MCP server (`fable-mcp`) exposes Fable as a set of MCP tools that Claude (and other MCP clients) can use to read and write your notes, tasks, projects, and more. +Scribe exposes itself as a set of MCP tools that Claude (and other MCP clients) +can use to read and write your notes, tasks, projects, rulebooks, and more. The +server is **built into the app** — it is mounted as a streamable-HTTP endpoint +at **`/mcp`** on the running Scribe instance (`src/scribe/mcp/server.py`). There +is nothing to install: no wheel, no separate package, no CLI. You connect a +client straight to the URL with a Bearer token. -### Download +### Authentication -The wheel is bundled into the Docker image at build time and available for download from **Settings → API Keys → Fable MCP** when you are logged in. - -You can also download it directly: -``` -GET /api/fable-mcp/download -``` -(Requires login — authenticated browser session or API key in `Authorization: Bearer ` header.) - -### Installation - -```bash -# Install the wheel -pip install fable_mcp-*.whl - -# Verify -fable-mcp --help -``` - -### Configuration - -The server reads two environment variables: - -| Variable | Description | -|----------|-------------| -| `FABLE_URL` | Base URL of your Fable instance (e.g. `https://notes.example.com`) | -| `FABLE_API_KEY` | API key generated from Settings → API Keys | - -Create a `.env` file in your working directory, or set them in your shell / MCP config. - -### Claude Code (Global) - -Add to `~/.claude.json`: - -```json -{ - "mcpServers": { - "fable": { - "type": "stdio", - "command": "fable-mcp", - "env": { - "FABLE_URL": "https://your-fable-instance.example.com", - "FABLE_API_KEY": "your-api-key" - } - } - } -} -``` +Authenticate with an API key generated from **Settings → API Keys** (see above), +sent as `Authorization: Bearer fmcp_`. A `read`-scoped key may call only the +read tools (`get_*`, `list_*`, `search`, `enter_project`); any write/delete tool +is rejected with `403`. A `write`-scoped key may call everything. ### Claude Code (Project-scoped) -Add a `.mcp.json` at the project root (same format as the global config). Project-scoped config takes precedence over global when the same server name is defined in both. This is useful for using a dev instance or admin key within a specific project. +Add a `.mcp.json` at the project root. The server `type` is `http` and the URL is +your instance's `/mcp` endpoint: ```json { "mcpServers": { - "fable": { - "type": "stdio", - "command": "fable-mcp", - "env": { - "FABLE_URL": "http://localhost:5000", - "FABLE_API_KEY": "your-dev-api-key" + "scribe": { + "type": "http", + "url": "https://your-scribe-instance.example.com/mcp", + "headers": { + "Authorization": "Bearer fmcp_your-api-key" } } } @@ -106,39 +67,33 @@ Add a `.mcp.json` at the project root (same format as the global config). Projec Note: `.mcp.json` contains an API key and should be added to `.gitignore`. +### Claude Code (Global) + +The same `mcpServers` block can live in `~/.claude.json` to make the server +available across all projects. A project-scoped `.mcp.json` takes precedence over +the global entry when both define the same server name — useful for pointing a +specific project at a dev instance or an admin key. + ### Available Tools -| Tool | Description | -|------|-------------| -| `fable_list_notes` | List notes, filter by tag or search text | -| `fable_get_note` | Fetch a note by ID | -| `fable_create_note` | Create a new note | -| `fable_update_note` | Update a note | -| `fable_delete_note` | Delete a note | -| `fable_list_tasks` | List tasks, filter by status or project | -| `fable_get_task` | Fetch a task by ID | -| `fable_create_task` | Create a new task | -| `fable_update_task` | Update a task | -| `fable_add_task_log` | Append a work log entry to a task | -| `fable_list_projects` | List all projects | -| `fable_get_project` | Fetch a project with milestone summary | -| `fable_create_project` | Create a project | -| `fable_update_project` | Update a project | -| `fable_list_milestones` | List milestones for a project | -| `fable_create_milestone` | Create a milestone | -| `fable_update_milestone` | Update a milestone | -| `fable_search` | Semantic search over notes and tasks | -| `fable_list_conversations` | List MCP chat conversations | -| `fable_send_message` | Send a message to Fable's LLM | -| `fable_get_app_logs` | Fetch application logs (admin key required) | +The tool surface is large (~70 tools) and evolves with the app, so the live +registration in **`src/scribe/mcp/tools/`** is the source of truth rather than a +table here. The tools are grouped by family: -### Development Notes +| Family | Examples | Purpose | +|--------|----------|---------| +| Notes | `create_note`, `get_note`, `update_note`, `delete_note`, `list_notes` | Free-form knowledge | +| Tasks | `create_task`, `update_task`, `add_task_log`, `start_planning` | Actionable work + plans | +| Projects / Milestones | `enter_project`, `get_project`, `create_milestone`, … | Containers and outcomes | +| Search / Recall | `search`, `get_recent`, `list_tags` | Semantic + structured recall | +| Typed entities | `create_person`, `create_place`, `create_list`, … | Structured records | +| Events | `create_event`, `list_events`, `update_event`, … | Calendar | +| Rulebooks | `list_always_on_rules`, `list_rules`, `create_rule`, `create_project_rule`, `subscribe_project_to_rulebook`, … | Engineering/workflow rules | +| Processes | `list_processes`, `get_process`, `create_process` | Saved prompts/workflows | +| Trash | `list_trash`, `restore`, `purge_trash` | Recoverable deletes | +| Admin | `get_app_logs` (write/admin key) | Diagnostics | -The `fable-mcp` package lives in `fable-mcp/` in this repository. The Docker build compiles it into a wheel at `/app/dist/` so it can be served for download without requiring the source tree at runtime. - -To build the wheel locally: -```bash -cd fable-mcp -pip install build hatchling -python -m build --wheel . -``` +Server-level usage guidance — when to reach for each entity, the +recall-before-acting reflex, and the rulebook conventions — is delivered to the +client automatically via the MCP server's `instructions` block (defined in +`src/scribe/mcp/server.py`). diff --git a/docs/api-reference.md b/docs/api-reference.md index 8038546..523e2d0 100644 --- a/docs/api-reference.md +++ b/docs/api-reference.md @@ -179,12 +179,11 @@ All endpoints require login (session cookie or `Authorization: Bearer ` | POST | `/api/api-keys` | Create key `{name, scope}` → `{key, ...}` (key shown once) | | DELETE | `/api/api-keys/:id` | Revoke key | -## Fable MCP Distribution +## Scribe MCP -| Method | Path | Description | -|--------|------|-------------| -| GET | `/api/fable-mcp/info` | `{available: bool, filename: string\|null}` | -| GET | `/api/fable-mcp/download` | Download wheel file | +The MCP tool surface is served at `POST /mcp` (streamable HTTP, Bearer auth) by +the in-app server in `src/scribe/mcp/`. It is not a REST surface — see +[API Keys and Scribe MCP](api-keys-and-mcp.md) for client configuration. ## Notifications diff --git a/docs/architecture.md b/docs/architecture.md index 6b800b9..7329c0d 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -49,16 +49,14 @@ scribe/ ├── Dockerfile # Multi-stage build (Node → Python) ├── alembic/ # Database migrations │ └── versions/ # Migration files (idempotent raw SQL) -├── fable-mcp/ # Fable MCP server package -│ └── fable_mcp/ -│ ├── server.py # FastMCP tool registrations -│ ├── client.py # FableClient (httpx wrapper) -│ └── tools/ # Tool modules (notes, tasks, projects, …) ├── src/scribe/ │ ├── app.py # Quart app factory + blueprint registration │ ├── config.py # Config class (reads env vars) │ ├── auth.py # login_required decorator, session checks │ ├── models/ # SQLAlchemy models +│ ├── mcp/ # In-app MCP server (FastMCP, mounted at /mcp) +│ │ ├── server.py # FastMCP instance + instructions + Quart mount +│ │ └── tools/ # Tool modules (notes, tasks, projects, rulebooks, …) │ ├── routes/ # API blueprints (one file per resource) │ ├── services/ # Business logic (access, llm, tools, sharing, …) │ └── static/ # Built Vue SPA (generated at Docker build time) @@ -202,7 +200,7 @@ Permission resolution is centralised in `services/access.py`. `get_project_permi | `routes/images.py` | Serve cached images at `/api/images/` | | `routes/export.py` | `GET /api/export` — personal Markdown ZIP or JSON array download | | `routes/api_keys.py` | API key CRUD (`GET/POST/DELETE /api/api-keys`) | -| `routes/fable_mcp_dist.py` | `GET /api/fable-mcp/info` + `GET /api/fable-mcp/download` — package distribution | +| `mcp/server.py` | Mounts the in-app FastMCP server at `/mcp` (streamable HTTP, Bearer auth) | | `routes/quick_capture.py` | `POST /api/quick-capture` — single-shot natural language item creation | | `routes/search.py` | `GET /api/search` — semantic + keyword hybrid search | | `services/auth.py` | `create_user`, `authenticate`, user lookups, password reset tokens, invitation tokens | diff --git a/docs/configuration.md b/docs/configuration.md index f456ed3..e77c145 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -58,12 +58,6 @@ See [sso-oauth.md](sso-oauth.md) for provider-specific setup. | `LOG_RETENTION_DAYS` | `90` | Days to keep app logs before automatic pruning | | `DATA_DIR` | `/data` | Root directory for persistent data (VAPID keys, backups) | -### Fable MCP Distribution - -| Variable | Default | Description | -|----------|---------|-------------| -| `FABLE_MCP_DIST_DIR` | `/app/dist` | Directory where the bundled `fable-mcp` wheel is placed at build time | - ## Docker Compose Setup ### Development (`docker-compose.yml`) diff --git a/docs/development.md b/docs/development.md index 8a9a9f2..2afdebe 100644 --- a/docs/development.md +++ b/docs/development.md @@ -164,7 +164,7 @@ Co-Authored-By: Claude Sonnet 4.6 ``` Types: `feat`, `fix`, `refactor`, `docs`, `chore`, `test` -Scopes: feature area (e.g. `chat`, `briefing`, `fable-mcp`, `notes`) +Scopes: feature area (e.g. `chat`, `journal`, `mcp`, `notes`) ## Testing diff --git a/docs/superpowers/plans/2026-04-03-chatpanel-unification.md b/docs/superpowers/plans/2026-04-03-chatpanel-unification.md deleted file mode 100644 index cac0f63..0000000 --- a/docs/superpowers/plans/2026-04-03-chatpanel-unification.md +++ /dev/null @@ -1,2141 +0,0 @@ -# ChatPanel Unification Implementation Plan - -> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. - -**Goal:** Replace four divergent chat surfaces with a single `ChatPanel` component so every fix and feature applies everywhere automatically. - -**Architecture:** Extract `ChatInputBar.vue` (input + note picker + PTT) and `ChatStreamingBubble.vue` (streaming state display), then build `ChatPanel.vue` with `variant="full"` and `variant="widget"`, and migrate each view to use it. ChatPanel reads from `useChatStore` directly — no prop-drilling of messages or streaming state. - -**Tech Stack:** Vue 3 Composition API, TypeScript, Pinia (useChatStore), existing composables (useStreamingTts, useVoiceRecorder, useVoiceAudio, useListenMode) - -**Important context:** -- `ChatPanel.vue` already exists but is orphaned (zero usages). Overwrite it completely. -- `InlineAssistPanel.vue` and `HistoryPanel.vue` are also orphaned — ignore them. -- `chatStore.sendMessage(content, contextNoteId?, includeNoteIds?, think?, contextNoteTitle?, excludeNoteIds?, ragProjectId?, workspaceProjectId?)` — always pass `think: true` -- The store adds an optimistic user message immediately in `sendMessage`, so no manual optimistic push needed. -- TypeScript check command: `cd frontend && npm run typecheck` (or `make typecheck` from repo root) - ---- - -## File Map - -| File | Action | Purpose | -|---|---|---| -| `frontend/src/components/ChatInputBar.vue` | **Create** | Unified input bar: textarea, note picker, PTT, send/abort | -| `frontend/src/components/ChatStreamingBubble.vue` | **Create** | Streaming state: tool calls, think block, content, typing indicator | -| `frontend/src/components/ChatPanel.vue` | **Overwrite** | Full+widget chat panel, owns TTS/listen/scroll | -| `frontend/src/views/ChatView.vue` | **Modify** | Replace chat-main section with `` | -| `frontend/src/views/BriefingView.vue` | **Modify** | Replace briefing-center chat with `` | -| `frontend/src/views/WorkspaceView.vue` | **Modify** | Replace inline chat with `` | -| `frontend/src/views/HomeView.vue` | **Modify** | Replace DashboardChatInput + response section with `` | -| `frontend/src/components/DashboardChatInput.vue` | **Delete** | Replaced by ChatPanel widget | - ---- - -### Task 1: Create `ChatInputBar.vue` - -**Files:** -- Create: `frontend/src/components/ChatInputBar.vue` - -- [ ] **Step 1: Create the file** - -```vue - - - - - -``` - -- [ ] **Step 2: TypeScript check** - -```bash -cd /path/to/project/frontend && npm run typecheck 2>&1 | tail -20 -``` -Expected: no errors related to `ChatInputBar.vue`. - -- [ ] **Step 3: Commit** - -```bash -git add frontend/src/components/ChatInputBar.vue -git commit -m "feat: add ChatInputBar unified input bar component" -``` - ---- - -### Task 2: Create `ChatStreamingBubble.vue` - -**Files:** -- Create: `frontend/src/components/ChatStreamingBubble.vue` - -- [ ] **Step 1: Create the file** - -This extracts the identical streaming bubble HTML that currently lives in both `ChatView.vue` and `WorkspaceView.vue`. - -```vue - - - - - -``` - -- [ ] **Step 2: TypeScript check** - -```bash -cd /path/to/project/frontend && npm run typecheck 2>&1 | tail -20 -``` -Expected: no errors. - -- [ ] **Step 3: Commit** - -```bash -git add frontend/src/components/ChatStreamingBubble.vue -git commit -m "feat: add ChatStreamingBubble extracted streaming state component" -``` - ---- - -### Task 3: Rewrite `ChatPanel.vue` — full variant - -**Files:** -- Overwrite: `frontend/src/components/ChatPanel.vue` - -The existing `ChatPanel.vue` is orphaned (zero usages) — overwrite it entirely. - -**Context for this component:** -- `chatStore.sendMessage(content, contextNoteId?, includeNoteIds?, think?, contextNoteTitle?, excludeNoteIds?, ragProjectId?, workspaceProjectId?)` -- Always pass `think: true` -- For workspace: both `ragProjectId` and `workspaceProjectId` = `props.projectId` -- For briefing: no extra args beyond content -- For full chat: pass `includedNoteIds`, `excludedNoteIds`, `store.ragProjectId` - -- [ ] **Step 1: Write the full variant implementation** - -```vue - - - - - -``` - -- [ ] **Step 2: TypeScript check** - -```bash -cd /path/to/project/frontend && npm run typecheck 2>&1 | tail -30 -``` -Expected: no errors in `ChatPanel.vue`, `ChatInputBar.vue`, or `ChatStreamingBubble.vue`. - -- [ ] **Step 3: Commit** - -```bash -git add frontend/src/components/ChatPanel.vue -git commit -m "feat: rewrite ChatPanel with full and widget variants" -``` - ---- - -### Task 4: Migrate `ChatView.vue` - -**Files:** -- Modify: `frontend/src/views/ChatView.vue` - -ChatView keeps: sidebar (conversation list, bulk delete), route wiring, `onMounted`/`watch(convId)`, summarize button, research modal. It removes: all input bar HTML, streaming bubble HTML, scroll management, TTS/PTT/listen wiring, note context state. - -- [ ] **Step 1: Remove imports that ChatPanel now owns** - -In `