by baruchiro (community) Claude Desktop, Paperless-NGX
MCP-сервер для управления документами в Paperless-NGX — self-hosted системе управления документами. Позволяет искать, читать и организовывать скан-архив через LLM. Возможности: - Поиск документов по содержимому, тегам, корреспонденту - Просмотр метаданных документа - Получение OCR-текста документа - Управление тегами и корреспондентами - Список документов с фильтрацией - Идеально для "спроси у своего архива" сценариев
# Claude Desktop — claude_desktop_config.json:
{
"mcpServers": {
"paperless": {
"command": "npx",
"args": ["-y", "@baruchiro/paperless-mcp@latest"],
"env": {
"PAPERLESS_URL": "http://your-paperless-instance:8000",
"PAPERLESS_API_KEY": "your_api_token"
}
}
}
}
# Claude Code (CLI):
claude mcp add paperless --env PAPERLESS_URL=http://localhost:8000 --env PAPERLESS_API_KEY=your_token -- npx -y @baruchiro/paperless-mcp@latest
# OpenCode — ~/.config/opencode/opencode.json:
{
"mcp": {
"paperless": {
"type": "local",
"command": ["npx", "-y", "@baruchiro/paperless-mcp@latest"],
"environment": {
"PAPERLESS_URL": "http://your-paperless-instance:8000",
"PAPERLESS_API_KEY": "your_api_token"
}
}
}
}
MCP (Model Context Protocol) сервер для взаимодействия с API сервером Paperless-NGX. Этот сервер предоставляет инструменты для управления документами, тегами, корреспондентами и типами документов в вашем экземпляре Paperless-NGX.
Добавьте следующее в ваш конфигурационный файл MCP:
// Режим STDIO (рекомендуется для локального использования или через CLI)
"paperless": {
"command": "npx",
"args": [
"-y",
"@baruchiro/paperless-mcp@latest",
],
"env": {
"PAPERLESS_URL": "http://your-paperless-instance:8000",
"PAPERLESS_API_KEY": "your-api-token",
"PAPERLESS_PUBLIC_URL": "https://your-public-domain.com"
}
}
// Режим HTTP (рекомендуется для Docker или удалённого использования)
"paperless": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"ghcr.io/baruchiro/paperless-mcp:latest",
],
"env": {
"PAPERLESS_URL": "http://your-paperless-instance:8000",
"PAPERLESS_API_KEY": "your-api-token",
"PAPERLESS_PUBLIC_URL": "https://your-public-domain.com"
}
}
Нажмите кнопку с круговой стрелкой для генерации нового токена
Замените плейсхолдеры в вашем конфиге MCP:
http://your-paperless-instance:8000 на URL вашего Paperless-NGXyour-api-token на токен, который вы только что сгенерировалиhttps://your-public-domain.com на публичный URL вашего Paperless-NGX (необязательно, по умолчанию используется PAPERLESS_URL)| Переменная | Обязательна | Значение по умолчанию | Описание |
|---|---|---|---|
PAPERLESS_URL |
Да | — | Базовый URL вашего экземпляра Paperless-NGX |
PAPERLESS_API_KEY |
Да | — | API токен из вашего профиля Paperless-NGX |
PAPERLESS_PUBLIC_URL |
Нет | PAPERLESS_URL |
Публичный URL для ссылок на документы |
PAPERLESS_API_VERSION |
Нет | 5 |
Версия REST API Paperless-ngx. Используйте 10 для Paperless-ngx v3+. Если вы видите ошибки HTTP 406, установите значение 10. |
PAPERLESS_MCP_UPLOAD_PATHS |
Нет | — | Список разрешённых директорий для загрузок через file_path, разделённых двоеточием. Рекомендуется для безопасности. Пример: /var/uploads:/tmp/scans |
Вот и всё! Теперь вы можете попросить Claude помочь вам управлять документами Paperless-NGX.
Вот что вы можете попросить Claude сделать:
Получить постраничный список всех документов.
Параметры: - page (необязательно): Номер страницы - page_size (необязательно): Количество документов на странице
list_documents({
page: 1,
page_size: 25
})
Получить конкретный документ по ID.
Параметры: - id: ID документа
get_document({
id: 123
})
Полнотекстовый поиск по документам.
Параметры: - query: Строка поискового запроса
search_documents({
query: "invoice 2024"
})
Скачать файл документа по ID.
Параметры: - id: ID документа - original (необязательно): Если true, скачивает оригинальный файл вместо архивированной версии
download_document({
id: 123,
original: false
})
Получить миниатюру документа (изображение-превью) по ID. Возвращает миниатюру как ресурс изображения WebP, закодированный в base64.
Параметры: - id: ID документа
get_document_thumbnail({
id: 123
})
Выполнить массовые операции над несколькими документами.
Параметры: - documents: Массив ID документов - method: Одно из значений: - set_correspondent: Установить корреспондента для документов - set_document_type: Установить тип документа для документов - set_storage_path: Установить путь хранения для документов - add_tag: Добавить тег к документам - remove_tag: Удалить тег у документов - modify_tags: Добавить и/или удалить несколько тегов - delete: Удалить документы - reprocess: Переобработать документы - set_permissions: Установить права доступа к документам - merge: Объединить несколько документов - split: Разделить документ на несколько документов - rotate: Повернуть страницы документа - delete_pages: Удалить определённые страницы из документа - Дополнительные параметры в зависимости от метода: - correspondent: ID для set_correspondent - document_type: ID для set_document_type - storage_path: ID для set_storage_path - tag: ID для add_tag/remove_tag - add_tags: Массив ID тегов для modify_tags - remove_tags: Массив ID тегов для modify_tags - permissions: Объект для set_permissions с полями owner, permissions, флагом merge - metadata_document_id: ID для merge для указания источника метаданных - delete_originals: Булево значение для merge/split - pages: Строка для split "[1,2-3,4,5-7]" или delete_pages "[2,3,4]" - degrees: Число для rotate (90, 180 или 270)
Примеры:
// Добавить тег к нескольким документам
bulk_edit_documents({
documents: [1, 2, 3],
method: "add_tag",
tag: 5
})
// Установить корреспондента и тип документа
bulk_edit_documents({
documents: [4, 5],
method: "set_correspondent",
correspondent: 2
})
// Объединить документы
bulk_edit_documents({
documents: [6, 7, 8],
method: "merge",
metadata_document_id: 6,
delete_originals: true
})
// Разделить документ на части
bulk_edit_documents({
documents: [9],
method: "split",
pages: "[1-2,3-4,5]"
})
// Изменить несколько тегов одновременно
bulk_edit_documents({
documents: [10, 11],
method: "modify_tags",
add_tags: [1, 2],
remove_tags: [3, 4]
})
// Изменить пользовательские поля
bulk_edit_documents({
documents: [12, 13],
method: "modify_custom_fields",
add_custom_fields: [
{ field: 2, value: "year" }
],
remove_custom_fields: []
})
// Установить пустое значение пользовательского поля, например, поле даты, используемое как маркер ожидания
bulk_edit_documents({
documents: [14],
method: "modify_custom_fields",
add_custom_fields: [
{ field: 9, value: "" }
],
remove_custom_fields: []
})
Загрузить новый документ в Paperless-NGX.
Два режима загрузки:
file (контент в кодировке base64) + filenamefile_path (абсолютный путь на сервере)Примечание по безопасности: При использовании file_path установите переменную окружения PAPERLESS_MCP_UPLOAD_PATHS (список разрешённых директорий, разделённых двоеточием) для ограничения загрузок определёнными расположениями. Без этого любой файл в файловой системе сервера может быть загружен.
Параметры:
- file (необязательно): Содержимое файла в кодировке base64. Требуется либо file, либо file_path.
- file_path (необязательно): Абсолютный путь к файлу в файловой системе сервера. Требуется либо file, либо file_path.
- filename (необязательно): Имя файла. Обязательно при использовании file, необязательно при использовании file_path (определяется из пути).
- title (необязательно): Заголовок документа
- created (необязательно): Дата и время создания документа (например, "2024-01-19" или "2024-01-19 06:15:00+02:00")
- correspondent (необязательно): ID корреспондента
- document_type (необязательно): ID типа документа
- storage_path (необязательно): ID пути хранения
- tags (необязательно): Массив ID тегов
- archive_serial_number (необязательно): Архивный серийный номер
- custom_fields (необязательно): Массив ID пользовательских полей
Ограничение размера файла: 100 МБ для обоих режимов
// Режим Base64 (традиционный)
post_document({
file: "base64_encoded_content",
filename: "invoice.pdf",
title: "January Invoice",
created: "2024-01-19",
correspondent: 1,
document_type: 2,
tags: [1, 3],
archive_serial_number: "2024-001",
custom_fields: [1, 2]
})
// Режим файловой системы (более эффективен для больших файлов)
post_document({
file_path: "/var/uploads/invoice.pdf",
title: "January Invoice",
correspondent: 1,
document_type: 2,
tags: [1, 3]
})
Получить все теги.
list_tags()
Создать новый тег.
Параметры: - name: Имя тега - color (необязательно): Цвет в формате HEX (например, "#ff0000") - match (необязательно): Текстовый шаблон для сопоставления - matching_algorithm (необязательно): Число от 0 до 6: 0 - Нет 1 - Любое слово 2 - Все слова 3 - Точное совпадение 4 - Регулярное выражение 5 - Нечёткое слово 6 - Автоматически
create_tag({
name: "Invoice",
color: "#ff0000",
match: "invoice",
matching_algorithm: 5
})
Получить всех корреспондентов.
list_correspondents()
Создать нового корреспондента.
Параметры: - name: Имя корреспондента - match (необязательно): Текстовый шаблон для сопоставления - matching_algorithm (необязательно): Число от 0 до 6: 0 - Нет 1 - Любое слово 2 - Все слова 3 - Точное совпадение 4 - Регулярное выражение 5 - Нечёткое слово 6 - Автоматически
create_correspondent({
name: "ACME Corp",
match: "ACME",
matching_algorithm: 5
})
Получить все типы документов.
list_document_types()
Создать новый тип документа.
Параметры: - name: Имя типа документа - match (необязательно): Текстовый шаблон для сопоставления - matching_algorithm (необязательно): Число от 0 до 6: 0 - Нет 1 - Любое слово 2 - Все слова 3 - Точное совпадение 4 - Регулярное выражение 5 - Нечёткое слово 6 - Автоматически
create_document_type({
name: "Invoice",
match: "invoice total amount due",
matching_algorithm: 1
})
Получить все пользовательские поля.
list_custom_fields()
Получить конкретное пользовательское поле по ID.
Параметры: - id: ID пользовательского поля
get_custom_field({
id: 1
})
Создать новое пользовательское поле.
Параметры: - name: Имя пользовательского поля - data_type: Одно из значений "string", "url", "date", "boolean", "integer", "float", "monetary", "documentlink", "select" - extra_data (необязательно): Дополнительные данные для пользовательского поля, такие как варианты для select
create_custom_field({
name: "Invoice Number",
data_type: "string"
})
Обновить существующее пользовательское поле.
Параметры: - id: ID пользовательского поля - name (необязательно): Новое имя пользовательского поля - data_type (необязательно): Новый тип данных - extra_data (необязательно): Дополнительные данные для пользовательского поля
update_custom_field({
id: 1,
name: "Updated Invoice Number",
data_type: "string"
})
Удалить пользовательское поле.
Параметры: - id: ID пользовательского поля
delete_custom_field({
id: 1
})
Выполнить массовые операции над несколькими пользовательскими полями.
Параметры: - custom_fields: Массив ID пользовательских полей - operation: Одно из значений "delete"
bulk_edit_custom_fields({
custom_fields: [1, 2, 3],
operation: "delete"
})
Инструменты для управления почтовыми учётными записями Paperless и почтовыми правилами, обеспечивающими автоматическую загрузку писем. Пароли/токены учётных записей никогда не отображаются: они заменяются на *** во всех ответах инструментов.
Получить список почтовых учётных записей, чтобы выбрать ID учётной записи при создании почтового правила. Пароли заменены на ***.
Параметры: - page (необязательно): Номер страницы - page_size (необязательно): Количество результатов на странице
list_mail_accounts()
Получить одну почтовую учётную запись по ID. Поля пароля/токена заменены на ***.
Параметры: - id: ID почтовой учётной записи
get_mail_account({
id: 1
})
Вручную запустить обработку почты Paperless для одной учётной записи. Это может обработать письма, соответствующие активным почтовым правилам учётной записи.
Параметры: - id: ID почтовой учётной записи
process_mail_account({
id: 1
})
Получить список почтовых правил с опциональной пагинацией.
Параметры: - page (необязательно): Номер страницы - page_size (необязательно): Количество результатов на странице
list_mail_rules()
Получить одно почтовое правило по ID.
Параметры: - id: ID почтового правила
get_mail_rule({
id: 1
})
Создать почтовое правило. Сначала используйте list_mail_accounts для выбора учётной записи.
Обязательные параметры: - name: Имя правила - account: ID почтовой учётной записи - folder: Папка IMAP для сканирования (например, "INBOX")
Основные необязательные параметры: - enabled (по умолчанию true): Активно ли правило - filter_from / filter_to / filter_subject / filter_body: Сопоставление входящих писем - maximum_age: Обрабатывать только письма новее указанного количества дней - action: 1=Удалить, 2=Переместить в папку, 3=Отметить как прочитанное, 4=Пометить флагом, 5=Добавить тег - action_parameter: Целевая папка/тег для выбранного действия - assign_title_from: 1=Тема, 2=Имя вложения, 3=Не назначать - assign_tags / assign_correspondent / assign_document_type: Метаданные для применения - assign_correspondent_from: 1=Нет, 2=Адрес электронной почты, 3=Имя отправителя, 4=Использовать assign_correspondent - attachment_type: 1=Только вложения, 2=Все файлы, включая встроенные - consumption_scope: 1=Только вложения, 2=Полное письмо как .eml, 3=Оба варианта - pdf_layout: 0=Системная настройка по умолчанию, 1=Текст+HTML, 2=HTML+текст, 3=Только HTML, 4=Только текст
create_mail_rule({
name: "Invoices",
account: 1,
folder: "INBOX",
filter_subject: "invoice",
action: 3,
attachment_type: 1
})
Обновить существующее почтовое правило. Изменяются только те поля, которые вы указали.
Параметры:
- id: ID почтового правила
- ...любое из полей create_mail_rule для обновления
update_mail_rule({
id: 1,
enabled: false
})
Удалить почтовое правило. Требуется явный флаг подтверждения. Это изменяет поведение будущей загрузки почты, но не удаляет существующие документы.
Параметры:
- id: ID почтового правила
- confirm: Должно быть true для подтверждения удаления
delete_mail_rule({
id: 1,
confirm: true
})
Сервер будет отображать понятные сообщения об ошибках, если: - URL Paperless-NGX или API токен указаны неверно - Сервер Paperless-NGX недоступен - Запрошенная операция не удалась - Предоставленные параметры недействительны
Запуск набора юнит-тестов (внешние зависимости не требуются):
npm test
Набор E2E тестов запускает пустой экземпляр Paperless-ngx, компилированный MCP сервер и выполняет детерминированный последовательный сценарий через запросы tools/call — создаёт тег, корреспондента и тип документа, загружает PDF, затем выполняет list / get / search / download / thumbnail / bulk-edit для одного и того же документа. Без LLM и без клиента Paperless REST за пределами MCP.
Необходимые условия: Docker, Docker Compose и jq.
# 1. Собрать MCP сервер
npm run build
# 2. Запустить Paperless-ngx
docker compose -f docker-compose.e2e.yml up -d
# 3. Дождаться готовности Paperless и получить токен
TOKEN=$(curl -s -X POST http://localhost:8000/api/token/ \
-H 'Content-Type: application/json' \
-d '{"username":"admin","password":"admin123"}' | jq -r '.token')
# 4. Запустить MCP сервер
node build/index.js --http --port 3001 \
--baseUrl http://localhost:8000 --token "$TOKEN" &
MCP_PID=$!
# 5. Запустить E2E тесты
MCP_URL=http://localhost:3001/mcp \
PAPERLESS_URL=http://localhost:8000 \
PAPERLESS_TOKEN="$TOKEN" \
npm run test:e2e
# 6. Очистка
kill "$MCP_PID"
docker compose -f docker-compose.e2e.yml down -v
E2E тесты также автоматически запускаются в CI при каждом pull request и push в main, охватывая как CLI build/index.js, так и опубликованный Docker образ.
Хотите внести вклад или изменить сервер? Вот что вам нужно знать:
npm install
node server.js http://localhost:8000 your-test-token
Сервер построен с использованием: - litemcp: Фреймворк на TypeScript для создания MCP серверов - zod: Валидация схем с приоритетом TypeScript
Этот MCP сервер реализует эндпоинты из REST API Paperless-NGX. Для получения дополнительной информации об основном API см. официальную документацию.
MCP сервер может работать в двух режимах:
Это режим по умолчанию. Сервер взаимодействует через stdio, что подходит для CLI и прямых интеграций.
npm run start -- <baseUrl> <token>
Для запуска сервера как HTTP сервиса используйте флаг --http. Вы также можете указать порт с помощью --port (по умолчанию: 3000). Этот режим требует установки Express (он включён как зависимость).
npm run start -- <baseUrl> <token> --http --port 3000
POST /mcp на указанном порту./mcp вернут 405 Method Not Allowed.В HTTP режиме клиенты аутентифицируются, предоставляя API токен Paperless-NGX через стандартный заголовок Authorization:
Authorization: Bearer <paperless-ngx-api-token>
Токен передаётся напрямую в Paperless-NGX, поэтому права доступа Paperless каждого клиента обеспечиваются на протяжении всего процесса. Это позволяет одному экземпляру сервера обслуживать нескольких пользователей, каждый со своим токеном. Такое поведение применимо к обоим эндпоинтам /mcp и /sse.
⚠️ Изменение, не совместимое с предыдущими версиями, в v2.0.0 — HTTP режим теперь по умолчанию требует аутентификации.
Ранее запрос без заголовка
Authorizationмолча использовал токен сервераPAPERLESS_API_KEY, что делало HTTP эндпоинт доступным для любого, кто мог подключиться к порту. Начиная с v2.0.0, запросы безBearerтокена отклоняются с ошибкой401 Unauthorized. Серверный токен никогда не используется для неаутентифицированных запросов, если вы явно не включите его с помощью--no-auth.
| Сценарий | --no-auth выключен (по умолчанию) |
--no-auth включён |
|---|---|---|
Клиент отправляет Authorization: Bearer <tok> |
<tok> (от клиента) |
<tok> (от клиента) |
Нет заголовка, PAPERLESS_API_KEY / --token задан |
401 Unauthorized |
серверный токен |
| Нет заголовка, нет серверного токена | 401 Unauthorized |
401 Unauthorized |
Миграция с v1.x: если вы использовали старый механизм отката (общий PAPERLESS_API_KEY для клиентов, которые не отправляют токен), у вас есть два варианта:
Authorization: Bearer <paperless-token>.--no-auth, например, добавьте его к command/args Docker или к вашей команде в CLI. Для этого необходим серверный токен (PAPERLESS_API_KEY или --token).Развёртывание с помощью Docker
MCP сервер может быть развёрнут с помощью Docker и Docker Compose. Docker образ автоматически запускается в HTTP режиме с поддержкой SSE (Server-Sent Events) на порту 3000.
Создайте файл docker-compose.yml:
services:
paperless-mcp:
container_name: paperless-mcp
image: ghcr.io/baruchiro/paperless-mcp:latest
environment:
- PAPERLESS_URL=http://your-paperless-ngx-server:8000
- PAPERLESS_API_KEY=your-paperless-api-key
- PAPERLESS_PUBLIC_URL=https://paperless-ngx.yourpublicurl.com
ports:
- "3000:3000"
restart: unless-stopped
Затем выполните:
docker-compose up -d
Если вы используете расширение Continue для VS Code, вы можете настроить его для работы с Dockerизированным MCP сервером через SSE.
Создайте или отредактируйте файл .continue/mcpServers/paperless-mcp.yaml в корне вашего рабочего пространства:
name: Paperless
version: 0.0.1
schema: v1
mcpServers:
- name: Paperless
type: sse
url: http://localhost:3000/sse
Примечания:
- Замените localhost на IP-адрес или имя хоста Docker, если сервер запущен на удалённой машине
- Docker контейнер обрабатывает аутентификацию через переменные окружения, поэтому указывать учётные данные в конфиге Continue не нужно
- SSE эндпоинт доступен по адресу /sse на настроенном порту (по умолчанию: 3000)
Этот проект является форком nloui/paperless-mcp. Большое спасибо автору оригинала за его работу. Вклады и улучшения могут быть возвращены в основной репозиторий.
Для отладки MCP сервера в VS Code используйте следующую конфигурацию запуска:
{
"type": "node",
"request": "launch",
"name": "Debug Paperless MCP (HTTP, ts-node ESM)",
"program": "${workspaceFolder}/node_modules/ts-node/dist/bin.js",
"args": [
"--esm",
"src/index.ts",
"--http",
"--baseUrl",
"http://your-paperless-instance:8000",
"--token",
"your-api-token",
"--port",
"3002"
],
"env": {
"NODE_OPTIONS": "--loader ts-node/esm",
},
"console": "integratedTerminal",
"skipFiles": [
"<node_internals>/**"
]
}
Важно: Перед отладкой раскомментируйте следующую строку в src/index.ts (примерно на строке 175):
// await new Promise((resolve) => setTimeout(resolve, 1000000));
Это предотвратит немедленное завершение работы сервера и позволит вам устанавливать точки останова и отлаживать код.