Project+apps

Документация MCP Project+apps

MCP нужен прежде всего для чтения контекста Project+apps и навигации по продуктовому штабу без raw data. Основной write-контракт для внешних агентов живёт в HTTP API.

Local MCP: http://127.0.0.1:8010/mcp/project-apps Local Port: 8010 / HTTP Public MCP: https://apps.farmchel.org/mcp/project-apps Public Port: 443 / HTTPS
Публичная документация этой страницы: https://apps.farmchel.org/mcp-docs. Endpoint MCP для клиентов: POST только на путь /mcp/project-apps (GET возвращает 405 Method Not Allowed).

Роль MCP в агентной работе

В Project+apps MCP считается прежде всего контуром чтения и навигации: агент читает контекст, канон и карту портфеля, а затем принимает решение, что нужно создать или обновить.

MCP помогает агенту ориентироваться в штабе целиком: портфель, направления, продукты, приложения, внимание сейчас и канон. Он не должен становиться обходным write-слоем там, где есть нормальный HTTP API.
Короткий контракт для агентов: MCP читает, API пишет.
Отдельная страница с кратким рабочим протоколом агента: Контракт для агента.

Основное подключение

Для локальной работы основной MCP endpoint должен смотреть в локальный Project+apps, а не в публичный домен.

{
  "mcpServers": {
    "project-apps": {
      "url": "http://127.0.0.1:8010/mcp/project-apps"
    }
  }
}
Если ты работаешь локально, основной endpoint должен быть именно http://127.0.0.1:8010/mcp/project-apps.

Cursor config

{
  "mcpServers": {
    "project-apps": {
      "url": "http://127.0.0.1:8010/mcp/project-apps"
    },
    "project-apps-stdio": {
      "command": "php",
      "args": [
        "C:\Users\MSI\Desktop\ProjectWatch\artisan",
        "mcp:start",
        "project-apps"
      ]
    }
  }
}

Stdio fallback

Если web MCP не используется, сервер можно поднять как stdio-handle.

php artisan mcp:start project-apps

Промпты

Пример вызова промпта (prompts/get)

{
  "jsonrpc": "2.0",
  "id": 40,
  "method": "prompts/get",
  "params": {
    "name": "project_apps_director_brief",
    "arguments": {
      "direction_slug": "fitness",
      "product_slug": "push-ups"
    }
  }
}

Точное имя промпта и доступные аргументы уточняйте через prompts/list на вашей версии сервера.

Инструменты

Если агентный клиент не умеет передавать arguments в write-tools, считай эти инструменты недоступными для записи и используй API.
Если на сервере задано PROJECT_APPS_MCP_WRITE_ENABLED=false, write-tools в MCP отключены — запись только через HTTP API с заголовком X-Project-Apps-Token.
Для допустимых direction_slug агент должен читать project-apps://portfolio или HTTP endpoint /api/project-apps/directions до записи.
Имена полей в write-tools: поддерживаются и snake_case, и camelCase (например health_summary и healthSummary). Сервер приводит ключи к snake_case до валидации. В ответах инструментов обновления (project_apps_update_product, project_apps_update_app, project_apps_update_canon_rule) в structuredContent есть массив applied_field_keys — какие поля реально были приняты; если он пустой, данные в БД не менялись по смыслу (часто из‑за неверных имён полей во входе).

Протокол JSON-RPC, методы и формат тела запроса

Web MCP принимает одно JSON-RPC 2.0 сообщение в теле POST (обычно Content-Type: application/json). Ответ — JSON; при стриминге возможен SSE (зависит от транспорта клиента).

Минимальное тело для tools/call

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "project_apps_overview",
    "arguments": {}
  }
}

Где могут лежать аргументы инструмента (приоритет сверху вниз)

  1. params.arguments — объект JSON (основной вариант).
  2. params.input, params.payload, params.body — те же данные под другим именем (совместимость).
  3. params._meta.arguments / params._meta.input — редкие клиенты.
  4. Строка JSON вместо объекта для полей выше — будет распарсена.
  5. Плоский fallback: после удаления служебных ключей (name, arguments, input, …) оставшиеся поля верхнего уровня params считаются аргументами инструмента (legacy-клиенты).
Если write-tool вызывают без аргументов вообще, сервер возвращает ошибку с текстом вроде «Пустой MCP write-вызов» — это ожидаемо для create/update без данных.

Пример: список инструментов (tools/list)

curl -sS -X POST "https://apps.farmchel.org/mcp/project-apps" \
  -H "Content-Type: application/json" \
  -d "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/list\",\"params\":{}}"

Пример: обзор портфеля (tools/call)

curl -sS -X POST "https://apps.farmchel.org/mcp/project-apps" \
  -H "Content-Type: application/json" \
  -d "{\"jsonrpc\":\"2.0\",\"id\":2,\"method\":\"tools/call\",\"params\":{\"name\":\"project_apps_overview\",\"arguments\":{}}}"

