Skip to main content
Glama
borgels

mcp-server-productive

by borgels

mcp-server-productive

MCP-сервер для API v2 Productive.io — проекты, задачи, учёт времени, планирование ресурсов, финансы, CRM и отчёты для одной организации.

Productive предоставляет около 650 операций над 132 ресурсами. Превращение их в 650 MCP-инструментов переполнило бы список инструментов любого клиента, поэтому этот сервер — двенадцать инструментов на основе сгенерированного реестра: инструменты универсальны, а реестр знает, что именно принимает каждый ресурс.

Инструменты

Обнаружениеproductive_search_capabilities, productive_describe_resource, productive_check_connection, productive_describe_custom_fields

Чтениеproductive_list (фильтры, сортировки, включения, постраничный вывод и 26 конечных точек отчётов с группировкой), productive_get

Записьproductive_create, productive_update, productive_delete, productive_run_action (150 именованных действий: archive, restore, approve, close, copy, finalize, send…), productive_track_time, productive_commit_operation

Авторизация для каждого пользователя (опционально)productive_connect, productive_status, productive_disconnect — см. Аутентификация

Начните с productive_search_capabilities. У Productive собственные имена ресурсов — бюджет — это deal, колонка доски — workflow_status, согласование табеля находится в time_entries, — и угадывание стоит запросов.

Related MCP server: productive-mcp-rb2

Реестр

src/productive/registry.generated.ts создаётся из опубликованного OpenAPI-документа Productive скриптом scripts/generate-registry.mjs и сохраняется в репозиторий, поэтому CI никогда не требует сети, а изменение спецификации видно как проверяемый дифф. Для каждого ресурса в нём записаны поля фильтров, ключи сортировки, ключи группировки отчётов, включаемые связи, атрибуты, доступные для записи при создании и обновлении, с помеченными обязательными, а также каждое именованное действие.

Именно это позволяет двенадцати инструментам оставаться честными. productive_describe_resource возвращает точный контракт для одного ресурса, и каждый аргумент проверяется по нему перед отправкой запроса.

Перегенерируйте с помощью npm run registry:generate (добавьте аргумент пути, чтобы использовать локальную копию спецификации). Генератор останавливает сборку, если рукописная классификация — уровень риска, флаг внешнего воздействия, заблокированная операция — больше не соответствует ни одному пути в спецификации, поэтому переименование на стороне API не может незаметно убрать защиту.

Что API делает, по результатам измерений

Всё здесь проверено на реальной организации, потому что спецификация и API расходятся в важных местах.

Время — в минутах. Деньги — в минимальных единицах. Запись времени 2 — это две минуты. И в ответе они приходят так же.

Неизвестные фильтры, сортировки и включения падают громко. HTTP 400 с unsupported_filter, sort_param_unsupported, unsupported_include. Поэтому проверка их здесь — это более качественная ошибка, а не страховочная сеть.

Неизвестные атрибуты записи падают молча. PATCH с опечаткой в атрибуте возвращает HTTP 200 и ничего не меняет — неотличимо от успеха. Поэтому этот сервер отказывает в атрибуте, который ресурс не объявляет, вместо того чтобы сообщить о записи, которой не было. Это самое полезное, что делает реестр.

Есть ровно шесть операторов фильтрации для каждого поля: contains, eq, gt, lt, not_contain, not_eq. Спецификация перечисляет четыре на поле и опускает gt/lt, которые работают; gte, lte, in, not_in, starts_with, ends_with, blank и present все отклоняются с unsupported_filter_operation. Не существует включающего сравнения, поэтому для включающего диапазона нужны собственные поля фильтра ресурса after/before или <field>_after/<field>_before.

page[size] ограничен 200 и молча урезается. Запрос 500 возвращает 200 без ошибки. Результаты содержат total и nextPage, чтобы страницу не приняли за весь ответ.

PATCH действительно частичный. Опущенные атрибуты сохраняют свои значения; нет необходимости пересылать всю запись.

data.type не проверяется. Патч задачи с type: "projects" успешно применяет изменение. Этот сервер в любом случае отправляет правильный тип.

403 с сообщением, что id организации «has to be provided», может означать, что он был неверным, а не отсутствующим. Один и тот же код no_organization_id покрывает отсутствующий заголовок и организацию, до которой токен не может дотянуться.

Отсутствующая функция отвечает 404, а не 403. /boards даёт 404 в организации, где её нет, что выглядит как сломанный путь.

