update_workspace
Modify workspace settings in AFFiNE by updating workspace ID, public visibility, and AI feature status to customize and enhance workspace functionality.
Instructions
Update workspace settings
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| enableAi | No | Enable AI features | |
| id | Yes | Workspace ID | |
| public | No | Make workspace public |
Implementation Reference
- src/tools/workspaces.ts:382-402 (handler)The main handler function for the update_workspace tool. It constructs a GraphQL mutation to update the workspace's public status and AI enablement, executes it via the GraphQL client, and returns the result.const updateWorkspaceHandler = async ({ id, public: isPublic, enableAi }: { id: string; public?: boolean; enableAi?: boolean }) => { try { const mutation = ` mutation UpdateWorkspace($input: UpdateWorkspaceInput!) { updateWorkspace(input: $input) { id public } } `; const input: any = { id }; if (isPublic !== undefined) input.public = isPublic; const data = await gql.request<{ updateWorkspace: any }>(mutation, { input }); return text(data.updateWorkspace); } catch (error: any) { return text({ error: error.message }); } };
- src/tools/workspaces.ts:403-415 (registration)Primary registration of the 'update_workspace' tool with the MCP server, including input schema using Zod.server.registerTool( "update_workspace", { title: "Update Workspace", description: "Update workspace settings", inputSchema: { id: z.string().describe("Workspace ID"), public: z.boolean().optional().describe("Make workspace public"), enableAi: z.boolean().optional().describe("Enable AI features") } }, updateWorkspaceHandler as any );
- src/tools/workspaces.ts:416-428 (registration)Secondary registration of the 'affine_update_workspace' tool alias using the same handler and schema.server.registerTool( "affine_update_workspace", { title: "Update Workspace", description: "Update workspace settings", inputSchema: { id: z.string().describe("Workspace ID"), public: z.boolean().optional().describe("Make workspace public"), enableAi: z.boolean().optional().describe("Enable AI features") } }, updateWorkspaceHandler as any );
- src/tools/workspaces.ts:408-412 (schema)Zod-based input schema definition for the tool parameters: workspace ID (required), public and enableAi (optional booleans).inputSchema: { id: z.string().describe("Workspace ID"), public: z.boolean().optional().describe("Make workspace public"), enableAi: z.boolean().optional().describe("Enable AI features") }
- src/tools/workspaces.ts:134-468 (helper)The registerWorkspaceTools function that sets up all workspace-related tools, including the update_workspace handler and registrations.export function registerWorkspaceTools(server: McpServer, gql: GraphQLClient) { // LIST WORKSPACES const listWorkspacesHandler = async () => { try { const query = `query { workspaces { id public enableAi createdAt } }`; const data = await gql.request<{ workspaces: any[] }>(query); return text(data.workspaces || []); } catch (error: any) { return text({ error: error.message }); } }; server.registerTool( "list_workspaces", { title: "List Workspaces", description: "List all available AFFiNE workspaces" }, listWorkspacesHandler as any ); server.registerTool( "affine_list_workspaces", { title: "List Workspaces", description: "List all available AFFiNE workspaces" }, listWorkspacesHandler ); // GET WORKSPACE const getWorkspaceHandler = async ({ id }: { id: string }) => { try { const query = `query GetWorkspace($id: String!) { workspace(id: $id) { id public enableAi createdAt permissions { Workspace_Read Workspace_CreateDoc } } }`; const data = await gql.request<{ workspace: any }>(query, { id }); return text(data.workspace); } catch (error: any) { return text({ error: error.message }); } }; server.registerTool( "get_workspace", { title: "Get Workspace", description: "Get details of a specific workspace", inputSchema: { id: z.string().describe("Workspace ID") } }, getWorkspaceHandler as any ); server.registerTool( "affine_get_workspace", { title: "Get Workspace", description: "Get details of a specific workspace", inputSchema: { id: z.string().describe("Workspace ID") } }, getWorkspaceHandler as any ); // CREATE WORKSPACE const createWorkspaceHandler = async ({ name, avatar }: { name: string; avatar?: string }) => { try { // Get endpoint and headers from GraphQL client const endpoint = (gql as any).endpoint || process.env.AFFINE_BASE_URL + '/graphql'; const headers = (gql as any).headers || {}; const cookie = (gql as any).cookie || headers.Cookie || ''; // Create initial workspace data const { workspaceUpdate, firstDocId, docUpdate } = createInitialWorkspaceData(name); // Only send workspace update - document will be created separately const initData = Buffer.from(workspaceUpdate); // Create multipart form const form = new FormData(); // Add GraphQL operation form.append('operations', JSON.stringify({ name: 'createWorkspace', query: `mutation createWorkspace($init: Upload!) { createWorkspace(init: $init) { id public createdAt enableAi } }`, variables: { init: null } })); // Map file to variable form.append('map', JSON.stringify({ '0': ['variables.init'] })); // Add workspace init data form.append('0', initData, { filename: 'init.yjs', contentType: 'application/octet-stream' }); // Send request const response = await fetch(endpoint, { method: 'POST', headers: { ...headers, 'Cookie': cookie, ...form.getHeaders() }, body: form as any }); const result = await response.json() as any; if (result.errors) { throw new Error(result.errors[0].message); } const workspace = result.data.createWorkspace; // Now create the actual document via WebSocket const wsUrl = endpoint.replace('https://', 'wss://').replace('http://', 'ws://').replace('/graphql', ''); return new Promise((resolve) => { const socket = io(wsUrl, { transports: ['websocket'], path: '/socket.io/', extraHeaders: cookie ? { Cookie: cookie } : undefined }); socket.on('connect', () => { // Join the workspace socket.emit('space:join', { spaceType: 'workspace', spaceId: workspace.id }); // Send the document update setTimeout(() => { const docUpdateBase64 = Buffer.from(docUpdate).toString('base64'); socket.emit('space:push-doc-update', { spaceType: 'workspace', spaceId: workspace.id, docId: firstDocId, update: docUpdateBase64 }); // Wait longer for sync and disconnect setTimeout(() => { socket.disconnect(); resolve(text({ ...workspace, name: name, avatar: avatar, firstDocId: firstDocId, status: "success", message: "Workspace created successfully", url: `${process.env.AFFINE_BASE_URL}/workspace/${workspace.id}` })); }, 3000); }, 1000); }); socket.on('error', () => { socket.disconnect(); // Even if WebSocket fails, workspace was created resolve(text({ ...workspace, name: name, avatar: avatar, firstDocId: firstDocId, status: "partial", message: "Workspace created (document sync may be pending)", url: `${process.env.AFFINE_BASE_URL}/workspace/${workspace.id}` })); }); // Timeout setTimeout(() => { socket.disconnect(); resolve(text({ ...workspace, name: name, avatar: avatar, firstDocId: firstDocId, status: "success", message: "Workspace created", url: `${process.env.AFFINE_BASE_URL}/workspace/${workspace.id}` })); }, 10000); }); } catch (error: any) { return text({ error: error.message, status: "failed" }); } }; server.registerTool( "create_workspace", { title: "Create Workspace", description: "Create a new workspace with initial document (accessible in UI)", inputSchema: { name: z.string().describe("Workspace name"), avatar: z.string().optional().describe("Avatar emoji or URL") } }, createWorkspaceHandler as any ); server.registerTool( "affine_create_workspace", { title: "Create Workspace", description: "Create a new workspace with initial document (accessible in UI)", inputSchema: { name: z.string().describe("Workspace name"), avatar: z.string().optional().describe("Avatar emoji or URL") } }, createWorkspaceHandler as any ); server.registerTool( "affine_create_workspace_fixed", { title: "Create Workspace (Fixed)", description: "Create a new workspace with initial document (backward compatible alias)", inputSchema: { name: z.string().describe("Workspace name"), avatar: z.string().optional().describe("Avatar emoji or URL") } }, createWorkspaceHandler as any ); // UPDATE WORKSPACE const updateWorkspaceHandler = async ({ id, public: isPublic, enableAi }: { id: string; public?: boolean; enableAi?: boolean }) => { try { const mutation = ` mutation UpdateWorkspace($input: UpdateWorkspaceInput!) { updateWorkspace(input: $input) { id public } } `; const input: any = { id }; if (isPublic !== undefined) input.public = isPublic; const data = await gql.request<{ updateWorkspace: any }>(mutation, { input }); return text(data.updateWorkspace); } catch (error: any) { return text({ error: error.message }); } }; server.registerTool( "update_workspace", { title: "Update Workspace", description: "Update workspace settings", inputSchema: { id: z.string().describe("Workspace ID"), public: z.boolean().optional().describe("Make workspace public"), enableAi: z.boolean().optional().describe("Enable AI features") } }, updateWorkspaceHandler as any ); server.registerTool( "affine_update_workspace", { title: "Update Workspace", description: "Update workspace settings", inputSchema: { id: z.string().describe("Workspace ID"), public: z.boolean().optional().describe("Make workspace public"), enableAi: z.boolean().optional().describe("Enable AI features") } }, updateWorkspaceHandler as any ); // DELETE WORKSPACE const deleteWorkspaceHandler = async ({ id }: { id: string }) => { try { const mutation = ` mutation DeleteWorkspace($id: String!) { deleteWorkspace(id: $id) } `; const data = await gql.request<{ deleteWorkspace: boolean }>(mutation, { id }); return text({ success: data.deleteWorkspace, message: "Workspace deleted successfully" }); } catch (error: any) { return text({ error: error.message }); } }; server.registerTool( "delete_workspace", { title: "Delete Workspace", description: "Delete a workspace permanently", inputSchema: { id: z.string().describe("Workspace ID") } }, deleteWorkspaceHandler as any ); server.registerTool( "affine_delete_workspace", { title: "Delete Workspace", description: "Delete a workspace permanently", inputSchema: { id: z.string().describe("Workspace ID") } }, deleteWorkspaceHandler as any ); }