quill-flowy
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@quill-flowylist pages in my main workspace"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
quill-flowy
A lean, MIT-licensed Model Context Protocol (MCP) server that lets an AI agent (Claude Code, Claude Desktop, …) read — and, in a separate module, write — a self-hosted AppFlowy instance.
AppFlowy stores a page's body as a Yjs CRDT, not plain text, so the pages are a silo
your agent can't see. quill-flowy authenticates to your instance, walks the workspace/page
tree, and decodes the CRDT document into Markdown — the same thing AppFlowy's own web
client does, using the same yjs library.
Companion to
anythingllm-mcp— same minimal Node +@modelcontextprotocol/sdkstack, same safety posture.
Tools
Read (Phase 1 — always on, strictly read-only):
Tool | What it does |
| Verify the account can log in and reach the instance |
| List workspaces (name, id, role, members) |
| The page/view tree of a workspace (titles, ids, document/grid/board type) |
| A document page's body as Markdown (the Yjs decoder — headings, lists, to-dos, code, links, page mentions) |
| Find pages by title, or by body text ( |
Write (Phase 2 — mutating, opt-in): create_page, append_to_page, rename_page,
move_page. These live in a separate module and are registered only when
QUILL_FLOWY_WRITE=1, so the default install exposes zero write surface to the agent.
All four are additive or reversible (none deletes content). append_to_page converts
Markdown to AppFlowy blocks (headings, lists, to-dos, code, quotes, formatting).
update_page(replace an existing body in place) is not supported: AppFlowy exposes no high-level endpoint for editing/deleting arbitrary existing blocks — it would require raw Yjs collab over the sync protocol. Useappend_to_pageto add content, or edit in the AppFlowy app.
Related MCP server: notion-export-mcp-server
Requirements
Node 18+ (developed on Node 24).
A self-hosted AppFlowy Cloud instance with a password-based account.
Install
git clone https://github.com/DezGDNY/quill-flowy
cd quill-flowy
npm installRegister it with your MCP client, passing config via an env block, e.g. Claude Code:
claude mcp add quill-flowy --scope user -- node /absolute/path/to/quill-flowy/index.jswith APPFLOWY_BASE_URL, APPFLOWY_EMAIL, and APPFLOWY_PASSWORD set in the environment
(see .env.example).
Configuration
Env var | Meaning |
| Your instance URL. Use your self-hosted domain, not |
| The account to log in as. |
| The account password (see secure handling below). |
|
|
Secure credential handling
Don't store a plaintext password in production. On Windows, keep it in a
DPAPI-encrypted file and use a small launcher that decrypts it into APPFLOWY_PASSWORD
in-process before exec'ing the server — the password never touches disk in plaintext,
your shell history, or your MCP config. (On macOS/Linux, use the OS keychain or a secret
manager the same way.) quill-flowy itself only ever reads APPFLOWY_PASSWORD from its
environment and uses it for a single login; it is never logged.
How it works
Auth:
POST /gotrue/token?grant_type=password→ JWT bearer (cached; re-login on expiry).Navigate:
GET /api/workspace…and…/folder?depth=Ngive the workspace and page tree directly — no decoding needed.Read a body:
GET /api/workspace/v1/{wid}/collab/{vid}?collab_type=0returns the Yjsdoc_state; quill-flowy loads it withyjsand walks the AppFlowy document schema (data → document → blocks / meta.children_map / meta.text_map) into Markdown, reading each text run's delta for inline formatting.
License
MIT © 2026 Dez
Available Tools
5 toolscheck_authCheck AppFlowy authA
Verify the configured account can log in to AppFlowy and reach it. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden of behavioral disclosure. It does state 'Read-only,' which is a key safety trait, but it omits details about failure behavior, response format, or any side effects beyond the read-only claim. The description is not contradictory to annotations, but it is thin on behavioral context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences with zero waste. The core purpose is front-loaded, and the read-only qualifier is placed immediately after the action. Every word earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool is simple (no params, no output schema), but the description does not state what the tool returns (e.g., success/failure, error details). Since there is no output schema to fill that gap, an agent cannot know what to expect from a call. The description covers the action but leaves the outcome ambiguous.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so there is nothing to explain. The schema coverage is trivially 100%, and the description does not need to elaborate on parameters. Baseline of 4 applies per the rubric for tools with no parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific action ('Verify') and a specific resource ('the configured account can log in to AppFlowy and reach it'), clearly distinguishing it from sibling tools that list or search pages. It also explicitly marks it as read-only, reinforcing its distinct role as an authentication check.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies a use case—checking auth before other operations—but does not explicitly state when to use this tool versus alternatives or mention prerequisites or exclusions. An agent would infer it is a prerequisite check, but the guidance is not spelled out.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_pageGet a page body as MarkdownA
Return a document page's body rendered as Markdown. Accepts a page title or view id. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| page | Yes | Page title (exact) or view id (from list_pages). | |
| workspace | Yes | Workspace name or id. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the behavioral burden. It explicitly states the operation is read-only and specifies the output format (Markdown), which is meaningful context. It does not cover error behavior, but for a simple read-only retrieval the key behavioral traits are disclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two concise sentences with no filler. The core action and return format are front-loaded, and the input modes and read-only nature are stated efficiently in the second sentence.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple read-only tool with two fully documented parameters, the description provides everything an agent needs: what it returns, what inputs it accepts, and its safety profile. No output schema exists, so the explicit 'Markdown' return format is especially valuable and sufficient.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already fully documents both parameters. The description's statement that it accepts a page title or view id largely restates the page parameter description, adding minimal semantic value beyond the structured schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb and resource: it returns a document page's body rendered as Markdown. This clearly differentiates get_page from the sibling tools list_pages, search_pages, and list_workspaces, and the mention of view ids from list_pages reinforces the intended scope.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage: use it when you need a page's body as Markdown, especially after obtaining a view id from list_pages. However, it does not explicitly state when to avoid it or name alternative tools for other retrieval needs, leaving the routing partly to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_pagesList pages in a workspaceA
Show the page/view tree of a workspace (titles, ids, and type: document/grid/board/…). Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| workspace | Yes | Workspace name or id (from list_workspaces). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full behavioral burden, and it does disclose a key trait: 'Read-only.' It also states the payload outlook (titles, ids, and page types), which is not available elsewhere since there is no output schema. It stops short of covering failure modes or pagination on larger workspaces, but for a simple read operation this is solid transparency.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences with zero wasted words: the primary action and scope are front-loaded, the output contents follow in a parenthetical, and the read-only note is a compact trailing clause. Each element earns its place and none duplicates schema content.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the minimal signature (one required param, no nested objects, no output schema), the description is largely complete: it names the input from the schema, states the output composition, and flags side-effect safety. The only missing bits are lower-priority context, such as sort order/tree-depth presentation or behavior on invalid workspace names, which are minor for such a simple read-only tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The only parameter, 'workspace', is 100% described in the input schema ('Workspace name or id (from list_workspaces)'), so the schema does the heavy lifting. The description adds no parameter-specific meaning beyond stating the tool's scope ('of a workspace'), so the high-coverage baseline of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names the specific resource ('page/view tree of a workspace'), enumerates the returned data (titles, ids, type: document/grid/board/…), and adds a 'Read-only' safety marker. The tree-listing phrasing implicitly differentiates this tool from siblings like search_pages and get_page, but it never explicitly names the alternative, which keeps this from the top score.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The intended use case—retrieve the whole page tree of a workspace for an overview—is implied by the wording. However, there's no explicit routing guidance, such as when to prefer search_pages (e.g., finding a page by content) or get_page (e.g., retrieving a single page's detail). An agent comparing this to search_pages gets only an implicit signal of how they differ.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_workspacesList AppFlowy workspacesA
List all AppFlowy workspaces (name, id, role, member count). Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full behavioral disclosure burden. It explicitly states 'Read-only', which signals no side effects, and 'List all' indicates the absence of filtering. This is meaningful beyond the name and title, though it does not mention authentication requirements or response formatting.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, efficient sentence with the core behavior front-loaded and the read-only caveat immediately following. Every part earns its place; there is no redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a parameterless read-only list tool, the description is complete: it states the operation, the resource scope, the fields returned, and the side-effect-free nature. No additional details are required for an agent to invoke and interpret the result.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
This tool has zero parameters, so the baseline is 4. The description adds value by listing the output fields, which is the only semantic context an agent needs here.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses the specific verb 'List' with the resource 'AppFlowy workspaces' and explicitly names the returned fields: name, id, role, member count. This clearly distinguishes it from sibling tools like list_pages and search_pages.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description makes clear that this tool returns all workspaces, which is the correct context for calling it. It does not explicitly name alternatives or exclusion criteria, but the resource-specific wording is unambiguous enough for an agent to select it appropriately.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_pagesSearch pages in a workspaceA
Find pages by title, or by body text when body=true (decodes each document). Returns matches with ids. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| body | No | Also search page body text (slower; decodes each document). | |
| query | Yes | Text to search for. | |
| workspace | Yes | Workspace name or id. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden of behavioral disclosure. It states the tool is read-only, explains that body=true is slower and decodes documents, and reports that matches are returned with ids. It omits details like result limits or pagination, but covers the key operational profile for a simple search tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences with no filler. The core behavior is front-loaded, the body-mode caveat is included, and the read-only claim is expressed in a single word.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a search tool with no output schema, the description provides the essential return information ('Returns matches with ids') and the main performance tradeoff. It is sufficient for an agent to invoke correctly, though it does not specify match limits, ordering, or exact matching behavior.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema already documents workspace, query, and body. The description adds the performance implication of body=true and implies that title-only search is the default, but this is complementary rather than substantial new semantic information.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with 'Find pages by title, or by body text when body=true' – a precise verb, resource, and search mode. It clearly distinguishes itself from sibling tools like list_pages or get_page by emphasizing search over listing or fetching, and the read-only note clarifies its non-mutating nature.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear context for when the optional body search is appropriate, including the warning that it 'decodes each document' and is slower. It does not explicitly name sibling tools or state when to prefer list_pages/get_page, so it falls short of full routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
5 tool updates
v0.1.0- First observed
check_auth - First observed
get_page - First observed
list_pages - First observed
list_workspaces - First observed
search_pages
TDQS
Scored across 5 tools
Each tool has a clearly distinct purpose: auth verification, workspace listing, page tree listing, page content retrieval, and page search. The only minor overlap is get_page and search_pages by title, but their outputs differ enough to avoid real confusion.
All tools follow the same snake_case verb_noun pattern: check_auth, list_workspaces, list_pages, get_page, search_pages. The naming is predictable and makes the toolset easy to navigate.
Five tools is a well-scoped size for a read-only AppFlowy exploration server. Each tool covers a distinct need without redundancy or unnecessary bulk.
The read-only workflow is well covered: authenticate, list workspaces, browse the page tree, retrieve page bodies, and search content. The main gap is that list_pages mentions grid/board view types, but get_page only handles document page bodies, leaving non-document views without a retrieval path.
Maintenance
Related MCP Connectors
Markdown workspace for AI agents: read, write, organize, and share markdown documents.
MCP-native open-source Notion alternative: read & write pages, databases and kanban boards.
Persistent docs and memory for AI agents — read, write, organize & search a shared workspace.
Self-hostable shared brain for you and your AI agents — docs, flows, meetings, decisions, rationale
Related MCP Servers
- AlicenseBqualityDmaintenanceEnables automatic upload of AI-generated rich text content to AppFlowy with Markdown syntax support, allowing seamless document creation and management through natural language instructions.13Apache 2.0
- AlicenseCqualityCmaintenanceEnables AI assistants to export Notion pages as markdown using Notion's unofficial API.17 npm1MIT
- AlicenseNot gradedqualityBmaintenanceA self-hosted, token-scoped Model Context Protocol server for AppFlowy. It gives AI agents tools to read and edit your AppFlowy workspaces while bounding each client to exactly the pages you allow via per-token tree-shaped scopes.5MIT
- AlicenseNot gradedqualityAmaintenanceEnables AI agents to safely read, search, edit, and organize SiYuan notes, with git-like document timeline and notebook-level permissions.284 npm104MIT