AFFiNE MCP Server

Read, write and organise AFFiNE workspaces, docs, databases and comments from an MCP client

By DongHyeok-Seo (individual) TypeScript Local · stdio, Streamable HTTP ProductivityKnowledge and memory

62 popularity score ★ 323 ↓ 1.1k/wk

Connect your client

Local (once it is running)

Add in one click

Opens the app, which asks before it adds the server.

Or add it by command or config

Claude CodeTerminal
claude mcp add --transport http affine http://localhost:3000/mcp
Cursor~/.cursor/mcp.json
{
  "mcpServers": {
    "affine": {
      "url": "http://localhost:3000/mcp"
    }
  }
}
VS Code.vscode/mcp.json
{
  "servers": {
    "affine": {
      "type": "http",
      "url": "http://localhost:3000/mcp"
    }
  }
}
Codex~/.codex/config.toml
[mcp_servers.affine]
url = "http://localhost:3000/mcp"
Gemini CLITerminal
gemini mcp add --scope user --transport http affine http://localhost:3000/mcp
Local (npm)

Add in one click

Opens the app, which asks before it adds the server. Then replace each <NAME> in its settings with your value.

Or add it by command or config

It needs AFFINE_BASE_URL, AFFINE_COOKIE. Replace each <NAME> with your value.

Claude CodeTerminal
claude mcp add affine -e AFFINE_BASE_URL=<AFFINE_BASE_URL> -e AFFINE_COOKIE=<AFFINE_COOKIE> -- npx -y -p affine-mcp-server affine-mcp
Claude Desktopclaude_desktop_config.json
{
  "mcpServers": {
    "affine": {
      "command": "npx",
      "args": [
        "-y",
        "-p",
        "affine-mcp-server",
        "affine-mcp"
      ],
      "env": {
        "AFFINE_BASE_URL": "<AFFINE_BASE_URL>",
        "AFFINE_COOKIE": "<AFFINE_COOKIE>"
      }
    }
  }
}
Cursor~/.cursor/mcp.json
{
  "mcpServers": {
    "affine": {
      "command": "npx",
      "args": [
        "-y",
        "-p",
        "affine-mcp-server",
        "affine-mcp"
      ],
      "env": {
        "AFFINE_BASE_URL": "<AFFINE_BASE_URL>",
        "AFFINE_COOKIE": "<AFFINE_COOKIE>"
      }
    }
  }
}
VS Code.vscode/mcp.json
{
  "servers": {
    "affine": {
      "type": "stdio",
      "command": "npx",
      "args": [
        "-y",
        "-p",
        "affine-mcp-server",
        "affine-mcp"
      ],
      "env": {
        "AFFINE_BASE_URL": "<AFFINE_BASE_URL>",
        "AFFINE_COOKIE": "<AFFINE_COOKIE>"
      }
    }
  }
}
Codex~/.codex/config.toml
[mcp_servers.affine]
command = "npx"
args = ["-y", "-p", "affine-mcp-server", "affine-mcp"]

[mcp_servers.affine.env]
AFFINE_BASE_URL = "<AFFINE_BASE_URL>"
AFFINE_COOKIE = "<AFFINE_COOKIE>"
Gemini CLITerminal
gemini mcp add --scope user -e AFFINE_BASE_URL=<AFFINE_BASE_URL> -e AFFINE_COOKIE=<AFFINE_COOKIE> affine npx -- -y -p affine-mcp-server affine-mcp

Settings 12

AFFINE_BASE_URL Required: AFFiNE address: https://app.affine.pro for Cloud, or your self-hosted URL. Default http://localhost:3010.
AFFINE_COOKIE secret Required: Cookie header from a signed-in browser session, the only way in on AFFiNE Cloud. Self-hosted can use AFFINE_EMAIL and AFFINE_PASSWORD or a saved `affine-mcp login` instead.
AFFINE_API_TOKEN secret Optional: Bearer token for older deployments that still accept one (removed in AFFiNE 0.27+).
AFFINE_WORKSPACE_ID Optional: Workspace used when a tool call omits workspaceId.
AFFINE_TOOL_PROFILE Optional: Tool set: full, read_only, core or authoring. Default full.
AFFINE_DISABLED_GROUPS Optional: Comma-separated tool groups to turn off, e.g. destructive, admin, docs.database.
AFFINE_DISABLED_TOOLS Optional: Comma-separated tool names to turn off.
MCP_TRANSPORT Optional: Set to http to serve /mcp instead of stdio. Default stdio.
AFFINE_MCP_HTTP_TOKEN secret Optional: Bearer secret clients must send in HTTP mode, needed for a non-loopback listener. For HTTP mode.
AFFINE_BLOB_UPLOAD_FILE_ROOTS Optional: Directories (absolute paths) that upload_blob may read local files from. Unset, filePath uploads are refused. For upload_blob.
Set together: password sign-in
AFFINE_EMAIL Optional: Self-hosted sign-in email, paired with AFFINE_PASSWORD.
AFFINE_PASSWORD secret Optional: Self-hosted sign-in password.

