Skip to main content
Glama
llego
by llego

Anchor MCP

Plan de implementación para un sidecar MCP pequeño que expone herramientas seguras de Anchor Notes a ChatGPT a través de un cliente de túnel que se ejecuta en la misma pila de Docker Compose que Anchor.

Base de investigación: repositorio upstream de Anchor ZhFahim/anchor, rama predeterminada main, inspeccionado el 2026-08-20. Anchor es un backend de Nest.js con endpoints REST autenticados bajo /api/*.

Objetivo

Ejecutar un servidor MCP junto a Anchor para que asistentes externos puedan listar, buscar, leer, crear, actualizar, importar y adjuntar archivos a las notas de Anchor sin exponer la base de datos de Anchor ni su API privada directamente.

Related MCP server: NotesBridge

Estado actual

El primer hito está implementado:

  • Endpoint MCP HTTP transmisible por stream en POST /mcp.

  • Endpoint de salud en GET /healthz.

  • Herramientas de solo lectura de Anchor: anchor_list_notes, anchor_search_notes, anchor_get_note, anchor_list_tags, anchor_list_attachments.

  • Guarda MCP opcional con portador usando ANCHOR_MCP_TOKEN.

  • Las llamadas a la API de Anchor usan ANCHOR_TOKEN y ANCHOR_BASE_URL.

  • Se incluye el Dockerfile.

Las herramientas de escritura no están implementadas intencionalmente todavía.

Desarrollo

En NixOS, usa nix-shell para los comandos de Node/npm:

nix-shell -p nodejs --run 'npm install'
nix-shell -p nodejs --run 'npm run typecheck'
nix-shell -p nodejs --run 'npm run build'

Ejecutar localmente:

ANCHOR_BASE_URL=https://anchor.cri.su \
ANCHOR_TOKEN=... \
ANCHOR_MCP_TOKEN=... \
nix-shell -p nodejs --run 'npm run dev'

El endpoint MCP es http://localhost:8000/mcp. Si ANCHOR_MCP_TOKEN está definido, los llamadores deben enviar Authorization: Bearer <token>.

Modelo de despliegue

La pila prevista tiene tres servicios:

services:
  anchor:
    # Existing Anchor service.

  anchor-mcp:
    build: /path/to/anchor-mcp
    environment:
      ANCHOR_BASE_URL: http://anchor:3000
      ANCHOR_TOKEN: ${ANCHOR_TOKEN}
      ANCHOR_MCP_TOKEN: ${ANCHOR_MCP_TOKEN}
    expose:
      - "8000"
    depends_on:
      - anchor

  chatgpt-tunnel-client:
    # Outbound tunnel client.
    environment:
      MCP_TARGET_URL: http://anchor-mcp:8000/mcp
      MCP_TARGET_TOKEN: ${ANCHOR_MCP_TOKEN}
    depends_on:
      - anchor-mcp

El servidor MCP solo debe ser accesible en la red de Docker. El cliente de túnel es el único puente externo.

Superficie confirmada de la API de Anchor

Todos los endpoints siguientes están protegidos por el AuthGuard de Anchor y esperan Authorization: Bearer <token>. La guarda acepta tokens de Anchor que se resuelven a un usuario activo.

Notas:

  • POST /api/notes

  • GET /api/notes?search=<query>&tagId=<tagId>&limit=<limit>

  • GET /api/notes/:id

  • PATCH /api/notes/:id

  • DELETE /api/notes/:id

  • DELETE /api/notes/:id/permanent

  • PATCH /api/notes/:id/restore

  • GET /api/notes/trash

  • GET /api/notes/archive

  • POST /api/notes/bulk/delete

  • POST /api/notes/bulk/archive

  • POST /api/notes/bulk/pin

  • POST /api/notes/bulk/tags

Etiquetas:

  • POST /api/tags

  • GET /api/tags

  • GET /api/tags/:id

  • GET /api/tags/:id/notes

  • PATCH /api/tags/:id

  • DELETE /api/tags/:id

Adjuntos:

  • POST /api/notes/:noteId/attachments

  • GET /api/notes/:noteId/attachments

  • GET /api/notes/:noteId/attachments/:id

  • DELETE /api/notes/:noteId/attachments/:id

  • PATCH /api/notes/:noteId/attachments/reorder

Importación/exportación:

  • POST /api/import/notes

  • POST /api/import/notes/:noteId/attachments

  • GET /api/export

API de sincronización:

  • POST /api/sync

  • GET /api/sync/events como eventos enviados por el servidor

Compartición:

  • POST /api/notes/:id/shares

  • GET /api/notes/:id/shares

  • PATCH /api/notes/:id/shares/:shareId

  • DELETE /api/notes/:id/shares/:shareId

El servidor MCP debería comenzar con endpoints normales de notas/etiquetas/adjuntos/importación. La API de sincronización es útil para clientes offline conscientes de conflictos, pero un sidecar MCP puede omitirla inicialmente.

Formas de datos

Cuerpo de creación de nota:

{
  "title": "string",
  "content": "optional string",
  "isPinned": false,
  "isArchived": false,
  "background": "optional string",
  "tagIds": ["tag-id"]
}

El cuerpo de actualización de nota es un cuerpo de creación parcial más bloqueo optimista opcional:

{
  "title": "optional string",
  "content": "optional string",
  "isPinned": false,
  "isArchived": false,
  "background": "optional string",
  "tagIds": ["tag-id"],
  "baseVersion": 1
}

Anchor devuelve notas transformadas con estos campos importantes:

{
  "id": "uuid",
  "title": "string",
  "content": "string or null",
  "version": 1,
  "isPinned": false,
  "isArchived": false,
  "background": null,
  "state": "active",
  "createdAt": "iso timestamp",
  "updatedAt": "iso timestamp",
  "userId": "uuid",
  "tagIds": ["tag-id"],
  "permission": "owner",
  "attachmentCount": 0,
  "imagePreviewIds": []
}

Cuerpo de importación de notas:

{
  "notes": [
    {
      "ref": "external stable reference, max 256 chars",
      "id": "optional uuid",
      "title": "string",
      "content": "stringified Quill Delta JSON",
      "isPinned": false,
      "isArchived": false,
      "isTrashed": false,
      "background": "optional background id",
      "tagNames": ["tag name"],
      "createdAt": "iso timestamp",
      "updatedAt": "iso timestamp"
    }
  ],
  "tags": [{ "name": "tag", "color": "#8B5CF6" }],
  "skipExisting": true
}

Forma del resultado de importación:

{
  "results": [
    {
      "ref": "external reference",
      "status": "created | skipped | remapped | failed",
      "noteId": "uuid",
      "warning": "optional string",
      "error": "optional string"
    }
  ],
  "tags": { "created": 0, "reused": 0 }
}

Formas de carga de adjuntos:

  • Carga de nota normal: campo file multiparte hacia POST /api/notes/:noteId/attachments.

  • Carga de adjunto de importación: campo file multiparte más campo de formulario position hacia POST /api/import/notes/:noteId/attachments.

  • La respuesta de adjunto incluye id, noteId, type, originalFilename, mimeType, fileSize, position, uploadedByUserId y createdAt.

Límites y validación

Límite de listado de notas:

  • GET /api/notes limita limit a 1..200.

Límites de operaciones masivas:

  • noteIds: máximo 200.

  • tagIds: máximo 50.

Límites de importación:

  • Notas por lote: 50.

  • Longitud del contenido Delta serializado: 1.000.000 bytes/caracteres.

  • Longitud del título: 1000.

  • Etiquetas por nota: 50.

  • Etiquetas por lote de importación: 500.

  • Longitud del nombre de etiqueta: 100.

Límites de adjuntos:

  • Tamaño máximo de archivo: 50 MB.

  • Imágenes permitidas: image/jpeg, image/png, image/webp, image/gif.

  • Audio permitido: audio/mpeg, audio/wav, audio/mp4, audio/x-m4a, audio/ogg, audio/aac, audio/webm.

  • PDF, JSON, ZIP y application/octet-stream genérico son rechazados por la fuente actual.

Identificadores de fondo permitidos por la importación:

  • color_red, color_orange, color_yellow, color_green, color_teal, color_blue, color_dark_blue, color_purple, color_pink, color_brown.

  • pattern_dots, pattern_grid, pattern_lines, pattern_waves, pattern_groceries, pattern_music, pattern_travel, pattern_code.

Formato de contenido

Anchor almacena el content de la nota como una cadena. El trabajo de importación existente confirma que debe ser JSON de Quill Delta serializado para la importación de texto enriquecido.

El servidor MCP debería exponer herramientas amigables con Markdown y convertir Markdown a Quill Delta internamente. También puede exponer herramientas nativas de Delta para modo experto más adelante.

Política de conversión recomendada:

  • anchor_create_note acepta Markdown, lo convierte a Delta y llama a POST /api/notes.

  • anchor_update_note acepta Markdown, lo convierte a Delta y llama a PATCH /api/notes/:id con baseVersion opcional.

  • anchor_import_notes acepta Markdown o Delta nativo, procesa en lotes mediante POST /api/import/notes.

  • anchor_get_note devuelve el contenido bruto más una proyección de texto/Markdown de mejor esfuerzo para la legibilidad del LLM.

Modelo de autenticación

La fuente de Anchor usa extracción de token de portador desde Authorization: Bearer <token>. El sidecar MCP debería mantener por tanto dos capas de autenticación:

  • ANCHOR_TOKEN: token usado por anchor-mcp al llamar a Anchor.

  • ANCHOR_MCP_TOKEN: token esperado del cliente de túnel antes de atender cualquier solicitud MCP.

El servidor MCP nunca debe reenviar tokens arbitrarios del llamador a Anchor.

Referencias de la fuente

Archivos principales inspeccionados upstream:

  • server/src/notes/controllers/notes.controller.ts

  • server/src/notes/controllers/note-attachments.controller.ts

  • server/src/notes/controllers/note-shares.controller.ts

  • server/src/tags/tags.controller.ts

  • server/src/import-export/import.controller.ts

  • server/src/import-export/export.controller.ts

  • server/src/sync/sync.controller.ts

  • server/src/sync/sync-events.controller.ts

  • server/src/notes/dto/create-note.dto.ts

  • server/src/notes/dto/update-note.dto.ts

  • server/src/import-export/dto/import-notes.dto.ts

  • server/src/import-export/dto/import-attachment.dto.ts

  • server/src/notes/constants/notes.constants.ts

  • server/src/import-export/constants/import.constants.ts

  • server/src/notes/utils/note-transformer.util.ts

  • server/src/notes/utils/attachment-storage.util.ts

Herramientas MCP

Herramientas de lectura de la fase 1:

  • anchor_list_notes(limit, offset)

  • anchor_search_notes(query, limit)

  • anchor_get_note(note_id)

  • anchor_list_tags()

  • anchor_list_attachments(note_id)

Detalles de las herramientas implementadas:

  • anchor_list_notes admite limit, offset, include_content y tag_id. Dado que Anchor solo expone listado basado en límite, offset + limit debe ser como máximo 200.

  • anchor_search_notes admite query, limit, include_content y tag_id.

  • anchor_get_note admite note_id y include_content.

  • anchor_list_tags no recibe entrada.

  • anchor_list_attachments devuelve solo metadatos y no descarga los bytes de los adjuntos.

Herramientas de escritura de la fase 2:

  • anchor_create_note(title, markdown)

  • anchor_update_note(note_id, markdown, base_version)

  • anchor_import_notes(notes)

  • anchor_create_tag(name, color)

  • anchor_upload_attachment(note_id, file, filename, mime_type)

Herramientas de gestión de la fase 3:

  • anchor_archive_notes(note_ids)

  • anchor_pin_notes(note_ids, is_pinned)

  • anchor_add_tags(note_ids, tag_ids)

  • anchor_export() si el cliente de túnel puede manejar un archivo transmitido por stream.

Evitar o restringir herramientas destructivas:

  • anchor_delete_note(note_id, confirm) se asigna a eliminación suave y debe requerir confirm=true.

  • anchor_permanent_delete_note(note_id, confirm) debe omitirse inicialmente.

  • anchor_delete_tag(tag_id, confirm) debe omitirse inicialmente.

  • No exponer una herramienta proxy HTTP arbitraria en bruto.

Seguridad

  • Almacenar ANCHOR_TOKEN solo en el entorno de la pila Docker o en .env; no incrustarlo en la imagen.

  • Añadir un ANCHOR_MCP_TOKEN separado para las llamadas del cliente de túnel a anchor-mcp.

  • Vincular el servidor MCP solo a la red del contenedor; no añadir etiquetas de Traefik a menos que se exponga intencionalmente.

  • Mantener las herramientas estrechas y tipadas. No permitir que los llamadores elijan rutas arbitrarias de la API de Anchor.

  • Registrar metadatos de solicitudes, no contenido de notas ni tokens.

  • Predeterminar herramientas de solo lectura hasta que se verifique la ruta de autenticación del túnel.

  • Exigir confirm=true explícito para eliminación suave y acciones destructivas masivas.

  • Rechazar la eliminación permanente a menos que esté presente un ajuste separado ENABLE_DANGEROUS_TOOLS=true.

Fases de implementación

  1. Crear un servidor HTTP MCP mínimo en TypeScript.

  2. Añadir configuración desde el entorno: ANCHOR_BASE_URL, ANCHOR_TOKEN, ANCHOR_MCP_TOKEN, host/puerto de vinculación.

  3. Implementar /healthz para diagnóstico de Docker y túnel.

  4. Implementar un cliente pequeño de la API de Anchor con métodos tipados y sin vía de escape de rutas arbitrarias.

  5. Implementar anchor_list_notes, anchor_search_notes, anchor_get_note y anchor_list_tags.

  6. Añadir modelado de respuestas que elimine campos pesados a menos que se soliciten explícitamente.

  7. Implementar ayudantes de conversión de Markdown a Delta y pruebas.

  8. Implementar creación/actualización con bloqueo optimista opcional mediante baseVersion.

  9. Implementar procesamiento por lotes de importación con los límites de importación conocidos.

  10. Implementar carga de adjuntos solo para imágenes/audio permitidos.

  11. Añadir Dockerfile y ejemplo de Compose incluido el marcador de posición del cliente de túnel.

  12. Añadir pruebas con respuestas simuladas de Anchor y fallos de validación.

  13. Añadir documentación operativa para rotar tokens y conectar el cliente de túnel de ChatGPT.

Preguntas abiertas

  • Imagen exacta del cliente de túnel, variables de entorno y formato del encabezado de autenticación.

  • Si Anchor puede configurarse o parchearse para permitir PDF y otros tipos de archivo.

  • Si el contenido de las notas debe aceptarse como Markdown y convertirse a Quill Delta, o si el MCP debe exponer el formato de contenido nativo de Anchor directamente.

  • Si el cliente de túnel puede pasar cargas binarias lo suficientemente bien para la carga de adjuntos y la descarga de exportaciones.

  • Si offset debe simularse en el lado del cliente porque GET /api/notes solo expone limit, no paginación por desplazamiento.

Primer hito recomendado

Construir un servidor MCP de solo lectura con anchor_list_notes, anchor_search_notes, anchor_get_note y anchor_list_tags. Desplegarlo de forma privada en la pila de Anchor detrás del cliente de túnel. Añadir creación/actualización/importación solo después de verificar la ruta de lectura y el modelo de autenticación.

A
license - permissive license
Not graded
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    MCP server for AI agents to read, write, and organize notes in a local-first, human-in-the-loop note-taking app.
    0
    1
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    A secure multi-tenant MCP proxy that exposes 81 tools for full CRUD, search, chat, podcast, and command management on the OpenNotebook API, enabling natural language interaction with notebooks, notes, sources, and more.
    GPL 3.0

View all related MCP servers

Related MCP Connectors

  • Search, read, and write your Apple Notes from ChatGPT/Claude via a local Mac agent + MCP relay.

  • Search your AI chat history (ChatGPT, Claude, Codex) from any MCP client. Remote, private, read-only

  • Agent-native MCP server over the public saagarpatel.dev corpus. Read-only, stateless.

View all MCP Connectors

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/llego/anchor-mcp'

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