Appflowy MCP

MCP para instância auto-hospedada do Appflowy Cloud com interface HTTP, preparado no Docker

Documentação

appflowy-mcp

Docker Image Version Docker Pulls Docker Image Size Architectures MCP Coverage License: MIT

🐳 m2n2/appflowy-mcp:latest on Docker Hub

Um servidor auto-hospedado, com escopo por token, do Model Context Protocol para AppFlowy. Ele fornece a agentes de IA (Claude, ou qualquer cliente MCP) ferramentas para ler e editar seus espaços de trabalho do AppFlowy — listar espaços de trabalho, percorrer a árvore de páginas, criar/atualizar/ler páginas e editar blocos individuais no lugar — enquanto limita cada cliente exatamente às páginas que você permite por meio de escopos em forma de árvore por token.

  • 🔒 Acesso com escopo por token. O servidor faz login no AppFlowy uma vez como conta de serviço. Os clientes nunca veem essas credenciais — eles apresentam um token opaco, e cada token é restrito a um conjunto de espaços de trabalho / subárvores de páginas.
  • 🌳 Escopos em forma de árvore. Conceda um espaço de trabalho inteiro, uma página de nível superior e tudo abaixo dela, ou uma página quatro níveis abaixo e seus descendentes. Combine várias concessões por token.
  • 🐳 Roda em qualquer lugar. Transporte HTTP streamable, imagem multi-arquitetura pequena (m2n2/appflowy-mcp, amd64 + arm64) no Docker Hub, pronta para Docker Compose, Kubernetes ou um chart Helm.
  • ✏️ Edição real. Anexar blocos, inserir blocos em qualquer posição, editar texto de blocos (formatação rica preservada) e excluir blocos — pelo mesmo caminho Yjs/CRDT que o cliente web oficial usa.

Como o acesso funciona

            ┌─────────────┐   token: scopes               ┌──────────────┐
 MCP client │  Authorization: Bearer <token>  ──────────▶ │  appflowy-mcp │
 (Claude)   └─────────────┘                               │  enforces     │
                                                          │  scope, then  │
                                                          │  acts as the  │
            service account (email+password / JWT) ◀──────│  service acct │
                                                          └──────┬───────┘
                                                                 ▼
                                                          AppFlowy Cloud REST

Duas camadas de autenticação, mantidas separadas:

  1. Autenticação de backend (uma conta de serviço). APPFLOWY_BASE_URL + APPFLOWY_EMAIL/APPFLOWY_PASSWORD (ou um APPFLOWY_ACCESS_TOKEN pré-gerado). O servidor faz login uma vez e atualiza automaticamente na expiração.
  2. Autenticação de cliente (muitos tokens). Cada cliente MCP apresenta um token. O token decide o que ele pode acessar — as credenciais de backend nunca são expostas.

Escopos

Um escopo é um caminho de ids do AppFlowy:

EscopoConcessões
(lista vazia)tudo que a conta de serviço pode ver
WORKSPACEo espaço de trabalho inteiro
WORKSPACE/VIEWessa página e tudo aninhado abaixo dela
WORKSPACE/VIEW_L1/VIEW_L2/VIEW_L3uma página vários níveis abaixo e sua subárvore

O último id é a raiz da subárvore permitida; ids anteriores apenas ajudam a localizá-la (os ids de visualização do AppFlowy são globalmente únicos, então ids intermediários são opcionais). Um token pode listar vários escopos para conceder múltiplas subárvores disjuntas de uma vez.

A aplicação é por ancestralidade: para qualquer página que uma ferramenta toque, o servidor sobe a árvore de pastas; se alcançar uma das raízes permitidas do token, a chamada prossegue, caso contrário é rejeitada. Get workspace list e Get workspace folder são podados para o que o token pode ver.

Configuração

Tudo é configurável por variáveis de ambiente (ideal para Docker / Helm) e/ou um arquivo YAML/JSON. As variáveis de ambiente têm precedência sobre o arquivo.