What it does

This is a community-built Node.js server that links an MCP client to AFFiNE, the open-source notes and whiteboard app. It talks to AFFiNE over GraphQL and WebSocket, plus REST for file downloads. Both AFFiNE Cloud and self-hosted instances work, and the default transport is stdio. Set MCP_TRANSPORT=http and it serves an HTTP endpoint at /mcp instead.

The tool manifest lists 108 tools. They handle workspaces, docs (search, read, create from Markdown, export, publish, move, trash and restore), single blocks, tags, collections and folders, AFFiNE databases, comments, edgeless canvases and mind maps, version history, notifications and stored files. Code blocks can be created and edited with their language and preview state. The newest tool, get_blob, downloads the file behind an image or attachment block and hands images back as image content. Higher-level helpers build a page from sections or fill in native templates, and one reports how well a doc survives export.

The package ships an affine-mcp CLI too. Running `affine-mcp login` saves credentials to ~/.config/affine-mcp/config with mode 600, while doctor checks the setup and snippet prints client config. AFFINE_TOOL_PROFILE cuts the tool set down to read_only, core or authoring, and AFFINE_DISABLED_GROUPS or AFFINE_DISABLED_TOOLS switch off groups like destructive.

Two things the README skips, both in the source: AFFINE_BASE_URL falls back to http://localhost:3010, so a Cloud user who skips `affine-mcp login` has to set it to https://app.affine.pro. And upload_blob only reads a local file when its folder is listed in AFFINE_BLOB_UPLOAD_FILE_ROOTS, which is empty unless you set it.

What it needs

RuntimeNode.js 20.18.1+
Runs onmacOS, Windows, Linux
AFFiNEFree tierAn AFFiNE Cloud account or a self-hosted AFFiNE server; Cloud needs a browser session cookie

CI covers Node.js 20, 22, 24 and 26. For Cloud, copy the Cookie header from a signed-in browser session; for self-hosted, email and password or a cookie work. Either run `affine-mcp login` once (after `npm i -g affine-mcp-server`) or pass the settings in the client config. The Docker image runs in HTTP mode, is started separately and is then reached at http://localhost:3000/mcp.

Limits

  • Not covered Only server-backed workspaces are reachable. Workspaces kept only in a browser's local storage are not.
  • Limit On AFFiNE Cloud, email/password sign-in is blocked by Cloudflare, so a browser session cookie is needed, and a saved cookie must be renewed with login when it expires.
  • Not covered AFFiNE 0.27+ removed personal access tokens, so AFFINE_API_TOKEN works only on older deployments and there are no token tools.
  • Limit delete_doc may leave content on some AFFiNE servers; it then returns a partial result with a warning. trash_doc is the recoverable route.
  • Size cap get_blob refuses files over 10 MiB by default, up to 25 MiB with maxBytes; upload_blob takes up to 25 MiB unless AFFINE_BLOB_UPLOAD_MAX_BYTES says otherwise.
  • Limit upload_blob refuses a filePath outside the folders listed in AFFINE_BLOB_UPLOAD_FILE_ROOTS, which is empty by default.
  • Size cap HTTP mode keeps at most 32 sessions by default (AFFINE_MCP_HTTP_MAX_SESSIONS) and closes idle ones after 30 minutes.
  • Early release Some organize and folder helpers are marked experimental.

