@mtcsistemas/appflowy-mcp-server 1.0.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.
Files changed (55) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +324 -0
  3. package/dist/config.d.ts +25 -0
  4. package/dist/config.d.ts.map +1 -0
  5. package/dist/config.js +56 -0
  6. package/dist/config.js.map +1 -0
  7. package/dist/index.d.ts +15 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +53 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/prompts/appflowy-prompts.d.ts +7 -0
  12. package/dist/prompts/appflowy-prompts.d.ts.map +1 -0
  13. package/dist/prompts/appflowy-prompts.js +115 -0
  14. package/dist/prompts/appflowy-prompts.js.map +1 -0
  15. package/dist/resources/workspace-resources.d.ts +7 -0
  16. package/dist/resources/workspace-resources.d.ts.map +1 -0
  17. package/dist/resources/workspace-resources.js +86 -0
  18. package/dist/resources/workspace-resources.js.map +1 -0
  19. package/dist/server.d.ts +7 -0
  20. package/dist/server.d.ts.map +1 -0
  21. package/dist/server.js +31 -0
  22. package/dist/server.js.map +1 -0
  23. package/dist/services/appflowy-client.d.ts +65 -0
  24. package/dist/services/appflowy-client.d.ts.map +1 -0
  25. package/dist/services/appflowy-client.js +303 -0
  26. package/dist/services/appflowy-client.js.map +1 -0
  27. package/dist/services/auth.d.ts +26 -0
  28. package/dist/services/auth.d.ts.map +1 -0
  29. package/dist/services/auth.js +89 -0
  30. package/dist/services/auth.js.map +1 -0
  31. package/dist/tools/databases.d.ts +7 -0
  32. package/dist/tools/databases.d.ts.map +1 -0
  33. package/dist/tools/databases.js +199 -0
  34. package/dist/tools/databases.js.map +1 -0
  35. package/dist/tools/documents.d.ts +7 -0
  36. package/dist/tools/documents.d.ts.map +1 -0
  37. package/dist/tools/documents.js +197 -0
  38. package/dist/tools/documents.js.map +1 -0
  39. package/dist/tools/files.d.ts +7 -0
  40. package/dist/tools/files.d.ts.map +1 -0
  41. package/dist/tools/files.js +196 -0
  42. package/dist/tools/files.js.map +1 -0
  43. package/dist/tools/search.d.ts +7 -0
  44. package/dist/tools/search.d.ts.map +1 -0
  45. package/dist/tools/search.js +60 -0
  46. package/dist/tools/search.js.map +1 -0
  47. package/dist/tools/workspaces.d.ts +7 -0
  48. package/dist/tools/workspaces.d.ts.map +1 -0
  49. package/dist/tools/workspaces.js +66 -0
  50. package/dist/tools/workspaces.js.map +1 -0
  51. package/dist/types.d.ts +140 -0
  52. package/dist/types.d.ts.map +1 -0
  53. package/dist/types.js +6 -0
  54. package/dist/types.js.map +1 -0
  55. package/package.json +64 -0
