Читать 6 мин

Безопасность конфигурации MCP при изменениях в репозитории

Безопасность конфигурации MCP начинается с проверки pull request. Узнайте, как пути к командам, менеджеры пакетов, аргументы, cwd и переменные окружения меняют риски.

Безопасность конфигурации MCP при изменениях в репозитории

Конфигурация MCP в репозитории это исполняемый материал для развертывания, замаскированный под небольшой JSON-файл. Она может выбрать бинарный файл, скачать пакет, указать, где запустится процесс, передать ему данные и открыть ему доступ к рабочей копии. Поэтому безопасность конфигурации MCP нужно проверять уже на этапе pull request, еще до того, как возникнет вопрос о безопасности агента.

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

Конфигурация дает указание запустить процесс

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

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

Рецензенты часто судят о безопасности по имени пакета или ограниченности заявленных инструментов. Оба вывода могут оказаться ошибочными. Сервер с именем issue-reader после запуска может предоставлять только операции чтения, а его лаунчер при этом вызывать оболочку, которая читает токен из домашней директории. Сервер с широким названием может оказаться бинарным файлом из репозитория, который делает ровно то, что описано в проекте. Начинайте с фактов, а не с названий.

Опасная строка часто выглядит совершенно обычно:

{
  "mcpServers": {
    "docs": {
      "command": "npx",
      "args": ["-y", "@example/docs-mcp"]
    }
  }
}

Это не значит, что npx или пакет из реестра автоматически неприемлемы. Это значит, что pull request переносит часть цепочки поставки исполняемого кода на более поздний момент, причем на каждой машине, которая запускает сервер. Рецензент должен знать, какая версия пакета будет работать, откуда она взялась, что устанавливает и что делает при первом запуске.

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

Сообщения MCP и лаунчеры репозитория это разные уровни

Спецификация Model Context Protocol описывает взаимодействие клиента MCP с сервером, включая инициализацию, обнаружение инструментов, вызовы инструментов и поведение транспорта. Она не создает единого формата .mcp.json и не делает конфигурацию клиента безвредной. Каждый клиент сам решает, где читать конфигурацию и как запускать локальный stdio-сервер.

Эта разница перестает казаться теоретической, когда проверка дает сбой. Протокол может ограничивать сервер набором объявленных методов после установки соединения. Конфигурация хоста решает, какая программа вообще получит возможность объявить эти методы. Если проверять только поведение, связанное с протоколом, проверка начинается уже после того, как лаунчер успел отработать.

Разделяйте два вопроса:

  • Какие действия подключенный сервер может запрашивать или выполнять через свои инструменты?
  • Что делает локальный лаунчер до того, как клиент установит соединение с сервером?

Первый вопрос относится к разрешениям агента, процессу подтверждения и дизайну инструментов. Второй касается доверия к репозиторию, запуска процессов, происхождения зависимостей и границ файловой системы. Хорошая проверка отвечает на оба вопроса, но ответ на один никогда не заменяет ответ на другой.

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

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

Сначала читайте запускаемую команду, потом список инструментов

Проверяйте разрешение команды как цепочку, а не как первую строку в JSON. Спросите, какую программу хост фактически запустит после разрешения команды через текущее окружение. python, node, uvx, npx, bunx, sh и относительный путь означают, что конечный исполняемый файл определяет дополнительный механизм разрешения.

Прямой абсолютный путь проще всего проверить, хотя и для него нужна история происхождения. Относительный путь внутри репозитория может быть приемлемым, если файл находится в репозитории и обычное ревью кода охватывает его. Простое имя команды требует проверки того, как в окружении разработчика работает PATH. Команда оболочки требует наибольшей настороженности: кавычки, подстановка, конвейеры, перенаправления и подстановка команд скрывают больше действий, чем обычный массив аргументов.

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

Сравните эти две записи:

{
  "command": "node",
  "args": ["tools/mcp-server.js", "--root", "."]
}
{
  "command": "node",
  "args": ["tools/mcp-server.js", "--config", "../../shared/runtime.json"]
}

