Fresh Jots MCP Server

Servidor MCP FreshJotsDotCom

Documentação

REST com token Bearer. Apenas notas de texto simples. Disponível nos planos Dev e Team. Para a apresentação sistêmica — cada script tem seu próprio caderno, anexação por nome de arquivo para jobs cron e resumos de sessões de IA, fluxos de trabalho do mundo real — veja /for/developers. URL base: https://freshjots.com/api/v1

Referência rápida — clientes

Linux e macOS

homebrew-freshjots

Windows e JS

freshjots-js

Gem Ruby

gem "freshjots"

Exemplos rápidos de uso da API. Exemplos curl prontos para copiar para os fluxos de trabalho comuns: criar, logs somente-anexação, anexar por nome de arquivo, listar.

Exemplos rápidos →

Trabalhando com pastas? Crie pastas, coloque notas nelas na criação, envio em massa para uma pasta.

API de pastas →

No Windows, ou prefere não instalar? Escreva na sua conta via PowerShell sem instalação, ou com o cliente npm / pip — sem precisar de WSL.

Windows / PowerShell →

Autenticação

Gere um token pessoal em /settings/api_tokens. Os tokens são exibidos apenas uma vez na criação e armazenados como hash de via única — copie para o seu gerenciador de senhas ou perfil do shell imediatamente.

Authorization: Bearer mn_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Token ausente ou inválido retorna 401 unauthenticated. Titular do token sem acesso à API (plano Free / Personal) retorna 403 forbidden.

Escopos. Cada token é emitido com um nível de permissão — read_write (acesso total, o padrão), read_only (somente GET / HEAD) ou write_only (somente POST / PATCH / PUT / DELETE). Um token também pode ser bloqueado para uma única nota, para que possa ler ou anexar exatamente a esse fluxo e nada mais — útil como credencial por script. Uma solicitação fora do escopo do token retorna 403 forbidden com uma mensagem nomeando a restrição. Escolha o escopo ao criar o token.

Tokens de equipe

