Doco
Doco
📖 中文版
The document space where humans and AI agents write together. An open-source rich-text collaborative editor that puts your data back in your hands — and treats your AI agents with the same care: block-level stable addressing, optimistic concurrency control, and a 29-tool MCP server, so agents read and write your knowledge base as safely as a careful human editor.
Hosted: doco.page — free during beta
Connect your agent:
claude mcp add doco -- npx -y --package doco-agent-cli doco mcpCLI:
npm i -g doco-agent-cli && doco loginnpm: doco-agent-cli · API docs: doco.page/api-docs
Claude Code Plugin Marketplace
/plugin marketplace add songofhawk/doco
/plugin install doco@docoThe marketplace bundles the Doco MCP server and the safe read → version → protected-write operating protocol. Tokens remain in Claude Code's local configuration and are never included in the plugin repository.

Why agents are safe here
Capability | What it means |
Block-level stable addressing | Every paragraph has a |
Optimistic concurrency | Reads return a |
Markdown round-trip | Export with |
Human–agent co-editing | Agent writes flow through the same Yjs document — changes appear live in the browser |
Transactions & idempotency | Batch operations commit atomically; |
Related MCP server: session-coord-mcp
Features
Editing Experience
Rich text editing: headings, lists, blockquotes, task lists, code blocks (syntax highlighting), tables, images, links, text styling, and more
/slash command: type/to open the command palette with fuzzy search — supports pinyin abbreviations for Chinese usersFloating toolbar: auto-appears on text selection, all formatting actions within two centimeters of your cursor
Block drag-and-drop: hover the left edge of any paragraph to reveal a drag handle — reorder content like building blocks
Collapsible sections: fold away sections you're not working on; collapse state persists across sessions
Auto heading numbering: one-click toggle — H1–H4 headings automatically maintain hierarchical numbering (
1.1.11.1.1)Keyboard shortcuts:
⌥↑/↓move blocks,⌘Dduplicate blocks,⌘⌥1/2/3/0switch heading levels
Text-to-Diagram
Write Mermaid or PlantUML source code directly in your document. Diagrams render in place. Double-click to edit, fullscreen view, pinch-to-zoom — no more export-import-replace cycles with draw.io.
Mermaid: flowcharts, sequence diagrams, class diagrams, Gantt charts, state diagrams, and more
PlantUML: sequence diagrams, class diagrams, use case diagrams, component diagrams, and more
Spreadsheet
A full spreadsheet engine embedded in your documents:
Formula evaluation, cell formatting
Freeze panes, sort & filter
Cell merge / split
CSV import / export
Use it inline as a content block, or pop it out as a standalone full-screen spreadsheet.
Knowledge Base
Knowledge Base → Folders (nestable) → Documents — a three-level structure
Drag-and-drop reordering, renaming, and moving in the sidebar
Whole-KB ZIP export preserving folder hierarchy, with bundled images
Lossless native
.doco.ziptransfer for a document, folder, or whole knowledge base
Real-time Collaboration
Built on the Yjs CRDT algorithm:
No save button — changes sync automatically
Offline-first: browser IndexedDB is the primary store; the server holds a snapshot. Edit without a network, merge automatically when reconnected
Seamless device switching: close your laptop, pick up your phone, keep writing
Import / Export
Format | Import | Export |
Doco native package | ✅ Document / folder / KB | ✅ Lossless document / folder / KB |
Markdown | ✅ Paste / file upload | ✅ Single doc & KB bundle |
Word (DOCX) | ✅ | ✅ |
✅ | ✅ | |
HTML | ✅ | — |
WeChat Official Account | — | ✅ (with theme preview) |
Images (in-document) | ✅ (paste / drag-drop) | ✅ (bundled in ZIP) |
API · MCP · CLI
Three channels, one contract:
REST API: OpenAPI 3.1 spec, Bearer Token auth, ETag versioning, cursor pagination, idempotency keys
MCP server:
doco mcp(ships insidedoco-agent-cli) — 29 tools plusdoco://resourcesdoco CLI:
login / whoami / docs / blocks / edit / mcp, global--json, writes internalize ETag/If-Match
Turn your docs into programmable assets — script your own backups, let an agent organize your knowledge base, pipe docs from your publishing workflow to your blog. Built-in API documentation page, ready to use out of the box.
Tech Stack
Layer | Technology |
Frontend Framework | React 18 + Vite + TypeScript |
CSS | Tailwind CSS v4 |
Editor | Tiptap v3 (ProseMirror) |
Collaboration | Yjs (CRDT) + Hocuspocus |
Diagrams | Mermaid + PlantUML |
Backend | Node.js + Express + Hocuspocus Server |
Database | better-sqlite3 (SQLite, WAL mode) |
UI Components | Radix UI, Lucide React, Tippy.js |
Quick Start
Prerequisites
Node.js >= 22
pnpm
Install & Run
# Install frontend dependencies
pnpm install
# Install backend dependencies
cd backend && npm install && cd ..
# Start the frontend dev server (Vite, default :5173)
pnpm run dev
# In another terminal, start the backend (Express + WebSocket, default :8000)
cd backend
npm run devOpen http://localhost:5173 — it will auto-connect to the backend WebSocket service.
Docker Deployment (recommended)
The complete self-hosted package includes a Caddy frontend, Node.js collaboration backend, persistent SQLite storage, health checks, and a same-origin WebSocket proxy. The public images support both linux/amd64 and linux/arm64.
git clone https://github.com/songofhawk/doco.git
cd doco
cp .env.docker.example .env.docker
# Review .env.docker first, then start with prebuilt Docker Hub images
docker compose --env-file .env.docker up -d
# Verify the deployment
docker compose --env-file .env.docker ps
curl --fail http://localhost:8080/healthzOpen http://localhost:8080 by default. Set ALLOWED_ORIGINS, COOKIE_SECURE, Google OAuth, and SMTP values in .env.docker for your environment. These values are injected when the containers start and are not baked into the images. Application data is stored in the doco-data named volume.
Docker Hub: songofhawkg/doco-frontend · songofhawkg/doco-backend
To build the same images from source instead:
docker compose --env-file .env.docker up -d --buildSee the Docker deployment guide for all configuration options, HTTPS, logs, backup, restore, and upgrades. Do not run docker compose down -v unless you intend to delete the database and attachments.
Manual Build & Deployment
# Frontend build
pnpm run build # output → dist/
pnpm run deploy # deploy to Cloudflare Pages
# Backend (production)
cd backend
npm startProject Structure
doco/
├── src/
│ ├── main.tsx # App entry point
│ ├── App.tsx # Root component, routing, import/export
│ ├── components/
│ │ └── Sidebar.tsx # KB sidebar (document tree)
│ └── editor/ # Editor module
│ ├── index.ts # Entry, exports DocoEditor component
│ ├── DocoEditor.tsx # Editor core (Yjs/Hocuspocus init, extension registration)
│ ├── types.ts # DocoEditor Props/Ref type definitions
│ └── components/
│ ├── BubbleMenu.tsx # Selection floating toolbar
│ ├── BlockHandle.tsx # Block drag handle
│ ├── SlashCommand.ts # / command palette
│ ├── CommandList.tsx # Command palette UI
│ ├── suggestions.ts # Command menu data
│ ├── CollapseExtension.ts # Block collapse extension
│ ├── DocSettings.tsx # Document settings (heading numbering, background)
│ ├── MermaidBlock.ts # Mermaid node definition
│ ├── MermaidComponent.tsx # Mermaid renderer
│ ├── PlantUMLBlock.ts # PlantUML node definition
│ ├── PlantUMLComponent.tsx # PlantUML renderer
│ ├── CalloutBlock.ts # Callout block definition
│ ├── CalloutComponent.tsx # Callout renderer
│ ├── SpreadsheetBlock.ts # Spreadsheet node definition
│ ├── SpreadsheetComponent.tsx # Spreadsheet renderer
│ ├── spreadsheetEngine.ts # Spreadsheet calculation engine
│ ├── WeChatExportDialog.tsx # WeChat Official Account export
│ ├── KeyboardShortcuts.ts # Keyboard shortcuts
│ ├── TableOfContents.tsx # Table of contents
│ ├── CodeBlockComponent.tsx # Code block (highlight + copy)
│ └── ImageComponent.tsx # Image renderer
├── backend/
│ ├── server.js # Entry: Express + Hocuspocus + export routes
│ ├── database.js # better-sqlite3 init & schema
│ ├── api.js # KB / folder / document REST API
│ ├── auth.js # Auth (OAuth + Email + API Token)
│ ├── markdown.js # YDoc → Markdown server-side export
│ ├── permissions.js # Permission management
│ ├── quota.js # Quota management
│ ├── openapi.js # OpenAPI spec definition
│ └── tests/ # Backend tests
└── docs/ # Design docs & proposalsStandalone Frontend Component
The editor core is also published as doco-text-editor. It contains the full Doco editing experience and built-in styles, but has no dependency on Doco authentication, REST APIs, collaboration services, or IndexedDB. The host application decides whether content lives in memory, browser storage, its own backend, or an external system such as ClickUp.
npm install doco-text-editorimport { useRef } from 'react'
import {
DocoTextEditor,
type DocoTextEditorRef,
} from 'doco-text-editor'
import 'doco-text-editor/style.css'
const editorRef = useRef<DocoTextEditorRef>(null)
<DocoTextEditor
ref={editorRef}
defaultValue="# Browser-only draft"
format="markdown"
onChange={({ steps }) => {
// Only the ProseMirror steps changed by this transaction.
queueIncrementalChanges(steps)
}}
/>
// Read the complete document only when needed.
const json = editorRef.current?.getContent('tiptap-json')
const markdown = editorRef.current?.getContent('markdown')
const html = editorRef.current?.getContent('html')
const text = editorRef.current?.getContent('text')The package includes headings, inline formatting, blockquotes, ordered/unordered/task lists, code blocks, images, tables, callouts, Mermaid, optional PlantUML rendering, and embedded spreadsheets. See src/editor/README.md for the complete API and integration notes.
Full Doco Editor Component Usage
import { DocoEditor } from './editor'
import type { DocoEditorRef } from './editor/types'
const editorRef = useRef<DocoEditorRef>(null)
<DocoEditor
ref={editorRef}
docId="doc-001"
userId="user-001"
collaboration={{
websocketUrl: 'ws://localhost:8000',
}}
onTitleChange={(docId, title) => console.log('Title changed:', title)}
placeholder="Start writing…"
/>
{/* Call export methods via ref */}
<button onClick={() => editorRef.current?.exportMarkdown()}>Export MD</button>Collaboration Architecture
Browser IndexedDB (y-indexeddb) ← local primary store
↕
Browser Y.Doc ← @hocuspocus/provider (WebSocket)
↕ Yjs binary delta messages
Server @hocuspocus/server → SQLite ydoc_state (one merged snapshot per doc)The browser IndexedDB is the primary store; the server snapshot is auxiliary. If the server snapshot is lost, simply open the document in the browser to repopulate it.
Offline editing works seamlessly; changes sync automatically when the network returns.
Collaborative cursors: supported by the framework, not enabled by default.
Markdown Export
Both single documents and KB bundles support Markdown export, generated on-the-fly from YDoc on the server:
# Single document export
curl http://localhost:8000/api/docs/{id}/export.md
# KB ZIP bundle
curl http://localhost:8000/api/kb/{id}/export.zipCustom nodes (Mermaid, PlantUML, Callout, etc.) have corresponding serialization rules in backend/markdown.js. When adding new custom nodes, update the server-side serializer accordingly.
Lossless Doco Transfer
Use Export Doco File in a document, folder, or knowledge-base menu. The resulting .doco.zip contains the original Yjs state, hierarchy, document settings, standalone spreadsheets, and attachments. Importing always creates a copy with fresh resource and attachment IDs, so it can safely move between independent Doco deployments without colliding with existing data.
Use the upload button beside the knowledge-base heading to import a whole knowledge base. To import a document or folder package, choose Import Doco File from the destination knowledge base or folder menu.
License
MIT
Available Tools
29 toolsdoco_batch_editDoco Batch EditADestructive
单事务批量编辑(1–100 个操作,全有或全无):operations 为 {op: insert|replace|delete, ...} 数组。base_version 必填语义由服务端强制(不填自动读取)。
Inputs: operations (required), document_id (required), base_version, idempotency_key. Returns: object
doco_changesDoco ChangesARead-onlyIdempotent
建立或增量读取文档的块级变更水位。首次不传 after 返回 manifest 与 cursor;后续传 cursor 获取 added/removed/modified/moved。sync_required=true 时必须重新读取正文并建立新基线。
Inputs: document_id (required), after, limit, locale. Returns: object
doco_conceptsDoco ConceptsARead-onlyIdempotent
统一读取概念层:列出/获取显式概念、沿概念关系遍历,或列出待审核候选。候选与显式概念严格分离。
Inputs: action (required), q, limit, cursor, +6 more. Returns: object
doco_create_documentDoco Create DocumentA
新建文档,可同时灌入初始正文(content: {format: markdown|tiptap-json|html, content|document})
Inputs: title (required), content, folder_id, idempotency_key, +1 more. Returns: object
doco_create_relationDoco Create RelationA
从稳定来源块创建一条显式、可审计的类型关系。target_uri 使用 doco://doc/{id}#block={block_id};创建前服务端校验两端权限与块存在性。
Inputs: target_uri (required), source_block_id (required), source_document_id (required), predicate, +2 more. Returns: object
doco_delete_blockDoco Delete BlockCDestructiveIdempotent
删除单个块
Inputs: block_id (required), document_id (required), base_version. Returns: object
doco_edit_conceptsDoco Edit ConceptsADestructive
统一写入显式概念:创建、更新、补来源/关系、合并,以及接受/拒绝候选。客户端自动读取 ETag、发送 If-Match,并为每次写入生成幂等键。
Inputs: action (required), name, reason, status, +9 more. Returns: object
doco_get_blocksDoco Get BlocksARead-onlyIdempotent
按块读取文档:返回顶层(或 recursive=true 时全部)块及其稳定 block_id 与 version
Inputs: document_id (required), recursive. Returns: object
doco_get_documentDoco Get DocumentARead-onlyIdempotent
读取整篇文档正文。format: markdown(读懂语义,附带 warnings 降级提示)/ tiptap-json(无损,精确编辑用)/ html。返回含 version(后续写入需携带)。annotate=anchors 时 markdown 每个顶层块带 锚点,改完整篇写回(PUT content format=markdown)可按锚点保留未改动块的 ID。
Inputs: document_id (required), format, locale, annotate. Returns: object
doco_get_treeDoco Get TreeARead-onlyIdempotent
获取一个知识库的完整目录树(文件夹 + 文档)
Inputs: kb_id (required). Returns: object
doco_insert_blocksDoco Insert BlocksA
在指定位置插入一个或多个块。position 六选一:after_block_id / before_block_id / parent_block_id(+child_index) / document_start / document_end / after_heading(按标题文本定位,服务端匹配)
Inputs: nodes (required), position (required), document_id (required), base_version. Returns: object
doco_list_documentsDoco List DocumentsARead-onlyIdempotent
按知识库 / 文件夹 / 关键词搜索文档列表(分页)
Inputs: q, limit, cursor, locale, +3 more. Returns: object
doco_list_knowledge_basesDoco List Knowledge BasesARead-onlyIdempotent
列出当前用户可见的全部知识库
Inputs: no named parameters. Returns: object
doco_outlineDoco OutlineARead-onlyIdempotent
读取文档结构大纲:每个标题以稳定 block_id、heading_path 和顶层块区间表达,适合先规划再局部读取。
Inputs: document_id (required). Returns: object
doco_patch_blockDoco Patch BlockAIdempotent
更新单个块:提供完整 node 替换,或用 attrs/content 局部修改。带 base_version 做乐观并发校验;不带则自动读取最新版本。409 时请重读合并重试。
Inputs: block_id (required), document_id (required), node, attrs, +2 more. Returns: object
doco_readDoco ReadARead-onlyIdempotent
按 token 预算局部读取文档。可用 around 锚定任意嵌套 block_id,或用 next_cursor 续读;游标绑定正文版本,read_cursor_stale 时必须重新规划。
Inputs: document_id (required), view, around, cursor, +4 more. Returns: object
doco_rebuild_summaryDoco Rebuild SummaryAIdempotent
重建摘要。deterministic 同步返回可追溯 fallback;model 只创建异步任务,必须随后用 doco_summary(job_id) 查询,来源变化或摘要被钉住时结果会 obsolete 而不会覆盖。
Inputs: target_id (required), scope, block_id, generator, +2 more. Returns: object
doco_refresh_concept_candidatesDoco Refresh Concept CandidatesAIdempotent
触发概念候选抽取/刷新。只生成待审核候选,不会直接污染显式概念层;写入自动带幂等键。
Inputs: document_id (required). Returns: object
doco_review_translation_unitDoco Review Translation UnitAIdempotent
在具体目标语言文档上确认当前译文或忽略单元;不接受机器结果直接覆盖,遇到 409 必须重读目标版本。
Inputs: unit_id (required), document_id (required), review_status (required), target_document_id (required), +2 more. Returns: object
doco_save_summaryDoco Save SummaryAIdempotent
人工编辑并可钉住摘要。客户端会先读取当前 summary/source 双版本后带保护写入;pinned 只防自动覆盖,来源变化后仍会显示 stale。
Inputs: summary (required), target_id (required), scope, pinned, +3 more. Returns: object
doco_searchDoco SearchARead-onlyIdempotent
按标题和正文全文搜索文档。正文命中返回稳定 block_id 与摘要,适合先定位再用块 API 精确读取或修改。
Inputs: q (required), limit, locale, knowledge_base_id. Returns: object
doco_search_v2Doco Search V2ARead-onlyIdempotent
带查询级完整性证明的全文搜索。返回目录路径、标题路径、前后文、分数解释、source/indexed 水位;exhaustive 模式可用 cursor 完整遍历。projection.complete=false 时结果不完整,不能据此断言“知识不存在”。
Inputs: q (required), mode, limit, cursor, +2 more. Returns: object
doco_summaryDoco SummaryARead-onlyIdempotent
读取章节、文档、文件夹或知识库摘要,或查询异步生成任务。结果带来源块、来源版本、覆盖率、freshness 与 fallback 语义;模型关闭时仍始终可用。
Inputs: query, scope, job_id, block_id, +1 more. Returns: object
doco_translationsDoco TranslationsBRead-onlyIdempotent
读取一个具体文档的 Document Set、源语言、可用语言版本和每种语言的新鲜度。
Inputs: document_id (required). Returns: object
doco_translation_unitsDoco Translation UnitsARead-onlyIdempotent
读取目标语言的块级翻译单元、稳定块映射、source_version 和 missing/current/conflict 等状态。
Inputs: document_id (required), locale, status, target_document_id. Returns: object
doco_traverseDoco TraverseARead-onlyIdempotent
沿显式关系遍历文档。返回正向/反向关系、注册谓词、来源块与来源版本;status=dangling_* 时目标已失效,evidence_freshness=stale 时应重新确认证据,projection_freshness=stale 时不得当作完整关系图。
Inputs: document_id (required), direction, predicate. Returns: object
doco_update_documentDoco Update DocumentADestructiveIdempotent
整篇写回文档正文。markdown 写回凭 锚点保留未改动块 ID(配合 doco_get_document 的 annotate=anchors);tiptap-json 为整篇无损替换。强烈建议带 base_version,409 时重读合并重试。
Inputs: format (required), document_id (required), content, document, +1 more. Returns: object
doco_upload_attachmentDoco Upload AttachmentA
上传附件(图片/PDF/文本/Word),返回 attachment_id 与 URL;在文档块中用 image 节点 attrs.attachmentId 引用
Inputs: file_path (required), document_id (required), filename, idempotency_key. Returns: object
doco_whoamiDoco WhoamiARead-onlyIdempotent
自检身份:当前 Token 对应的用户与权限 scope
Inputs: no named parameters. Returns: object
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 29 tools
Most tools map to a distinct resource and action (documents, blocks, translations, relations, concepts, summaries), so an agent can generally pick the right one. The main ambiguities are doco_search vs. doco_search_v2 and the easily confused doco_translations vs. doco_translation_units, though the descriptions give enough detail to resolve them.
The doco_ prefix, snake_case, and familiar verb_noun forms (list_, get_, create_, update_, delete_, insert_, patch_) give the set a strong, predictable pattern. A few noun-only readers (doco_changes, doco_outline, doco_concepts, doco_summary) and the doco_search_v2 suffix are minor deviations.
29 tools is a large surface, but the server covers many distinct subdomains: knowledge-base navigation, document/block editing, search, translations, relations, concepts, summaries, and attachments. Still, the count is heavy and some functions (search_v2, separate block readers) could plausibly be merged, so the set is borderline rather than tightly scoped.
The tool set covers document create/read/update, block-level editing, search, summaries, concepts, and translations, so most core workflows are supported. Notable gaps are the lack of document deletion, relation deletion, and attachment lifecycle operations (list/download/delete), which agents cannot work around easily.
Related MCP Connectors
Real-time chat for AI agents. Claude Code, Cursor, Cline and Codex join channels over MCP.
An agent-first office suite Claude & ChatGPT read and write over one MCP URL.
MCP-native collaborative markdown editor with real-time AI document editing
MarkupBase turns AI-generated Markdown and HTML into durable, versioned artifacts that people can review and discuss. Its MCP server lets agents publish new versions, preserve contextual comments, include hosted images, and respond to feedback through secure account-linked identities, creating a clear human review boundary without requiring real-time editing.
Related MCP Servers
- AlicenseAqualityBmaintenanceMCP server that gives AI coding agents on-demand access to private project docs via BM25 ranked search. One setup for Claude Code, Cursor, Codex, Gemini CLI, and more. Docs stay private, never in public repos.1516Apache 2.0
- AlicenseNot gradedqualityDmaintenanceA local-first MCP server for coordinating parallel AI coding sessions with tools like Claude Code and Codex in a single repository.2MIT

Writespaceofficial
AlicenseNot gradedqualityDmaintenancePersistent docs and memory for AI agents. Writespace is a collaborative markdown editor with a built-in MCP server — your model reads, writes, organizes, and searches a shared workspace while humans edit the same docs live. Drop the ranked full-text search straight in as RAG retrieval.MIT- AlicenseNot gradedqualityFmaintenanceMCP server for collaborative markdown editing, allowing agents to write documents and humans to comment, with comments fed back as agent input.377,398 npmMIT