Вторая запись может быть оправданной. Но она также создает зависимость от файла за пределами границы рабочей копии, которого может не быть в pull request. Если сервер читает из этого файла инструкции или учетные данные, рецензенты не смогут оценить изменение только по diff. Попросите автора добавить указанную конфигурацию в ревью, заменить ее явным путем внутри репозитория или объяснить необходимость внешнего файла.

Не принимайте расплывчатый ответ вроде «пакет сам с этим разбирается». Сегодня пакет может делать это правильно, но изменение все равно наделяет его полномочиями. Полезный ответ называет программу, ее версию, входные данные и ожидаемые файлы. Если автор не запускал точную команду из чистой рабочей копии, он описывает намерение, а не поведение.

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

Менеджеры пакетов превращают запуск в событие цепочки поставки

Менеджер пакетов может скачать и выполнить код во время первого запуска сервера, поэтому одного имени пакета недостаточно для полноценной проверки зависимости. Поэтому формы npx -y package, uvx package и им подобные требуют большего внимания, чем команда, запускающая файл из репозитория.

Главный аргумент в пользу незакрепленной версии это удобство. Участникам не нужно ничего устанавливать вручную, и проект выглядит всегда актуальным. Цена в том, что репозиторий больше не указывает точный код, который просит запустить на каждой машине. Новая версия пакета, изменившаяся зависимость или перенаправление реестра могут изменить поведение без нового pull request.

Как минимум, укажите версию явно и сделайте источник понятным:

{
  "mcpServers": {
    "schema-checker": {
      "command": "npx",
      "args": ["-y", "@acme/[email protected]"],
      "cwd": "${workspaceFolder}"
    }
  }
}

Фиксация версии не сертифицирует пакет. Она делает объект ревью стабильным. Рецензент может проверить этот выпуск, сравнить его с предыдущим и потребовать отдельный pull request для обновления. Используйте lockfile менеджера пакетов, данные о целостности или артефакт из репозитория, если это поддерживает окружающий инструментарий. Одна строка с версией без способа проверить скачанное содержимое оставляет пробел, но все же лучше неограниченного имени.

Не путайте кэш менеджера пакетов с проверкой. Кэш лишь меняет источник байтов на одной машине. Он не сообщает рецензенту, какие байты получат другие участники, запускаются ли хуки установки и ведет ли себя чистая машина так же.

Задайте неудобный вопрос, который выявляет множество слабых изменений: что произойдет, если пакета нет? Если ответ звучит как «он установит себя сам», значит, конфигурация содержит путь к сети и выполнению кода. Если ответ звучит как «запуск завершится с инструкцией установить задокументированную зависимость», команда выбрала более медленную, но прозрачную настройку. Ни один вариант сам по себе не является правильным. Ошибочно делать вид, будто разницы нет.

Рабочая директория и переменные окружения задают настоящую область доступа

Подтверждайте рискованные вызовы
Требуйте подтверждение одним нажатием или через Touch ID при каждом использовании чувствительного ключа.

Поле cwd указывает процессу, где начинать поиск относительных файлов, и этот выбор часто влияет на большее, чем ожидают разработчики. Многие инструменты находят конфигурацию проекта, среды выполнения языков, файлы исключений, учетные данные и плагины, двигаясь вверх от рабочей директории. Сервер, начинающий работу в корне репозитория, видит другой набор данных по сравнению с сервером, запущенным в отдельном каталоге с тестовыми данными.

Задавайте рабочую директорию осознанно. Если серверу нужны только сгенерированные спецификации API в tools/specs, не запускайте его из родительской директории, где лежат материалы для развертывания и личные заметки разработчиков. Если он должен проверять всю рабочую копию, укажите это в pull request. Цель не в том, чтобы сделать каждый путь минимальным. Нужно, чтобы доступ, который одобряет рецензент, совпадал с доступом, который получает сервер.

