Metadata-Version: 2.4
Name: auto-assessor-mcp
Version: 0.1.0
Summary: MCP server for automatic assessment (grading) of tasks.
Author: Alexandr Latushkin
License-Expression: LicenseRef-Proprietary
Project-URL: Repository, https://gitverse.ru/alex314/auto_assessor_mcp
Keywords: mcp,assessment,grading,automation
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Operating System :: OS Independent
Classifier: Environment :: Console
Classifier: Topic :: Utilities
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: fastmcp>=4.0.5
Requires-Dist: uvicorn>=0.30
Requires-Dist: starlette>=0.40
Requires-Dist: typer>=0.9.0
Requires-Dist: pydantic>=2.0
Requires-Dist: pydantic-settings>=2.0
Requires-Dist: filelock>=3.13
Requires-Dist: pypdfium2>=4.30
Requires-Dist: Pillow>=10.0
Requires-Dist: openpyxl>=3.1
Requires-Dist: mammoth>=1.8
Requires-Dist: lxml>=5.0
Requires-Dist: pyyaml>=6.0
Requires-Dist: ruamel.yaml>=0.18
Provides-Extra: dev
Requires-Dist: python-docx>=1.1; extra == "dev"
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: pytest-cov>=4.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
Requires-Dist: ruff>=0.1.0; extra == "dev"
Requires-Dist: mypy>=1.0; extra == "dev"
Requires-Dist: types-PyYAML>=6.0; extra == "dev"
Requires-Dist: build>=1.0; extra == "dev"
Requires-Dist: twine>=5.0; extra == "dev"
Dynamic: license-file

# auto-assessor-mcp

MCP-сервер для автоматической оценки: принимает материалы компании, расшивает их на
части, читаемые моделью, и раздаёт исполнителям-субагентам задания по описанию содержимого.

Сервер работает **по HTTP** на локальном адресе и обслуживает нескольких агентов
одновременно. Экземпляр всегда один на Хранилище.

Сервер осмыслен только вместе с развёрнутым дистрибутивом АРМ: в нём лежат справочники и
данные компаний.

## Термины и расположение файлов

```
<Базовый каталог>/
    .auto_assessor.env     Файл настроек  (создаётся при первом запуске)
    .auto_assessor/        Хранилище      (наше: пишет только сервер)
    assessments/           АРМ            (чужое: сервер только читает)
```

| Термин | Что это |
|---|---|
| **Базовый каталог** | `$WORK`, если задана и не пуста, иначе домашний каталог пользователя |
| **Хранилище** | всё, что порождает сервер: принятые материалы, журнал, служебные файлы |
| **Файл настроек** | `<Базовый каталог>/.auto_assessor.env`, настройки сервера |
| **АРМ** | развёрнутый дистрибутив АРМ Оценщика; по умолчанию `<Базовый каталог>/assessments` |
| **Данные оценок** | каталог `data/` внутри АРМ: анкеты, описания оценок |
| **Библиотека** | справочники методолога, входят в АРМ |

## Установка

```bash
pip install auto-assessor-mcp
```

## Запуск и остановка

Запустите сервер в фоне в начале работы. Команда безопасна: если сервер уже запущен, она
напечатает «уже запущен» и его адрес и завершится с кодом 0.

```bash
auto-assessor-mcp serve
```

Адрес по умолчанию — `http://127.0.0.1:17000/mcp` (добавьте его один раз в конфигурацию
MCP-клиента; он остаётся верным после перезапусков). Сервер работает, пока его не остановят:

```bash
auto-assessor-mcp stop
```

Обновление пакета: `stop`, затем обычный `serve`. Лог сервера — `logs/server.log` в Хранилище
(не путать с Журналом заданий, `journal/`, — см. ниже).
Без аргументов `auto-assessor-mcp` и `python -m auto_assessor_mcp` запускают `serve`.

### Настройки

Значение настройки берётся из первого доступного источника: параметр команды
(`serve --log-level`), переменная окружения процесса, Файл настроек, умолчание. Пустое
значение считается незаданным. Ключи Файла настроек называются так же, как переменные окружения.