Удаления могут быть восстанавливаемыми. Удалённая задача появляется в deleted_items с item_type и item_id и может быть восстановлена через действие restore этого ресурса. Проверено только для задач — не предполагайте, что это верно для всех типов.

GET /users — единственная конечная точка, ограниченная вызывающим. Она возвращает ровно одну запись — вас, — и именно так этот сервер определяет владельца токена. /users/me не существует; этот путь даёт 404. Остерегайтесь /organization_memberships: он не ограничен закреплённой организацией, а перечисляет членства вызывающего во всех организациях, к которым он принадлежит, так что количество его строк — это не численность сотрудников.

Нет заголовков ограничения частоты запросов. Только x-request-id, который цитируют ошибки этого сервера. При 429 снижайте темп, а не выясняйте лимит.

Разрешения

Четыре переключателя, все по умолчанию выключены. Сервер только для чтения — полезный и безопасный вариант по умолчанию.

Переключатель

Что охватывает

PRODUCTIVE_ENABLE_WRITES

Главный переключатель. Без него ничто не изменяется.

PRODUCTIVE_ENABLE_FINANCIALS

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

PRODUCTIVE_ENABLE_ADMIN

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

PRODUCTIVE_ENABLE_DELETES

Удаления, поверх уровневого ограничения.

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

PRODUCTIVE_ALLOWED_RESOURCES / PRODUCTIVE_DENIED_RESOURCES дополнительно сужают инстанс и применяются также к чтению — инстанс, ограниченный учётом времени, не должен читать и оклады.