Переменные окружения имеют такой же вес. Некоторые безобидны, например настройки локали или порта. Другие выбирают реестр пакетов, расширяют путь поиска модулей, включают режим отладки с записью тел запросов или передают учетные данные. Конфигурация с ${TOKEN} скрывает значение токена из файла, но все равно передает секрет дочернему процессу.

По возможности не помещайте учетные данные в конфигурацию MCP репозитория, если сервер может работать через отдельную границу действий. Если секрет действительно нужен серверу, задокументируйте его источник, назначение и возможность передачи дочерним процессам. Не добавляйте в комментарий пример рабочего производственного токена или скопированный фрагмент сеанса оболочки. Разработчики скопируют пример, который проще всего заставить работать.

Стоит проверить и унаследованные значения окружения. Процесс может получить гораздо больше, чем перечислено в JSON. Хост решает, что передать, но автор репозитория может выбрать команду, читающую стандартные места хранения во время работы. Это еще одна причина предпочитать прямые небольшие лаунчеры универсальным оболочкам и менеджерам пакетов.

По diff pull request можно восстановить граф выполнения

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

git diff --check
git diff -- .mcp.json

Первая команда сообщает об ошибках пробелов, если находит их. Вторая должна показать каждую добавленную, удаленную и измененную строку в пути конфигурации. Если файл хранится в другом месте или генерируется, скорректируйте путь и попросите показать изменение генератора. Сгенерированная конфигурация без исходного кода для нее не дает полной картины.

Рассмотрим небольшое изменение:

 \"mcpServers\": {
   \"release-notes\": {
-    \"command\": \"node\",
-    \"args\": [\"tools/release-notes-server.js\"],
-    \"cwd\": \"${workspaceFolder}\"
+    \"command\": \"npx\",
+    \"args\": [\"-y\", \"release-notes-mcp\"],
+    \"cwd\": \"..\"
   }
 }

На поверхности кажется, что команда заменила локальный вспомогательный процесс опубликованным сервером. Граф выполнения показывает больше. Клиент разрешает npx через PATH разработчика. npx может скачать release-notes-mcp и его зависимости. Пакет запускается за пределами корня репозитория, потому что cwd теперь указывает на родительскую директорию. Сервер может найти там конфигурацию, записать файлы кэша или прочитать соседние проекты. На каждый переход нужна точная ответная информация до слияния изменения.

Дисциплинированная проверка идет в таком порядке:

  1. Определите конечный исполняемый файл и точный пакет или файл репозитория, из которого он берется.
  2. Перечислите каждый путь к файлу, URL, реестр и значение окружения, способные изменить поведение при запуске.
  3. Укажите рабочую директорию процесса и каталоги, которые сервер читает или изменяет во время обычной работы.
  4. Подтвердите, что происходит на чистой машине без кэша пакетов.
  5. Сопоставьте заявленное назначение инструмента с разрешениями, которые на самом деле нужны лаунчеру.

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

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

Описания инструментов не компенсируют широкий лаунчер

Храните учетные данные вне MCP
Агенты подключаются через встроенный адаптер sp mcp, а Sallyport выполняет действие с учетными данными.

Узкая схема инструмента не отменяет того, что произошло до рукопожатия MCP. Команды часто воспринимают вывод tools/list как полный список разрешений, а затем считают сервер безопасным, потому что он предлагает search_docs и read_status. Этот список описывает интерфейс после инициализации. Он почти ничего не говорит об установке пакетов, поиске конфигурации, телеметрии, дочерних процессах или файлах, прочитанных при запуске.

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

Попросите автора описать жизненный цикл простыми словами: что запускается, что читается до подключения, что скачивается, если вообще скачивается, и к чему сервер может получить доступ после подключения. Ответ должен помещаться в описание pull request. Если для него требуется длительное расследование, конфигурация слишком непрямая для обычного ревью.