| Настройка | Границы | Умолчание | Назначение |
|---|---|---|---|
| `AUTO_ASSESSOR_PORT` | 1–65535 | 17000 | порт (только `127.0.0.1`) |
| `AUTO_ASSESSOR_STORAGE_DIR` | путь | `.auto_assessor` в Базовом каталоге | Хранилище |
| `AUTO_ASSESSOR_ARM_DIR` | путь | `assessments` в Базовом каталоге | АРМ |
| `AUTO_ASSESSOR_LIBRARY_DIR` | путь | подкаталог `.gigacode/skills/auto-assessor/scripts/library` внутри текущего АРМ | Библиотека |
| `AUTO_ASSESSOR_LOG_LEVEL` | DEBUG, INFO, WARNING, ERROR | INFO | уровень журнала |
| `AUTO_ASSESSOR_EXPERT_ID` | строка 1–100 знаков | имя учётной записи ОС | происхождение записей Журнала |
| `AUTO_ASSESSOR_TASK_TIMEOUT_SECONDS` | 1–86400 | 900 | через сколько невозвращённое задание снова выдаётся |
| `AUTO_ASSESSOR_PARTS_PER_TASK` | 1–50 | 10 | частей материала в одном задании описания |
| `AUTO_ASSESSOR_MAX_FILE_SIZE_MB` | 1–10240 | 200 | наибольший принимаемый файл |
| `AUTO_ASSESSOR_MAX_PARTS_PER_MATERIAL` | 1–5000 | 500 | наибольшее число частей материала |
| `AUTO_ASSESSOR_MAX_SHEET_ROWS` | 1–1000000 | 2000 | строк листа Excel в тексте части |
| `AUTO_ASSESSOR_MAX_DOC_PART_CHARS` | 1000–200000 | 60000 | длина документа Word, выше которой он делится на части |
| `AUTO_ASSESSOR_MAX_IMAGE_SIDE` | 256–10000 | 3000 | наибольшая сторона изображения части, пикселей |
| `AUTO_ASSESSOR_SYNC_REPO` | URL либо путь к репозиторию git, без пароля в адресе | не задана (синхронизация выключена) | центральный репозиторий, куда `sync` отправляет Журнал, архив и Итоги Требований |
| `AUTO_ASSESSOR_PRECEDENTS_REPO` | URL либо путь к репозиторию git, без пароля в адресе; не совпадает с `AUTO_ASSESSOR_SYNC_REPO` | не задана (обмен прецедентами выключен) | Репозиторий прецедентов: `sync` отправляет в него кандидатов в прецеденты и получает общую базу |
| `AUTO_ASSESSOR_COMPLETENESS_MAX_CHARS` | 1000–1000000 | 20000 | потолок знаков на задание `assess_completeness` |
| `AUTO_ASSESSOR_COMPLETENESS_MAX_REQUIREMENTS` | 1–500 | 15 | потолок требований на задание `assess_completeness` |
| `AUTO_ASSESSOR_BINDING_MAX_CHARS` | 1000–1000000 | 20000 | потолок знаков Кейса на задание `bind_materials` |
| `AUTO_ASSESSOR_BINDING_MAX_MATERIALS` | 1–1000 | 100 | потолок материалов на задание `bind_materials` |
| `AUTO_ASSESSOR_ARTIFACT_MAX_CHARS` | 1000–1000000 | 20000 | потолок знаков Кейса на задание `verify_artifacts` |
| `AUTO_ASSESSOR_ARTIFACT_MAX_REQUIREMENTS` | 1–500 | 15 | потолок требований на задание `verify_artifacts` |
| `AUTO_ASSESSOR_VERDICT_MAX_CHARS` | 1000–1000000 | 60000 | потолок знаков на задание `assess_compliance` |
| `AUTO_ASSESSOR_VERDICT_MAX_REQUIREMENTS` | 1–500 | 15 | потолок требований на задание `assess_compliance` |
| `AUTO_ASSESSOR_PREFILL_MAX_CHARS` | 1000–1000000 | 20000 | потолок знаков разделов групп на задание `prefill_answers` (статья КА ДЗО, `metainfo` и глоссарий в вес не входят) |
| `AUTO_ASSESSOR_PREFILL_MAX_REQUIREMENTS` | 1–500 | 15 | потолок требований на задание `prefill_answers` |
| `AUTO_ASSESSOR_TASK_PAGE_MAX_CHARS` | 1000–1000000 | 20000 | бюджет страницы текста задания в знаках: `get_task` отдаёт задание страницами; уменьшите, если ответ уходит в файл |

