affine-mcp-server 1.9.0 → 1.10.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.
- package/README.md +81 -14
- package/dist/cli.js +361 -25
- package/dist/config.js +47 -1
- package/dist/httpAuth.js +147 -0
- package/dist/httpDiagnostics.js +38 -0
- package/dist/index.js +52 -18
- package/dist/oauth.js +154 -0
- package/dist/sse.js +12 -35
- package/dist/tools/docs.js +946 -17
- package/package.json +7 -1
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 (default) or HTTP (`/mcp`).
|
|
4
4
|
|
|
5
|
-
[](https://github.com/dawncr0w/affine-mcp-server/releases)
|
|
6
6
|
[](https://github.com/modelcontextprotocol/typescript-sdk)
|
|
7
7
|
[](https://github.com/dawncr0w/affine-mcp-server/actions/workflows/ci.yml)
|
|
8
8
|
[](LICENSE)
|
|
@@ -16,10 +16,10 @@ A Model Context Protocol (MCP) server that integrates with AFFiNE (self‑hosted
|
|
|
16
16
|
- Purpose: Manage AFFiNE workspaces and documents through MCP
|
|
17
17
|
- Transport: stdio (default) and optional HTTP (`/mcp`) for remote MCP deployments
|
|
18
18
|
- Auth: Token, Cookie, or Email/Password (priority order)
|
|
19
|
-
- Tools:
|
|
19
|
+
- Tools: 61 focused tools with WebSocket-based document editing
|
|
20
20
|
- Status: Active
|
|
21
21
|
|
|
22
|
-
> New in v1.
|
|
22
|
+
> New in v1.10.1: Refreshed packaged docs and release metadata for the v1.10.x toolset, and tightened tag-publish validation with E2E coverage. No runtime or tool-behavior changes.
|
|
23
23
|
|
|
24
24
|
## Features
|
|
25
25
|
|
|
@@ -93,7 +93,12 @@ The MCP server will use these credentials automatically.
|
|
|
93
93
|
```
|
|
94
94
|
|
|
95
95
|
Other CLI commands:
|
|
96
|
+
- `affine-mcp --help` / `-h` / `help` — show command help
|
|
96
97
|
- `affine-mcp status` — show current config and test connection
|
|
98
|
+
- `affine-mcp doctor` — run config and connectivity diagnostics
|
|
99
|
+
- `affine-mcp show-config` — print the effective config with secrets redacted
|
|
100
|
+
- `affine-mcp config-path` — print the config file path
|
|
101
|
+
- `affine-mcp snippet <claude|cursor|codex> [--env]` — print ready-to-paste client configuration snippets
|
|
97
102
|
- `affine-mcp logout` — remove stored credentials
|
|
98
103
|
- `affine-mcp --version` / `-v` / `version` — print the installed CLI version and exit
|
|
99
104
|
|
|
@@ -186,6 +191,8 @@ Or with email/password for self-hosted instances (not supported on AFFiNE Cloud
|
|
|
186
191
|
Tips
|
|
187
192
|
- Prefer `affine-mcp login` or `AFFINE_API_TOKEN` for zero‑latency startup.
|
|
188
193
|
- If your password contains `!` (zsh history expansion), wrap it in single quotes in shells or use the JSON config above.
|
|
194
|
+
- `affine-mcp doctor` is the fastest way to confirm that your saved config still works.
|
|
195
|
+
- `affine-mcp snippet claude --env` and `affine-mcp snippet codex --env` can generate ready-to-paste client setup from your current config.
|
|
189
196
|
|
|
190
197
|
### Codex CLI
|
|
191
198
|
|
|
@@ -246,12 +253,16 @@ If you want to host the server remotely (e.g., using Render, Railway, Docker, or
|
|
|
246
253
|
Required:
|
|
247
254
|
- `MCP_TRANSPORT=http`
|
|
248
255
|
- `AFFINE_BASE_URL` (example: `https://app.affine.pro`)
|
|
249
|
-
-
|
|
256
|
+
- `AFFINE_MCP_AUTH_MODE=bearer` (default) or `AFFINE_MCP_AUTH_MODE=oauth`
|
|
257
|
+
|
|
258
|
+
Bearer mode backend auth:
|
|
250
259
|
- `AFFINE_API_TOKEN` (recommended), or `AFFINE_COOKIE`, or `AFFINE_EMAIL` + `AFFINE_PASSWORD`
|
|
251
260
|
|
|
261
|
+
OAuth mode backend auth:
|
|
262
|
+
- `AFFINE_API_TOKEN` (required service credential for AFFiNE backend access)
|
|
263
|
+
|
|
252
264
|
Recommended for remote/public deployments:
|
|
253
265
|
- `AFFINE_MCP_HTTP_HOST=0.0.0.0`
|
|
254
|
-
- `AFFINE_MCP_HTTP_TOKEN=<strong-random-token>` (protects `/mcp`, `/sse`, `/messages`)
|
|
255
266
|
- `AFFINE_MCP_HTTP_ALLOWED_ORIGINS=<comma-separated-origins>` (for browser clients)
|
|
256
267
|
|
|
257
268
|
Optional:
|
|
@@ -260,31 +271,68 @@ Optional:
|
|
|
260
271
|
- `AFFINE_GRAPHQL_PATH` (defaults to `/graphql`)
|
|
261
272
|
- `AFFINE_MCP_HTTP_ALLOW_ALL_ORIGINS=true` (testing only)
|
|
262
273
|
|
|
274
|
+
Bearer-mode only:
|
|
275
|
+
- `AFFINE_MCP_HTTP_TOKEN=<strong-random-token>` (protects `/mcp`, `/sse`, `/messages`)
|
|
276
|
+
|
|
277
|
+
OAuth-mode only:
|
|
278
|
+
- `AFFINE_MCP_PUBLIC_BASE_URL=https://mcp.yourdomain.com`
|
|
279
|
+
- `AFFINE_OAUTH_ISSUER_URL=https://auth.yourdomain.com`
|
|
280
|
+
- `AFFINE_OAUTH_SCOPES=mcp` (defaults to `mcp`)
|
|
281
|
+
|
|
282
|
+
#### HTTP auth modes
|
|
283
|
+
|
|
284
|
+
`AFFINE_MCP_AUTH_MODE=bearer` keeps the current static bearer-token behavior.
|
|
285
|
+
|
|
263
286
|
```bash
|
|
264
|
-
# Export your configuration first
|
|
265
287
|
export MCP_TRANSPORT=http
|
|
288
|
+
export AFFINE_MCP_AUTH_MODE=bearer
|
|
266
289
|
export AFFINE_API_TOKEN="your_token..."
|
|
267
|
-
export AFFINE_MCP_HTTP_HOST="0.0.0.0"
|
|
290
|
+
export AFFINE_MCP_HTTP_HOST="0.0.0.0"
|
|
268
291
|
export AFFINE_MCP_HTTP_TOKEN="your-super-secret-token"
|
|
269
292
|
export PORT=3000
|
|
270
293
|
|
|
271
|
-
# Start in HTTP mode (Streamable HTTP on /mcp)
|
|
272
294
|
npm run start:http
|
|
273
|
-
# OR manually:
|
|
274
|
-
# MCP_TRANSPORT=http node dist/index.js
|
|
275
|
-
# ("sse" is still accepted at /sse)
|
|
276
295
|
```
|
|
277
296
|
|
|
297
|
+
`AFFINE_MCP_AUTH_MODE=oauth` turns the MCP endpoint into an OAuth-protected resource for web MCP clients. In this mode:
|
|
298
|
+
- the server exposes `/.well-known/oauth-protected-resource`
|
|
299
|
+
- unauthenticated `/mcp` requests return `401` with a `WWW-Authenticate` challenge
|
|
300
|
+
- `AFFINE_MCP_HTTP_TOKEN` and `?token=` are disabled
|
|
301
|
+
- `sign_in` is not registered
|
|
302
|
+
- `AFFINE_API_TOKEN` is still required so the server can call AFFiNE as a service credential
|
|
303
|
+
|
|
304
|
+
```bash
|
|
305
|
+
export MCP_TRANSPORT=http
|
|
306
|
+
export AFFINE_MCP_AUTH_MODE=oauth
|
|
307
|
+
export AFFINE_API_TOKEN="your-affine-service-token"
|
|
308
|
+
export AFFINE_MCP_HTTP_HOST="0.0.0.0"
|
|
309
|
+
export AFFINE_MCP_PUBLIC_BASE_URL="https://mcp.yourdomain.com"
|
|
310
|
+
export AFFINE_OAUTH_ISSUER_URL="https://auth.yourdomain.com"
|
|
311
|
+
export AFFINE_OAUTH_SCOPES="mcp"
|
|
312
|
+
export PORT=3000
|
|
313
|
+
|
|
314
|
+
npm run start:http
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
Notes for OAuth mode:
|
|
318
|
+
- use HTTPS for non-local deployments
|
|
319
|
+
- `AFFINE_MCP_HTTP_ALLOW_ALL_ORIGINS=true` is rejected in OAuth mode
|
|
320
|
+
- tokens are validated against the issuer discovery metadata and JWKS
|
|
321
|
+
- the protected resource metadata is also served at `/.well-known/oauth-protected-resource/mcp` for path-specific discovery
|
|
322
|
+
- `GET /healthz` and `GET /readyz` are available for deployment diagnostics
|
|
323
|
+
|
|
278
324
|
#### Recommended presets
|
|
279
325
|
|
|
280
326
|
Local testing (HTTP mode):
|
|
281
327
|
- `MCP_TRANSPORT=http`
|
|
328
|
+
- `AFFINE_MCP_AUTH_MODE=bearer`
|
|
282
329
|
- `AFFINE_MCP_HTTP_HOST=127.0.0.1`
|
|
283
330
|
- `AFFINE_MCP_HTTP_TOKEN=<token>` (recommended even locally)
|
|
284
331
|
- `AFFINE_MCP_HTTP_ALLOWED_ORIGINS=http://localhost:3000` (if testing from a browser app)
|
|
285
332
|
|
|
286
333
|
Docker / container runtime:
|
|
287
334
|
- `MCP_TRANSPORT=http`
|
|
335
|
+
- `AFFINE_MCP_AUTH_MODE=bearer`
|
|
288
336
|
- `AFFINE_MCP_HTTP_HOST=0.0.0.0`
|
|
289
337
|
- `PORT=3000` (or container/platform port)
|
|
290
338
|
- `AFFINE_MCP_HTTP_TOKEN=<strong-token>`
|
|
@@ -292,14 +340,19 @@ Docker / container runtime:
|
|
|
292
340
|
|
|
293
341
|
Render / Railway / VPS (public endpoint):
|
|
294
342
|
- `MCP_TRANSPORT=http`
|
|
343
|
+
- `AFFINE_MCP_AUTH_MODE=bearer` or `oauth`
|
|
295
344
|
- `AFFINE_MCP_HTTP_HOST=0.0.0.0`
|
|
296
|
-
- `AFFINE_MCP_HTTP_TOKEN=<strong-token>`
|
|
345
|
+
- `AFFINE_MCP_HTTP_TOKEN=<strong-token>` (bearer mode)
|
|
346
|
+
- `AFFINE_MCP_PUBLIC_BASE_URL=<public base URL>` (OAuth mode)
|
|
347
|
+
- `AFFINE_OAUTH_ISSUER_URL=<issuer URL>` (OAuth mode)
|
|
297
348
|
- `AFFINE_MCP_HTTP_ALLOWED_ORIGINS=<your client origin(s)>`
|
|
298
349
|
|
|
299
350
|
Endpoints currently available:
|
|
300
351
|
- `/mcp` - MCP server (Streamable HTTP)
|
|
301
352
|
- `/sse` - SSE endpoint (old protocol compatible)
|
|
302
353
|
- `/messages` - Messages endpoint (old protocol compatible)
|
|
354
|
+
- `/healthz` - HTTP liveness probe
|
|
355
|
+
- `/readyz` - HTTP readiness probe
|
|
303
356
|
|
|
304
357
|
## Available Tools
|
|
305
358
|
|
|
@@ -309,23 +362,33 @@ Endpoints currently available:
|
|
|
309
362
|
- `create_workspace` – create workspace with initial document
|
|
310
363
|
- `update_workspace` – update workspace settings
|
|
311
364
|
- `delete_workspace` – delete workspace permanently
|
|
365
|
+
- `list_workspace_tree` – return the workspace document hierarchy as a tree
|
|
366
|
+
- `get_orphan_docs` – find documents that are not linked from any parent doc in the sidebar tree
|
|
312
367
|
|
|
313
368
|
### Documents
|
|
314
369
|
- `list_docs` – list documents with pagination (includes `node.tags`)
|
|
315
370
|
- `list_tags` – list all tags in a workspace
|
|
316
|
-
- `
|
|
371
|
+
- `search_docs` – fast title search with substring/prefix/exact matching, optional tag filtering, and updatedAt sorting
|
|
372
|
+
- `list_docs_by_tag` – list documents that contain the requested tag
|
|
373
|
+
- `get_docs_by_tag` – discover documents by case-insensitive tag substring and return `availableTags` when nothing matches
|
|
317
374
|
- `get_doc` – get document metadata
|
|
375
|
+
- `get_doc_by_title` – find a document by title and return its Markdown content
|
|
318
376
|
- `read_doc` – read document block content and plain text snapshot (WebSocket)
|
|
319
377
|
- `export_doc_markdown` – export document content as markdown
|
|
320
378
|
- `publish_doc` – make document public
|
|
321
379
|
- `revoke_doc` – revoke public access
|
|
322
380
|
- `create_doc` – create a new document (WebSocket)
|
|
323
381
|
- `create_doc_from_markdown` – create a document from markdown content
|
|
382
|
+
- `create_doc_from_template` – clone a template doc, substitute `{{variables}}`, and optionally link it under a parent doc
|
|
383
|
+
- `duplicate_doc` – clone a document into a new doc, optionally under a parent doc
|
|
324
384
|
- `create_tag` – create a reusable workspace-level tag
|
|
325
385
|
- `add_tag_to_doc` – attach a tag to a document
|
|
326
386
|
- `remove_tag_from_doc` – detach a tag from a document
|
|
387
|
+
- `update_doc_title` – rename a document in both workspace metadata and the internal page block
|
|
327
388
|
- `append_paragraph` – append a paragraph block (WebSocket)
|
|
328
389
|
- `append_block` – append canonical block types (text/list/code/media/embed/database/edgeless) with strict validation and placement control (`viewMode=kanban` enables preset-backed data views; `data_view` defaults to kanban)
|
|
390
|
+
- `move_doc` – move a document in the sidebar by relinking it under a different parent
|
|
391
|
+
- `batch_create_docs` – create up to 20 documents in a single call
|
|
329
392
|
- `add_database_column` – add a column to a database block (`rich-text`, `select`, `multi-select`, `number`, `checkbox`, `link`, `date`)
|
|
330
393
|
- `add_database_row` – add a row to a database block with values mapped by column name/ID (`title` / `Title` updates the built-in row title)
|
|
331
394
|
- `read_database_columns` – read database schema metadata including column IDs/types, select options, and table view column mappings
|
|
@@ -334,6 +397,10 @@ Endpoints currently available:
|
|
|
334
397
|
- `update_database_row` – batch update multiple cells on a database row (`createOption` defaults to `true` for select fields)
|
|
335
398
|
- `append_markdown` – append markdown content to an existing document
|
|
336
399
|
- `replace_doc_with_markdown` – replace the main note content with markdown content
|
|
400
|
+
- `list_children` – list the direct child docs linked from a document
|
|
401
|
+
- `list_backlinks` – list the parent/reference docs that link to a document
|
|
402
|
+
- `cleanup_orphan_embeds` – remove linked-doc embeds that point to missing docs
|
|
403
|
+
- `find_and_replace` – preview or apply text replacement across a document
|
|
337
404
|
- `delete_doc` – delete a document (WebSocket)
|
|
338
405
|
|
|
339
406
|
### Comments
|
|
@@ -380,7 +447,7 @@ npm run pack:check
|
|
|
380
447
|
- For full tool-surface verification, run `npm run test:comprehensive` (self-bootstraps a local Docker AFFiNE stack).
|
|
381
448
|
- For pre-provisioned environments, use `npm run test:comprehensive:raw`.
|
|
382
449
|
- For full environment verification, run `npm run test:e2e` (Docker + MCP + Playwright).
|
|
383
|
-
- Additional focused runners: `npm run test:db-create`, `npm run test:db-cells`, `npm run test:db-schema`, `npm run test:supporting-tools`, `npm run test:bearer`, `npm run test:cli-version`, `npm run test:playwright`.
|
|
450
|
+
- Additional focused runners: `npm run test:db-create`, `npm run test:db-cells`, `npm run test:db-schema`, `npm run test:supporting-tools`, `npm run test:bearer`, `npm run test:http-email-password`, `npm run test:http-bearer`, `npm run test:oauth-http`, `npm run test:doc-discovery`, `npm run test:cli-version`, `npm run test:cli-commands`, `npm run test:playwright`.
|
|
384
451
|
|
|
385
452
|
## Troubleshooting
|
|
386
453
|
|