Variáveis de ambiente

VariávelDescrição
APPFLOWY_BASE_URLURL base do AppFlowy Cloud, ex.: https://appflowy.example.com
APPFLOWY_EMAIL / APPFLOWY_PASSWORDLogin da conta de serviço (concessão de senha GoTrue)
APPFLOWY_ACCESS_TOKENJWT pré-gerado em vez de e-mail/senha (tem precedência)
APPFLOWY_MCP_CONFIGCaminho opcional para um arquivo de configuração YAML/JSON
APPFLOWY_MCP_HOST / APPFLOWY_MCP_PORT / APPFLOWY_MCP_PATHEndereço de escuta (padrão 0.0.0.0:8000/mcp)
APPFLOWY_MCP_REQUIRE_AUTHtrue (padrão) rejeita solicitações não autenticadas; false + sem tokens = modo aberto
APPFLOWY_MCP_FOLDER_CACHE_TTLSegundos para armazenar em cache as árvores de pastas para verificações de escopo (padrão 15)
APPFLOWY_MCP_LOG_LEVELINFO (padrão), DEBUG, …

Tokens via env — duas formas equivalentes.

Blob JSON (melhor como um único segredo Helm/Docker):

APPFLOWY_MCP_TOKENS='[
  {"token":"sk-full",    "name":"full",    "scopes":[]},
  {"token":"sk-teamws",  "name":"team",    "scopes":["WORKSPACE_ID"]},
  {"token":"sk-project", "name":"project", "scopes":["WORKSPACE_ID/ROOT_VIEW_ID",
                                                     "WORKSPACE_ID/A/B/DEEP_VIEW_ID"]}
]'

Indexado (sem JSON embutido):

APPFLOWY_MCP_TOKEN_0=sk-full
APPFLOWY_MCP_TOKEN_0_NAME=full
APPFLOWY_MCP_TOKEN_0_SCOPES=                       # empty => all workspaces

APPFLOWY_MCP_TOKEN_1=sk-project
APPFLOWY_MCP_TOKEN_1_NAME=project
APPFLOWY_MCP_TOKEN_1_SCOPES=WORKSPACE_ID/ROOT_VIEW_ID,WORKSPACE_ID/A/B/DEEP_VIEW_ID

Arquivo de configuração

appflowy:
  base_url: https://appflowy.example.com
  email: service@example.com
  password: ${APPFLOWY_PASSWORD}   # plain string; env is not interpolated — set real value
server:
  host: 0.0.0.0
  port: 8000
  path: /mcp
  require_auth: true
tokens:
  - token: sk-full
    name: full
    scopes: []                     # all workspaces
  - token: sk-project
    name: project
    scopes:
      - WORKSPACE_ID/ROOT_VIEW_ID            # a page + its whole subtree
      - WORKSPACE_ID/A/B/DEEP_VIEW_ID        # a deep page + its subtree

Veja config.example.yaml e .env.example.

Executando

Docker

docker run --rm -p 8000:8000 \
  -e APPFLOWY_BASE_URL=https://appflowy.example.com \
  -e APPFLOWY_EMAIL=service@example.com \
  -e APPFLOWY_PASSWORD=secret \
  -e APPFLOWY_MCP_TOKENS='[{"token":"sk-full","scopes":[]}]' \
  m2n2/appflowy-mcp:latest

Docker Compose

cp .env.example .env   # fill in values
docker compose up -d

Kubernetes / Helm

Um chart mínimo está em deploy/helm:

helm install appflowy-mcp ./deploy/helm \
  --set appflowy.baseUrl=https://appflowy.example.com \
  --set appflowy.email=service@example.com \
  --set appflowy.password=secret \
  --set-json 'tokens=[{"token":"sk-full","scopes":[]}]'

A partir do código-fonte

uv run appflowy-mcp

Conectando um cliente