Workspaces no plano Team emitem tokens em /team/api_tokens (somente proprietário / administrador). Mesmo formato de fio do token Bearer, mesmos endpoints, mesmo envelope de erro — mas cada leitura e escrita resolve para as notas, pastas e pool de armazenamento da equipe, em vez do pool pessoal do ator.

  • GET /notes lista apenas as notas da equipe; as notas pessoais do ator nunca aparecem.
  • POST /notes cria com team_id definido; o user_id da linha registra o ator (quem escreveu) para o log de auditoria em /team/audit_events.
  • /folders/*, /notes/bulk e /notes/:id/move são sensíveis a escopo — um token de equipe só vê as pastas da equipe, nunca as pessoais, e recusa colocação entre pools com 404 not_found.
  • Armazenamento, limites de taxa e limites por nível vêm da assinatura da equipe, não do ator. O envio em massa é habilitado em todo token de equipe — a assinatura da equipe é o direito.

O limite de tokens ativos de uma equipe é de 30 tokens ativos por vez. A revogação fica no mesmo painel — tokens revogados permanecem listados para auditoria, mas param de autenticar imediatamente.

Endpoints

MétodoCaminhoFinalidade
GET/notesListar notas (resumo). Filtrar por ?format=plain|rich, ?folder_id=N (ou none para sem pasta). Ordenar por ?sort=created|updated|appended (padrão: atualizado). Paginar com ?limit=N&offset=N (máx. 200/página).
GET/notes/:idNota completa (plain_body + byte_size).
POST/notesCriar nota de texto simples. Corpo: {note: {title, plain_body, folder_id?, append_only?, client_encrypted?}}. client_encrypted: true armazena uma nota que você criptografou localmente com sua própria chave — mantida literalmente, nunca lida ou indexada (somente contas pessoais; imutável após a criação).
PATCH/notes/:idAtualizar título / plain_body / configurações. O formato é imutável. Em notas somente-anexação, campos de conteúdo são recusados, mas configurações (folder_id, append_deadline_hours, alert_email, webhook_url, webhook_secret) são aceitas.
DELETE/notes/:idExcluir nota.
POST/notes/:id/appendAnexação atômica a plain_body. Corpo: {text}.
POST/notes/:id/moveMover para pasta. Corpo: {folder_id} ou null.
GET/notes/by-filename/:filenameEncontrar por nome de arquivo em vez de id.
PATCH/notes/by-filename/:filenameMesma forma de corpo que PATCH /notes/:id, endereçada pelo nome do fluxo. Útil para reconfigurar a nota de um script (prazo, URL de webhook) sem primeiro procurar o id.
POST/notes/by-filename/:filename/appendEndereçamento de fluxo — anexar por nome de arquivo. Cria a nota se ausente (somente-anexação por padrão). No primeiro toque, client_encrypted: true a abre como fluxo criptografado pelo cliente — envie uma linha de ciphertext autocontida por anexação (somente contas pessoais). Ignorado quando a nota já existe.
POST/notes/bulkAté 50 criações por chamada. Corpo: {notes: [...]}.
GET/foldersListar pastas.
GET/folders/:idMostrar uma única pasta.
POST/foldersCriar pasta. Corpo: {folder: {name}}.
PATCH/folders/:idRenomear pasta.
DELETE/folders/:idExcluir pasta. As notas dentro são preservadas (sem pasta).

Limites de taxa

  • Dev: 600 leituras / 60 escritas / 300 anexações por minuto, por token. 3 tokens ativos. 15 GB de armazenamento. Endpoint em massa habilitado.
  • Team: 2.000 leituras / 200 escritas / 1.000 anexações por minuto, por token. 30 tokens ativos por equipe. 50 GB de armazenamento do workspace. Endpoint em massa habilitado. 50.000 notas de texto simples / 1.000 notas ricas por equipe.

Solicitações limitadas retornam 429 rate_limited com os cabeçalhos Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining e X-RateLimit-Reset.

A divisão completa por nível — incluindo limites de tamanho por nota, limites de superfície do navegador, tetos de paginação, política de expiração de token e a janela de exportação — está na página Service limits.

Repetições idempotentes

Todo endpoint de escrita (POST, PATCH, PUT, DELETE) aceita um cabeçalho de solicitação Idempotency-Key. Uma solicitação repetida com a mesma chave + mesma impressão digital de corpo reproduz a resposta original em vez de executar a ação duas vezes — seguro para repetições de "a solicitação anterior foi bem-sucedida antes do meu timeout?" em jobs cron e scripts de CI.

  • Cabeçalho: Idempotency-Key: <your-key>
  • Formato da chave: 8..255 caracteres. UUIDs funcionam; qualquer string nesse intervalo também.
  • Janela de repetição: 24 horas. Depois disso, a mesma chave é aceita como uma nova solicitação.
  • Repetições carregam Idempotent-Replay: true na resposta para que seu cliente possa identificar.

Uma chave repetida com uma impressão digital de corpo diferente retorna 409 idempotency_key_conflict — o servidor se recusa a sobrescrever silenciosamente a resposta de uma solicitação anterior. Repita com o corpo original ou gere uma nova chave.

curl -X POST https://freshjots.com/api/v1/notes \
  -H "Authorization: Bearer $FRESH_JOTS_TOKEN" \
  -H "Idempotency-Key: cron-2026-05-06-evening-digest" \
  -H "Content-Type: application/json" \
  -d '{"note":{"title":"Evening digest","plain_body":"...","format":"plain"}}'

Envelope de erro

Todas as respostas de erro compartilham a mesma forma:

{ "error": { "code": "validation_failed", "message": "Title can't be blank", "details": ["Title can't be blank"] } }

Códigos de erro estáveis:

  • unauthenticated — token ausente / inválido (401)
  • forbidden — token sem acesso à API, fora do escopo ou conta não confirmada (403)
  • note_locked — atualização ou exclusão tentada em nota somente-anexação; apenas mais anexações são permitidas (403)
  • not_found — registro ausente ou pertencente a outro usuário (404)
  • validation_failed — entrada inválida ou violação de esquema (422)
  • cap_exceeded — contagem de notas acima do limite do seu nível (422)
  • storage_cap_exceeded — total de bytes excederia seu limite de armazenamento (422)
  • content_too_large — nota única acima do limite de bytes por formato (413)
  • content_type_mismatch — tentativa de escrita de nota rica via API (422)
  • rate_limited — janela de limitação excedida (429)
  • idempotency_key_conflict — chave de repetição reutilizada com corpo diferente (409). Veja Repetições idempotentes acima.
  • service_unavailable — backend temporariamente inacessível; seguro repetir com backoff (503)

Watchdog e webhooks

Dois controles por nota para transformar um fluxo em substrato de monitoramento. Ambos são configurados via PATCH /notes/:id (ou PATCH /notes/by-filename/:filename) e também podem ser definidos na página de Configurações por nota na interface web. Ambos exigem que a nota seja somente-anexação; o sinalizador subjacente é definido na criação ({"append_only": true}) ou pelo alternador de bloqueio no navegador.

Alertas de interruptor de homem morto

Defina append_deadline_hours em uma nota somente-anexação (1–720) e o Fresh Jots envia um e-mail quando nenhuma anexação chega nessa janela. A próxima anexação limpa o alerta; se o script se recuperar e falhar novamente, você recebe um novo e-mail — sem redefinição manual. alert_email opcional substitui o destino (padrão: e-mail da sua conta).

curl -X PATCH https://freshjots.com/api/v1/notes/by-filename/cron-jobs-prod \
  -H "Authorization: Bearer $FRESHJOTS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"note":{"append_deadline_hours":2,"alert_email":"oncall@example.com"}}'

Webhooks de saída

Defina webhook_url em uma nota somente-anexação e cada anexação bem-sucedida faz POST do novo conteúdo para seu endpoint. Por padrão, o corpo é um envelope JSON assinado — HMAC-SHA256 no cabeçalho X-FreshJots-Signature (formato: sha256=<hex>) usando o webhook_secret que você configura; um segredo em branco assina com a string vazia, e o segredo nunca é lido de volta via API. Defina webhook_format como slack ou discord para enviar uma mensagem de chat nativa (veja "Formatos de payload" abaixo).

Dez respostas não-2xx consecutivas (ou falhas de transporte) desativam automaticamente o webhook para que um receptor morto não drene a fila de jobs. Reative-o salvando a nota novamente — seja com uma nova URL ou, após desativação automática, com a URL inalterada (o salvamento deliberado é o reconhecimento). webhook_failure_count e webhook_disabled_at são expostos em GET /notes/:id para monitoramento.

curl -X PATCH https://freshjots.com/api/v1/notes/by-filename/payments-prod \
  -H "Authorization: Bearer $FRESHJOTS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"note":{"webhook_url":"https://hooks.example.com/x","webhook_secret":"sk_..."}}'

Forma do payload:

{
  "event": "note.appended",
  "delivered_at": "2026-05-02T12:34:56Z",
  "delivery_id": "<uuid>",
  "note": {
    "id": 123, "filename": "payments-prod", "title": "payments-prod",
    "byte_size": 4096, "last_appended_at": "2026-05-02T12:34:55Z"
  },
  "appended_text": "...new chunk (capped at 8 KB)...",
  "appended_bytes": 42,
  "appended_truncated": false
}

Formatos de payload

webhook_format controla a forma do payload e aceita três valores: generic (padrão — o envelope note.appended assinado mostrado acima, para seu próprio servidor ou um hub de automação como Zapier / Make / n8n); slack (uma mensagem de chat nativa do Slack — cole uma URL https://hooks.slack.com/services/... e pronto, sem adaptador para escrever); e discord (a mesma ideia para URLs https://discord.com/api/webhooks/...). Defina pelo menu suspenso da página de Configurações ou pelo mesmo endpoint PATCH que aceita webhook_url / webhook_secret; o valor atual volta em cada GET /notes/:id. Uma nota sem definição usa o padrão generic.

Mensagens em formato de chat são truncadas para caber em cada plataforma: Slack para 3.500 caracteres, Discord para 1.900 caracteres sob o teto rígido de 2.000 caracteres do Discord no campo content. A prévia Genérica appended_text permanece inalterada (limitada a 8 KB; o corpo completo é sempre acessível via GET /notes/:id).

Entregas do Slack e Discord não são assinadas. Os webhooks de entrada de nenhuma das plataformas podem verificar uma assinatura, então o cabeçalho X-FreshJots-Signature é omitido completamente. Para esses formatos, a URL de hook impossível de adivinhar é a credencial; trate-a como senha. As regras de assinatura em "Verificando entregas" abaixo se aplicam apenas ao formato Genérico.

curl -X PATCH https://freshjots.com/api/v1/notes/by-filename/cron-jobs-prod \
  -H "Authorization: Bearer $FRESHJOTS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"note":{"webhook_url":"https://hooks.slack.com/services/T.../B.../...","webhook_format":"slack"}}'

Verificando entregas (somente Genérico)

Seu endpoint é uma URL pública, então verifique cada entrega antes de confiar nela. Defina o mesmo webhook_secret no seu servidor receptor, recalcule o HMAC sobre o corpo da solicitação bruto, não analisado, e compare com o cabeçalho X-FreshJots-Signature usando uma comparação de tempo constante. Rejeite em caso de incompatibilidade antes de analisar o JSON. (Se você configurou um segredo em branco, a chave é a string vazia.)

require "openssl"
require "active_support/security_utils"

SECRET = ENV.fetch("FRESHJOTS_WEBHOOK_SECRET")  # the same value you set on the note

def verified?(raw_body, header)
  expected = "sha256=#{OpenSSL::HMAC.hexdigest("SHA256", SECRET, raw_body)}"
  header.to_s.bytesize == expected.bytesize &&
    ActiveSupport::SecurityUtils.secure_compare(header.to_s, expected)
end

# Rails: verify request.raw_post (NOT params) against
# request.headers["X-FreshJots-Signature"], then head(:unauthorized) on false.

Atualizações ao vivo no navegador

Aviso: quando você tem uma nota aberta na interface web e uma escrita via API a atinge, apenas notas somente-anexação atualizam no lugar — o navegador assina um fluxo por usuário e substitui o corpo conforme novo conteúdo chega, sem precisar atualizar. Experimente: abra uma nota somente-anexação em uma aba e depois curl uma anexação de outra janela.

Notas editáveis (CRUD) atualizadas via API (PATCH /api/v1/notes/:id, POST /notes/:id/append em uma nota não bloqueada) não são enviadas para uma aba aberta no navegador — atualize a página para obter o novo conteúdo. Isso é por design: empurrar trocas de conteúdo no meio da edição colidiria com o autosave em andamento do editor.

Dúvidas? Fale comigo diretamente.