affine-mcp-server 1.2.0 → 1.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -37
- package/bin/affine-mcp +5 -0
- package/dist/config.js +0 -2
- package/dist/index.js +28 -10
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
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.
|
|
4
4
|
|
|
5
|
-
[](https://github.com/dawncr0w/affine-mcp-server/releases)
|
|
6
6
|
[](https://github.com/modelcontextprotocol/typescript-sdk)
|
|
7
7
|
[](LICENSE)
|
|
8
8
|
|
|
@@ -12,9 +12,9 @@ A Model Context Protocol (MCP) server that integrates with AFFiNE (self‑hosted
|
|
|
12
12
|
- Transport: stdio only (Claude Desktop / Codex compatible)
|
|
13
13
|
- Auth: Token, Cookie, or Email/Password (priority order)
|
|
14
14
|
- Tools: 30+ tools plus WebSocket-based document editing
|
|
15
|
-
- Status: Production Ready (v1.2.
|
|
16
|
-
|
|
17
|
-
> New in v1.2.
|
|
15
|
+
- Status: Production Ready (v1.2.1)
|
|
16
|
+
|
|
17
|
+
> New in v1.2.2: Fixed CLI binary to always run via Node (no shell mis-execution). Startup remains non-blocking for email/password login by default; set `AFFINE_LOGIN_AT_START=sync` to block at startup.
|
|
18
18
|
|
|
19
19
|
## Features
|
|
20
20
|
|
|
@@ -37,35 +37,21 @@ A Model Context Protocol (MCP) server that integrates with AFFiNE (self‑hosted
|
|
|
37
37
|
# Global install (recommended)
|
|
38
38
|
npm i -g affine-mcp-server
|
|
39
39
|
|
|
40
|
-
# Or run ad
|
|
41
|
-
npx affine-mcp-server
|
|
40
|
+
# Or run ad‑hoc via npx (no install)
|
|
41
|
+
npx -y -p affine-mcp-server affine-mcp -- --version
|
|
42
42
|
```
|
|
43
43
|
|
|
44
44
|
The package installs a CLI named `affine-mcp` that runs the MCP server over stdio.
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
Note: From v1.2.2 the CLI wrapper (`bin/affine-mcp`) ensures Node runs the ESM entrypoint, preventing shell from misinterpreting JS.
|
|
47
47
|
|
|
48
48
|
## Configuration
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
```env
|
|
53
|
-
# AFFiNE server URL (required)
|
|
54
|
-
AFFINE_BASE_URL=https://your-affine-instance.com
|
|
50
|
+
Configure via environment variables (shell or app config). `.env` files are no longer recommended.
|
|
55
51
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
# 2) Session Cookie
|
|
60
|
-
AFFINE_COOKIE=affine_session=xxx; affine_csrf=yyy
|
|
61
|
-
# 3) Email/Password (fallback)
|
|
62
|
-
AFFINE_EMAIL=your@email.com
|
|
63
|
-
AFFINE_PASSWORD=your_password
|
|
64
|
-
|
|
65
|
-
# Optional settings
|
|
66
|
-
AFFINE_GRAPHQL_PATH=/graphql # Default: /graphql
|
|
67
|
-
AFFINE_WORKSPACE_ID=workspace-uuid # Default workspace for operations
|
|
68
|
-
```
|
|
52
|
+
- Required: `AFFINE_BASE_URL`
|
|
53
|
+
- Auth (choose one): `AFFINE_API_TOKEN` | `AFFINE_COOKIE` | `AFFINE_EMAIL` + `AFFINE_PASSWORD`
|
|
54
|
+
- Optional: `AFFINE_GRAPHQL_PATH` (default `/graphql`), `AFFINE_WORKSPACE_ID`, `AFFINE_LOGIN_AT_START` (`async` default, `sync` to block)
|
|
69
55
|
|
|
70
56
|
Authentication priority:
|
|
71
57
|
1) `AFFINE_API_TOKEN` → 2) `AFFINE_COOKIE` → 3) `AFFINE_EMAIL` + `AFFINE_PASSWORD`
|
|
@@ -87,29 +73,38 @@ Add to your Claude Desktop configuration:
|
|
|
87
73
|
"command": "affine-mcp",
|
|
88
74
|
"env": {
|
|
89
75
|
"AFFINE_BASE_URL": "https://your-affine-instance.com",
|
|
90
|
-
"
|
|
76
|
+
"AFFINE_EMAIL": "you@example.com",
|
|
77
|
+
"AFFINE_PASSWORD": "secret!",
|
|
78
|
+
"AFFINE_LOGIN_AT_START": "async"
|
|
91
79
|
}
|
|
92
80
|
}
|
|
93
81
|
}
|
|
94
82
|
}
|
|
95
83
|
```
|
|
96
84
|
|
|
85
|
+
Tips
|
|
86
|
+
- Prefer `AFFINE_COOKIE` or `AFFINE_API_TOKEN` for zero‑latency startup.
|
|
87
|
+
- If your password contains `!` (zsh history expansion), wrap it in single quotes in shells or use the JSON config above.
|
|
88
|
+
|
|
97
89
|
### Codex CLI
|
|
98
90
|
|
|
99
|
-
|
|
91
|
+
Register the MCP server with Codex:
|
|
100
92
|
|
|
101
|
-
-
|
|
102
|
-
- `
|
|
93
|
+
- Global install path (fastest)
|
|
94
|
+
- `npm i -g affine-mcp-server`
|
|
95
|
+
- `codex mcp add affine --env AFFINE_BASE_URL=https://your-affine-instance.com --env 'AFFINE_EMAIL=you@example.com' --env 'AFFINE_PASSWORD=secret!' --env AFFINE_LOGIN_AT_START=async -- affine-mcp`
|
|
103
96
|
|
|
104
|
-
-
|
|
105
|
-
-
|
|
97
|
+
- Use npx (no global install)
|
|
98
|
+
- `codex mcp add affine --env AFFINE_BASE_URL=https://your-affine-instance.com --env 'AFFINE_EMAIL=you@example.com' --env 'AFFINE_PASSWORD=secret!' --env AFFINE_LOGIN_AT_START=async -- npx -y -p affine-mcp-server affine-mcp`
|
|
106
99
|
|
|
107
|
-
|
|
100
|
+
- Token or cookie (no startup login)
|
|
101
|
+
- Token: `codex mcp add affine --env AFFINE_BASE_URL=https://... --env AFFINE_API_TOKEN=... -- affine-mcp`
|
|
102
|
+
- Cookie: `codex mcp add affine --env AFFINE_BASE_URL=https://... --env "AFFINE_COOKIE=affine_session=...; affine_csrf=..." -- affine-mcp`
|
|
103
|
+
|
|
104
|
+
Notes
|
|
108
105
|
- MCP name: `affine`
|
|
109
106
|
- Command: `affine-mcp`
|
|
110
|
-
-
|
|
111
|
-
|
|
112
|
-
Refer to your Codex CLI docs for the exact config keys/paths.
|
|
107
|
+
- Environment: `AFFINE_BASE_URL` + one auth method (`AFFINE_API_TOKEN` | `AFFINE_COOKIE` | `AFFINE_EMAIL`/`AFFINE_PASSWORD`)
|
|
113
108
|
|
|
114
109
|
## Available Tools
|
|
115
110
|
|
|
@@ -150,14 +145,19 @@ Refer to your Codex CLI docs for the exact config keys/paths.
|
|
|
150
145
|
### Advanced
|
|
151
146
|
- `apply_doc_updates` – apply CRDT updates to documents
|
|
152
147
|
|
|
153
|
-
##
|
|
148
|
+
## Use Locally (clone)
|
|
154
149
|
|
|
155
150
|
```bash
|
|
156
151
|
git clone https://github.com/dawncr0w/affine-mcp-server.git
|
|
157
152
|
cd affine-mcp-server
|
|
158
153
|
npm install
|
|
159
154
|
npm run build
|
|
160
|
-
|
|
155
|
+
# Run directly
|
|
156
|
+
node dist/index.js
|
|
157
|
+
|
|
158
|
+
# Or expose as a global CLI for Codex/Claude without publishing
|
|
159
|
+
npm link
|
|
160
|
+
# Now use `affine-mcp` like a global binary
|
|
161
161
|
```
|
|
162
162
|
|
|
163
163
|
## Troubleshooting
|
|
@@ -166,6 +166,7 @@ Authentication
|
|
|
166
166
|
- Email/Password: ensure your instance allows password auth and credentials are valid
|
|
167
167
|
- Cookie: copy cookies (e.g., `affine_session`, `affine_csrf`) from the browser DevTools after login
|
|
168
168
|
- Token: generate a personal access token; verify it hasn’t expired
|
|
169
|
+
- Startup timeouts: v1.2.2 includes a CLI wrapper fix and the default async login to avoid blocking the MCP handshake. Set `AFFINE_LOGIN_AT_START=sync` only if needed.
|
|
169
170
|
|
|
170
171
|
Connection
|
|
171
172
|
- Confirm `AFFINE_BASE_URL` is reachable
|
|
@@ -182,6 +183,16 @@ Connection
|
|
|
182
183
|
|
|
183
184
|
## Version History
|
|
184
185
|
|
|
186
|
+
### 1.2.2 (2025‑09‑18)
|
|
187
|
+
- CLI wrapper added to ensure Node runs ESM entry (`bin/affine-mcp`), preventing shell mis-execution
|
|
188
|
+
- Docs cleaned: use env vars via shell/app config; `.env` file no longer recommended
|
|
189
|
+
- MCP startup behavior unchanged from 1.2.1 (async login by default)
|
|
190
|
+
|
|
191
|
+
### 1.2.1 (2025‑09‑17)
|
|
192
|
+
- Default to asynchronous email/password login after MCP stdio handshake
|
|
193
|
+
- New `AFFINE_LOGIN_AT_START` env (`async` default, `sync` to block at startup)
|
|
194
|
+
- Expanded docs for Codex/Claude using npm, npx, and local clone
|
|
195
|
+
|
|
185
196
|
### 1.2.0 (2025‑09‑16)
|
|
186
197
|
- WebSocket-based document tools: `create_doc`, `append_paragraph`, `delete_doc` (create/edit/delete now supported)
|
|
187
198
|
- Tool aliases: both `affine_*` and non‑prefixed names
|
package/bin/affine-mcp
ADDED
package/dist/config.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -16,24 +16,42 @@ import { loginWithPassword } from "./auth.js";
|
|
|
16
16
|
import { registerAuthTools } from "./tools/auth.js";
|
|
17
17
|
const config = loadConfig();
|
|
18
18
|
async function buildServer() {
|
|
19
|
-
const server = new McpServer({ name: "affine-mcp", version: "1.
|
|
19
|
+
const server = new McpServer({ name: "affine-mcp", version: "1.2.2" });
|
|
20
20
|
// Initialize GraphQL client with authentication
|
|
21
21
|
const gql = new GraphQLClient({
|
|
22
22
|
endpoint: `${config.baseUrl}${config.graphqlPath}`,
|
|
23
23
|
headers: config.headers,
|
|
24
24
|
bearer: config.apiToken
|
|
25
25
|
});
|
|
26
|
-
// Try email/password authentication if no other auth method is configured
|
|
26
|
+
// Try email/password authentication if no other auth method is configured.
|
|
27
|
+
// To avoid startup timeouts in MCP clients, default to async login after the stdio handshake.
|
|
27
28
|
if (!gql.isAuthenticated() && config.email && config.password) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
const mode = (process.env.AFFINE_LOGIN_AT_START || "async").toLowerCase();
|
|
30
|
+
if (mode === "sync") {
|
|
31
|
+
console.error("No token/cookie; performing synchronous email/password authentication at startup...");
|
|
32
|
+
try {
|
|
33
|
+
const { cookieHeader } = await loginWithPassword(config.baseUrl, config.email, config.password);
|
|
34
|
+
gql.setCookie(cookieHeader);
|
|
35
|
+
console.error("Successfully authenticated with email/password");
|
|
36
|
+
}
|
|
37
|
+
catch (e) {
|
|
38
|
+
console.error("Failed to authenticate with email/password:", e);
|
|
39
|
+
console.error("WARNING: Continuing without authentication - some operations may fail");
|
|
40
|
+
}
|
|
33
41
|
}
|
|
34
|
-
|
|
35
|
-
console.error("
|
|
36
|
-
|
|
42
|
+
else {
|
|
43
|
+
console.error("No token/cookie; deferring email/password authentication (async after connect)...");
|
|
44
|
+
// Fire-and-forget async login so stdio handshake is not delayed.
|
|
45
|
+
(async () => {
|
|
46
|
+
try {
|
|
47
|
+
const { cookieHeader } = await loginWithPassword(config.baseUrl, config.email, config.password);
|
|
48
|
+
gql.setCookie(cookieHeader);
|
|
49
|
+
console.error("Successfully authenticated with email/password (async)");
|
|
50
|
+
}
|
|
51
|
+
catch (e) {
|
|
52
|
+
console.error("Failed to authenticate with email/password (async):", e);
|
|
53
|
+
}
|
|
54
|
+
})();
|
|
37
55
|
}
|
|
38
56
|
}
|
|
39
57
|
// Log authentication status
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "affine-mcp-server",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Model Context Protocol server for AFFiNE - enables AI assistants to interact with AFFiNE workspaces, documents, and collaboration features.",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"license": "MIT",
|
|
9
9
|
"repository": {
|
|
10
10
|
"type": "git",
|
|
11
|
-
"url": "https://github.com/dawncr0w/affine-mcp-server.git"
|
|
11
|
+
"url": "git+https://github.com/dawncr0w/affine-mcp-server.git"
|
|
12
12
|
},
|
|
13
13
|
"keywords": [
|
|
14
14
|
"mcp",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
],
|
|
21
21
|
"main": "dist/index.js",
|
|
22
22
|
"bin": {
|
|
23
|
-
"affine-mcp": "
|
|
23
|
+
"affine-mcp": "bin/affine-mcp"
|
|
24
24
|
},
|
|
25
25
|
"scripts": {
|
|
26
26
|
"build": "tsc -p tsconfig.json",
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"prepublishOnly": "npm run build"
|
|
30
30
|
},
|
|
31
31
|
"files": [
|
|
32
|
+
"bin",
|
|
32
33
|
"dist",
|
|
33
34
|
"README.md",
|
|
34
35
|
"LICENSE"
|
|
@@ -41,7 +42,6 @@
|
|
|
41
42
|
},
|
|
42
43
|
"dependencies": {
|
|
43
44
|
"@modelcontextprotocol/sdk": "^1.17.2",
|
|
44
|
-
"dotenv": "^16.6.1",
|
|
45
45
|
"form-data": "^4.0.4",
|
|
46
46
|
"node-fetch": "^3.3.2",
|
|
47
47
|
"socket.io-client": "^4.8.1",
|