O servidor fala HTTP streamable em http://HOST:PORT/mcp. Aponte seu cliente MCP para ele e envie o token como um cabeçalho bearer. Para Claude Code:

{
  "mcpServers": {
    "appflowy": {
      "type": "http",
      "url": "https://appflowy-mcp.example.com/mcp",
      "headers": { "Authorization": "Bearer sk-full" }
    }
  }
}

Verificação de saúde: GET /healthz{"status":"ok"}.

Ferramentas

FerramentaPropósito
Get workspace listListar espaços de trabalho visíveis ao token
Get workspace folderÁrvore de páginas de um espaço de trabalho, podada ao escopo
Create new pageCriar uma página sob um pai permitido
Update pageRenomear / definir ícone / bloquear
Get page detailsMetadados completos da página + conteúdo
Append content to pageAnexar blocos ao final
Get page blocksListar os blocos de uma página em ordem (ids + texto)
Insert blockInserir um novo bloco em qualquer posição (incl. um image de uma URL pública)
Edit block textSubstituir o texto/conteúdo rico de um bloco no lugar
Delete blockExcluir um bloco folha
Create databaseCriar um banco de dados de grade/quadro/calendário sob um pai
Get workspace databasesListar bancos de dados (+ suas visualizações), com escopo
Get database fieldsListar os campos/colunas de um banco de dados
Add database fieldAdicionar uma coluna (texto, número, seleção, data, …)
List database rowsListar linhas, células chaveadas por nome de campo (opcionalmente documentos de linha)
Get database rowLer as células de uma linha por id (opcionalmente seu documento)
Create database rowAdicionar uma linha a partir de células {field: value} (+ documento markdown opcional)
Update database rowEditar as células de uma linha existente no lugar, por id da linha
Delete database rowRemover uma linha de todas as visualizações do banco de dados
Move page to trash / Restore page from trash / Delete page from trashCiclo de vida da lixeira
Get trash / Get favorite pagesListagens, com escopo
Toggle favorite page(Des)favoritar uma página

Notas e limites

  • As ferramentas de edição de blocos exigem pycrdt (incluído). Elas espelham o CRDT web-update do cliente web; não há endpoint REST oficial por bloco.
  • Insert block com block_type="image" incorpora uma URL de imagem pública por referência (nada é enviado); remova-a com Delete block como qualquer bloco.
  • As células das linhas do banco de dados são chaveadas por nome ou id do campo; os valores seguem o tipo do campo (string para texto/URL, número para Número, bool para Caixa de seleção, ISO-8601 ou segundos unix para Data/Hora, nome(s) da opção para seleção). Create database row passa pelo endpoint REST; Update database row e Delete database row agem em uma linha existente pelo seu id através do caminho CRDT web-update (espelhando o cliente web), já que o REST não expõe rota para editar ou excluir uma linha por UUID.
  • As verificações de escopo dependem da árvore de pastas do espaço de trabalho, armazenada em cache por APPFLOWY_MCP_FOLDER_CACHE_TTL segundos. Páginas recém-criadas invalidam o cache para seu espaço de trabalho.
  • Modo aberto (APPFLOWY_MCP_REQUIRE_AUTH=false sem tokens) concede acesso total a qualquer pessoa que alcance a porta — use apenas em uma rede confiável.

Desenvolvimento

uv sync            # install runtime + dev dependencies
uv run pytest      # run the test suite with the 100% coverage gate
uv run ruff check  # lint

A suíte exige 100% de cobertura de linhas e ramos (--cov-fail-under=100 em pyproject.toml). O CI a executa como o job test em .github/workflows/docker.yml; a construção da imagem Docker needs: test, então uma falha de teste ou queda de cobertura bloqueia a construção da imagem. Veja AGENTS.md para a definição de pronto dos testes.

Licença

MIT — veja LICENSE.

Este projeto começou como uma reformulação focada em auto-hospedagem de LucasXu0/appflowy_mcp.