**Доступ к репозиториям git.** `sync` вызывает системный `git` с окружением и настройками git того пользователя, под которым запущен Сервер: подхватываются ключи SSH (в том числе `ssh-agent`), помощники учётных данных git и `~/.netrc`. Ввод пароля не ждётся (`GIT_TERMINAL_PROMPT=0`, `BatchMode=yes`): если вход требует его, этап `sync` завершится ошибкой. Проверка: `git ls-remote <адрес>` без запроса пароля в терминале того же пользователя. При запуске службой или из cron `ssh-agent` и помощники учётных данных могут быть недоступны.

#### Файл настроек

- Лежит только в Базовом каталоге (`$WORK`, иначе домашний); запасного поиска в другом месте нет.
- Создаётся при первом запуске `serve` со всеми ключами, умолчаниями и пояснениями. Существующий
  файл сервер не перезаписывает и не дополняет. Если создать файл не удалось, сервер работает с
  умолчаниями и пишет предупреждение в журнал.
- Формат: `КЛЮЧ=ЗНАЧЕНИЕ`, по строке на настройку. Строки с `#` и пустые пропускаются, значение
  можно взять в кавычки, в значении без кавычек `#` после пробела начинает комментарий,
  обратная косая черта — обычный знак (пути Windows пишутся как есть). Если ключ повторён,
  действует последняя строка.
- Пути: `~` раскрывается; относительный путь из файла отсчитывается от каталога файла (поэтому
  `AUTO_ASSESSOR_STORAGE_DIR=.auto_assessor` означает Хранилище рядом с файлом).
- Правка действует после перезапуска (`stop`, затем `serve`), кроме `AUTO_ASSESSOR_ARM_DIR` и
  `AUTO_ASSESSOR_LIBRARY_DIR`: оба перечитываются при каждом обращении к АРМ и Библиотеке. Менять
  `AUTO_ASSESSOR_STORAGE_DIR` следует при остановленном сервере.
- `AUTO_ASSESSOR_LIBRARY_DIR` в создаваемом файле — закомментированная строка: умолчание зависит от
  текущего пути к АРМ, а не от Базового каталога, поэтому мнимый путь в файл не пишется.
- Ошибка в файле (нет знака `=`, неизвестный ключ `AUTO_ASSESSOR_*`, значение вне границ) —
  ошибка запуска с указанием файла и строки. Команда `stop` при этом работает: она проверяет
  только синтаксис файла и ключ `AUTO_ASSESSOR_STORAGE_DIR`.
- Секретов в файле нет: секрет остановки лежит в `admin.token` Хранилища.

Хранилище содержит `server.lock`, `server.json`, `admin.token`, `logs/`, `materials/`, `tasks/`
(записи заданий), `journal/` (Журнал заданий — вход, попытки, принятый результат каждого
задания; независим от `logs/server.log`), `blobs/` (архив шаблонов и справочников по содержимому).
АРМ сервер не создаёт и не меняет.
Сервер слушает только `127.0.0.1` и отклоняет запросы с чужими `Host` (421) и `Origin` (403).

## Как это работает

Два вида клиентов, роли разведены описаниями инструментов:

- **Ведущий** (основной агент): `accept_materials` (принять файл либо каталог по
  абсолютному пути; сервер сам копирует файлы), `list_materials` (реестр
  описаний), `list_tasks` (задания; `wait_seconds` — подождать расшивку).
