SiYuan MCP Server
OFFICIAL SERVERMCP endpoint built into the SiYuan note app for searching, reading and editing a workspace's notes
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
Opens the app, which asks before it adds the server.
claude mcp add --transport http affine http://localhost:3000/mcp{
"mcpServers": {
"affine": {
"url": "http://localhost:3000/mcp"
}
}
}{
"servers": {
"affine": {
"type": "http",
"url": "http://localhost:3000/mcp"
}
}
}[mcp_servers.affine]
url = "http://localhost:3000/mcp"gemini mcp add --scope user --transport http affine http://localhost:3000/mcpOpens the app, which asks before it adds the server. Then replace each <NAME> in its settings with your value.
It needs AFFINE_BASE_URL, AFFINE_COOKIE. Replace each <NAME> with your value.
claude mcp add affine -e AFFINE_BASE_URL=<AFFINE_BASE_URL> -e AFFINE_COOKIE=<AFFINE_COOKIE> -- npx -y -p affine-mcp-server affine-mcp{
"mcpServers": {
"affine": {
"command": "npx",
"args": [
"-y",
"-p",
"affine-mcp-server",
"affine-mcp"
],
"env": {
"AFFINE_BASE_URL": "<AFFINE_BASE_URL>",
"AFFINE_COOKIE": "<AFFINE_COOKIE>"
}
}
}
}{
"mcpServers": {
"affine": {
"command": "npx",
"args": [
"-y",
"-p",
"affine-mcp-server",
"affine-mcp"
],
"env": {
"AFFINE_BASE_URL": "<AFFINE_BASE_URL>",
"AFFINE_COOKIE": "<AFFINE_COOKIE>"
}
}
}
}{
"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>"
}
}
}
}[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 mcp add --scope user -e AFFINE_BASE_URL=<AFFINE_BASE_URL> -e AFFINE_COOKIE=<AFFINE_COOKIE> affine npx -- -y -p affine-mcp-server affine-mcpAFFINE_BASE_URL |
Required: AFFiNE address: https://app.affine.pro for Cloud, or your self-hosted URL. |
|---|---|
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. |
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. |
AFFINE_MCP_HTTP_TOKEN secret |
Optional: Bearer secret clients must send in HTTP mode, needed for a non-loopback listener. |
AFFINE_BLOB_UPLOAD_FILE_ROOTS |
Optional: Directories (absolute paths) that upload_blob may read local files from. Unset, filePath uploads are refused. |
| 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. |
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.
| Runtime | Node.js 20.18.1+ |
|---|---|
| Runs on | macOS, Windows, Linux |
| AFFiNE | Free 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.
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.
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.
24 only read, 30 change things, 5 can delete or overwrite. A ? marks an optional parameter.
list_workspacesget_workspacecreate_workspace changesupdate_workspace changesdelete_workspace deleteslist_workspace_treelist_docssearch_docsfind_doc_by_titleget_docread_doclist_childrenget_orphan_docscreate_doc changescreate_doc_from_markdown changesappend_markdown changesreplace_doc_with_markdown deletesexport_doc_markdownexport_with_fidelity_reportanalyze_doc_fidelityupdate_doc_title changesmove_doc changespublish_doc changesrevoke_doc changestrash_doc changesrestore_doc changesdelete_doc deletesset_doc_journal changesappend_block changesupdate_block changesmove_block changesdelete_block deletescreate_semantic_page changesappend_semantic_section changesinspect_template_structureinstantiate_template_native changescreate_workspace_blueprint changeslist_tagsadd_tag_to_doc changeslist_docs_by_taglist_doc_propertiesset_doc_property changeslist_collectionscreate_collection changesupdate_collection_rules changesadd_database_column changesadd_database_row changesupdate_database_row changesdelete_database_row deletesread_database_columnsread_database_cellscompose_database_from_intent changeslist_commentscreate_comment changesresolve_comment changeslist_historiesget_edgeless_canvasget_blobworkspaceId?: stringkey: stringmaxBytes?: integerupload_blob changesworkspaceId: stringcontent?: stringfilePath?: stringencoding?: enumfilename?: stringcontentType?: string