{
  "markdown": "# mcp-writing\n\n[![CI](https://github.com/hannasdev/mcp-writing/actions/workflows/ci.yml/badge.svg)](https://github.com/hannasdev/mcp-writing/actions/workflows/ci.yml) [![GitHub release](https://img.shields.io/github/v/release/hannasdev/mcp-writing)](https://github.com/hannasdev/mcp-writing/releases) [![npm version](https://img.shields.io/npm/v/%40hanna84%2Fmcp-writing)](https://www.npmjs.com/package/@hanna84/mcp-writing) [![npm downloads](https://img.shields.io/npm/dm/%40hanna84%2Fmcp-writing)](https://www.npmjs.com/package/@hanna84/mcp-writing) [![Node.js](https://img.shields.io/badge/node-%3E%3D22.13.0-339933?logo=node.js&logoColor=white)](https://nodejs.org/) [![License: AGPL v3](https://img.shields.io/badge/License-AGPL--v3-blue.svg)](https://www.gnu.org/licenses/agpl-3.0)\n\nAn MCP service for AI-assisted reasoning and editing on long-form fiction projects.\n\nDesigned to work with [OpenClaw](https://github.com/openclaw/openclaw) but compatible with any MCP-capable AI gateway.\n\n## Quick launch\n\nFor local stdio MCP clients, run the published package directly:\n\n```sh\nWRITING_SYNC_DIR=/path/to/sync-dir DB_PATH=./writing.db npx -y @hanna84/mcp-writing\n```\n\nThe CLI wrapper defaults to stdio transport and adds the Node 22 SQLite flag automatically when needed.\n\n## VS Code extension\n\nFor VS Code-native setup flows (including prose styleguide setup), use:\n\n- [hannasdev/mcp-writing-vscode](https://github.com/hannasdev/mcp-writing-vscode)\n\n## What it does\n\nInstead of feeding an entire manuscript to an AI and hoping it fits in the context window, `mcp-writing` builds a structured index from your scene files. The AI queries that index first — finding relevant characters, beats, and loglines — then loads only the specific prose it needs.\n\n**Current status:**\n- **Core platform complete:** Metadata-first analysis, SQLite-canonical structural and relationship metadata, compatibility sidecar maintenance, AI-assisted prose editing with confirmation + git history, review bundles, and Scrivener Direct extraction are all implemented.\n- **Recently completed:** Human Input Forgiveness made selected request-boundary inputs more forgiving, clarified keyword metadata search boundaries, and recorded temp-fixture replay validation while preserving stable canonical IDs.\n- **Active development:** No initiative is currently selected.\n- **Deferred backlog:** OpenClaw integration, client-agnostic setup, divisions, and embeddings search.\n- **Ideas and open questions:** tracked separately so future exploration does not distort the active roadmap.\n\n## Who it is for\n\n- Novelists and writing teams working on long manuscripts with many scenes, characters, and continuity constraints.\n- AI-assisted editing workflows where you want targeted context retrieval instead of full-manuscript prompting.\n- Projects that need traceable, reversible edits with metadata that stays synchronized as drafts evolve.\n\n## Documentation\n\n| Guide | Description |\n|---|---|\n| [docs/guides/setup.md](docs/guides/setup.md) | Prerequisites, first-time setup, Scrivener import, native sync format |\n| [mcp-writing-vscode](https://github.com/hannasdev/mcp-writing-vscode) | VS Code extension for client-native setup flows |\n| [docs/guides/docker.md](docs/guides/docker.md) | Docker Compose, deployment operations, MCP gateway notes |\n| [docs/guides/backup-recovery.md](docs/guides/backup-recovery.md) | Project backup artifacts, diagnostics, and explicit restore workflow |\n| [docs/guides/sidecar-compatibility.md](docs/guides/sidecar-compatibility.md) | Sidecar compatibility roles, migration posture, and daily-work authority boundaries |\n| [docs/foundations/managed-structure-contract.md](docs/foundations/managed-structure-contract.md) | Design boundaries for structural mutation, generated views, import, and maintenance workflows |\n| [docs/agents/tools.md](docs/agents/tools.md) | Full tool reference — auto-generated from source |\n| [docs/agents/README.md](docs/agents/README.md) | Index of agent-focused guidance, examples, and boot files |\n| [docs/agents/use-cases.md](docs/agents/use-cases.md) | Agent-oriented transcripts and prompt/tooling examples |\n| [docs/guides/development.md](docs/guides/development.md) | Running locally, tests, environment variables, troubleshooting |\n\n## Breaking changes\n\n### `describe_workflows` surface redesign\n\n`describe_workflows` now exposes an outcome-first, discovery-first workflow map. This was a breaking change if your prompts or automation depend on previous workflow IDs or ordering; the newer `recommended_next_actions` tier is additive and appears before the full catalogue.\n\nUpdate integrations using this mapping:\n\n- `manuscript_exploration` -> `question_driven_discovery` (or `targeted_scene_reading` when the task is prose inspection)\n- `prose_editing` -> `safe_scene_revision`\n- `character_management` -> `character_understanding`\n- `place_management` -> `place_understanding`\n- `review_bundle` -> `review_preparation`\n\nNew workflow IDs added:\n\n- `thread_understanding`\n- `parity_recovery`\n\nStyleguide workflows are still available, but no longer positioned as part of the primary daily workflow surface.\n\n### `find_scenes` and `get_arc` response-shape standardization\n\n`find_scenes` and `get_arc` now always return structured envelopes, including non-paginated calls.\n\n- Envelope fields: `results`, `total_count`.\n- Pagination fields are included when paging is active.\n- `warning` / `next_step` are included when relevant.\n\nIf your integration previously handled raw arrays for non-paginated calls, update it to parse envelopes consistently.\n\nSafe parsing pattern:\n\n```js\nconst parsed = JSON.parse(toolText);\nif (parsed.ok === false) throw new Error(parsed.error?.message ?? \"tool error\");\nconst scenes = parsed.results ?? [];\nconst totalCount = parsed.total_count ?? scenes.length;\nconst warning = parsed.warning ?? null;\nconst nextStep = parsed.next_step ?? null;\n```\n\n### `get_character_sheet`, `get_place_sheet`, `list_scene_references`, `get_relationship_arc` response-shape standardization\n\nThese metadata-read tools now return structured envelopes instead of flat objects or raw arrays.\n\n- `get_character_sheet` and `get_place_sheet`: previously returned a flat object of field values; now return `{ results: [row], total_count: 1, next_step }`.\n- `list_scene_references`: previously returned `{ references, scene_id, project_id }`; now returns `{ results, total_count, scene_id, project_id }`.\n- `get_relationship_arc`: previously returned a raw JSON array; now returns `{ results, total_count, from_character, to_character }`.\n\nSafe parsing pattern for sheet tools:\n\n```js\nconst parsed = JSON.parse(toolText);\nif (parsed.ok === false) throw new Error(parsed.error?.message ?? \"tool error\");\nconst sheet = parsed.results?.[0] ?? {};\nconst nextStep = parsed.next_step ?? null;\n```\n\nSafe parsing pattern for list/arc tools:\n\n```js\nconst parsed = JSON.parse(toolText);\nif (parsed.ok === false) throw new Error(parsed.error?.message ?? \"tool error\");\nconst items = parsed.results ?? [];\nconst totalCount = parsed.total_count ?? items.length;\n```\n\n## Canonical IDs and forgiving inputs\n\nStable IDs remain the canonical identity for projects, chapters, scenes, characters, places, and relationship writes. When you already know the ID, pass it exactly.\n\nSome request-boundary fields now accept unambiguous human-shaped inputs, such as scene titles, character names, place names, or case variants. Successful tools still write and return canonical IDs, with `resolved_from` details when the input was resolved from a non-canonical value. Ambiguous matches, near matches, or suggested-only values fail or return advisory suggestions without mutating canonical state.\n\nTags and Save the Cat beats remain freeform editorial vocabulary. `find_scenes` can match existing tag and beat casing variants, and metadata updates can suggest nearby existing vocabulary, but supplied tag and beat text is preserved unless you intentionally change it.\n\n`search_metadata` is keyword/FTS metadata search over indexed titles, loglines, tags, characters, places, and versions. It is not semantic search and does not search prose text; use `get_scene_prose` after metadata search or structured filters identify likely scenes. Semantic/prose search remains deferred to the Embedding-Based Search backlog.\n\n## Usage scenarios\n\n### 1) Continuity pass before sending chapters to beta readers\n\nGoal: catch inconsistencies before sharing pages.\n\n1. Run `sync` after your latest writing session.\n2. Ask `find_scenes` for scenes involving a specific character or tag (for example, all scenes tagged `injury` or `promise`). Canonical IDs remain preferred, but character/POV filters can resolve unambiguous project-scoped character names, tag and beat filters can suggest near matches, and `chapter_id` accepts exact IDs or unambiguous case variants.\n3. Use `get_arc` to review that character's ordered progression across the manuscript.\n4. Load only the suspect scenes with `get_scene_prose`.\n5. Attach follow-up notes with `flag_scene` where continuity needs a fix.\n\nOutcome: you review one narrative thread at a time instead of rereading the entire novel to find contradictions.\n\n### 2) Planning and tracking subplot beats during revisions\n\nGoal: make sure subplot threads progress intentionally and resolve on time.\n\n1. Run `list_threads` for the project.\n2. Use `get_thread_arc` to inspect scene order and beat labels for each thread.\n3. When a beat is missing, call `track_thread_arc` to add or update it on the right scene.\n4. Re-run `get_thread_arc` to confirm pacing and coverage.\n\nOutcome: subplot structure stays visible and auditable, which reduces dropped threads in late drafts.\n\n### 3) Tightening scene metadata after heavy prose edits\n\nGoal: keep indexes accurate without manually re-tagging everything.\n\n1. After rewriting scenes, call `enrich_scene` to re-derive lightweight metadata from current prose.\n2. Use `update_scene_metadata` for intentional editorial fields (for example, beat, POV, status, and tags). Tags and beats remain freeform; the tool preserves supplied text while returning suggestions when a value resembles existing vocabulary. It rejects scene `characters` and `places`; use `connect_character_place_evidence` when a scene proves paired sheet-backed character/place evidence, `connect_scene_character_evidence` for character-only evidence, and `connect_scene_place_evidence` for place-only evidence. Those relationship evidence tools prefer canonical IDs but also accept unambiguous scene titles, character names, place names, and case variants; ambiguous or suggested-only matches fail without mutating state. Use `audit_relationship_metadata` for retained sidecar/frontmatter relationship fields. Use `list_chapters` plus `assign_scene_to_chapter` or `move_scene` for chapter placement and ordering.\n3. Use `search_metadata` for keyword/FTS metadata searches across indexed titles, loglines, tags, characters, places, and versions, and use `find_scenes` to verify scenes are discoverable under structured filters. After identifying likely scenes, use `get_scene_prose` for prose context.\n\nOutcome: your AI assistant can reliably find the right scenes without drifting from the manuscript.\n\n### 4) Safe AI-assisted line edits with rollback\n\nGoal: let AI propose prose edits without losing control of your draft.\n\n1. Ask the AI to call `propose_edit` for a specific scene.\n2. Review the staged diff.\n3. Accept with `commit_edit` or reject with `discard_edit`.\n4. Use `list_snapshots` (and optional `snapshot_scene`) to inspect or preserve revision history.\n\nOutcome: you get AI speed with explicit approval and recoverable history for every applied change.\n\n### 5) Refreshing scene-character links after imports or major rewrites\n\nGoal: rebuild scene-to-character links in a controlled way after imported prose changes or metadata drift.\n\n1. Start with `enrich_scene_characters_batch` using the default `dry_run=true` to preview inferred links for a project, chapter, or explicit scene list.\n2. Poll `get_async_job_status` until the batch job completes, then review `job.result.results` for changed scenes, ambiguous matches, and partial failures.\n3. Spot-check a few affected scenes with `get_scene_prose` if the changes touch important continuity or cast-heavy chapters.\n4. Re-run `enrich_scene_characters_batch` with `dry_run=false` once the preview looks correct.\n5. If you want a destructive overwrite instead of additive merge behavior, use `replace_mode=replace` with `confirm_replace=true` deliberately.\n\nOutcome: character-link maintenance becomes a preview-first relationship repair operation instead of a one-off regex script or manual sidecar cleanup.\n\n### 6) Post-upgrade recovery after legacy migration warnings\n\nGoal: recover index confidence quickly when legacy upgrade warnings indicate ambiguous rows were skipped.\n\n1. Start by checking `get_runtime_config` (or `describe_workflows`) and confirm whether `db_migration_warnings` contains `LEGACY_JOIN_ROWS_SKIPPED`.\n2. If present, run `sync` immediately to rebuild scene relationships from compatibility sidecars and prose metadata.\n3. Continue normal discovery (`find_scenes`, `get_arc`, `get_thread_arc`) and watch for stale-metadata warnings.\n4. When you touch stale scenes, run `enrich_scene(scene_id, project_id)` to recover metadata parity incrementally.\n5. If many scenes remain stale, switch to `enrich_scene_characters_batch` (dry-run first) for broader catch-up.\n\nOutcome: upgrade-related data loss risk becomes an explicit, operator-visible recovery workflow instead of a silent state mismatch.\n\n## License\nAGPL-3.0-only\n",
  "bytes": 13657,
  "sha": "f98bd20e01d80906b5c104ccaa6f38d8826c7353535448a90862a0f44022797f",
  "repo_slug": "hannasdev/mcp-writing",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_hannasdev_mcp_writing_224434fe/readme"
}