Skip to main content
Glama

list_workspaces

Retrieve all available workspaces on the AFFiNE MCP Server to manage documents, search content, handle comments, and access version history efficiently.

Instructions

List all available AFFiNE workspaces

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • The core handler function that implements the list_workspaces tool logic by querying the GraphQL endpoint for available workspaces and returning the list or an error.
    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 });
      }
    };
  • Direct registration of the 'list_workspaces' tool with the MCP server, including metadata and handler reference.
    server.registerTool(
      "list_workspaces",
      {
        title: "List Workspaces",
        description: "List all available AFFiNE workspaces"
      },
      listWorkspacesHandler as any
    );
  • Additional registration of an alias 'affine_list_workspaces' using the same handler.
    server.registerTool(
      "affine_list_workspaces",
      {
        title: "List Workspaces",
        description: "List all available AFFiNE workspaces"
      },
      listWorkspacesHandler
    );
  • src/index.ts:65-65 (registration)
    Top-level call to register all workspace-related tools, including list_workspaces, during server initialization.
    registerWorkspaceTools(server, gql);
  • Helper function that defines and registers all workspace tools, including the listWorkspacesHandler and its 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
      );
    }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/DAWNCR0W/affine-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server