Browser-local workspaces kept only in the browser's storage are out of reach. On AFFiNE Cloud, email/password sign-in is blocked by Cloudflare, so a browser session cookie is the only way in, and a saved cookie does not renew: re-run login when it expires (saving self-hosted email/password with --save-credentials avoids this). AFFiNE 0.27+ removed personal access tokens, so AFFINE_API_TOKEN works only on older deployments and there are no token-management tools. HTTP mode allows 32 sessions by default (AFFINE_MCP_HTTP_MAX_SESSIONS) and closes idle ones after 30 minutes; upload_blob accepts up to 25 MiB by default. Some organize and folder helpers are marked experimental.

Who it suits

Suits AFFiNE users who want an assistant to search, draft and restructure notes, databases and canvases, on Cloud or a self-hosted instance, from Claude Code, Claude Desktop, Codex CLI or Cursor. Self-hosted users get the smoothest setup, since email/password login renews itself; Cloud users must paste and refresh a browser cookie. Teams sharing one deployment can run the HTTP mode with bearer or OAuth auth and a read_only or authoring profile. It is not made by AFFiNE: the configuration guide notes AFFiNE has its own built-in, workspace-scoped MCP endpoint with separate credentials, which may suit a user who only needs that.

Tools 59 of 108

24 only read, 30 change things, 5 can delete or overwrite. A ? marks an optional parameter.

list_workspaces
List the workspaces the account can reach
get_workspace
Show details of one workspace
create_workspace changes
Create a new workspace
update_workspace changes
Change a workspace's settings
delete_workspace deletes
Delete a workspace
list_workspace_tree
Show a workspace's doc hierarchy
list_docs
List docs in a workspace
search_docs
Search docs in a workspace
find_doc_by_title
Find a doc by its title
get_doc
Fetch a doc's metadata
read_doc
Read a doc's content and blocks
list_children
List the child docs of a doc
get_orphan_docs
Find docs not linked from anywhere
create_doc changes
Create a doc, optionally with one plain paragraph
create_doc_from_markdown changes
Create a doc from Markdown with headings, lists, code and math
append_markdown changes
Add Markdown content to the end of a doc
replace_doc_with_markdown deletes
Overwrite a whole doc with Markdown
export_doc_markdown
Export a doc as Markdown
export_with_fidelity_report
Export a doc and report what did not convert
analyze_doc_fidelity
Report how faithfully a doc can be exported
update_doc_title changes
Rename a doc
move_doc changes
Move a doc under another parent
publish_doc changes
Make a doc public
revoke_doc changes
Withdraw a doc's public link
trash_doc changes
Move a doc to the trash, where it can be restored
restore_doc changes
Bring a doc back from the trash
delete_doc deletes
Delete a doc's page record and ask the server to drop its content
set_doc_journal changes
Set or clear a doc's journal date
append_block changes
Add a block to a doc, code blocks included
update_block changes
Change a block's content, such as a code block's language
move_block changes
Move a block within a doc
delete_block deletes
Remove a block
create_semantic_page changes
Build a page from structured sections
append_semantic_section changes
Add a structured section to a page
inspect_template_structure
Show how a template is built
instantiate_template_native changes
Create a doc from an AFFiNE template
create_workspace_blueprint changes
Set up a workspace structure from a blueprint
list_tags
List tags
add_tag_to_doc changes
Tag a doc
list_docs_by_tag
List docs carrying a tag
list_doc_properties
Show a doc's custom properties
set_doc_property changes
Set a custom property on a doc
list_collections
List collections
create_collection changes
Create a collection
update_collection_rules changes
Change the rules that fill a collection
add_database_column changes
Add a column to a database block
add_database_row changes
Add a row to a database block
update_database_row changes
Edit a database row
delete_database_row deletes
Remove a database row
read_database_columns
Show a database's columns
read_database_cells
Read cell values from a database
compose_database_from_intent changes
Build a database from a described purpose
list_comments
List comments on a doc
create_comment changes
Add a comment
resolve_comment changes
Mark a comment resolved
list_histories
List a doc's saved versions
get_edgeless_canvas
Read the elements on an edgeless canvas
get_blob
Download a stored file, such as the image or attachment behind a blockworkspaceId?: stringkey: stringmaxBytes?: integer
upload_blob changes
Store a file in the workspace and return its keyworkspaceId: stringcontent?: stringfilePath?: stringencoding?: enumfilename?: stringcontentType?: string

Similar servers