Skip to main content
Glama

AFFiNE MCP Server

by DAWNCR0W
index.ts4.11 kB
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { loadConfig } from "./config.js"; import { GraphQLClient } from "./graphqlClient.js"; import { registerWorkspaceTools } from "./tools/workspaces.js"; import { registerDocTools } from "./tools/docs.js"; import { registerCommentTools } from "./tools/comments.js"; import { registerHistoryTools } from "./tools/history.js"; import { registerUserTools } from "./tools/user.js"; import { registerUserCRUDTools } from "./tools/userCRUD.js"; import { registerUpdateTools } from "./tools/updates.js"; import { registerAccessTokenTools } from "./tools/accessTokens.js"; import { registerBlobTools } from "./tools/blobStorage.js"; import { registerNotificationTools } from "./tools/notifications.js"; import { loginWithPassword } from "./auth.js"; import { registerAuthTools } from "./tools/auth.js"; const config = loadConfig(); async function buildServer() { const server = new McpServer({ name: "affine-mcp", version: "1.2.2" }); // Initialize GraphQL client with authentication const gql = new GraphQLClient({ endpoint: `${config.baseUrl}${config.graphqlPath}`, headers: config.headers, bearer: config.apiToken }); // Try email/password authentication if no other auth method is configured. // To avoid startup timeouts in MCP clients, default to async login after the stdio handshake. if (!gql.isAuthenticated() && config.email && config.password) { const mode = (process.env.AFFINE_LOGIN_AT_START || "async").toLowerCase(); if (mode === "sync") { console.error("No token/cookie; performing synchronous email/password authentication at startup..."); try { const { cookieHeader } = await loginWithPassword(config.baseUrl, config.email, config.password); gql.setCookie(cookieHeader); console.error("Successfully authenticated with email/password"); } catch (e) { console.error("Failed to authenticate with email/password:", e); console.error("WARNING: Continuing without authentication - some operations may fail"); } } else { console.error("No token/cookie; deferring email/password authentication (async after connect)..."); // Fire-and-forget async login so stdio handshake is not delayed. (async () => { try { const { cookieHeader } = await loginWithPassword(config.baseUrl, config.email!, config.password!); gql.setCookie(cookieHeader); console.error("Successfully authenticated with email/password (async)"); } catch (e) { console.error("Failed to authenticate with email/password (async):", e); } })(); } } // Log authentication status if (!gql.isAuthenticated()) { console.error("WARNING: No authentication configured. Some operations may fail."); console.error("Please provide one of: AFFINE_API_TOKEN, AFFINE_COOKIE, or AFFINE_EMAIL/AFFINE_PASSWORD"); } registerWorkspaceTools(server, gql); registerDocTools(server, gql, { workspaceId: config.defaultWorkspaceId }); registerCommentTools(server, gql, { workspaceId: config.defaultWorkspaceId }); registerHistoryTools(server, gql, { workspaceId: config.defaultWorkspaceId }); registerUserTools(server, gql); registerUserCRUDTools(server, gql); registerUpdateTools(server, gql, { workspaceId: config.defaultWorkspaceId }); registerAccessTokenTools(server, gql); registerBlobTools(server, gql); registerNotificationTools(server, gql); registerAuthTools(server, gql, config.baseUrl); return server; } async function start() { // stdio transport is the only supported mode in MCP SDK 1.17+ const server = await buildServer(); const transport = new StdioServerTransport(); await server.connect(transport); // The server is now ready to accept stdio communication // It will continue running until the process is terminated } start().catch((err) => { console.error("Failed to start affine-mcp server:", err); process.exit(1); });

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