affine-mcp-server 1.2.2 → 1.4.0

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 CHANGED
@@ -2,28 +2,34 @@
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.2-blue)](https://github.com/dawncr0w/affine-mcp-server/releases)
5
+ [![Version](https://img.shields.io/badge/version-1.4.0-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
+ [![CI](https://github.com/dawncr0w/affine-mcp-server/actions/workflows/ci.yml/badge.svg)](https://github.com/dawncr0w/affine-mcp-server/actions/workflows/ci.yml)
7
8
  [![License](https://img.shields.io/badge/license-MIT-yellow)](LICENSE)
8
9
 
10
+ <a href="https://glama.ai/mcp/servers/@DAWNCR0W/affine-mcp-server">
11
+ <img width="380" height="200" src="https://glama.ai/mcp/servers/@DAWNCR0W/affine-mcp-server/badge" alt="AFFiNE Server MCP server" />
12
+ </a>
13
+
9
14
  ## Overview
10
15
 
11
16
  - Purpose: Manage AFFiNE workspaces and documents through MCP
12
17
  - Transport: stdio only (Claude Desktop / Codex compatible)
13
18
  - Auth: Token, Cookie, or Email/Password (priority order)
14
- - Tools: 30+ tools plus WebSocket-based document editing
15
- - Status: Production Ready (v1.2.1)
19
+ - Tools: 32 focused tools with WebSocket-based document editing
20
+ - Status: Active
16
21
 
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.
22
+ > New in v1.4.0: Added `read_doc` for document content snapshots (blocks + plain text), plus Cursor setup/troubleshooting guidance.
18
23
 
19
24
  ## Features
20
25
 
21
26
  - Workspace: create (with initial doc), read, update, delete
22
- - Documents: list/get/search/publish/revoke + create/append paragraph/delete (WebSocket‑based) — added in v1.2.0
27
+ - Documents: list/get/read/publish/revoke + create/append paragraph/delete (WebSocket‑based)
23
28
  - Comments: full CRUD and resolve
24
- - Version History: list and recover
25
- - Users & Tokens: profile/settings and personal access tokens
29
+ - Version History: list
30
+ - Users & Tokens: current user, sign in, profile/settings, and personal access tokens
26
31
  - Notifications: list and mark as read
32
+ - Blob storage: upload/delete/cleanup
27
33
 
28
34
  ## Requirements
29
35
 
@@ -43,7 +49,7 @@ npx -y -p affine-mcp-server affine-mcp -- --version
43
49
 
44
50
  The package installs a CLI named `affine-mcp` that runs the MCP server over stdio.
45
51
 
46
- Note: From v1.2.2 the CLI wrapper (`bin/affine-mcp`) ensures Node runs the ESM entrypoint, preventing shell from misinterpreting JS.
52
+ Note: From v1.2.2+ the CLI wrapper (`bin/affine-mcp`) ensures Node runs the ESM entrypoint, preventing shell from misinterpreting JS.
47
53
 
48
54
  ## Configuration
49
55
 
@@ -106,6 +112,43 @@ Notes
106
112
  - Command: `affine-mcp`
107
113
  - Environment: `AFFINE_BASE_URL` + one auth method (`AFFINE_API_TOKEN` | `AFFINE_COOKIE` | `AFFINE_EMAIL`/`AFFINE_PASSWORD`)
108
114
 
115
+ ### Cursor
116
+
117
+ Cursor also supports MCP over stdio with `mcp.json`.
118
+
119
+ Project-local (`.cursor/mcp.json`) example:
120
+
121
+ ```json
122
+ {
123
+ "mcpServers": {
124
+ "affine": {
125
+ "command": "affine-mcp",
126
+ "env": {
127
+ "AFFINE_BASE_URL": "https://your-affine-instance.com",
128
+ "AFFINE_API_TOKEN": "apt_xxx"
129
+ }
130
+ }
131
+ }
132
+ }
133
+ ```
134
+
135
+ If you prefer `npx`:
136
+
137
+ ```json
138
+ {
139
+ "mcpServers": {
140
+ "affine": {
141
+ "command": "npx",
142
+ "args": ["-y", "-p", "affine-mcp-server", "affine-mcp"],
143
+ "env": {
144
+ "AFFINE_BASE_URL": "https://your-affine-instance.com",
145
+ "AFFINE_API_TOKEN": "apt_xxx"
146
+ }
147
+ }
148
+ }
149
+ }
150
+ ```
151
+
109
152
  ## Available Tools
110
153
 
111
154
  ### Workspace
@@ -118,33 +161,30 @@ Notes
118
161
  ### Documents
119
162
  - `list_docs` – list documents with pagination
120
163
  - `get_doc` – get document metadata
121
- - `search_docs` – search documents by keyword
122
- - `recent_docs` – list recently updated documents
164
+ - `read_doc` – read document block content and plain text snapshot (WebSocket)
123
165
  - `publish_doc` – make document public
124
166
  - `revoke_doc` – revoke public access
125
167
  - `create_doc` – create a new document (WebSocket)
126
168
  - `append_paragraph` – append a paragraph block (WebSocket)
169
+ - `append_block` – append slash-command style blocks (`heading/list/todo/code/divider/quote`)
127
170
  - `delete_doc` – delete a document (WebSocket)
128
171
 
129
172
  ### Comments
130
173
  - `list_comments`, `create_comment`, `update_comment`, `delete_comment`, `resolve_comment`
131
174
 
132
175
  ### Version History
133
- - `list_histories`, `recover_doc`
176
+ - `list_histories`
134
177
 
135
178
  ### Users & Tokens
136
179
  - `current_user`, `sign_in`, `update_profile`, `update_settings`
137
180
  - `list_access_tokens`, `generate_access_token`, `revoke_access_token`
138
181
 
139
182
  ### Notifications
140
- - `list_notifications`, `read_notification`, `read_all_notifications`
183
+ - `list_notifications`, `read_all_notifications`
141
184
 
142
185
  ### Blob Storage
143
186
  - `upload_blob`, `delete_blob`, `cleanup_blobs`
144
187
 
145
- ### Advanced
146
- - `apply_doc_updates` – apply CRDT updates to documents
147
-
148
188
  ## Use Locally (clone)
149
189
 
150
190
  ```bash
@@ -160,19 +200,39 @@ npm link
160
200
  # Now use `affine-mcp` like a global binary
161
201
  ```
162
202
 
203
+ ## Quality Gates
204
+
205
+ ```bash
206
+ npm run build
207
+ npm run test:tool-manifest
208
+ npm run pack:check
209
+ ```
210
+
211
+ - `tool-manifest.json` is the source of truth for publicly exposed tool names.
212
+ - CI validates that `registerTool(...)` declarations match the manifest exactly.
213
+
163
214
  ## Troubleshooting
164
215
 
165
216
  Authentication
166
217
  - Email/Password: ensure your instance allows password auth and credentials are valid
167
218
  - Cookie: copy cookies (e.g., `affine_session`, `affine_csrf`) from the browser DevTools after login
168
- - Token: generate a personal access token; verify it hasnt 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.
219
+ - Token: generate a personal access token; verify it hasn't expired
220
+ - Startup timeouts: v1.2.2+ includes a CLI wrapper fix and default async login to avoid blocking the MCP handshake. Set `AFFINE_LOGIN_AT_START=sync` only if needed.
170
221
 
171
222
  Connection
172
223
  - Confirm `AFFINE_BASE_URL` is reachable
173
224
  - GraphQL endpoint default is `/graphql`
174
225
  - Check firewall/proxy rules; verify CORS if self‑hosted
175
226
 
227
+ Method not found
228
+ - MCP tool names (for example `list_workspaces`) are not JSON-RPC top-level method names.
229
+ - Use an MCP client (`tools/list`, `tools/call`) instead of sending direct JSON-RPC calls like `{\"method\":\"list_workspaces\"}`.
230
+ - From v1.3.0, only canonical tool names are exposed (legacy `affine_*` aliases were removed).
231
+
232
+ Workspace visibility
233
+ - This MCP server can access server-backed workspaces only (AFFiNE cloud/self-hosted).
234
+ - Browser local-storage workspaces are client-side data, so they are not visible via server GraphQL/WebSocket APIs.
235
+
176
236
  ## Security Considerations
177
237
 
178
238
  - Never commit `.env` with secrets
@@ -183,6 +243,17 @@ Connection
183
243
 
184
244
  ## Version History
185
245
 
246
+ ### 1.4.0 (2026‑02‑13)
247
+ - Added `read_doc` for reading document block snapshot + plain text
248
+ - Added Cursor setup examples and troubleshooting notes for JSON-RPC method usage
249
+ - Added explicit local-storage workspace limitation notes
250
+
251
+ ### 1.3.0 (2026‑02‑13)
252
+ - Added `append_block` for slash-command style editing (`heading/list/todo/code/divider/quote`)
253
+ - Tool surface simplified to 31 canonical tools (duplicate aliases removed)
254
+ - Added CI + manifest parity verification (`npm run test:tool-manifest`, `npm run ci`)
255
+ - Added open-source community health docs and issue/PR templates
256
+
186
257
  ### 1.2.2 (2025‑09‑18)
187
258
  - CLI wrapper added to ensure Node runs ESM entry (`bin/affine-mcp`), preventing shell mis-execution
188
259
  - Docs cleaned: use env vars via shell/app config; `.env` file no longer recommended
@@ -195,7 +266,7 @@ Connection
195
266
 
196
267
  ### 1.2.0 (2025‑09‑16)
197
268
  - WebSocket-based document tools: `create_doc`, `append_paragraph`, `delete_doc` (create/edit/delete now supported)
198
- - Tool aliases: both `affine_*` and nonprefixed names
269
+ - Tool aliases introduced at the time (`affine_*` + non-prefixed names). They were removed later to reduce duplication.
199
270
  - ESM resolution: NodeNext; improved build stability
200
271
  - CLI binary: `affine-mcp` for easy `npm i -g` usage
201
272
 
@@ -212,11 +283,16 @@ Connection
212
283
  ## Contributing
213
284
 
214
285
  Contributions are welcome!
215
- 1. Fork the repository
216
- 2. Create a feature branch
217
- 3. Add tests for new features
218
- 4. Ensure all tests pass
219
- 5. Submit a Pull Request
286
+ 1. Read `CONTRIBUTING.md`
287
+ 2. Run `npm run ci` locally before opening PR
288
+ 3. Keep tool changes synced with `tool-manifest.json`
289
+ 4. Use issue/PR templates in `.github/`
290
+
291
+ ## Community Health
292
+
293
+ - Code of Conduct: `CODE_OF_CONDUCT.md`
294
+ - Security policy: `SECURITY.md`
295
+ - Contributing guide: `CONTRIBUTING.md`
220
296
 
221
297
  ## License
222
298
 
package/bin/affine-mcp CHANGED
File without changes
package/dist/index.js CHANGED
@@ -8,7 +8,6 @@ import { registerCommentTools } from "./tools/comments.js";
8
8
  import { registerHistoryTools } from "./tools/history.js";
9
9
  import { registerUserTools } from "./tools/user.js";
10
10
  import { registerUserCRUDTools } from "./tools/userCRUD.js";
11
- import { registerUpdateTools } from "./tools/updates.js";
12
11
  import { registerAccessTokenTools } from "./tools/accessTokens.js";
13
12
  import { registerBlobTools } from "./tools/blobStorage.js";
14
13
  import { registerNotificationTools } from "./tools/notifications.js";
@@ -16,7 +15,7 @@ import { loginWithPassword } from "./auth.js";
16
15
  import { registerAuthTools } from "./tools/auth.js";
17
16
  const config = loadConfig();
18
17
  async function buildServer() {
19
- const server = new McpServer({ name: "affine-mcp", version: "1.2.2" });
18
+ const server = new McpServer({ name: "affine-mcp", version: "1.4.0" });
20
19
  // Initialize GraphQL client with authentication
21
20
  const gql = new GraphQLClient({
22
21
  endpoint: `${config.baseUrl}${config.graphqlPath}`,
@@ -65,7 +64,6 @@ async function buildServer() {
65
64
  registerHistoryTools(server, gql, { workspaceId: config.defaultWorkspaceId });
66
65
  registerUserTools(server, gql);
67
66
  registerUserCRUDTools(server, gql);
68
- registerUpdateTools(server, gql, { workspaceId: config.defaultWorkspaceId });
69
67
  registerAccessTokenTools(server, gql);
70
68
  registerBlobTools(server, gql);
71
69
  registerNotificationTools(server, gql);
@@ -3,20 +3,15 @@ import { text } from "../util/mcp.js";
3
3
  export function registerAccessTokenTools(server, gql) {
4
4
  const listAccessTokensHandler = async () => {
5
5
  try {
6
- const query = `query { accessTokens { id name createdAt expiresAt } }`;
6
+ const query = `query { currentUser { accessTokens { id name createdAt expiresAt } } }`;
7
7
  const data = await gql.request(query);
8
- return text(data.accessTokens || []);
8
+ return text(data.currentUser?.accessTokens || []);
9
9
  }
10
10
  catch (error) {
11
11
  console.error("List access tokens error:", error.message);
12
- return text([]);
12
+ return text({ error: error.message });
13
13
  }
14
14
  };
15
- server.registerTool("affine_list_access_tokens", {
16
- title: "List Access Tokens",
17
- description: "List personal access tokens (metadata).",
18
- inputSchema: {}
19
- }, listAccessTokensHandler);
20
15
  server.registerTool("list_access_tokens", {
21
16
  title: "List Access Tokens",
22
17
  description: "List personal access tokens (metadata).",
@@ -27,14 +22,6 @@ export function registerAccessTokenTools(server, gql) {
27
22
  const data = await gql.request(mutation, { input: { name: parsed.name, expiresAt: parsed.expiresAt ?? null } });
28
23
  return text(data.generateUserAccessToken);
29
24
  };
30
- server.registerTool("affine_generate_access_token", {
31
- title: "Generate Access Token",
32
- description: "Generate a personal access token (returns token).",
33
- inputSchema: {
34
- name: z.string(),
35
- expiresAt: z.string().optional()
36
- }
37
- }, generateAccessTokenHandler);
38
25
  server.registerTool("generate_access_token", {
39
26
  title: "Generate Access Token",
40
27
  description: "Generate a personal access token (returns token).",
@@ -48,13 +35,6 @@ export function registerAccessTokenTools(server, gql) {
48
35
  const data = await gql.request(mutation, { id: parsed.id });
49
36
  return text({ success: data.revokeUserAccessToken });
50
37
  };
51
- server.registerTool("affine_revoke_access_token", {
52
- title: "Revoke Access Token",
53
- description: "Revoke a personal access token by id.",
54
- inputSchema: {
55
- id: z.string()
56
- }
57
- }, revokeAccessTokenHandler);
58
38
  server.registerTool("revoke_access_token", {
59
39
  title: "Revoke Access Token",
60
40
  description: "Revoke a personal access token by id.",
@@ -7,14 +7,6 @@ export function registerAuthTools(server, gql, baseUrl) {
7
7
  gql.setCookie(cookieHeader);
8
8
  return text({ signedIn: true });
9
9
  };
10
- server.registerTool("affine_sign_in", {
11
- title: "Sign In",
12
- description: "Sign in to AFFiNE using email and password; sets session cookies for subsequent calls.",
13
- inputSchema: {
14
- email: z.string().email(),
15
- password: z.string().min(1)
16
- }
17
- }, signInHandler);
18
10
  server.registerTool("sign_in", {
19
11
  title: "Sign In",
20
12
  description: "Sign in to AFFiNE using email and password; sets session cookies for subsequent calls.",
@@ -1,36 +1,76 @@
1
1
  import { z } from "zod";
2
2
  import { text } from "../util/mcp.js";
3
+ import FormData from "form-data";
4
+ import fetch from "node-fetch";
5
+ function decodeBlobContent(content) {
6
+ const normalized = content.trim().replace(/\s+/g, "");
7
+ const base64Like = normalized.length > 0 && normalized.length % 4 === 0 && /^[A-Za-z0-9+/=]+$/.test(normalized);
8
+ if (base64Like) {
9
+ try {
10
+ const decoded = Buffer.from(normalized, "base64");
11
+ if (decoded.length > 0) {
12
+ return decoded;
13
+ }
14
+ }
15
+ catch {
16
+ // Fallback to UTF-8 text below.
17
+ }
18
+ }
19
+ return Buffer.from(content, "utf8");
20
+ }
3
21
  export function registerBlobTools(server, gql) {
4
22
  // UPLOAD BLOB/FILE
5
23
  const uploadBlobHandler = async ({ workspaceId, content, filename, contentType }) => {
6
24
  try {
7
- // Note: Actual file upload requires multipart form data
8
- // This is a simplified version that returns structured data
9
- const blobId = `blob_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
25
+ const endpoint = gql.endpoint || `${process.env.AFFINE_BASE_URL || "http://localhost:3010"}/graphql`;
26
+ const headers = gql.headers || {};
27
+ const cookie = gql.cookie || headers.Cookie || "";
28
+ const payload = decodeBlobContent(content);
29
+ const safeFilename = filename || `blob-${Date.now()}.bin`;
30
+ const mime = contentType || "application/octet-stream";
31
+ const form = new FormData();
32
+ form.append("operations", JSON.stringify({
33
+ query: `mutation SetBlob($workspaceId: String!, $blob: Upload!) {
34
+ setBlob(workspaceId: $workspaceId, blob: $blob)
35
+ }`,
36
+ variables: {
37
+ workspaceId,
38
+ blob: null
39
+ }
40
+ }));
41
+ form.append("map", JSON.stringify({ "0": ["variables.blob"] }));
42
+ form.append("0", payload, { filename: safeFilename, contentType: mime });
43
+ const response = await fetch(endpoint, {
44
+ method: "POST",
45
+ headers: {
46
+ ...headers,
47
+ Cookie: cookie,
48
+ ...form.getHeaders(),
49
+ },
50
+ body: form,
51
+ });
52
+ const result = await response.json();
53
+ if (result.errors?.length) {
54
+ throw new Error(result.errors[0].message);
55
+ }
56
+ const blobKey = result.data?.setBlob;
57
+ if (!blobKey) {
58
+ throw new Error("Upload succeeded but no blob key was returned.");
59
+ }
10
60
  return text({
11
- id: blobId,
61
+ id: blobKey,
62
+ key: blobKey,
12
63
  workspaceId,
13
- filename: filename || "unnamed",
14
- contentType: contentType || "application/octet-stream",
15
- size: content.length,
16
- uploadedAt: new Date().toISOString(),
17
- note: "Blob metadata created. Use AFFiNE UI for actual file upload."
64
+ filename: safeFilename,
65
+ contentType: mime,
66
+ size: payload.length,
67
+ uploadedAt: new Date().toISOString()
18
68
  });
19
69
  }
20
70
  catch (error) {
21
71
  return text({ error: error.message });
22
72
  }
23
73
  };
24
- server.registerTool("affine_upload_blob", {
25
- title: "Upload Blob",
26
- description: "Upload a file or blob to workspace storage.",
27
- inputSchema: {
28
- workspaceId: z.string().describe("Workspace ID"),
29
- content: z.string().describe("Base64 encoded content or text"),
30
- filename: z.string().optional().describe("Filename"),
31
- contentType: z.string().optional().describe("MIME type")
32
- }
33
- }, uploadBlobHandler);
34
74
  server.registerTool("upload_blob", {
35
75
  title: "Upload Blob",
36
76
  description: "Upload a file or blob to workspace storage.",
@@ -60,15 +100,6 @@ export function registerBlobTools(server, gql) {
60
100
  return text({ error: error.message });
61
101
  }
62
102
  };
63
- server.registerTool("affine_delete_blob", {
64
- title: "Delete Blob",
65
- description: "Delete a blob/file from workspace storage.",
66
- inputSchema: {
67
- workspaceId: z.string().describe("Workspace ID"),
68
- key: z.string().describe("Blob key/ID to delete"),
69
- permanently: z.boolean().optional().describe("Delete permanently")
70
- }
71
- }, deleteBlobHandler);
72
103
  server.registerTool("delete_blob", {
73
104
  title: "Delete Blob",
74
105
  description: "Delete a blob/file from workspace storage.",
@@ -95,13 +126,6 @@ export function registerBlobTools(server, gql) {
95
126
  return text({ error: error.message });
96
127
  }
97
128
  };
98
- server.registerTool("affine_cleanup_blobs", {
99
- title: "Cleanup Deleted Blobs",
100
- description: "Permanently remove deleted blobs to free up storage.",
101
- inputSchema: {
102
- workspaceId: z.string().describe("Workspace ID")
103
- }
104
- }, cleanupBlobsHandler);
105
129
  server.registerTool("cleanup_blobs", {
106
130
  title: "Cleanup Deleted Blobs",
107
131
  description: "Permanently remove deleted blobs to free up storage.",
@@ -9,17 +9,6 @@ export function registerCommentTools(server, gql, defaults) {
9
9
  const data = await gql.request(query, { workspaceId, docId: parsed.docId, first: parsed.first, offset: parsed.offset, after: parsed.after });
10
10
  return text(data.workspace.comments);
11
11
  };
12
- server.registerTool("affine_list_comments", {
13
- title: "List Comments",
14
- description: "List comments of a doc (with replies).",
15
- inputSchema: {
16
- workspaceId: z.string().optional(),
17
- docId: z.string(),
18
- first: z.number().optional(),
19
- offset: z.number().optional(),
20
- after: z.string().optional()
21
- }
22
- }, listCommentsHandler);
23
12
  server.registerTool("list_comments", {
24
13
  title: "List Comments",
25
14
  description: "List comments of a doc (with replies).",
@@ -36,22 +25,12 @@ export function registerCommentTools(server, gql, defaults) {
36
25
  if (!workspaceId)
37
26
  throw new Error("workspaceId required (or set AFFINE_WORKSPACE_ID)");
38
27
  const mutation = `mutation CreateComment($input: CommentCreateInput!){ createComment(input:$input){ id content createdAt updatedAt resolved } }`;
39
- const input = { content: parsed.content, docId: parsed.docId, workspaceId, docTitle: parsed.docTitle || "", docMode: parsed.docMode || "Page", mentions: parsed.mentions };
28
+ const normalizedDocMode = (parsed.docMode || 'page').toLowerCase() === 'edgeless' ? 'edgeless' : 'page';
29
+ const normalizedContent = typeof parsed.content === 'string' ? { text: parsed.content } : parsed.content;
30
+ const input = { content: normalizedContent, docId: parsed.docId, workspaceId, docTitle: parsed.docTitle || "", docMode: normalizedDocMode, mentions: parsed.mentions };
40
31
  const data = await gql.request(mutation, { input });
41
32
  return text(data.createComment);
42
33
  };
43
- server.registerTool("affine_create_comment", {
44
- title: "Create Comment",
45
- description: "Create a comment on a doc.",
46
- inputSchema: {
47
- workspaceId: z.string().optional(),
48
- docId: z.string(),
49
- docTitle: z.string().optional(),
50
- docMode: z.enum(["Page", "Edgeless"]).optional(),
51
- content: z.any(),
52
- mentions: z.array(z.string()).optional()
53
- }
54
- }, createCommentHandler);
55
34
  server.registerTool("create_comment", {
56
35
  title: "Create Comment",
57
36
  description: "Create a comment on a doc.",
@@ -59,7 +38,7 @@ export function registerCommentTools(server, gql, defaults) {
59
38
  workspaceId: z.string().optional(),
60
39
  docId: z.string(),
61
40
  docTitle: z.string().optional(),
62
- docMode: z.enum(["Page", "Edgeless"]).optional(),
41
+ docMode: z.enum(["Page", "Edgeless", "page", "edgeless"]).optional(),
63
42
  content: z.any(),
64
43
  mentions: z.array(z.string()).optional()
65
44
  }
@@ -69,14 +48,6 @@ export function registerCommentTools(server, gql, defaults) {
69
48
  const data = await gql.request(mutation, { input: { id: parsed.id, content: parsed.content } });
70
49
  return text({ success: data.updateComment });
71
50
  };
72
- server.registerTool("affine_update_comment", {
73
- title: "Update Comment",
74
- description: "Update a comment content.",
75
- inputSchema: {
76
- id: z.string(),
77
- content: z.any()
78
- }
79
- }, updateCommentHandler);
80
51
  server.registerTool("update_comment", {
81
52
  title: "Update Comment",
82
53
  description: "Update a comment content.",
@@ -90,13 +61,6 @@ export function registerCommentTools(server, gql, defaults) {
90
61
  const data = await gql.request(mutation, { id: parsed.id });
91
62
  return text({ success: data.deleteComment });
92
63
  };
93
- server.registerTool("affine_delete_comment", {
94
- title: "Delete Comment",
95
- description: "Delete a comment by id.",
96
- inputSchema: {
97
- id: z.string()
98
- }
99
- }, deleteCommentHandler);
100
64
  server.registerTool("delete_comment", {
101
65
  title: "Delete Comment",
102
66
  description: "Delete a comment by id.",
@@ -109,14 +73,6 @@ export function registerCommentTools(server, gql, defaults) {
109
73
  const data = await gql.request(mutation, { input: parsed });
110
74
  return text({ success: data.resolveComment });
111
75
  };
112
- server.registerTool("affine_resolve_comment", {
113
- title: "Resolve Comment",
114
- description: "Resolve or unresolve a comment.",
115
- inputSchema: {
116
- id: z.string(),
117
- resolved: z.boolean()
118
- }
119
- }, resolveCommentHandler);
120
76
  server.registerTool("resolve_comment", {
121
77
  title: "Resolve Comment",
122
78
  description: "Resolve or unresolve a comment.",