一键导入
affine-mcp-server-integration
Connect AI assistants to AFFiNE workspaces, documents, databases, and collaboration APIs using the Model Context Protocol.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Connect AI assistants to AFFiNE workspaces, documents, databases, and collaboration APIs using the Model Context Protocol.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Policy-centered context budget layer that turns sprawling codebases into compact, high-signal context for AI coding agents using symbol graphs and precision tools
Control and automate Slay the Spire 2 gameplay through REST API or MCP server for AI agents
MCP server for browser automation using natural language through kogiQA, enabling AI agents to interact with web pages without selectors
Professional browser automation for Claude Code, Codex, and MCP clients powered by DrissionPage MCP Server
MCP server for Yuque (语雀) knowledge base - search, create, and manage documents through AI assistants
MCP server connecting AI assistants to Shopify Admin GraphQL API for products, orders, customers, inventory, and metafields management
| name | affine-mcp-server-integration |
| description | Connect AI assistants to AFFiNE workspaces, documents, databases, and collaboration APIs using the Model Context Protocol. |
| triggers | ["connect to my AFFiNE workspace","set up AFFiNE MCP server","configure MCP for AFFiNE Cloud","create and manage AFFiNE documents with AI","integrate Claude with AFFiNE","access my AFFiNE knowledge base","use AFFiNE database with MCP","deploy AFFiNE MCP server"] |
Skill by ara.so — MCP Skills collection.
AFFiNE MCP Server is a Model Context Protocol server that exposes AFFiNE workspaces, documents, databases, and collaboration features to AI assistants. It supports both AFFiNE Cloud and self-hosted deployments, offering 85+ tools across workspace management, document operations, database manipulation, and organizational features.
Key capabilities:
# Install globally via npm
npm i -g affine-mcp-server
# Verify installation
affine-mcp --version
# Run without installing
npx -y -p affine-mcp-server affine-mcp -- --version
# Pull the official image
docker pull ghcr.io/dawncr0w/affine-mcp-server:latest
# Run with environment variables
docker run -d \
-p 3000:3000 \
-e MCP_TRANSPORT=http \
-e AFFINE_BASE_URL=https://app.affine.pro \
-e AFFINE_API_TOKEN=${AFFINE_API_TOKEN} \
-e AFFINE_MCP_AUTH_MODE=bearer \
-e AFFINE_MCP_HTTP_TOKEN=${MCP_HTTP_TOKEN} \
ghcr.io/dawncr0w/affine-mcp-server:latest
# Store credentials securely (~/.config/affine-mcp/config with mode 600)
affine-mcp login
# Interactive prompts will ask for:
# - AFFiNE base URL (default: https://app.affine.pro)
# - Authentication method (token, cookie, or email/password)
# - Credentials
# For AFFiNE Cloud (token required)
export AFFINE_BASE_URL=https://app.affine.pro
export AFFINE_API_TOKEN=ut_your_token_here
# For self-hosted with email/password
export AFFINE_BASE_URL=https://your-affine-instance.com
export AFFINE_EMAIL=user@example.com
export AFFINE_PASSWORD=${AFFINE_PASSWORD}
# For self-hosted with cookie
export AFFINE_BASE_URL=https://your-affine-instance.com
export AFFINE_COOKIE=${AFFINE_COOKIE}
AFFiNE Cloud:
Self-hosted:
Add to your .claude/project_config.json:
{
"mcpServers": {
"affine": {
"command": "affine-mcp"
}
}
}
Or with explicit environment variables:
{
"mcpServers": {
"affine": {
"command": "affine-mcp",
"env": {
"AFFINE_BASE_URL": "https://app.affine.pro",
"AFFINE_API_TOKEN": "${AFFINE_API_TOKEN}"
}
}
}
}
Add to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS):
{
"mcpServers": {
"affine": {
"command": "affine-mcp"
}
}
}
Add to ~/.cursor/mcp_config.json:
{
"mcpServers": {
"affine": {
"command": "affine-mcp"
}
}
}
# Add the server
codex mcp add affine -- affine-mcp
# Verify
codex mcp list
Client configuration:
{
"mcpServers": {
"affine": {
"type": "http",
"url": "https://your-mcp-server.com/mcp",
"headers": {
"Authorization": "Bearer ${MCP_HTTP_TOKEN}"
}
}
}
}
Server environment:
export MCP_TRANSPORT=http
export MCP_HTTP_PORT=3000
export AFFINE_MCP_AUTH_MODE=bearer
export AFFINE_MCP_HTTP_TOKEN=${MCP_HTTP_TOKEN}
# Show current configuration (secrets redacted)
affine-mcp show-config
# Get config file path
affine-mcp config-path
# Generate client configuration snippets
affine-mcp snippet claude
affine-mcp snippet cursor
affine-mcp snippet codex
affine-mcp snippet all
# Generate with environment variables
affine-mcp snippet claude --env
# Logout (remove stored credentials)
affine-mcp logout
# Test effective configuration
affine-mcp status
# Machine-readable status
affine-mcp status --json
# Diagnose configuration and connectivity
affine-mcp doctor
# Start stdio server (default)
affine-mcp
# Start HTTP server
MCP_TRANSPORT=http MCP_HTTP_PORT=3000 affine-mcp
# With custom log level
LOG_LEVEL=debug affine-mcp
The server exposes 85 tools organized by domain:
// List all workspaces
list_workspaces()
// Get workspace details
get_workspace({ workspaceId: "workspace-id" })
// Create workspace
create_workspace({
name: "My New Workspace",
description: "Project workspace"
})
// Update workspace
update_workspace({
workspaceId: "workspace-id",
name: "Updated Name"
})
// Delete workspace
delete_workspace({ workspaceId: "workspace-id" })
// Search documents
search_docs({
workspaceId: "workspace-id",
query: "meeting notes",
limit: 10
})
// Get document by exact title
get_doc_by_title({
workspaceId: "workspace-id",
title: "Project Roadmap"
})
// Read document content
read_doc({
workspaceId: "workspace-id",
docId: "doc-id"
})
// Create document
create_doc({
workspaceId: "workspace-id",
title: "New Document",
text: "Initial content",
folderId: "folder-id" // Optional, new in v2.1.0
})
// Update document
update_doc({
workspaceId: "workspace-id",
docId: "doc-id",
text: "Updated content"
})
// Delete document
delete_doc({
workspaceId: "workspace-id",
docId: "doc-id"
})
// Move document to trash
trash_doc({
workspaceId: "workspace-id",
docId: "doc-id"
})
// Restore from trash
restore_doc({
workspaceId: "workspace-id",
docId: "doc-id"
})
// List available templates
list_templates({ workspaceId: "workspace-id" })
// Inspect template structure
inspect_template({
workspaceId: "workspace-id",
templateId: "template-id"
})
// Create document from template
create_doc_from_template({
workspaceId: "workspace-id",
templateId: "template-id",
title: "Q1 Report",
folderId: "folder-id" // Optional
})
// Create database
create_database({
workspaceId: "workspace-id",
docId: "doc-id",
blockId: "block-id", // Optional
name: "Project Tracker"
})
// Add database column
add_database_column({
workspaceId: "workspace-id",
docId: "doc-id",
databaseId: "database-id",
name: "Status",
type: "select",
options: ["Todo", "In Progress", "Done"]
})
// Add database row
add_database_row({
workspaceId: "workspace-id",
docId: "doc-id",
databaseId: "database-id",
values: {
"Task": "Implement feature",
"Status": "In Progress"
}
})
// Update database row
update_database_row({
workspaceId: "workspace-id",
docId: "doc-id",
databaseId: "database-id",
rowId: "row-id",
values: {
"Status": "Done"
}
})
// Inspect database schema
inspect_database_schema({
workspaceId: "workspace-id",
docId: "doc-id",
databaseId: "database-id"
})
// List collections
list_collections({ workspaceId: "workspace-id" })
// Create collection
create_collection({
workspaceId: "workspace-id",
name: "Project Docs"
})
// Add document to collection
add_doc_to_collection({
workspaceId: "workspace-id",
collectionId: "collection-id",
docId: "doc-id"
})
// Remove document from collection
remove_doc_from_collection({
workspaceId: "workspace-id",
collectionId: "collection-id",
docId: "doc-id"
})
// List comments on document
list_comments({
workspaceId: "workspace-id",
docId: "doc-id"
})
// Create comment
create_comment({
workspaceId: "workspace-id",
docId: "doc-id",
text: "Great point!",
quote: "original text" // Optional
})
// Update comment
update_comment({
workspaceId: "workspace-id",
docId: "doc-id",
commentId: "comment-id",
text: "Updated comment"
})
// Delete comment
delete_comment({
workspaceId: "workspace-id",
docId: "doc-id",
commentId: "comment-id"
})
// 1. Create workspace
const workspace = await create_workspace({
name: "Q1 Project",
description: "Project tracking workspace"
});
// 2. Create main document
const mainDoc = await create_doc({
workspaceId: workspace.id,
title: "Project Overview",
text: "# Project Overview\n\nKey objectives..."
});
// 3. Create database for task tracking
const database = await create_database({
workspaceId: workspace.id,
docId: mainDoc.id,
name: "Task Tracker"
});
// 4. Add columns
await add_database_column({
workspaceId: workspace.id,
docId: mainDoc.id,
databaseId: database.id,
name: "Priority",
type: "select",
options: ["High", "Medium", "Low"]
});
// 5. Add initial tasks
await add_database_row({
workspaceId: workspace.id,
docId: mainDoc.id,
databaseId: database.id,
values: {
"Task": "Define requirements",
"Priority": "High"
}
});
// 1. Search for documents
const results = await search_docs({
workspaceId: "workspace-id",
query: "meeting notes",
limit: 5
});
// 2. Find specific document by exact title
const doc = await get_doc_by_title({
workspaceId: "workspace-id",
title: "Weekly Standup - 2024-01-15"
});
// 3. Read current content
const content = await read_doc({
workspaceId: "workspace-id",
docId: doc.id
});
// 4. Append new content
const updatedText = content.text + "\n\n## Action Items\n- Follow up on design";
await update_doc({
workspaceId: "workspace-id",
docId: doc.id,
text: updatedText
});
// 1. List available templates
const templates = await list_templates({
workspaceId: "workspace-id"
});
// 2. Inspect template to understand structure
const template = await inspect_template({
workspaceId: "workspace-id",
templateId: templates[0].id
});
// 3. Create document from template with placement
const newDoc = await create_doc_from_template({
workspaceId: "workspace-id",
templateId: templates[0].id,
title: "Q1 Planning Doc",
folderId: "planning-folder-id"
});
// Compose a structured document with intent
const pageIntent = {
pageTitle: "Product Launch Plan",
sections: [
{
heading: "Executive Summary",
content: "Overview of product launch strategy..."
},
{
heading: "Timeline",
content: "Key milestones and dates",
database: {
name: "Launch Milestones",
columns: [
{ name: "Milestone", type: "text" },
{ name: "Date", type: "date" },
{ name: "Owner", type: "text" }
]
}
}
]
};
// Use semantic composition tool
const result = await compose_semantic_page({
workspaceId: "workspace-id",
intent: JSON.stringify(pageIntent)
});
// Create complex database structure from high-level intent
const dbIntent = {
name: "Bug Tracker",
columns: [
{ name: "Title", type: "text" },
{ name: "Severity", type: "select", options: ["Critical", "High", "Medium", "Low"] },
{ name: "Status", type: "select", options: ["Open", "In Progress", "Fixed", "Closed"] },
{ name: "Assigned To", type: "text" },
{ name: "Due Date", type: "date" }
],
initialRows: [
{
"Title": "Login page crash",
"Severity": "Critical",
"Status": "Open"
}
]
};
const result = await compose_database_from_intent({
workspaceId: "workspace-id",
docId: "doc-id",
intent: JSON.stringify(dbIntent)
});
# Limit to read-only operations
export AFFINE_TOOL_PROFILE=read_only
# Core tools only (no experimental features)
export AFFINE_TOOL_PROFILE=core
# Authoring tools (read + write, no admin)
export AFFINE_TOOL_PROFILE=authoring
# Full access (default)
export AFFINE_TOOL_PROFILE=full
# Disable entire tool groups
export AFFINE_DISABLED_GROUPS=destructive,admin,docs.database
# Disable specific tools
export AFFINE_DISABLED_TOOLS=delete_workspace,delete_doc,trash_doc
# Enable bearer token authentication
export AFFINE_MCP_AUTH_MODE=bearer
export AFFINE_MCP_HTTP_TOKEN=${MCP_HTTP_TOKEN}
# Use HTTPS in production
export MCP_HTTP_PORT=3000
# Then reverse proxy with nginx/caddy for TLS
docker run -d \
--name affine-mcp \
-p 3000:3000 \
-e MCP_TRANSPORT=http \
-e AFFINE_BASE_URL=${AFFINE_BASE_URL} \
-e AFFINE_API_TOKEN=${AFFINE_API_TOKEN} \
-e AFFINE_MCP_AUTH_MODE=bearer \
-e AFFINE_MCP_HTTP_TOKEN=${MCP_HTTP_TOKEN} \
ghcr.io/dawncr0w/affine-mcp-server:latest
version: '3.8'
services:
affine-mcp:
image: ghcr.io/dawncr0w/affine-mcp-server:latest
ports:
- "3000:3000"
environment:
MCP_TRANSPORT: http
MCP_HTTP_PORT: 3000
AFFINE_BASE_URL: ${AFFINE_BASE_URL}
AFFINE_API_TOKEN: ${AFFINE_API_TOKEN}
AFFINE_MCP_AUTH_MODE: bearer
AFFINE_MCP_HTTP_TOKEN: ${MCP_HTTP_TOKEN}
AFFINE_TOOL_PROFILE: authoring
LOG_LEVEL: info
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost:3000/healthz"]
interval: 30s
timeout: 10s
retries: 3
restart: unless-stopped
# Liveness check
curl http://localhost:3000/healthz
# Readiness check
curl http://localhost:3000/readyz
| Variable | Description | Example |
|---|---|---|
AFFINE_BASE_URL | AFFiNE instance URL | https://app.affine.pro |
AFFINE_API_TOKEN | API token (recommended) | ut_... |
| Variable | Description |
|---|---|
AFFINE_API_TOKEN | API token (recommended) |
AFFINE_EMAIL + AFFINE_PASSWORD | Email/password (self-hosted only) |
AFFINE_COOKIE | Session cookie |
| Variable | Default | Description |
|---|---|---|
MCP_TRANSPORT | stdio | stdio or http |
MCP_HTTP_PORT | 3000 | HTTP server port |
| Variable | Default | Description |
|---|---|---|
AFFINE_MCP_AUTH_MODE | none | bearer, oauth, or none |
AFFINE_MCP_HTTP_TOKEN | - | Bearer token for HTTP auth |
AFFINE_TOOL_PROFILE | full | read_only, core, authoring, full |
AFFINE_DISABLED_GROUPS | - | Comma-separated groups to disable |
AFFINE_DISABLED_TOOLS | - | Comma-separated tools to disable |
| Variable | Default | Description |
|---|---|---|
LOG_LEVEL | info | debug, info, warn, error |
# Diagnose configuration
affine-mcp doctor
# Check status with verbose output
affine-mcp status --json
# Verify config file exists and is readable
affine-mcp config-path
ls -la $(affine-mcp config-path)
"Authentication failed"
"Workspace not found"
"Tool not found"
AFFINE_TOOL_PROFILE and AFFINE_DISABLED_GROUPS settingsnpm i -g affine-mcp-server@latest"Connection refused" (HTTP mode)
docker ps or check processMCP_HTTP_PORT matches client configuration# Enable debug logging
LOG_LEVEL=debug affine-mcp
# Or with environment variable
export LOG_LEVEL=debug
affine-mcp
# List all available tools
affine-mcp status --json | jq '.tools'
# Check specific tool
affine-mcp status --json | jq '.tools[] | select(.name == "create_doc")'
// Check document capabilities before operations
const capabilities = await report_doc_capabilities({
workspaceId: "workspace-id",
docId: "doc-id"
});
// Returns: { canEdit, canComment, canShare, exportFormats, ... }
// Check content fidelity (what blocks/features are supported)
const fidelity = await report_content_fidelity({
workspaceId: "workspace-id",
docId: "doc-id"
});
// Append block to document
await append_block({
workspaceId: "workspace-id",
docId: "doc-id",
blockType: "paragraph",
content: "New paragraph text"
});
// Insert block at specific position
await insert_block({
workspaceId: "workspace-id",
docId: "doc-id",
afterBlockId: "block-id",
blockType: "heading",
content: "New Section",
level: 2
});
// Create workspace from blueprint
const blueprint = {
name: "Team Sprint",
folders: ["Planning", "Design", "Development"],
templates: ["standup", "retrospective"],
databases: ["task-tracker"]
};
const workspace = await create_workspace_from_blueprint({
blueprint: JSON.stringify(blueprint)
});
// Create collection with rules
await create_collection({
workspaceId: "workspace-id",
name: "Meeting Notes",
rules: {
tagFilter: ["meeting"],
autoSync: true
}
});
// Sync collection (apply rules)
await sync_collection_rules({
workspaceId: "workspace-id",
collectionId: "collection-id"
});
/healthz and /readyz for containerized deploymentsAFFINE_TOOL_PROFILE=authoring in production to prevent accidental deletions/docs directory in repository
getting-started.md - First-run setupclient-setup.md - Client-specific configurationconfiguration-and-deployment.md - Advanced deploymenttool-reference.md - Complete tool catalogworkflow-recipes.md - End-to-end examplesedgeless-canvas-cookbook.md - Canvas layout helperstool-manifest.json - Canonical tool definitions