Не позволяйте фразе «мы доверяем этому поставщику» закрыть обсуждение. Доверие важно, но оно не фиксирует версию, не сужает рабочую директорию и не показывает, использует ли команда другой реестр. Это отдельные меры контроля с разными сценариями отказа.

Владельцу репозитория нужен контроль во время работы

Контролируйте использование HTTP-учетных данных
Sallyport добавляет учетные данные bearer, basic или пользовательские заголовки к HTTP-вызовам, не раскрывая их агентам.

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

Граница должна оставаться четкой. Репозиторий управляет тем, что предлагает запустить. Человек за компьютером решает, может ли конкретный сеанс агента действовать. Для чувствительных действий нужны записи, позволяющие оператору восстановить ход работы агента и отозвать сеанс, если что-то пошло не так.

Sallyport не допускает API- и SSH-учетные данные в процесс агента, а авторизация сеанса и журнал активности дают оператору отдельное место для одобрения и проверки действий. Это не делает рискованную команду из репозитория безвредной, поэтому проверка конфигурации все равно должна быть первой.

Для команд, использующих другую границу контроля, применяйте тот же тест. Может ли разработчик увидеть, какой процесс агента запросил доступ? Может ли он остановить этот процесс, не прерывая несвязанную работу? Может ли он отличить попытку действия от успешно выполненного действия? Если нет, после слияния плохая конфигурация получает больше времени для нанесения вреда.

Считайте эти файлы принадлежащим репозиторию исполняемым кодом

Репозиторий должен назначить владельцев кода или эквивалентное правило ревью для конфигурации MCP, скриптов-оберток и манифестов пакетов, определяющих, что установит лаунчер. Владелец не обязан быть специалистом по безопасности. Ему нужно достаточно контекста, чтобы спросить, зачем это изменение запускает именно эту программу с таким доступом.

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

Практический тест прост. Передайте diff опытному разработчику, который не знаком с функцией, и попросите объяснить, что запустится на чистой машине, где это произойдет и что сможет увидеть процесс. Если на эти вопросы нельзя ответить по pull request и указанному в нем коду, изменение нужно доработать до добавления в репозиторий.

Вопросы и ответы

Входит ли .mcp.json в спецификацию MCP?

Нет. Протокол описывает обмен сообщениями между клиентом и сервером, а файл репозитория, который запускает сервер, является соглашением конкретного клиента или инструмента разработки. Считайте его команду, аргументы, переменные окружения и рабочую директорию локальными инструкциями по выполнению.

Может ли конфигурация MCP запускать код при открытии репозитория?

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

Можно ли использовать npx в конфигурации MCP?

Попросите указать точную версию пакета или использовать исполняемый файл из репозитория с зафиксированной контрольной суммой. Простое имя пакета оставляет фактическую программу зависимой от состояния реестра в момент запуска сервера разработчиком.

Почему в конфигурации MCP-сервера важна cwd?

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

Что нужно проверить в pull request для .mcp.json?

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

Как проверить установщик пакета в конфигурации MCP?

Попросите указать точную команду после разрешения, версию пакета, источник реестра и необходимые процессу разрешения. Если автор не может объяснить, что скачивается или записывается при первом запуске, изменение еще не готово к слиянию.

Запускается ли MCP-сервер автоматически из конфигурации репозитория?

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

Безопасны ли переменные окружения для учетных данных MCP?

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

Как сделать конфигурации MCP в репозитории безопаснее?

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

Заменяет ли подтверждение во время работы проверку конфигурации?

Нет. Подтверждение может остановить неожиданное действие на границе доступа, но не показывает, попросил ли репозиторий запустить нужную программу. Проверка конфигурации предотвращает один класс ошибок, а подтверждение во время работы ограничивает другой.

Sallyport

Sallyport выполняет API-вызовы и SSH-команды за вашего ИИ-агента. Ключи остаются в локальном хранилище на вашем Mac; вы подтверждаете каждый запуск, и каждое действие попадает в запечатанный журнал.

© 2026 Sallyport · Открытый код по лицензии Apache-2.0 · Oleg Sotnikov