DAWNCR0W/affine-mcp-server
If you are the rightful owner of affine-mcp-server and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to dayong@mcphub.com.
This document provides a comprehensive overview of the MCP server designed to manage AFFiNE workspaces, documents, and related functionalities via GraphQL.
AFFiNE MCP Server
A Model Context Protocol (MCP) server that integrates with AFFiNE (self‑hosted or cloud). It exposes AFFiNE workspaces and documents to AI assistants over stdio (default) or HTTP (/mcp).
Overview
- Purpose: Manage AFFiNE workspaces and documents through MCP
- Transport: stdio (default) and optional HTTP (
/mcp) for remote MCP deployments - Auth: Token, Cookie, or Email/Password (priority order)
- Tools: 43 focused tools with WebSocket-based document editing
- Status: Active
New in v1.7.2: Fixed tag visibility parity in AFFiNE Web/App for MCP-created tags and hardened Docker E2E startup reliability with retry/diagnostics.
Features
- Workspace: create (with initial doc), read, update, delete
- Documents: list/get/read/publish/revoke + create/append/replace/delete + markdown import/export + tags (WebSocket‑based)
- Database workflows: create database blocks, then add columns/rows via MCP tools
- Comments: full CRUD and resolve
- Version History: list
- Users & Tokens: current user, sign in, profile/settings, and personal access tokens
- Notifications: list and mark as read
- Blob storage: upload/delete/cleanup
Requirements
- Node.js 18+
- An AFFiNE instance (self‑hosted or cloud)
- Valid AFFiNE credentials or access token
Installation
# Global install (recommended)
npm i -g affine-mcp-server
# Or run ad‑hoc via npx (no install)
npx -y -p affine-mcp-server affine-mcp -- --version
The package installs a CLI named affine-mcp that runs the MCP server over stdio.
Note: From v1.2.2+ the CLI wrapper (bin/affine-mcp) ensures Node runs the ESM entrypoint, preventing shell from misinterpreting JS.
Configuration
Interactive login (recommended)
The easiest way to configure credentials:
npm i -g affine-mcp-server
affine-mcp login
This stores credentials in ~/.config/affine-mcp/config (mode 600). The MCP server reads them automatically — no environment variables needed.
AFFiNE Cloud (app.affine.pro): you'll be prompted to paste an API token from Settings → Integrations → MCP Server.
Self-hosted instances: you can choose between email/password (recommended — auto-generates an API token) or pasting a token manually.
$ affine-mcp login
Affine MCP Server — Login
Affine URL [https://app.affine.pro]: https://my-affine.example.com
Auth method — [1] Email/password (recommended) [2] Paste API token: 1
Email: user@example.com
Password: ****
Signing in...
✓ Signed in as: User Name <user@example.com>
Generating API token...
✓ Created token: ut_abc123... (name: affine-mcp-2026-02-18)
Detecting workspaces...
Found 1 workspace: abc-def-123 (by User Name, 1 member, 2/10/2026)
Auto-selected.
✓ Saved to /home/user/.config/affine-mcp/config (mode 600)
The MCP server will use these credentials automatically.
Other CLI commands:
affine-mcp status— show current config and test connectionaffine-mcp logout— remove stored credentials
Environment variables
You can also configure via environment variables (they override the config file):
- Required:
AFFINE_BASE_URL - Auth (choose one):
AFFINE_API_TOKEN|AFFINE_COOKIE|AFFINE_EMAIL+AFFINE_PASSWORD - Optional:
AFFINE_GRAPHQL_PATH(default/graphql),AFFINE_WORKSPACE_ID,AFFINE_LOGIN_AT_START(setsynconly when you must block startup)
Authentication priority:
AFFINE_API_TOKEN→ 2)AFFINE_COOKIE→ 3)AFFINE_EMAIL+AFFINE_PASSWORD
Cloudflare note:
AFFINE_EMAIL/AFFINE_PASSWORDauth requires programmatic access to/api/auth/sign-in. AFFiNE Cloud (app.affine.pro) is behind Cloudflare, which blocks these requests. UseAFFINE_API_TOKENfor cloud, or useaffine-mcp loginwhich handles this automatically. Email/password works for self-hosted instances without Cloudflare.
Quick Start
Claude Code
After running affine-mcp login, add to your project's .mcp.json:
{
"mcpServers": {
"affine": {
"command": "affine-mcp"
}
}
}
No env block needed — the server reads ~/.config/affine-mcp/config automatically.
If you prefer explicit env vars instead of the config file:
{
"mcpServers": {
"affine": {
"command": "affine-mcp",
"env": {
"AFFINE_BASE_URL": "https://app.affine.pro",
"AFFINE_API_TOKEN": "ut_xxx"
}
}
}
}
Claude Desktop
Add to your Claude Desktop configuration:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json - Linux:
~/.config/Claude/claude_desktop_config.json
{
"mcpServers": {
"affine": {
"command": "affine-mcp",
"env": {
"AFFINE_BASE_URL": "https://app.affine.pro",
"AFFINE_API_TOKEN": "ut_xxx"
}
}
}
}
Or with email/password for self-hosted instances (not supported on AFFiNE Cloud — see Cloudflare note above):
{
"mcpServers": {
"affine": {
"command": "affine-mcp",
"env": {
"AFFINE_BASE_URL": "https://your-self-hosted-affine.com",
"AFFINE_EMAIL": "you@example.com",
"AFFINE_PASSWORD": "secret!"
}
}
}
}
Tips
- Prefer
affine-mcp loginorAFFINE_API_TOKENfor zero‑latency startup. - If your password contains
!(zsh history expansion), wrap it in single quotes in shells or use the JSON config above.
Codex CLI
Register the MCP server with Codex:
-
With config file (after
affine-mcp login):codex mcp add affine -- affine-mcp
-
With API token:
codex mcp add affine --env AFFINE_BASE_URL=https://app.affine.pro --env AFFINE_API_TOKEN=ut_xxx -- affine-mcp
-
With email/password (self-hosted only):
codex mcp add affine --env AFFINE_BASE_URL=https://your-self-hosted-affine.com --env 'AFFINE_EMAIL=you@example.com' --env 'AFFINE_PASSWORD=secret!' -- affine-mcp
Cursor
Cursor also supports MCP over stdio with mcp.json.
Project-local (.cursor/mcp.json) example:
{
"mcpServers": {
"affine": {
"command": "affine-mcp",
"env": {
"AFFINE_BASE_URL": "https://app.affine.pro",
"AFFINE_API_TOKEN": "ut_xxx"
}
}
}
}
If you prefer npx:
{
"mcpServers": {
"affine": {
"command": "npx",
"args": ["-y", "-p", "affine-mcp-server", "affine-mcp"],
"env": {
"AFFINE_BASE_URL": "https://app.affine.pro",
"AFFINE_API_TOKEN": "ut_xxx"
}
}
}
}
Remote Server
If you want to host the server remotely (e.g., using Render, Railway, Docker, or a VPS) and connect via HTTP MCP (Streamable HTTP on /mcp) instead of local stdio, run the server in HTTP mode.
Environment variables (HTTP mode)
Required:
MCP_TRANSPORT=httpAFFINE_BASE_URL(example:https://app.affine.pro)- One auth method:
AFFINE_API_TOKEN(recommended), orAFFINE_COOKIE, orAFFINE_EMAIL+AFFINE_PASSWORD
Recommended for remote/public deployments:
AFFINE_MCP_HTTP_HOST=0.0.0.0AFFINE_MCP_HTTP_TOKEN=<strong-random-token>(protects/mcp,/sse,/messages)AFFINE_MCP_HTTP_ALLOWED_ORIGINS=<comma-separated-origins>(for browser clients)
Optional:
PORT(defaults to3000; many platforms like Render inject this automatically)AFFINE_WORKSPACE_IDAFFINE_GRAPHQL_PATH(defaults to/graphql)AFFINE_MCP_HTTP_ALLOW_ALL_ORIGINS=true(testing only)
# Export your configuration first
export MCP_TRANSPORT=http
export AFFINE_API_TOKEN="your_token..."
export AFFINE_MCP_HTTP_HOST="0.0.0.0" # Default: 127.0.0.1
export AFFINE_MCP_HTTP_TOKEN="your-super-secret-token"
export PORT=3000
# Start in HTTP mode (Streamable HTTP on /mcp)
npm run start:http
# OR manually:
# MCP_TRANSPORT=http node dist/index.js
# ("sse" is still accepted at /sse)
Recommended presets
Local testing (HTTP mode):
MCP_TRANSPORT=httpAFFINE_MCP_HTTP_HOST=127.0.0.1AFFINE_MCP_HTTP_TOKEN=<token>(recommended even locally)AFFINE_MCP_HTTP_ALLOWED_ORIGINS=http://localhost:3000(if testing from a browser app)
Docker / container runtime:
MCP_TRANSPORT=httpAFFINE_MCP_HTTP_HOST=0.0.0.0PORT=3000(or container/platform port)AFFINE_MCP_HTTP_TOKEN=<strong-token>AFFINE_MCP_HTTP_ALLOWED_ORIGINS=<your app origin(s)>
Render / Railway / VPS (public endpoint):
MCP_TRANSPORT=httpAFFINE_MCP_HTTP_HOST=0.0.0.0AFFINE_MCP_HTTP_TOKEN=<strong-token>AFFINE_MCP_HTTP_ALLOWED_ORIGINS=<your client origin(s)>
Endpoints currently available:
/mcp- MCP server (Streamable HTTP)/sse- SSE endpoint (old protocol compatible)/messages- Messages endpoint (old protocol compatible)
Available Tools
Workspace
list_workspaces– list all workspacesget_workspace– get workspace detailscreate_workspace– create workspace with initial documentupdate_workspace– update workspace settingsdelete_workspace– delete workspace permanently
Documents
list_docs– list documents with pagination (includesnode.tags)list_tags– list all tags in a workspacelist_docs_by_tag– list documents by tagget_doc– get document metadataread_doc– read document block content and plain text snapshot (WebSocket)export_doc_markdown– export document content as markdownpublish_doc– make document publicrevoke_doc– revoke public accesscreate_doc– create a new document (WebSocket)create_doc_from_markdown– create a document from markdown contentcreate_tag– create a reusable workspace-level tagadd_tag_to_doc– attach a tag to a documentremove_tag_from_doc– detach a tag from a documentappend_paragraph– append a paragraph block (WebSocket)append_block– append canonical block types (text/list/code/media/embed/database/edgeless) with strict validation and placement control (data_viewcurrently falls back to database)add_database_column– add a column to a database block (rich-text,select,multi-select,number,checkbox,link,date)add_database_row– add a row to a database block with values mapped by column name/IDappend_markdown– append markdown content to an existing documentreplace_doc_with_markdown– replace the main note content with markdown contentdelete_doc– delete a document (WebSocket)
Comments
list_comments,create_comment,update_comment,delete_comment,resolve_comment
Version History
list_histories
Users & Tokens
current_user,sign_in,update_profile,update_settingslist_access_tokens,generate_access_token,revoke_access_token
Notifications
list_notifications,read_all_notifications
Blob Storage
upload_blob,delete_blob,cleanup_blobs
Use Locally (clone)
git clone https://github.com/dawncr0w/affine-mcp-server.git
cd affine-mcp-server
npm install
npm run build
# Run directly
node dist/index.js
# Or expose as a global CLI for Codex/Claude without publishing
npm link
# Now use `affine-mcp` like a global binary
Quality Gates
npm run build
npm run test:tool-manifest
npm run pack:check
tool-manifest.jsonis the source of truth for publicly exposed tool names.- CI validates that
registerTool(...)declarations match the manifest exactly. - For full tool-surface verification, run
npm run test:comprehensive. - For full environment verification, run
npm run test:e2e(Docker + MCP + Playwright). - Additional focused runners:
npm run test:db-create,npm run test:bearer,npm run test:playwright.
Troubleshooting
Authentication
- Cloudflare (403 "Just a moment..."): AFFiNE Cloud (
app.affine.pro) uses Cloudflare protection, which blocks programmatic sign-in via/api/auth/sign-in. UseAFFINE_API_TOKENinstead, or runaffine-mcp loginwhich guides you through the right method automatically. Email/password auth only works for self-hosted instances. - Email/Password: only works on self-hosted instances without Cloudflare. Ensure your instance allows password auth and credentials are valid.
- Cookie: copy cookies (e.g.,
affine_session,affine_csrf) from the browser DevTools after login - Token: generate a personal access token; verify it hasn't expired. Run
affine-mcp statusto test. - Startup timeouts: v1.2.2+ includes a CLI wrapper fix and default async login to avoid blocking the MCP handshake. Set
AFFINE_LOGIN_AT_START=synconly if needed.
Connection
- Confirm
AFFINE_BASE_URLis reachable - GraphQL endpoint default is
/graphql - Check firewall/proxy rules; verify CORS if self‑hosted
Method not found
- MCP tool names (for example
list_workspaces) are not JSON-RPC top-level method names. - Use an MCP client (
tools/list,tools/call) instead of sending direct JSON-RPC calls like{\"method\":\"list_workspaces\"}. - From v1.3.0, only canonical tool names are exposed (legacy
affine_*aliases were removed).
Workspace visibility
- This MCP server can access server-backed workspaces only (AFFiNE cloud/self-hosted).
- Browser local-storage workspaces are client-side data, so they are not visible via server GraphQL/WebSocket APIs.
Security Considerations
- Never commit
.envwith secrets - Prefer environment variables in production
- Rotate access tokens regularly
- Use HTTPS
- Store credentials in a secrets manager
Version History
1.7.2 (2026‑03‑04)
- Fixed MCP tag persistence to use AFFiNE canonical tag option IDs so tags are visible in Web/App UI
- Added backward-compatible tag normalization for legacy string tag entries
- Added tag visibility regression coverage (
tests/test-tag-visibility.mjs,tests/playwright/verify-tag-visibility.pw.ts) - Hardened E2E credential bootstrap with configurable health retries, retry attempts, and Docker diagnostics on failure
- Verified CI gates (
validate,e2e) for PR #46 and localnpm run ci
1.7.1 (2026‑03‑03)
- Fixed MCP-created document structure parity with AFFiNE UI (
sys:parenthandling) - Fixed callout text rendering parity in AFFiNE UI for MCP-created blocks
- Added regression assertions for visibility-sensitive document creation paths
1.7.0 (2026‑02‑27)
- Added Streamable HTTP MCP support on
/mcpfor remote hosting while keeping legacy SSE compatibility paths (/sse,/messages) - Added HTTP deployment controls:
AFFINE_MCP_HTTP_HOST,AFFINE_MCP_HTTP_TOKEN,AFFINE_MCP_HTTP_ALLOWED_ORIGINS,AFFINE_MCP_HTTP_ALLOW_ALL_ORIGINS - Added
npm run start:httpfor one-command HTTP mode startup - Hardened HTTP request handling with explicit 50MB parser application and case-insensitive Bearer auth parsing
- Expanded docs with remote deployment/security presets (Docker, Render, Railway, VPS)
- Verified full release checks with
npm run ci,npm run test:e2e, andnpm run test:comprehensive
1.6.0 (2026‑02‑24)
- Added 11 document workflow tools: tags (
list_tags,list_docs_by_tag,create_tag,add_tag_to_doc,remove_tag_from_doc), markdown roundtrip (export_doc_markdown,create_doc_from_markdown,append_markdown,replace_doc_with_markdown), and database operations (add_database_column,add_database_row) - Added interactive CLI commands:
affine-mcp login,affine-mcp status,affine-mcp logout - Added Docker + Playwright E2E pipeline and CI workflow for auth/database regression checks
- Tool surface increased from 32 to 43 canonical tools
- Added release test commands (
test:e2e,test:db-create,test:bearer,test:playwright) and package dependencies for markdown conversion + Playwright
1.5.0 (2026‑02‑13)
- Expanded
append_blockfrom Step1 to Step4 profiles: canonical text/list/code/divider/callout/latex/table/bookmark/media/embed plusdatabase,data_view,surface_ref,frame,edgeless_text,note(data_viewcurrently mapped to database for stability) - Added strict field validation and canonical parent enforcement for page/note/surface containers
- Added local integration runner coverage for all 30 append_block cases against a live AFFINE server
1.4.0 (2026‑02‑13)
- Added
read_docfor reading document block snapshot + plain text - Added Cursor setup examples and troubleshooting notes for JSON-RPC method usage
- Added explicit local-storage workspace limitation notes
1.3.0 (2026‑02‑13)
- Added
append_blockfor slash-command style editing (heading/list/todo/code/divider/quote) - Tool surface simplified to 31 canonical tools (duplicate aliases removed)
- Added CI + manifest parity verification (
npm run test:tool-manifest,npm run ci) - Added open-source community health docs and issue/PR templates
1.2.2 (2025‑09‑18)
- CLI wrapper added to ensure Node runs ESM entry (
bin/affine-mcp), preventing shell mis-execution - Docs cleaned: use env vars via shell/app config;
.envfile no longer recommended - MCP startup behavior unchanged from 1.2.1 (async login by default)
1.2.1 (2025‑09‑17)
- Default to asynchronous email/password login after MCP stdio handshake
AFFINE_LOGIN_AT_STARTsupportssyncwhen you need blocking startup (default is non-blocking)- Expanded docs for Codex/Claude using npm, npx, and local clone
1.2.0 (2025‑09‑16)
- WebSocket-based document tools:
create_doc,append_paragraph,delete_doc(create/edit/delete now supported) - Tool aliases introduced at the time (
affine_*+ non-prefixed names). They were removed later to reduce duplication. - ESM resolution: NodeNext; improved build stability
- CLI binary:
affine-mcpfor easynpm i -gusage
1.1.0 (2025‑08‑12)
- Fixed workspace creation with initial documents (UI accessible)
- 30+ tools, simplified tool names
- Improved error handling and authentication
1.0.0 (2025‑08‑12)
- Initial stable release
- Basic workspace and document operations
- Full authentication support
Contributing
Contributions are welcome!
- Read
CONTRIBUTING.md - Run
npm run cilocally before opening PR - Keep tool changes synced with
tool-manifest.json - Use issue/PR templates in
.github/
Community Health
- Code of Conduct:
CODE_OF_CONDUCT.md - Security policy:
SECURITY.md - Contributing guide:
CONTRIBUTING.md
License
MIT License - see LICENSE file for details
Support
For issues and questions:
- Open an issue on GitHub
- Check AFFiNE documentation at https://docs.affine.pro
Author
dawncr0w - GitHub
Acknowledgments
- Built for the AFFiNE knowledge base platform
- Uses the Model Context Protocol specification
- Powered by @modelcontextprotocol/sdk