- **Исполнитель** (субагент): только `get_task` (получить текст задания с
  абсолютными путями файлов) и `submit_task_result` (сдать результат).

Расшивка идёт в фоне; документ на сто страниц описывается десятью небольшими заданиями и
одним итоговым.

### Оценка в АРМ

Три инструмента Ведущего принимают `assessment_ref` и требуют, чтобы Оценка была объявлена
в Данных оценок АРМ (блок `sber.dka-dzo.assessment` в любом файле `*.yaml` каталога `data/`;
имя файла и `imports` не важны). Без развёрнутого АРМ они отказывают ошибкой «АРМ не найден»
с названием ключа `AUTO_ASSESSOR_ARM_DIR`.

| Инструмент | Оценки нет в Данных оценок | Оценка закрыта (`finished`, `cancelled`) |
|---|---|---|
| `accept_materials` | отказ, ни один файл не принят | отказ, ни один файл не принят |
| `list_materials` | отказ (не пустой список) | читается |
| `list_tasks` | отказ, без ожидания `wait_seconds` | читается |

Статус Оценки читается при каждом вызове: правка файла в АРМ действует без перезапуска
сервера. Любой другой статус (`preparation_start`, `in_progress`, незнакомый) и отсутствие
поля `status` приём не останавливают. Если одна Оценка объявлена в нескольких файлах с
разными статусами, приём отказывает, а чтение работает. Закрытие Оценки после приёма ничего
не меняет в принятых материалах и уже выданных заданиях: исполнители (`get_task`,
`submit_task_result`) от АРМ не зависят. Тексты отказов не содержат путей;
пути файлов АРМ записаны в `logs/server.log`.

### Форматы

| Что | Форматы | Замечания |
|---|---|---|
| PDF | `.pdf` | страница = часть (текст и изображение) |
| Word | `.docx`, `.docm` | в Markdown с таблицами и картинками |
| Excel | `.xlsx`, `.xlsm` | лист = часть, до `MAX_SHEET_ROWS` строк |
| Изображения | `.png .jpg .jpeg .gif .bmp .webp .tif .tiff` | в PNG |

**Старые форматы не принимаются и не конвертируются:** `.doc`, `.rtf`, `.odt` — сохраните как
`.docx`; `.xls`, `.ods` — как `.xlsx`; презентации (`.ppt`, `.pptx`, `.odp`) — сохраните в PDF.

**Ограничение Word:** текст внутри надписей и фигур обычно попадает в текст документа, но сам
рисунок (связи, стрелки), диаграммы, SmartArt, встроенные объекты (OLE) и векторные
изображения (EMF/WMF) не передаются. Сервер это замечает и пишет пояснение в материал и в
текст задания; для передачи такого содержимого сохраните документ в PDF и приложите его.
Документы с патологической вложенностью (сотни таблиц в таблицах) отклоняются с советом
сохранить их в PDF.

## Разработка

```bash
git clone https://gitverse.ru/alex314/auto_assessor_mcp
cd auto_assessor_mcp
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"

pytest -q --no-cov --ignore=tests/test_process_lifecycle.py   # быстрые тесты (~30 с)
pytest -v                                                     # весь набор (~6 мин)
ruff check .
ruff format --check .
mypy src/
```

Все изменения проекта вносятся через [OpenSpec](openspec/) change proposals
(см. [CLAUDE.md](CLAUDE.md)), кроме тривиальных правок вроде `.gitignore`.

Важный инвариант устройства: изменения состояния — синхронные функции в цикле событий,
**без `await` между чтением и записью** (см. `storage/doc_store.py`); именно он делает
параллельные обращения безопасными без блокировок.

## Релиз

Публикация в PyPI выполняется автоматически по тегу `vX.Y.Z` на ветке `master`
(см. `.gitverse/workflows/publish.yml`).

## Лицензия

Proprietary — все права защищены, см. [LICENSE](LICENSE).
