Skip to main content
Glama

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/sdk stack, same safety posture.

Tools

Read (Phase 1 — always on, strictly read-only):

Tool

What it does

check_auth

Verify the account can log in and reach the instance

list_workspaces

List workspaces (name, id, role, members)

list_pages

The page/view tree of a workspace (titles, ids, document/grid/board type)

get_page

A document page's body as Markdown (the Yjs decoder — headings, lists, to-dos, code, links, page mentions)

search_pages

Find pages by title, or by body text (body: true)

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. Use append_to_page to 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 install

Register 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.js

with APPFLOWY_BASE_URL, APPFLOWY_EMAIL, and APPFLOWY_PASSWORD set in the environment (see .env.example).

Configuration

Env var

Meaning

APPFLOWY_BASE_URL

Your instance URL. Use your self-hosted domain, not appflowy.com (the vendor cloud is a different backend). Default https://flow.example.com.

APPFLOWY_EMAIL

The account to log in as.

APPFLOWY_PASSWORD

The account password (see secure handling below).

QUILL_FLOWY_WRITE

1 to register the mutating write tools. Off by default.

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

  1. Auth: POST /gotrue/token?grant_type=password → JWT bearer (cached; re-login on expiry).

  2. Navigate: GET /api/workspace… and …/folder?depth=N give the workspace and page tree directly — no decoding needed.

  3. Read a body: GET /api/workspace/v1/{wid}/collab/{vid}?collab_type=0 returns the Yjs doc_state; quill-flowy loads it with yjs and 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 tools
check_authCheck AppFlowy authA

Verify the configured account can log in to AppFlowy and reach it. Read-only.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A3.9/5.0
Behavior3/5

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.

Conciseness5/5

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.

Completeness3/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines3/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
pageYesPage title (exact) or view id (from list_pages).
workspaceYesWorkspace name or id.

TDQS

A4.1/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines3/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
workspaceYesWorkspace name or id (from list_workspaces).

TDQS

A3.8/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.5/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
bodyNoAlso search page body text (slower; decodes each document).
queryYesText to search for.
workspaceYesWorkspace name or id.

TDQS

A4.2/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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.

  1. 5 tool updatesv0.1.0
    • First observedcheck_auth
    • First observedget_page
    • First observedlist_pages
    • First observedlist_workspaces
    • First observedsearch_pages

TDQS

A4.2/5.0

Scored across 5 tools

Disambiguation5/5

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.

Naming Consistency5/5

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.

Tool Count5/5

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.

Completeness4/5

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

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers