Skip to main content
Glama
llego
by llego

Anchor MCP

План реализации небольшого MCP-сайдкара, который предоставляет безопасные инструменты Anchor Notes для ChatGPT через туннельный клиент, работающий в том же Docker Compose стеке, что и Anchor.

Основа исследования: вышестоящий репозиторий Anchor ZhFahim/anchor, ветка по умолчанию main, проверено 2026-08-20. Anchor — это бэкенд на Nest.js с аутентифицированными REST-эндпоинтами в /api/*.

Цель

Запустить MCP-сервер рядом с Anchor, чтобы внешние ассистенты могли просматривать, искать, читать, создавать, обновлять, импортировать заметки Anchor и прикреплять к ним файлы, не раскрывая напрямую базу данных Anchor или его приватный API.

Related MCP server: NotesBridge

Текущий статус

Первый этап реализован:

  • Эндпоинт Streamable HTTP MCP на POST /mcp.

  • Эндпоинт проверки состояния на GET /healthz.

  • Инструменты Anchor только для чтения: anchor_list_notes, anchor_search_notes, anchor_get_note, anchor_list_tags, anchor_list_attachments.

  • Опциональная MCP-защита через bearer-токен с использованием ANCHOR_MCP_TOKEN.

  • Вызовы Anchor API используют ANCHOR_TOKEN и ANCHOR_BASE_URL.

  • Dockerfile включён.

Инструменты записи намеренно пока не реализованы.

Разработка

На NixOS используйте nix-shell для команд 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'

Локальный запуск:

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

MCP-эндпоинт: http://localhost:8000/mcp. Если задан ANCHOR_MCP_TOKEN, вызывающие стороны должны отправлять Authorization: Bearer <token>.

Модель развёртывания

Предполагаемый стек состоит из трёх сервисов:

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

MCP-сервер должен быть доступен только в Docker-сети. Туннельный клиент — единственный внешний мост.

Подтверждённая поверхность Anchor API

Все эндпоинты ниже защищены AuthGuard в Anchor и ожидают Authorization: Bearer <token>. Guard принимает токены Anchor, которые соответствуют активному пользователю.

Заметки:

  • 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

Теги:

  • POST /api/tags

  • GET /api/tags

  • GET /api/tags/:id

  • GET /api/tags/:id/notes

  • PATCH /api/tags/:id

  • DELETE /api/tags/:id

Вложения:

  • 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

Импорт/экспорт:

  • POST /api/import/notes

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

  • GET /api/export

Sync API:

  • POST /api/sync

  • GET /api/sync/events как server-sent events

Совместный доступ:

  • POST /api/notes/:id/shares

  • GET /api/notes/:id/shares

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

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

MCP-сервер должен начинать с обычных эндпоинтов заметок/тегов/вложений/импорта. Sync API полезен для офлайн-клиентов с учётом конфликтов, но MCP-сайдкар может на первых порах его не использовать.

Формы данных

Тело создания заметки:

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

Тело обновления заметки — это частичное тело создания плюс опциональная оптимистичная блокировка:

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

Anchor возвращает преобразованные заметки со следующими важными полями:

{
  "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": []
}

Тело импорта заметок:

{
  "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
}

Форма результата импорта:

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

Формы загрузки вложений:

  • Обычная загрузка вложения: multipart-поле file на POST /api/notes/:noteId/attachments.

  • Загрузка вложения при импорте: multipart-поле file плюс поле формы position на POST /api/import/notes/:noteId/attachments.

  • Ответ о вложении включает id, noteId, type, originalFilename, mimeType, fileSize, position, uploadedByUserId и createdAt.

Лимиты и валидация

Лимит списка заметок:

  • GET /api/notes ограничивает limit значениями 1..200.

Массовые лимиты:

  • noteIds: максимум 200.

  • tagIds: максимум 50.

Лимиты импорта:

  • Заметок в пакете: 50.

  • Длина строкового содержимого Delta: 1 000 000 байт/символов.

  • Длина заголовка: 1000.

  • Тегов на заметку: 50.

  • Тегов на пакет импорта: 500.

  • Длина имени тега: 100.

Лимиты вложений:

  • Максимальный размер файла: 50 МБ.

  • Разрешённые изображения: image/jpeg, image/png, image/webp, image/gif.

  • Разрешённый аудио: audio/mpeg, audio/wav, audio/mp4, audio/x-m4a, audio/ogg, audio/aac, audio/webm.

  • PDF, JSON, ZIP и универсальный application/octet-stream отклоняются текущим исходным кодом.

Фоновые идентификаторы, разрешённые при импорте:

  • 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.

Формат содержимого

Anchor хранит content заметки как строку. Существующая работа по импорту подтверждает, что для импорта форматированного текста это должен быть строковый JSON Quill Delta.

MCP-сервер должен предоставлять инструменты, дружественные к Markdown, и внутренне преобразовывать Markdown в Quill Delta. Позже он также сможет предоставлять нативные инструменты Delta для экспертного режима.

Рекомендуемая политика преобразования:

  • anchor_create_note принимает Markdown, преобразует в Delta, вызывает POST /api/notes.

  • anchor_update_note принимает Markdown, преобразует в Delta, вызывает PATCH /api/notes/:id с опциональным baseVersion.

  • anchor_import_notes принимает Markdown или нативный Delta, пакетирует через POST /api/import/notes.

  • anchor_get_note возвращает исходное содержимое плюс проекцию текста/Markdown по мере возможности для читаемости LLM.

Модель аутентификации

Исходный код Anchor извлекает bearer-токен из Authorization: Bearer <token>. Поэтому MCP-сайдкар должен поддерживать два уровня аутентификации:

  • ANCHOR_TOKEN: токен, который anchor-mcp использует при вызовах Anchor.

  • ANCHOR_MCP_TOKEN: токен, ожидаемый от туннельного клиента перед обработкой любого MCP-запроса.

MCP-сервер никогда не должен передавать произвольные токены вызывающих сторон в Anchor.

Ссылки на исходный код

Основные проверенные файлы в вышестоящем репозитории:

  • 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

Инструменты MCP

Инструменты чтения, фаза 1:

  • anchor_list_notes(limit, offset)

  • anchor_search_notes(query, limit)

  • anchor_get_note(note_id)

  • anchor_list_tags()

  • anchor_list_attachments(note_id)

Детали реализованных инструментов:

  • anchor_list_notes поддерживает limit, offset, include_content и tag_id. Поскольку Anchor предоставляет только листинг на основе лимита, offset + limit должно быть не более 200.

  • anchor_search_notes поддерживает query, limit, include_content и tag_id.

  • anchor_get_note поддерживает note_id и include_content.

  • anchor_list_tags не принимает входных данных.

  • anchor_list_attachments возвращает только метаданные и не скачивает байты вложений.

Инструменты записи, фаза 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)

Инструменты управления, фаза 3:

  • anchor_archive_notes(note_ids)

  • anchor_pin_notes(note_ids, is_pinned)

  • anchor_add_tags(note_ids, tag_ids)

  • anchor_export(), если туннельный клиент может обработать потоковый архив.

Избегать или ограничивать деструктивные инструменты:

  • anchor_delete_note(note_id, confirm) соответствует мягкому удалению и должен требовать confirm=true.

  • anchor_permanent_delete_note(note_id, confirm) следует на первых порах опустить.

  • anchor_delete_tag(tag_id, confirm) следует на первых порах опустить.

  • Не предоставлять сырой произвольный HTTP-прокси-инструмент.

Безопасность

  • Храните ANCHOR_TOKEN только в окружении Docker-стека или в .env; не встраивайте его в образ.

  • Добавьте отдельный ANCHOR_MCP_TOKEN для вызовов от туннельного клиента к anchor-mcp.

  • Привяжите MCP-сервер только к контейнерной сети; не добавляйте метки Traefik, если только не планируется намеренное раскрытие.

  • Держите инструменты узкими и типизированными. Не позволяйте вызывающим сторонам выбирать произвольные пути Anchor API.

  • Логируйте метаданные запросов, а не содержимое заметок или токены.

  • По умолчанию используйте инструменты только для чтения, пока путь туннельной аутентификации не будет проверен.

  • Требуйте явный confirm=true для мягкого удаления и массовых деструктивных действий.

  • Отказывайте в необратимом удалении, если только не задана отдельная настройка ENABLE_DANGEROUS_TOOLS=true.

Этапы реализации

  1. Создать минимальный TypeScript MCP HTTP-сервер.

  2. Добавить конфигурацию из окружения: ANCHOR_BASE_URL, ANCHOR_TOKEN, ANCHOR_MCP_TOKEN, хост/порт привязки.

  3. Реализовать /healthz для диагностики Docker и туннеля.

  4. Реализовать небольшой клиент Anchor API с типизированными методами и без произвольного обходного пути по путям.

  5. Реализовать anchor_list_notes, anchor_search_notes, anchor_get_note и anchor_list_tags.

  6. Добавить формирование ответов, которое отбрасывает тяжёлые поля, если они явно не запрошены.

  7. Реализовать вспомогательные функции преобразования Markdown в Delta и тесты.

  8. Реализовать создание/обновление с опциональной оптимистичной блокировкой через baseVersion.

  9. Реализовать пакетный импорт с учётом известных лимитов импорта.

  10. Реализовать загрузку вложений только для разрешённых изображений/аудио.

  11. Добавить Dockerfile и пример Compose, включая заглушку туннельного клиента.

  12. Добавить тесты с моками ответов Anchor и проверками валидации.

  13. Добавить эксплуатационную документацию по ротации токенов и подключению туннельного клиента ChatGPT.

Открытые вопросы

  • Точный образ туннельного клиента, переменные окружения и формат заголовка аутентификации.

  • Можно ли настроить или пропатчить Anchor, чтобы разрешить PDF и другие типы файлов.

  • Следует ли принимать содержимое заметок в Markdown и преобразовывать в Quill Delta, или MCP должен напрямую предоставлять нативный формат содержимого Anchor.

  • Сможет ли туннельный клиент достаточно хорошо передавать бинарные полезные нагрузки для загрузки вложений и скачивания экспорта.

  • Следует ли имитировать offset на стороне клиента, поскольку GET /api/notes предоставляет только limit, а не постраничную навигацию со смещением.

Рекомендуемый первый этап

Создайте MCP-сервер только для чтения с anchor_list_notes, anchor_search_notes, anchor_get_note и anchor_list_tags. Разверните его приватно в стеке Anchor за туннельным клиентом. Добавляйте создание/обновление/импорт только после проверки пути чтения и модели аутентификации.

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