affine-mcp-server 1.2.0 → 1.2.1

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.
Files changed (3) hide show
  1. package/README.md +43 -19
  2. package/dist/index.js +28 -10
  3. package/package.json +2 -2
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
- [![Version](https://img.shields.io/badge/version-1.2.0-blue)](https://github.com/dawncr0w/affine-mcp-server/releases)
5
+ [![Version](https://img.shields.io/badge/version-1.2.1-blue)](https://github.com/dawncr0w/affine-mcp-server/releases)
6
6
  [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-1.17.2-green)](https://github.com/modelcontextprotocol/typescript-sdk)
7
7
  [![License](https://img.shields.io/badge/license-MIT-yellow)](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.0)
16
-
17
- > New in v1.2.0: Document create/edit/delete is now supported via WebSocket sync. Use `create_doc`, `append_paragraph`, and `delete_doc` to manage real AFFiNE docs.
15
+ - Status: Production Ready (v1.2.1)
16
+
17
+ > New in v1.2.1: Email/Password login no longer blocks MCP startup. The server connects over stdio immediately and performs login asynchronously by default. Use `AFFINE_LOGIN_AT_START=sync` to restore the previous blocking behavior.
18
18
 
19
19
  ## Features
20
20
 
@@ -37,8 +37,8 @@ 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-hoc with npx
41
- npx affine-mcp-server
40
+ # Or run adhoc 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.
@@ -47,7 +47,7 @@ The package installs a CLI named `affine-mcp` that runs the MCP server over stdi
47
47
 
48
48
  ## Configuration
49
49
 
50
- Create a `.env` file or set environment variables:
50
+ Set environment variables (recommended) or create a `.env` file:
51
51
 
52
52
  ```env
53
53
  # AFFiNE server URL (required)
@@ -65,6 +65,10 @@ AFFINE_PASSWORD=your_password
65
65
  # Optional settings
66
66
  AFFINE_GRAPHQL_PATH=/graphql # Default: /graphql
67
67
  AFFINE_WORKSPACE_ID=workspace-uuid # Default workspace for operations
68
+
69
+ # Startup auth behavior (optional)
70
+ # AFFINE_LOGIN_AT_START=async # Default: async (don't block MCP handshake)
71
+ # AFFINE_LOGIN_AT_START=sync # Block at startup to sign in with email/password
68
72
  ```
69
73
 
70
74
  Authentication priority:
@@ -87,29 +91,38 @@ Add to your Claude Desktop configuration:
87
91
  "command": "affine-mcp",
88
92
  "env": {
89
93
  "AFFINE_BASE_URL": "https://your-affine-instance.com",
90
- "AFFINE_COOKIE": "affine_session=...; affine_csrf=..."
94
+ "AFFINE_EMAIL": "you@example.com",
95
+ "AFFINE_PASSWORD": "secret!",
96
+ "AFFINE_LOGIN_AT_START": "async"
91
97
  }
92
98
  }
93
99
  }
94
100
  }
95
101
  ```
96
102
 
103
+ Tips
104
+ - Prefer `AFFINE_COOKIE` or `AFFINE_API_TOKEN` for zero‑latency startup.
105
+ - If your password contains `!` (zsh history expansion), wrap it in single quotes in shells or use the JSON config above.
106
+
97
107
  ### Codex CLI
98
108
 
99
- Codex attaches MCP servers by executing commands over stdio. Depending on your Codex version, use one of these patterns:
109
+ Register the MCP server with Codex:
110
+
111
+ - Global install path (fastest)
112
+ - `npm i -g affine-mcp-server`
113
+ - `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`
100
114
 
101
- - Direct flag example:
102
- - `codex --mcp affine=affine-mcp --env AFFINE_BASE_URL=https://your-affine-instance.com --env AFFINE_COOKIE='affine_session=...; affine_csrf=...'`
115
+ - Use npx (no global install)
116
+ - `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`
103
117
 
104
- - Profile/config based registration (conceptual):
105
- - name: `affine`, command: `affine-mcp`, env: `AFFINE_*`
118
+ - Token or cookie (no startup login)
119
+ - Token: `codex mcp add affine --env AFFINE_BASE_URL=https://... --env AFFINE_API_TOKEN=... -- affine-mcp`
120
+ - Cookie: `codex mcp add affine --env AFFINE_BASE_URL=https://... --env "AFFINE_COOKIE=affine_session=...; affine_csrf=..." -- affine-mcp`
106
121
 
107
- General rules:
122
+ Notes
108
123
  - MCP name: `affine`
109
124
  - Command: `affine-mcp`
110
- - Env: `AFFINE_BASE_URL` and one auth method (`AFFINE_COOKIE` or `AFFINE_API_TOKEN` or `AFFINE_EMAIL`/`AFFINE_PASSWORD`)
111
-
112
- Refer to your Codex CLI docs for the exact config keys/paths.
125
+ - Environment: `AFFINE_BASE_URL` + one auth method (`AFFINE_API_TOKEN` | `AFFINE_COOKIE` | `AFFINE_EMAIL`/`AFFINE_PASSWORD`)
113
126
 
114
127
  ## Available Tools
115
128
 
@@ -150,14 +163,19 @@ Refer to your Codex CLI docs for the exact config keys/paths.
150
163
  ### Advanced
151
164
  - `apply_doc_updates` – apply CRDT updates to documents
152
165
 
153
- ## Run locally (dev)
166
+ ## Use Locally (clone)
154
167
 
155
168
  ```bash
156
169
  git clone https://github.com/dawncr0w/affine-mcp-server.git
157
170
  cd affine-mcp-server
158
171
  npm install
159
172
  npm run build
160
- npm start
173
+ # Run directly
174
+ node dist/index.js
175
+
176
+ # Or expose as a global CLI for Codex/Claude without publishing
177
+ npm link
178
+ # Now use `affine-mcp` like a global binary
161
179
  ```
162
180
 
163
181
  ## Troubleshooting
@@ -166,6 +184,7 @@ Authentication
166
184
  - Email/Password: ensure your instance allows password auth and credentials are valid
167
185
  - Cookie: copy cookies (e.g., `affine_session`, `affine_csrf`) from the browser DevTools after login
168
186
  - Token: generate a personal access token; verify it hasn’t expired
187
+ - If using Email/Password and your MCP client shows a startup timeout, ensure `AFFINE_LOGIN_AT_START=async` (default) so login happens after the stdio handshake.
169
188
 
170
189
  Connection
171
190
  - Confirm `AFFINE_BASE_URL` is reachable
@@ -182,6 +201,11 @@ Connection
182
201
 
183
202
  ## Version History
184
203
 
204
+ ### 1.2.1 (2025‑09‑17)
205
+ - Default to asynchronous email/password login after MCP stdio handshake
206
+ - New `AFFINE_LOGIN_AT_START` env (`async` default, `sync` to block at startup)
207
+ - Expanded docs for Codex/Claude using npm, npx, and local clone
208
+
185
209
  ### 1.2.0 (2025‑09‑16)
186
210
  - WebSocket-based document tools: `create_doc`, `append_paragraph`, `delete_doc` (create/edit/delete now supported)
187
211
  - Tool aliases: both `affine_*` and non‑prefixed names
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.1.0" });
19
+ const server = new McpServer({ name: "affine-mcp", version: "1.2.1" });
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
- console.error("No token or cookie provided, attempting email/password authentication...");
29
- try {
30
- const { cookieHeader } = await loginWithPassword(config.baseUrl, config.email, config.password);
31
- gql.setCookie(cookieHeader);
32
- console.error("Successfully authenticated with email/password");
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
- catch (e) {
35
- console.error("Failed to authenticate with email/password:", e);
36
- console.error("WARNING: Continuing without authentication - some operations may fail");
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.0",
3
+ "version": "1.2.1",
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",