Никогда не открываются вообще, независимо от переключателей: passwords, sessions, organization_subscriptions, неаутентифицированные ссылки общего доступа public/* и PATCH /users/{id}/update_password. Их нет в реестре, а не просто закрыты, поэтому никакая ошибка политики не сможет открыть их снова.

Запись в два шага

Обычная проектная работа — задача, запись времени, бронирование, комментарий — записывается одним вызовом. Требовать рукопожатие вокруг каждой записи времени сделало бы сервер непригодным для того, что люди делают чаще всего.

Всё с более широким радиусом поражения откладывается: инструмент возвращает точный запрос плюс хэш и ничего не отправляет, а productive_commit_operation выполняет его, только если операция вернулась без изменений. Это покрывает финансовый и административный уровни, каждое удаление, всё, что покидает организацию, и каждое действие bulk_* — они действуют на все записи, подходящие под фильтр, поэтому также отказываются выполняться без явного фильтра.

Шесть операций помечены как outward, потому что они обращаются к кому-то за пределами организации в момент выполнения: invoices.send, invoices.send_einvoice, people.invite, people.resend, organizations.resend_code и создание invitation.

Аутентификация

Два режима. PRODUCTIVE_ORGANIZATION_ID обязателен в обоих и никогда не является аргументом инструмента.

Персональные токены (рекомендуется)

Каждый человек привязывает собственный токен Productive, поэтому Productive применяет его разрешения и записывает его имя в том, что он делает.

Это важнее в Productive, чем в большинстве систем. Productive приписывает работу людям: запись времени принадлежит person_id, и каждое изменение помечается владельцем токена в журнале активности — именно этой записью защищают клиентский инвойс. При одном общем токене этот журнал говорит, что всё сделал сервисный аккаунт.

PRODUCTIVE_PER_USER_AUTH=true
PRODUCTIVE_TRUST_FORWARDED_USER=true
PRODUCTIVE_ENCRYPTION_KEY=<min 16 chars>
PRODUCTIVE_STORE_PATH=/data/store.json
PRODUCTIVE_PUBLIC_BASE_URL=https://productive.example.com
# PRODUCTIVE_API_TOKEN deliberately unset

Порядок действий:

  1. Вызывающий запускает productive_connect и получает одноразовую ссылку, действительную 10 минут, привязанную к его личности.

  2. Он открывает её и вставляет токен, созданный в Productive в разделе Settings → API integrations. Токен идёт из его браузера напрямую на сервер, поэтому никогда не попадает в транскрипт разговора — токен Productive эквивалентен предъявителю всего его аккаунта и, как показано ниже, обычно достаёт до более чем одной организации.

  3. Перед сохранением сервер вызывает GET /users с этим токеном и id этой организации. Один вызов доказывает три вещи: токен действителен, он достаёт до этой организации и кому он принадлежит. Затем страница подтверждает, какой аккаунт был привязан.

  4. Токены шифруются при хранении с помощью AES-256-GCM, одна строка на подтверждённую личность.

Острые углы:

  • Личность приходит только от шлюза. X-MCP-User читается только при PRODUCTIVE_TRUST_FORWARDED_USER=true, и никогда из того, чем управляет MCP-клиент. Включайте его только за шлюзом, который устанавливает заголовок из проверенного токена и удаляет копию, предоставленную клиентом, — иначе вызывающий может назвать любую личность и действовать от её имени.

  • Никакого запасного варианта. Не прошедший привязку вызывающий получает NOT_CONNECTED, а не общий токен, даже если PRODUCTIVE_API_TOKEN случайно задан. Запасной вариант передал бы ему чужие права — именно этот сбой данный режим и призван устранить.

  • /productive/enroll должен быть доступен браузеру пользователя в обход MCP-шлюза — браузер не может нести bearer-токен шлюза. Направляйте /productive/* на PRODUCTIVE_PUBLIC_BASE_URL напрямую в контейнер. Его безопасность — одноразовый state-токен, привязанный к личности.

  • Храните PRODUCTIVE_STORE_PATH на томе и держите PRODUCTIVE_ENCRYPTION_KEY стабильным — измените его, и каждый сохранённый токен станет нерасшифровываемым.

  • Если собственный email Productive у токена отличается от адреса вызывающего в каталоге, об этом громко сообщается на странице и в productive_status, и подключение всё равно происходит. Установите PRODUCTIVE_REQUIRE_EMAIL_MATCH=true, чтобы вместо этого отказать. По умолчанию это выключено, потому что тот, кто вставляет чужой токен, уже держит его в руках, так что отказ даёт мало безопасности, а аккаунт Productive под другим адресом вполне правдоподобен.

  • Авторизация для каждого пользователя разделяет разрешения и атрибуцию, а не организации. Привязка к организации по-прежнему действует для всех.

Общий токен

Установите PRODUCTIVE_API_TOKEN в один токен. Просто и правильно для stdio или одного оператора — но тогда каждый вызывающий действует как владелец этого токена, с его разрешениями, и журнал активности Productive приписывает каждое изменение ему.

PRODUCTIVE_TRUST_FORWARDED_USER по-прежнему помогает здесь: записи, относящиеся к человеку (учёт времени, бронирование), по умолчанию приписываются определённому вызывающему, а не владельцу токена, и сервер отказывается угадывать, когда адрес не соответствует никому или более чем одному человеку. productive_check_connection в любом случае называет владельца токена, так что атрибуция никогда не становится неожиданностью.

Несколько организаций

Один экземпляр обслуживает ровно одну организацию. X-Organization-Id берётся из окружения и никогда не является аргументом инструмента, поэтому ни один путь кода — включая универсальные инструменты — не может достичь другого тенанта. Запустите второй экземпляр для второй организации; образ тот же.

Это не теория. Один токен регулярно получает доступ к нескольким организациям: на аккаунте, на котором это разрабатывалось, GET /organizations вернул три, и изменение только заголовка переключало между ними (остальные две отвечали 403 subscription_expired, а не «не найдено»). Заголовок — это вся граница, поэтому он закреплён, а не передаётся — и поэтому зарегистрированный токен на пользователя проверяется против этой организации перед сохранением.

Конфигурация

Смотрите .env.example. Две обязательные переменные: PRODUCTIVE_API_TOKEN (Настройки → API-интеграции в Productive; он наследует права создавшего пользователя) и PRODUCTIVE_ORGANIZATION_ID (числовой id в вашем URL Productive).

Установите PRODUCTIVE_AUDIT_LOG, чтобы добавлять одну JSON-строку на каждую попытку изменения, включая те, которые политика отклонила. Тела запросов намеренно не записываются: они содержат зарплаты, ставки и персональные данные, а журнал аудита, который нужно охранять так же строго, как исходную систему, как правило, не читают.

Запуск

npm install
npm run dev          # stdio
npm run dev:http     # streamable HTTP on :3000/mcp (stateless), /healthz open
npm test
npm run smoke:live   # reads a real organization; stages one write, commits nothing

Docker-образы: ghcr.io/borgels/mcp-server-productive (публикуется при пуше в main).

Лицензия

Apache-2.0.

Install Server
A
license - permissive license
A
quality
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

View all related MCP servers

Related MCP Connectors

  • ClickUp MCP — wraps the ClickUp REST API v2 (BYO API key)

  • Product Hunt MCP — wraps the Product Hunt GraphQL API v2 (api.producthunt.com)

  • Direct access to your Sanity projects (content, datasets, releases, schemas) and agent rules

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/borgels/mcp-server-productive'

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