sgnl-mcp — MCP-сервер для SIGNAL Integration API
MCP-сервер, через который LLM-агент (Claude и др.) работает с документацией в SIGNAL: смотрит проекты и папки, ищет и скачивает документы, загружает новые документы и версии, работает с замечаниями, передачами и рассмотрениями.
Агент остаётся под контролем: чтение без ограничений, запись — только после предпросмотра и согласия пользователя, отправка передач и запуск рассмотрений — только после подтверждения пользователем в диалоге. Удалять, перемещать и переименовывать документы и папки, а также менять права агент не может вообще.
Построен на sgnl-api — обёртке над API из этого же репозитория.
Как обеспечивается контроль
| Рубеж | Что делает |
|---|---|
| 1. Scopes токена | Сервер запрашивает у SIGNAL только права своего профиля. В профиле read в токене нет ни одного права на запись — SIGNAL сам откажет. Права *:delete не запрашиваются никогда. |
| 2. Профиль | Инструменты выше профиля не регистрируются: агент их не видит. |
| 3. Белый список запросов | Каждый HTTP-запрос проверяется до отправки: только разрешённые метод и путь, никаких DELETE, никакого поля deleted в запросах на запись, внешние хосты — только для загрузки файла. |
| 4. Подтверждение | Запись — в два вызова: предпросмотр с токеном, затем выполнение с тем же токеном. Отправка передачи и запуск рассмотрения — через диалог подтверждения у пользователя (MCP elicitation). |
| 5. Клиент и аудит | Инструменты помечены readOnlyHint: клиент спрашивает разрешение на запись. Все записи и отказы пишутся в JSONL-журнал без секретов. |
Нагрузка на SIGNAL ограничена: по умолчанию не больше 3 запросов в секунду и 4 параллельных на весь сервер, у каждого вызова инструмента свой бюджет запросов, справочники кэшируются на 5 минут.
Установка
uvx sgnl-mcp # запуск без установки
# или
pip install sgnl-mcp
Нужен Python 3.11+.
Настройка
Вся настройка — через переменные окружения (или файл .env в рабочем каталоге). Агент не может их изменить.
| Переменная | Обязательна | По умолчанию | Назначение |
|---|---|---|---|
SGNL_CLIENT_ID |
да | — | Client ID интеграции SIGNAL |
SGNL_CLIENT_SECRET |
да | — | Client secret интеграции SIGNAL |
SGNL_MCP_PROFILE |
нет | read |
read, write или workflow |
SGNL_MCP_ACTOR_USER_ID |
для write/workflow |
— | ID пользователя SIGNAL, от имени которого делаются изменения (лучше служебная учётная запись «AI-агент») |
SGNL_MCP_UPLOAD_ROOT |
для write/workflow |
— | Каталог, из которого разрешено загружать файлы. Файлы вне него, в том числе через символические ссылки, недоступны |
SGNL_MCP_ALLOWED_EXTENSIONS |
нет | .pdf,.dwg,.dxf,… |
Разрешённые типы загружаемых файлов, через запятую |
SGNL_MCP_AUTO_CONFIRM |
нет | — | Write-инструменты, которые выполняются без предпросмотра (только для доверенных сценариев). Workflow сюда не входит |
SGNL_MCP_RATE_PER_SEC |
нет | 3 |
Запросов в секунду (не больше 10) |
SGNL_MCP_BURST |
нет | 6 |
Запас запросов для коротких всплесков |
SGNL_MCP_MAX_CONCURRENCY |
нет | 4 |
Параллельных запросов к SIGNAL |
SGNL_MCP_TOOL_TIMEOUT |
нет | 30 |
Таймаут вызова инструмента, с |
SGNL_MCP_UPLOAD_TIMEOUT |
нет | 600 |
Таймаут загрузки файла, с |
SGNL_MCP_CONFIRMATION_TTL_SEC |
нет | 300 |
Срок действия токена подтверждения |
SGNL_MCP_AUDIT_PATH |
нет | ~/.sgnl-mcp/audit.jsonl |
Журнал аудита |
SGNL_MCP_STATE_PATH |
нет | ~/.sgnl-mcp/state.sqlite |
Журнал выполненных операций (защита от повторов) |
При запуске сервер получает токен и проверяет, что интеграции выданы все права профиля, а для write/workflow — что пользователь SGNL_MCP_ACTOR_USER_ID есть в компании. Если что-то не так, сервер не запускается и пишет, чего не хватает.
Права интеграции по профилям
| Профиль | Scopes, которые должны быть выданы интеграции в SIGNAL |
|---|---|
read |
project:list, project:read, docs:folder:read, docs:folder:list, docs:item:list, docs:item:read, docs:version:list, docs:docs_transfer:list, docs:docs_transfer:read, docs:issue:list, docs:review:list, docs:signing:list, docs:attribute:list |
write |
всё из read + company:user:list, docs:object:create, docs:version:create, docs:version:update, docs:item:create, docs:docs_transfer:create, docs:docs_transfer:update, docs:issue:update, docs:review:create, docs:review:update |
workflow |
то же, что write |
Отправка передачи и запуск рассмотрения в SIGNAL используют те же права, что и их наполнение. Поэтому их отделяет сам MCP-сервер: в профиле write этих инструментов нет, а в workflow они всегда требуют подтверждения пользователя.
Подключение к Claude
Claude Desktop — claude_desktop_config.json:
{
"mcpServers": {
"sgnl": {
"command": "uvx",
"args": ["sgnl-mcp"],
"env": {
"SGNL_CLIENT_ID": "…",
"SGNL_CLIENT_SECRET": "…",
"SGNL_MCP_PROFILE": "read"
}
}
}
}
Claude Code:
claude mcp add sgnl -e SGNL_CLIENT_ID=… -e SGNL_CLIENT_SECRET=… -e SGNL_MCP_PROFILE=read -- uvx sgnl-mcp
Для профиля write добавьте SGNL_MCP_ACTOR_USER_ID и SGNL_MCP_UPLOAD_ROOT.
Разрешения в клиенте
- Инструменты чтения можно разрешить без вопросов.
- Инструменты записи и Workflow не добавляйте в «разрешить всегда»: клиент должен спрашивать перед каждым вызовом. Это один из рубежей контроля.
- Для профиля
workflowклиент должен поддерживать MCP elicitation (диалог подтверждения). Без неё отправка передач и запуск рассмотрений завершаются ошибкой и ничего не делают.
Инструменты
| Инструмент | Профиль | Что делает |
|---|---|---|
list_projects |
read | Проекты, доступные интеграции |
get_project |
read | Данные проекта и его корневая папка |
get_project_folder_tree |
read | Дерево папок с правами пользователя |
search_documents |
read | Поиск документов по проекту или папке (имя, расширение, автор, даты) |
list_folder_documents |
read | Документы одной папки (без вложенных) |
list_document_versions |
read | История версий документа |
get_document_version |
read | Связь «документ — версия файла» по item_version_id |
get_document_download_url |
read | Временная ссылка на скачивание версии (сам файл не передаётся) |
get_document_context |
read | Всё о документе за один вызов: версии, атрибуты, замечания, рассмотрения, подписи; у каждого блока свой статус |
list_document_transfers |
read | Передачи проекта с фильтрами |
get_document_transfer |
read | Полные данные передачи |
list_transfer_documents |
read | Документы в передаче |
list_document_transfer_types |
read | Типы передач проекта |
list_issues |
read | Замечания с фильтрами |
list_reviews |
read | Рассмотрения проекта |
get_review_details |
read | Версии рассмотрения и документы в них |
get_document_review_status |
read | Статус рассмотрения версий документов |
list_review_types |
read | Типы рассмотрений проекта |
upload_document |
write | Новый документ из файла |
add_document_version |
write | Новая версия существующего документа |
update_document_version_comment |
write | Комментарий версии |
create_document_transfer |
write | Новая передача (черновик) |
add_documents_to_transfer |
write | Добавить версии документов в неотправленную передачу |
update_issues |
write | Изменить 1–25 замечаний |
create_review |
write | Новое рассмотрение (черновик) |
add_documents_to_review |
write | Добавить до 20 версий документов в рассмотрение |
prepare_send_document_transfer |
workflow | Проверить передачу перед отправкой и получить токен |
send_document_transfer |
workflow | Отправить передачу (подтверждение пользователем в диалоге) |
prepare_start_review |
workflow | Проверить рассмотрение перед запуском и получить токен |
start_review |
workflow | Запустить рассмотрение (подтверждение пользователем в диалоге) |
Как проходит запись
- Агент вызывает инструмент без
confirmation_token. Сервер проверяет объекты и возвращает предпросмотр («было → станет», путь папки, состав передачи и т.п.) и токен. В SIGNAL ничего не меняется. - Агент показывает предпросмотр пользователю.
- После согласия агент вызывает инструмент с теми же аргументами и токеном. Сервер перепроверяет объекты: если с момента предпросмотра что-то изменилось (другой файл, кто-то правил замечание), токен отклоняется.
Токен одноразовый, действует 5 минут и привязан к аргументам. Повторный вызов с уже использованным токеном возвращает сохранённый результат, а не выполняет операцию второй раз.
Если запрос на запись завершился без ясного ответа (таймаут, ошибка сервера), сервер не повторяет его сам, а возвращает OUTCOME_UNKNOWN с тем, что удалось выяснить. Для загрузки файла можно завершить операцию параметром resume_version_id, не загружая файл заново.
Ограничения
- В API SIGNAL нет поиска передач по документу, поэтому блок
transfersвget_document_contextвсегдаnot_supported. - Создание замечаний, удаление, перемещение, переименование, изменение прав и пользователей в MCP-сервер намеренно не включены.
Ответы и ошибки
Все инструменты возвращают {"success": true, "data": …, "page": …, "warnings": […], "request_id": …} или {"success": false, "error": {"code", "message", "details"}, "request_id": …}.
| Код | Значение |
|---|---|
INVALID_REQUEST, NOT_FOUND, FORBIDDEN, AUTH_FAILED, QUOTA_EXCEEDED, RATE_LIMITED |
Ответ SIGNAL (400, 404, 403, 401, 450, 429) |
SERVER_ERROR, NETWORK_ERROR, TIMEOUT |
SIGNAL не ответил нормально; чтение можно повторить |
OUTCOME_UNKNOWN |
Запись могла пройти или не пройти; сервер её не повторял |
POLICY_DENIED |
Запрос запрещён политикой MCP-сервера |
CONFIRMATION_INVALID, CONFIRMATION_DECLINED |
Токен недействителен или пользователь не подтвердил |
INVALID_STATE, NOTHING_TO_DO, UPLOAD_FAILED, BUDGET_EXCEEDED |
Объект в неподходящем состоянии, изменять нечего, файл не передан, исчерпан бюджет запросов |
Metadata
Release files for sgnl-mcp 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| sgnl_mcp-0.1.0.tar.gz | 32.7 kB | Without provenance | Details for sgnl_mcp-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| sgnl_mcp-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for sgnl_mcp-0.1.0-py3-none-any.whl |
Total release size: 72.4 kB
Release files / sgnl_mcp-0.1.0.tar.gz
| Download URL | sgnl_mcp-0.1.0.tar.gz |
|---|---|
| Size | 32.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
10303ea1da7c2e4f34a0dd25b6a0a5c8028e9c8102b10d79392934dee2d95bdc
|
|
BLAKE2b-256 checksum How to use checksums |
831166c117733c31528505ec9805a2838508edc0980bc7f4a0c8bafe1b9d6549
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / sgnl_mcp-0.1.0-py3-none-any.whl
| Download URL | sgnl_mcp-0.1.0-py3-none-any.whl |
|---|---|
| Size | 39.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
af74521525a7c6abd517eab0380e3d2cb28acc5f3fe3cdded20d85310163ead3
|
|
BLAKE2b-256 checksum How to use checksums |
0cddc20b4b6066afbaa366e98a4c540e5c623ce534d324d0e6ca2d7924072ded
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for sgnl-mcp 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.