Пример: чтение ресурса контекста (resources/read)

curl -sS -X POST "https://apps.farmchel.org/mcp/project-apps" \
  -H "Content-Type: application/json" \
  -d "{\"jsonrpc\":\"2.0\",\"id\":3,\"method\":\"resources/read\",\"params\":{\"uri\":\"project-apps://context\"}}"

Справочник инструментов (кратко)

Ниже — ориентир для агентов; точная JSON Schema приходит из tools/list у живого сервера.

Имя Назначение Важные входные поля
project_apps_overview Сводка портфеля для директора. Опционально фильтры вроде направления/продукта (см. схему инструмента).
project_apps_attention Блок «что требует внимания». Обычно без аргументов или с узкими фильтрами.
project_apps_canon Чтение канона с фильтрами. status, limit, direction_slug, product_slug.
project_apps_product_search Поиск продуктов. query, direction_slug, статусы и др.
project_apps_create_product Создание продукта. direction_slug, name, портфельные поля; см. примеры ниже.
project_apps_update_product Обновление продукта. product_id или product_slug; остальное — только изменяемые поля. Ответ содержит applied_field_keys.
project_apps_create_app Создание приложения. Привязка к product_slug или к направлению для кандидата; store/bundle/package.
project_apps_update_app Обновление приложения. mobile_app_id или mobile_app_slug; ответ содержит applied_field_keys.
project_apps_record_decision Запись решения и опционально задач. Привязка к продукту/направлению/приложению; массив tasks.
project_apps_create_task Создание задачи. title, привязки к сущностям, сроки.
project_apps_create_canon_rule Новое правило канона. title, rule_type, body, область direction/product.
project_apps_update_canon_rule Обновление правила канона. canon_rule_id обязателен; ответ содержит applied_field_keys.

Обновление продукта: snake_case, camelCase и проверка результата

Один и тот же апдейт можно отправить в «админском» стиле полей или как в TypeScript. После нормализации ключей сервер валидирует и сохраняет данные. В ответе смотрите applied_field_keys: там перечислены поля, которые реально попали в обновление (без идентификаторов product_id / product_slug).

Вариант A — snake_case

{
  "jsonrpc": "2.0",
  "id": 10,
  "method": "tools/call",
  "params": {
    "name": "project_apps_update_product",
    "arguments": {
      "product_slug": "push-ups",
      "health_summary": "Актуальный паспорт здоровья после ревью.",
      "portfolio_status": "core",
      "next_step": "Согласовать рост канала."
    }
  }
}

Вариант B — camelCase (эквивалентно полям из варианта A)

{
  "jsonrpc": "2.0",
  "id": 11,
  "method": "tools/call",
  "params": {
    "name": "project_apps_update_product",
    "arguments": {
      "productSlug": "push-ups",
      "healthSummary": "Актуальный паспорт здоровья после ревью.",
      "portfolioStatus": "core",
      "nextStep": "Согласовать рост канала."
    }
  }
}

Фрагмент успешного ответа (упрощённо)

{
  "result": {
    "structuredContent": {
      "message": "Продукт обновлён в Project+apps.",
      "applied_field_keys": [
        "health_summary",
        "portfolio_status",
        "next_step"
      ],
      "id": 12,
      "slug": "push-ups",
      "portfolio_status": "core",
      "product_focus": "scale"
    }
  }
}
Если message говорит, что изменяемых полей не найдено, а applied_field_keys пустой — вход не содержал распознанных полей (проверьте имена, опечатки, или что клиент вообще передал arguments).

Примеры write-инструментов

Ниже в блоках <pre> для краткости показан только фрагмент params инструмента (поля name и arguments). Полный HTTP-запрос всегда оборачивается в JSON-RPC 2.0, как в разделе «Протокол JSON-RPC» и в примерах с curl выше.

Создать продукт

{
  "name": "project_apps_create_product",
  "arguments": {
    "direction_slug": "fitness",
    "name": "Бег",
    "portfolio_status": "next",
    "product_focus": "assess-development",
    "summary": "Кандидат в новый фитнес-продукт.",
    "next_step": "Проверить app map и economics."
  }
}

Обновить продукт

{
  "name": "project_apps_update_product",
  "arguments": {
    "product_slug": "push-ups",
    "portfolio_status": "core",
    "product_focus": "scale",
    "is_revenue_generating": true,
    "is_favorite": true,
    "health_summary": "Экономика подтверждена, продукт можно усиливать."
  }
}

Записать решение

{
  "name": "project_apps_record_decision",
  "arguments": {
    "product_slug": "push-ups",
    "title": "Масштабировать после подтверждения stores",
    "decision_type": "scale",
    "owner": "Growth",
    "decision": "Не масштабировать без store truth.",
    "review_at": "2026-04-30",
    "tasks": [
      {
        "title": "Проверить store truth по Отжиманиям",
        "owner": "Growth",
        "priority": "high"
      }
    ]
  }
}

Прочитать канон