@@ -0,0 +1,86 @@
1
+ /**
2
+ * AppFlowy MCP Server - MCP Resources
3
+ * Exposes AppFlowy data as MCP resources
4
+ */
5
+ import { appflowyClient } from '../services/appflowy-client.js';
6
+ export function registerWorkspaceResources(server) {
7
+ // Resource: List of workspaces
8
+ server.resource('appflowy_workspaces', 'appflowy://workspaces', {
9
+ description: 'List of all AppFlowy workspaces',
10
+ mimeType: 'application/json',
11
+ }, async () => {
12
+ const workspaces = await appflowyClient.listWorkspaces();
13
+ return {
14
+ contents: [
15
+ {
16
+ uri: 'appflowy://workspaces',
17
+ mimeType: 'application/json',
18
+ text: JSON.stringify(workspaces, null, 2),
19
+ },
20
+ ],
21
+ };
22
+ });
23
+ // Resource: Workspace details
24
+ server.resource('appflowy_workspace', 'appflowy://workspace/{workspace_id}', {
25
+ description: 'Details of a specific AppFlowy workspace',
26
+ mimeType: 'application/json',
27
+ }, async (uri) => {
28
+ const match = uri.href.match(/appflowy:\/\/workspace\/([^\/]+)/);
29
+ if (!match)
30
+ throw new Error('Invalid workspace URI');
31
+ const workspace = await appflowyClient.getWorkspace(match[1]);
32
+ return {
33
+ contents: [
34
+ {
35
+ uri: uri.href,
36
+ mimeType: 'application/json',
37
+ text: JSON.stringify(workspace, null, 2),
38
+ },
39
+ ],
40
+ };
41
+ });
42
+ // Resource: Document content
43
+ server.resource('appflowy_document', 'appflowy://document/{workspace_id}/{document_id}', {
44
+ description: 'Content of a specific AppFlowy document',
45
+ mimeType: 'application/json',
46
+ }, async (uri) => {
47
+ const match = uri.href.match(/appflowy:\/\/document\/([^\/]+)\/([^\/]+)/);
48
+ if (!match)
49
+ throw new Error('Invalid document URI');
50
+ const [, workspace_id, document_id] = match;
51
+ const content = await appflowyClient.getDocumentContent(workspace_id, document_id);
52
+ return {
53
+ contents: [
54
+ {
55
+ uri: uri.href,
56
+ mimeType: 'application/json',
57
+ text: JSON.stringify(content, null, 2),
58
+ },
59
+ ],
60
+ };
61
+ });
62
+ // Resource: Database rows
63
+ server.resource('appflowy_database', 'appflowy://database/{workspace_id}/{database_id}', {
64
+ description: 'All rows from a specific AppFlowy database',
65
+ mimeType: 'application/json',
66
+ }, async (uri) => {
67
+ const match = uri.href.match(/appflowy:\/\/database\/([^\/]+)\/([^\/]+)/);
68
+ if (!match)
69
+ throw new Error('Invalid database URI');
70
+ const [, workspace_id, database_id] = match;
71
+ const [dbInfo, rows] = await Promise.all([
72
+ appflowyClient.getDatabase(workspace_id, database_id),
73
+ appflowyClient.getDatabaseRows(workspace_id, database_id),
74
+ ]);
75
+ return {
76
+ contents: [
77
+ {
78
+ uri: uri.href,
79
+ mimeType: 'application/json',
80
+ text: JSON.stringify({ database: dbInfo, rows }, null, 2),
81
+ },
82
+ ],
83
+ };
84
+ });
85
+ }
86
+ //# sourceMappingURL=workspace-resources.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace-resources.js","sourceRoot":"","sources":["../../src/resources/workspace-resources.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * AppFlowy MCP Server - MCP Server Setup
3
+ * Configures and assembles the MCP server with all tools, resources, and prompts
4
+ */
5
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
6
+ export declare function createMcpServer(): McpServer;
7
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAWpE,wBAAgB,eAAe,IAAI,SAAS,CAoB3C"}
package/dist/server.js ADDED
@@ -0,0 +1,31 @@
1
+ /**
2
+ * AppFlowy MCP Server - MCP Server Setup
3
+ * Configures and assembles the MCP server with all tools, resources, and prompts
4
+ */
5
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
6
+ import { MCP_CONFIG } from './config.js';
7
+ import { registerWorkspaceTools } from './tools/workspaces.js';
8
+ import { registerDocumentTools } from './tools/documents.js';
9
+ import { registerDatabaseTools } from './tools/databases.js';
10
+ import { registerSearchTools } from './tools/search.js';
11
+ import { registerFileTools } from './tools/files.js';
12
+ import { registerWorkspaceResources } from './resources/workspace-resources.js';
13
+ import { registerAppFlowyPrompts } from './prompts/appflowy-prompts.js';
14
+ export function createMcpServer() {
15
+ const server = new McpServer({
16
+ name: MCP_CONFIG.serverName,
17
+ version: MCP_CONFIG.serverVersion,
18
+ });
19
+ // Register all tools
20
+ registerWorkspaceTools(server);
21
+ registerDocumentTools(server);
22
+ registerDatabaseTools(server);
23
+ registerSearchTools(server);
24
+ registerFileTools(server);
25
+ // Register resources
26
+ registerWorkspaceResources(server);
27
+ // Register prompts
28
+ registerAppFlowyPrompts(server);
29
+ return server;
30
+ }
31
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,0BAA0B,EAAE,MAAM,oCAAoC,CAAC;AAChF,OAAO,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AAExE,MAAM,UAAU,eAAe;IAC7B,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,UAAU,CAAC,UAAU;QAC3B,OAAO,EAAE,UAAU,CAAC,aAAa;KAClC,CAAC,CAAC;IAEH,qBAAqB;IACrB,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAC/B,qBAAqB,CAAC,MAAM,CAAC,CAAC;IAC9B,qBAAqB,CAAC,MAAM,CAAC,CAAC;IAC9B,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAC5B,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAE1B,qBAAqB;IACrB,0BAA0B,CAAC,MAAM,CAAC,CAAC;IAEnC,mBAAmB;IACnB,uBAAuB,CAAC,MAAM,CAAC,CAAC;IAEhC,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * AppFlowy MCP Server - AppFlowy API Client
3
+ * HTTP client for all AppFlowy Cloud REST API endpoints
4
+ */
5
+ import { Workspace, Document, DocumentContent, Database, DatabaseRow, SearchResult, FileUploadResult, FileMetadata, BlobInfo } from '../types.js';
6
+ declare class AppFlowyClient {
7
+ private client;
8
+ constructor();
9
+ listWorkspaces(): Promise<Workspace[]>;
10
+ getWorkspace(workspaceId: string): Promise<Workspace>;
11
+ listDocuments(workspaceId: string, parentViewId?: string): Promise<Document[]>;
12
+ getDocument(workspaceId: string, documentId: string): Promise<Document>;
13
+ getDocumentContent(workspaceId: string, documentId: string): Promise<DocumentContent>;
14
+ createDocument(workspaceId: string, name: string, parentViewId?: string): Promise<Document>;
15
+ updateDocument(workspaceId: string, documentId: string, updates: {
16
+ name?: string;
17
+ }): Promise<void>;
18
+ deleteDocument(workspaceId: string, documentId: string): Promise<void>;
19
+ moveDocument(workspaceId: string, documentId: string, newParentId: string): Promise<void>;
20
+ duplicateDocument(workspaceId: string, documentId: string): Promise<Document>;
21
+ listDatabases(workspaceId: string): Promise<Document[]>;
22
+ getDatabase(workspaceId: string, databaseId: string): Promise<Database>;
23
+ getDatabaseRows(workspaceId: string, databaseId: string): Promise<DatabaseRow[]>;
24
+ createDatabaseRow(workspaceId: string, databaseId: string, cells: Record<string, any>): Promise<DatabaseRow>;
25
+ updateDatabaseRow(workspaceId: string, databaseId: string, rowId: string, cells: Record<string, any>): Promise<DatabaseRow>;
26
+ deleteDatabaseRow(workspaceId: string, databaseId: string, rowId: string): Promise<void>;
27
+ search(workspaceId: string, query: string, limit?: number): Promise<SearchResult[]>;
28
+ globalSearch(query: string, limit?: number): Promise<SearchResult[]>;
29
+ /**
30
+ * Upload a file to AppFlowy Cloud storage
31
+ * @param workspaceId - Target workspace
32
+ * @param filePath - Local file path
33
+ * @param parentDir - Parent directory in storage (optional)
34
+ * @param onProgress - Progress callback
35
+ */
36
+ uploadFile(workspaceId: string, filePath: string, parentDir?: string, onProgress?: (progress: number) => void): Promise<FileUploadResult>;
37
+ /**
38
+ * Upload a file from a buffer (useful for generated content)
39
+ */
40
+ uploadBuffer(workspaceId: string, buffer: Buffer, fileName: string, mimeType?: string, parentDir?: string): Promise<FileUploadResult>;
41
+ /**
42
+ * Get file metadata and download URL
43
+ */
44
+ getFileMetadata(workspaceId: string, fileId: string, parentDir?: string): Promise<FileMetadata>;
45
+ /**
46
+ * Download a file as buffer
47
+ */
48
+ downloadFile(workspaceId: string, fileId: string, parentDir?: string): Promise<Buffer>;
49
+ /**
50
+ * Delete a file from storage
51
+ */
52
+ deleteFile(workspaceId: string, fileId: string, parentDir?: string): Promise<void>;
53
+ /**
54
+ * List files in a directory
55
+ */
56
+ listFiles(workspaceId: string, parentDir?: string): Promise<BlobInfo[]>;
57
+ /**
58
+ * Attach a file to a document by inserting a file block
59
+ */
60
+ attachFileToDocument(workspaceId: string, documentId: string, fileUploadResult: FileUploadResult, parentDir?: string): Promise<void>;
61
+ getWebSocketUrl(workspaceId: string, documentId: string): string;
62
+ }
63
+ export declare const appflowyClient: AppFlowyClient;
64
+ export {};
65
+ //# sourceMappingURL=appflowy-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"appflowy-client.d.ts","sourceRoot":"","sources":["../../src/services/appflowy-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,303 @@
1
+ /**
2
+ * AppFlowy MCP Server - AppFlowy API Client
3
+ * HTTP client for all AppFlowy Cloud REST API endpoints
4
+ */
5
+ import axios from 'axios';
6
+ import FormData from 'form-data';
7
+ import { createReadStream } from 'fs';
8
+ import { statSync } from 'fs';
9
+ import { basename } from 'path';
10
+ import { lookup } from 'mime-types';
11
+ import { APPFLOWY_CONFIG, getApiUrl, getFileStorageUrl } from '../config.js';
12
+ import { getAuthHeaders, getMultipartAuthHeaders } from './auth.js';
13
+ class AppFlowyClient {
14
+ client;
15
+ constructor() {
16
+ this.client = axios.create({
17
+ baseURL: getApiUrl(),
18
+ timeout: 30000,
19
+ });
20
+ // Request interceptor: add auth headers to all requests
21
+ this.client.interceptors.request.use(async (config) => {
22
+ const headers = await getAuthHeaders();
23
+ Object.assign(config.headers, headers);
24
+ return config;
25
+ });
26
+ // Response interceptor: handle token expiration
27
+ this.client.interceptors.response.use((response) => response, async (error) => {
28
+ if (error.response?.status === 401) {
29
+ // Token might be expired, clear and retry once
30
+ const { refreshToken } = await import('./auth.js');
31
+ await refreshToken();
32
+ const headers = await getAuthHeaders();
33
+ error.config.headers = { ...error.config.headers, ...headers };
34
+ return this.client.request(error.config);
35
+ }
36
+ return Promise.reject(error);
37
+ });
38
+ }
39
+ // ============================================
40
+ // WORKSPACE OPERATIONS
41
+ // ============================================
42
+ async listWorkspaces() {
43
+ const response = await this.client.get('/workspace');
44
+ return response.data.data || [];
45
+ }
46
+ async getWorkspace(workspaceId) {
47
+ const response = await this.client.get(`/workspace/${workspaceId}`);
48
+ return response.data.data;
49
+ }
50
+ // ============================================
51
+ // DOCUMENT / VIEW OPERATIONS
52
+ // ============================================
53
+ async listDocuments(workspaceId, parentViewId) {
54
+ const url = parentViewId
55
+ ? `/workspace/${workspaceId}/folder?parent_view_id=${parentViewId}`
56
+ : `/workspace/${workspaceId}/folder`;
57
+ const response = await this.client.get(url);
58
+ return response.data.data?.views || [];
59
+ }
60
+ async getDocument(workspaceId, documentId) {
61
+ const response = await this.client.get(`/workspace/${workspaceId}/page-view/${documentId}`);
62
+ return response.data.data;
63
+ }
64
+ async getDocumentContent(workspaceId, documentId) {
65
+ const response = await this.client.get(`/workspace/${workspaceId}/page/${documentId}`);
66
+ return response.data.data;
67
+ }
68
+ async createDocument(workspaceId, name, parentViewId) {
69
+ const response = await this.client.post(`/workspace/${workspaceId}/page-view`, {
70
+ name,
71
+ layout: 'Document',
72
+ parent_view_id: parentViewId,
73
+ });
74
+ return response.data.data;
75
+ }
76
+ async updateDocument(workspaceId, documentId, updates) {
77
+ await this.client.patch(`/workspace/${workspaceId}/page-view/${documentId}`, updates);
78
+ }
79
+ async deleteDocument(workspaceId, documentId) {
80
+ await this.client.delete(`/workspace/${workspaceId}/page-view/${documentId}`);
81
+ }
82
+ async moveDocument(workspaceId, documentId, newParentId) {
83
+ await this.client.post(`/workspace/${workspaceId}/page-view/${documentId}/move`, {
84
+ new_parent_view_id: newParentId,
85
+ });
86
+ }
87
+ async duplicateDocument(workspaceId, documentId) {
88
+ const response = await this.client.post(`/workspace/${workspaceId}/page-view/${documentId}/duplicate`);
89
+ return response.data.data;
90
+ }
91
+ // ============================================
92
+ // DATABASE OPERATIONS
93
+ // ============================================
94
+ async listDatabases(workspaceId) {
95
+ const docs = await this.listDocuments(workspaceId);
96
+ return docs.filter((d) => ['Grid', 'Board', 'Calendar', 'Gallery'].includes(d.layout));
97
+ }
98
+ async getDatabase(workspaceId, databaseId) {
99
+ const response = await this.client.get(`/workspace/${workspaceId}/database/${databaseId}`);
100
+ return response.data.data;
101
+ }
102
+ async getDatabaseRows(workspaceId, databaseId) {
103
+ const response = await this.client.get(`/workspace/${workspaceId}/database/${databaseId}/row/detail`);
104
+ return response.data.data || [];
105
+ }
106
+ async createDatabaseRow(workspaceId, databaseId, cells) {
107
+ const response = await this.client.post(`/workspace/${workspaceId}/database/${databaseId}/row`, {
108
+ cells,
109
+ });
110
+ return response.data.data;
111
+ }
112
+ async updateDatabaseRow(workspaceId, databaseId, rowId, cells) {
113
+ const response = await this.client.put(`/workspace/${workspaceId}/database/${databaseId}/row/${rowId}`, {
114
+ cells,
115
+ });
116
+ return response.data.data;
117
+ }
118
+ async deleteDatabaseRow(workspaceId, databaseId, rowId) {
119
+ await this.client.delete(`/workspace/${workspaceId}/database/${databaseId}/row/${rowId}`);
120
+ }
121
+ // ============================================
122
+ // SEARCH OPERATIONS
123
+ // ============================================
124
+ async search(workspaceId, query, limit = 20) {
125
+ const response = await this.client.get(`/workspace/${workspaceId}/search`, {
126
+ params: { query, limit },
127
+ });
128
+ return response.data.data || [];
129
+ }
130
+ async globalSearch(query, limit = 20) {
131
+ const response = await this.client.get('/search', {
132
+ params: { query, limit },
133
+ });
134
+ return response.data.data || [];
135
+ }
136
+ // ============================================
137
+ // FILE / ATTACHMENT OPERATIONS
138
+ // ============================================
139
+ /**
140
+ * Upload a file to AppFlowy Cloud storage
141
+ * @param workspaceId - Target workspace
142
+ * @param filePath - Local file path
143
+ * @param parentDir - Parent directory in storage (optional)
144
+ * @param onProgress - Progress callback
145
+ */
146
+ async uploadFile(workspaceId, filePath, parentDir = 'attachments', onProgress) {
147
+ const fileName = basename(filePath);
148
+ const fileSize = statSync(filePath).size;
149
+ const mimeType = lookup(filePath) || 'application/octet-stream';
150
+ // Check file size limit
151
+ const maxSizeBytes = APPFLOWY_CONFIG.maxFileSizeMB * 1024 * 1024;
152
+ if (fileSize > maxSizeBytes) {
153
+ throw new Error(`File size (${(fileSize / 1024 / 1024).toFixed(2)}MB) exceeds maximum allowed (${APPFLOWY_CONFIG.maxFileSizeMB}MB)`);
154
+ }
155
+ const formData = new FormData();
156
+ formData.append('file', createReadStream(filePath), {
157
+ filename: fileName,
158
+ contentType: mimeType,
159
+ knownLength: fileSize,
160
+ });
161
+ const headers = await getMultipartAuthHeaders();
162
+ const uploadUrl = `${getFileStorageUrl()}/${workspaceId}/v1/blob/${parentDir}`;
163
+ const response = await axios.post(uploadUrl, formData, {
164
+ headers: {
165
+ ...headers,
166
+ ...formData.getHeaders(),
167
+ },
168
+ maxBodyLength: maxSizeBytes,
169
+ maxContentLength: maxSizeBytes,
170
+ timeout: APPFLOWY_CONFIG.fileTimeoutSec * 1000,
171
+ onUploadProgress: onProgress
172
+ ? (progressEvent) => {
173
+ const percent = progressEvent.total
174
+ ? Math.round((progressEvent.loaded * 100) / progressEvent.total)
175
+ : 0;
176
+ onProgress(percent);
177
+ }
178
+ : undefined,
179
+ });
180
+ return {
181
+ file_id: response.data.file_id || response.data.id,
182
+ url: response.data.url,
183
+ name: fileName,
184
+ size: fileSize,
185
+ mime_type: mimeType,
186
+ created_at: new Date().toISOString(),
187
+ };
188
+ }
189
+ /**
190
+ * Upload a file from a buffer (useful for generated content)
191
+ */
192
+ async uploadBuffer(workspaceId, buffer, fileName, mimeType = 'application/octet-stream', parentDir = 'attachments') {
193
+ const maxSizeBytes = APPFLOWY_CONFIG.maxFileSizeMB * 1024 * 1024;
194
+ if (buffer.length > maxSizeBytes) {
195
+ throw new Error(`Buffer size (${(buffer.length / 1024 / 1024).toFixed(2)}MB) exceeds maximum allowed (${APPFLOWY_CONFIG.maxFileSizeMB}MB)`);
196
+ }
197
+ const formData = new FormData();
198
+ formData.append('file', buffer, {
199
+ filename: fileName,
200
+ contentType: mimeType,
201
+ });
202
+ const headers = await getMultipartAuthHeaders();
203
+ const uploadUrl = `${getFileStorageUrl()}/${workspaceId}/v1/blob/${parentDir}`;
204
+ const response = await axios.post(uploadUrl, formData, {
205
+ headers: {
206
+ ...headers,
207
+ ...formData.getHeaders(),
208
+ },
209
+ maxBodyLength: maxSizeBytes,
210
+ maxContentLength: maxSizeBytes,
211
+ timeout: APPFLOWY_CONFIG.fileTimeoutSec * 1000,
212
+ });
213
+ return {
214
+ file_id: response.data.file_id || response.data.id,
215
+ url: response.data.url,
216
+ name: fileName,
217
+ size: buffer.length,
218
+ mime_type: mimeType,
219
+ created_at: new Date().toISOString(),
220
+ };
221
+ }
222
+ /**
223
+ * Get file metadata and download URL
224
+ */
225
+ async getFileMetadata(workspaceId, fileId, parentDir = 'attachments') {
226
+ const headers = await getAuthHeaders();
227
+ const url = `${getFileStorageUrl()}/${workspaceId}/v1/blob/${parentDir}/${fileId}`;
228
+ // HEAD request to get metadata
229
+ const headResponse = await axios.head(url, { headers });
230
+ return {
231
+ file_id: fileId,
232
+ file_name: headResponse.headers['x-file-name'] || fileId,
233
+ file_size: parseInt(headResponse.headers['content-length'] || '0', 10),
234
+ mime_type: headResponse.headers['content-type'] || 'application/octet-stream',
235
+ created_at: headResponse.headers['x-created-at'] || new Date().toISOString(),
236
+ modified_at: headResponse.headers['x-modified-at'],
237
+ url: url,
238
+ };
239
+ }
240
+ /**
241
+ * Download a file as buffer
242
+ */
243
+ async downloadFile(workspaceId, fileId, parentDir = 'attachments') {
244
+ const headers = await getAuthHeaders();
245
+ const url = `${getFileStorageUrl()}/${workspaceId}/v1/blob/${parentDir}/${fileId}`;
246
+ const response = await axios.get(url, {
247
+ headers,
248
+ responseType: 'arraybuffer',
249
+ timeout: APPFLOWY_CONFIG.fileTimeoutSec * 1000,
250
+ });
251
+ return Buffer.from(response.data);
252
+ }
253
+ /**
254
+ * Delete a file from storage
255
+ */
256
+ async deleteFile(workspaceId, fileId, parentDir = 'attachments') {
257
+ const headers = await getAuthHeaders();
258
+ const url = `${getFileStorageUrl()}/${workspaceId}/v1/blob/${parentDir}/${fileId}`;
259
+ await axios.delete(url, { headers });
260
+ }
261
+ /**
262
+ * List files in a directory
263
+ */
264
+ async listFiles(workspaceId, parentDir = 'attachments') {
265
+ const headers = await getAuthHeaders();
266
+ const url = `${getFileStorageUrl()}/${workspaceId}/v1/blob/${parentDir}`;
267
+ const response = await axios.get(url, { headers });
268
+ return response.data.data || [];
269
+ }
270
+ /**
271
+ * Attach a file to a document by inserting a file block
272
+ */
273
+ async attachFileToDocument(workspaceId, documentId, fileUploadResult, parentDir = 'attachments') {
274
+ // Get current document content
275
+ const content = await this.getDocumentContent(workspaceId, documentId);
276
+ // Create a file block
277
+ const fileBlock = {
278
+ type: 'file',
279
+ data: {
280
+ url: `${getFileStorageUrl()}/${workspaceId}/v1/blob/${parentDir}/${fileUploadResult.file_id}`,
281
+ name: fileUploadResult.name,
282
+ size: fileUploadResult.size,
283
+ file_type: fileUploadResult.mime_type,
284
+ },
285
+ };
286
+ // Append file block to document
287
+ content.blocks.push(fileBlock);
288
+ // Update document content
289
+ await this.client.put(`/workspace/${workspaceId}/page/${documentId}`, {
290
+ blocks: content.blocks,
291
+ });
292
+ }
293
+ // ============================================
294
+ // WEBSOCKET (Real-time collaboration)
295
+ // ============================================
296
+ getWebSocketUrl(workspaceId, documentId) {
297
+ const wsBase = APPFLOWY_CONFIG.baseUrl.replace('https://', 'wss://').replace('http://', 'ws://');
298
+ return `${wsBase}/ws/v1?workspace_id=${workspaceId}&document_id=${documentId}`;
299
+ }
300
+ }
301
+ // Export singleton instance
302
+ export const appflowyClient = new AppFlowyClient();
303
+ //# sourceMappingURL=appflowy-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"appflowy-client.js","sourceRoot":"","sources":["../../src/services/appflowy-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * AppFlowy MCP Server - Authentication Service
3
+ * Handles JWT token management via GoTrue (Supabase Auth fork)
4
+ */
5
+ /**
6
+ * Authenticate with AppFlowy Cloud via GoTrue
7
+ * Returns a valid JWT access token
8
+ */
9
+ export declare function authenticate(): Promise<string>;
10
+ /**
11
+ * Refresh the current token
12
+ */
13
+ export declare function refreshToken(): Promise<string>;
14
+ /**
15
+ * Get authorization headers for API requests
16
+ */
17
+ export declare function getAuthHeaders(): Promise<Record<string, string>>;
18
+ /**
19
+ * Get authorization headers for multipart requests (file uploads)
20
+ */
21
+ export declare function getMultipartAuthHeaders(): Promise<Record<string, string>>;
22
+ /**
23
+ * Clear cached token (useful for logout or token invalidation)
24
+ */
25
+ export declare function clearToken(): void;
26
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/services/auth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AASH;;;GAGG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAsCpD;AAED;;GAEG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAuBpD;AAED;;GAEG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAMtE;AAED;;GAEG;AACH,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAK/E;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,IAAI,CAGjC"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * AppFlowy MCP Server - Authentication Service
3
+ * Handles JWT token management via GoTrue (Supabase Auth fork)
4
+ */
5
+ import axios from 'axios';
6
+ import { APPFLOWY_CONFIG, getGoTrueUrl } from '../config.js';
7
+ let cachedToken = null;
8
+ let tokenExpiry = null;
9
+ /**
10
+ * Authenticate with AppFlowy Cloud via GoTrue
11
+ * Returns a valid JWT access token
12
+ */
13
+ export async function authenticate() {
14
+ // Return cached token if still valid (with 5-minute buffer)
15
+ if (cachedToken && tokenExpiry && new Date() < tokenExpiry) {
16
+ return cachedToken.access_token;
17
+ }
18
+ // Use pre-configured JWT token if available
19
+ if (APPFLOWY_CONFIG.jwtToken) {
20
+ return APPFLOWY_CONFIG.jwtToken;
21
+ }
22
+ // Authenticate with email/password via GoTrue
23
+ const authUrl = `${getGoTrueUrl()}/token?grant_type=password`;
24
+ try {
25
+ const response = await axios.post(authUrl, {
26
+ email: APPFLOWY_CONFIG.email,
27
+ password: APPFLOWY_CONFIG.password,
28
+ }, {
29
+ headers: { 'Content-Type': 'application/json' },
30
+ timeout: 30000,
31
+ });
32
+ cachedToken = response.data;
33
+ // Set expiry with 5-minute safety buffer
34
+ const expiresInMs = (cachedToken.expires_in - 300) * 1000;
35
+ tokenExpiry = new Date(Date.now() + expiresInMs);
36
+ return cachedToken.access_token;
37
+ }
38
+ catch (error) {
39
+ const message = error.response?.data?.msg || error.message;
40
+ throw new Error(`AppFlowy authentication failed: ${message}`);
41
+ }
42
+ }
43
+ /**
44
+ * Refresh the current token
45
+ */
46
+ export async function refreshToken() {
47
+ if (!cachedToken?.refresh_token) {
48
+ return authenticate();
49
+ }
50
+ const refreshUrl = `${getGoTrueUrl()}/token?grant_type=refresh_token`;
51
+ try {
52
+ const response = await axios.post(refreshUrl, { refresh_token: cachedToken.refresh_token }, { headers: { 'Content-Type': 'application/json' } });
53
+ cachedToken = response.data;
54
+ const expiresInMs = (cachedToken.expires_in - 300) * 1000;
55
+ tokenExpiry = new Date(Date.now() + expiresInMs);
56
+ return cachedToken.access_token;
57
+ }
58
+ catch (error) {
59
+ // If refresh fails, try full re-authentication
60
+ return authenticate();
61
+ }
62
+ }
63
+ /**
64
+ * Get authorization headers for API requests
65
+ */
66
+ export async function getAuthHeaders() {
67
+ const token = await authenticate();
68
+ return {
69
+ Authorization: `Bearer ${token}`,
70
+ 'Content-Type': 'application/json',
71
+ };
72
+ }
73
+ /**
74
+ * Get authorization headers for multipart requests (file uploads)
75
+ */
76
+ export async function getMultipartAuthHeaders() {
77
+ const token = await authenticate();
78
+ return {
79
+ Authorization: `Bearer ${token}`,
80
+ };
81
+ }
82
+ /**
83
+ * Clear cached token (useful for logout or token invalidation)
84
+ */
85
+ export function clearToken() {
86
+ cachedToken = null;
87
+ tokenExpiry = null;
88
+ }
89
+ //# sourceMappingURL=auth.js.map