{
  "name": "project_apps_canon",
  "arguments": {
    "status": "active",
    "limit": 10
  }
}

Создать приложение

{
  "name": "project_apps_create_app",
  "arguments": {
    "product_slug": "push-ups",
    "name": "Отжимания Android",
    "platform": "Android",
    "implementation_status": "building",
    "store_url": "https://play.google.com/store/apps/details?id=org.farmchel.pushups.android",
    "bundle_id": "org.farmchel.pushups.android",
    "package_id": "org.farmchel.pushups.android"
  }
}

Спорный app-хвост внутри направления

{
  "name": "project_apps_create_app",
  "arguments": {
    "direction_slug": "fitness",
    "name": "Quit Alcohol Android",
    "platform": "Android",
    "implementation_status": "building",
    "product_binding_status": "product-candidate",
    "product_candidate_name": "Quit Alcohol",
    "package_id": "org.farmchel.quit.alcohol"
  }
}

Создать задачу

{
  "name": "project_apps_create_task",
  "arguments": {
    "product_slug": "push-ups",
    "title": "Собрать store links по Отжиманиям",
    "owner": "Operations",
    "status": "open",
    "priority": "high",
    "due_at": "2026-04-20"
  }
}

Создать каноническое правило

{
  "name": "project_apps_create_canon_rule",
  "arguments": {
    "title": "Один продукт может иметь несколько приложений",
    "rule_type": "summary-contract",
    "body": "Продукт не равен одному приложению, если смысл общий и решения принимаются на уровне продукта."
  }
}
Поддерживаемые типы канона: product-definition, portfolio-structure, freeze-policy, direction-policy, summary-contract, portfolio-governance. Значение structure-canon при записи нормализуется в portfolio-structure.
У правил канона можно задать область через direction_slug / product_slug (или id). Фильтр project_apps_canon принимает те же slug для отбора.
На проде можно отключить MCP write-tools: PROJECT_APPS_MCP_WRITE_ENABLED=false — в project-apps://context будет mcp_write_enabled: false.
В project-apps://context и project-apps://portfolio перечислены canonical_direction_slugs — эталонные slug направлений мобильного контура.

Альтернатива arguments: объект input

Часть клиентов кладёт данные в params.input — это поддерживается наравне с arguments. Для создания продукта так удобнее обходить коллизию имён (имя инструмента в params.name и человекочитаемое название продукта внутри input.name).

{
  "jsonrpc": "2.0",
  "id": 50,
  "method": "tools/call",
  "params": {
    "name": "project_apps_create_product",
    "input": {
      "direction_slug": "fitness",
      "name": "Ходьба",
      "portfolio_status": "next",
      "product_focus": "assess-development",
      "summary": "Создание через params.input."
    }
  }
}
Плоский перечень полей на верхнем уровне params рядом с name инструмента поддерживается только для полей без конфликта имён с name, arguments, jsonrpc и т.д. Для create/update продуктов безопаснее всегда использовать вложенный объект arguments или input.

Обновить приложение (project_apps_update_app)

{
  "jsonrpc": "2.0",
  "id": 51,
  "method": "tools/call",
  "params": {
    "name": "project_apps_update_app",
    "arguments": {
      "mobile_app_slug": "push-ups-ios",
      "store_url": "https://apps.apple.com/app/id000000000",
      "implementation_status": "implemented",
      "bundle_id": "org.farmchel.pushups.ios"
    }
  }
}

Идентификация приложения — только mobile_app_id или mobile_app_slug. В ответе — applied_field_keys без этих двух полей.

Обновить правило канона (project_apps_update_canon_rule)

{
  "jsonrpc": "2.0",
  "id": 52,
  "method": "tools/call",
  "params": {
    "name": "project_apps_update_canon_rule",
    "arguments": {
      "canon_rule_id": 3,
      "body": "Уточнённая формулировка правила после ревью.",
      "status": "active"
    }
  }
}

Ресурсы

Таблица окружений и портов

Окружение Базовый URL MCP Порт / протокол Страница документации
Локальная разработка http://127.0.0.1:8010/mcp/project-apps По умолчанию приложение слушает 8010, HTTP. http://127.0.0.1:8010/mcp-docs
Продакшен https://apps.farmchel.org/mcp/project-apps 443, HTTPS (стандартный порт не указывается в URL). https://apps.farmchel.org/mcp-docs
Для агента на машине разработчика почти всегда нужен локальный URL MCP, иначе запросы уйдут на прод и будут менять продовые данные.

Отладка: «ответ успешный, а в админке не изменилось»

Что возвращает MCP context

{
  "mcp": {
    "local_handle": "project-apps",
    "stdio_command": "php artisan mcp:start project-apps",
    "local_web_endpoint": "http://127.0.0.1:8010/mcp/project-apps",
    "local_port": "8010/HTTP",
    "public_web_endpoint": "https://apps.farmchel.org/mcp/project-apps",
    "public_port": "443/HTTPS"
  }
}

Правило работы