Ошибка подключения MCP к базе 1С: справочник кодов ответа HTTP-сервиса
Иван Недомолков · Жарияланды:
Когда модель в чате не может достучаться до базы 1С через MCP, первым делом хочется переставить клиент, обновить Node или пересобрать контейнер. По нашему опыту это почти всегда мимо. 26.09.2026 из тринадцати наших подключений к базам не работали три, ещё у двух работала только половина, и во всех пяти случаях сам сервер MCP был в порядке. Ломалась публикация базы и то, что за ней.
Хорошая новость в том, что HTTP-сервис 1С на каждую такую поломку отвечает своим кодом. Ниже справочник: какой код что значит, где чинить и какой командой это проверить за минуту. Коды сняты на IIS 10 и 7.5 с платформой 8.3.27, часть взята из наших записей подключений за август и сентябрь.
Проверка одним запросом
Прежде чем читать таблицу, получите код. Для этого MCP не нужен совсем: достаточно обычного GET на адрес внутри /hs/, которого заведомо нет, с логином той учётки, под которой ходит MCP.
curl -i -u mcp_check http://server/base/hs/zz_proverka/x
curl спросит пароль и напечатает заголовки ответа. Смысл выбора несуществующего адреса простой: у исправной связки ответ будет 404. Чтобы его выдать, модуль 1С на веб-сервере должен загрузиться, дойти до кластера, получить рабочий процесс, узнать пользователя и только потом не найти сервис. Любая поломка по дороге ответит своим кодом раньше.
Второй запрос идёт уже на сам сервис MCP:
curl -i -u mcp_check http://server/base/hs/mcp/rpc
Здесь хороший ответ 405. Сервис найден, просто на GET он не рассчитан и ждёт POST. В базе при этом ничего не выполняется.
Корень публикации в браузере для диагностики не годится. В нашем прогоне стартовая страница веб-клиента отдавалась с кодом 200 на всех трёх сломанных базах, включая ту, где кластер не выдавал рабочий процесс. Эту страницу IIS отдаёт сам, до сервера 1С запрос не доходит.
Таблица кодов
Номер этажа означает, где сломано, считая от сети к сервису: 1 сеть и веб-сервер, 2 публикация, 3 модуль расширения веб-сервера 1С, 4 кластер и рабочий процесс, 5 пользователь базы, 6 сам HTTP-сервис. Ответ всегда приходит от самого нижнего сломанного этажа, остальные в этот момент просто не проверялись.
| Ответ | Этаж | Что значит | Что проверить | Чем проверить |
|---|---|---|---|---|
| нет соединения | 1 | имя не резолвится, порт закрыт, мешает брандмауэр | адрес, DNS, VPN, служба веб-сервера | curl -i http://server/base/ |
| 404 на корне публикации | 2 | веб-сервер жив, публикации с таким именем нет | имя базы в адресе, на Apache ещё и регистр букв | тот же запрос к корню |
| 404.2 | 3 | модуль 1С запрещён в “Ограничениях ISAPI и CGI” | настройки IIS | запрос к /hs/zz_proverka/x, в теле 0x800704ec |
500 с 0x8007007f | 3 | модуль не загрузился после смены версии платформы | пул приложений под нужную версию модуля | тот же запрос, код в теле ответа |
| 409 с текстом 1С | 3 | версии модуля веб-сервера и кластера разошлись | переопубликовать базу нужной версией | любой адрес внутри /hs/ |
| 502 с текстом 1С | 4 | кластер не выдал свободный рабочий процесс | сервер 1С, адрес кластера в файле публикации, лицензии | любой адрес внутри /hs/ |
| 401 (в IIS 401.5) | 5 | логин или пароль не подходят к этой базе | пользователь базы, кодировка логина | запрос к /hs/zz_proverka/x с паролем и без |
| 404 на адресе сервиса | 6 | сервиса нет в конфигурации или он не опубликован | расширение и корневой URL, строка сервиса в файле публикации | curl -i -u mcp_check http://server/base/hs/mcp/rpc |
| 500 на адресе сервиса | 6 | модуль сервиса не компилируется | проверка модулей конфигуратором | /CheckModules, ниже |
| 405 | 6 | сервис есть, метод запроса не тот | ничего, на GET это правильный ответ | запрос к сервису MCP |
| 403 на методе исполнения кода | 6 | у нас появлялся, когда мост звал метод GET-ом; кто его отдаёт, не разобрали | перевести вызов на POST | вызов тем же методом, что у моста |
Дальше по группам: какие коды зависят от адреса, какие нет, и где код прячется.
Коды, которым всё равно, какой адрес
Три этажа ниже пользователя ломаются так, что ответ одинаков на корень /hs/, на выдуманный сервис, с паролем и без. Если два разных адреса внутри /hs/ дали один и тот же 409 или 502, смотреть на сервис MCP бессмысленно.
409. Типичная история: кластер обновили, а публикацию оставили от прежней версии. Для кластера клиентом здесь выступает сам модуль веб-сервера, и сервер его не пускает. Текст ответа говорит об этом прямо:
HTTP: Conflict by reason: Различаются версии клиента и сервера
(8.3.27.1606 - 8.3.27.2325), клиентское приложение: Модуль расширения веб-сервера
Чинится переопубликованием базы из конфигуратора нужной версии или правкой пути к модулю в настройках веб-сервера.
502. Модуль дошёл до кластера, но рабочий процесс не получил:
Ошибка установки соединения by reason: Свободный рабочий процесс сервера
1С:Предприятия не найден за 5 попыток с интервалом 1000 миллисекунд
У нас такой ответ приходил за 4,07-4,19 секунды на каждый запрос. Арифметика сходится: пять попыток дают четыре паузы по секунде. Количество попыток и интервал задаются элементом pool в файле публикации. Прочитать этот файл и пулы IIS целиком помогает чек-ап веб-публикации, но при 502 первым делом смотрите на сам сервер 1С: публикация честно сообщила, что кластер процесс не выдал.
404.2 и 500 с 0x8007007f. Оба про модуль 1С на IIS. Первый значит, что модуль запрещён в ограничениях ISAPI и CGI, второй встречался после смены версии платформы, когда пул приложений смотрел не на ту версию модуля. Оба кода из наших августовских записей: повторять их сейчас значило бы ломать живую публикацию.
401: пароль проверяется раньше всего остального
С неверным паролем мы получали 401 на существующий сервис, на несуществующий и на адрес, которого не бывает вообще. Без пароля ответ тот же, 401.5. Пользователь базы проверяется до того, как модуль начнёт искать сервис, поэтому при 401 о существовании сервиса ничего сказать нельзя.
Частая ошибка на этом месте: 401 читают как “сервис есть, но закрыт правами” и идут раздавать роли. Порядок обратный. Сначала пароль, потом кодировка логина. Basic-авторизация кодирует строку “логин:пароль”, и разные клиенты делают это кто в UTF-8, кто в однобайтовой кодировке. Логин латиницей проходит везде, кириллический не у всех, поэтому для технической учётки MCP мы берём латиницу.
Коды на адресе самого сервиса
Если несуществующий адрес ответил 404, а сервис MCP 405, публикация, кластер и пользователь исправны. Остаются вопросы к сервисам.
404 на адресе сервиса. Сервиса нет в конфигурации или расширении либо он не опубликован. По коду эти случаи не различить. На одном сервере выключенный в файле публикации сервис отвечал 404 с короткой страницей 1С “HTTP: Not found”, а выдуманное имя давало 404.0 от IIS. На другом сервере одну и ту же страницу IIS получали и выдуманное имя, и живой сервис на неизвестный путь. Поэтому проверяем два места: есть ли сервис в конфигурации и есть ли он в блоке httpServices файла default.vrd.
<!-- вариант 1: опубликовать все сервисы, включая сервисы расширений -->
<httpServices publishByDefault="true" publishExtensionsByDefault="true"/>
<!-- вариант 2: каждый сервис своей строкой -->
<httpServices publishByDefault="false">
<service name="mcp" rootUrl="mcp" enable="true"/>
<service name="api" rootUrl="api" enable="true"/>
</httpServices>
Имена условные. Подвох в том, что сервисов у MCP-решения часто больше одного. В нашей сборке через первый клиент получает список методов, через второй идут сами вызовы. Опубликован первый и забыт второй: модель видит инструменты, а любой вызов падает. У двух баз из тринадцати мы увидели ровно это: проверка сервиса MCP зелёная, второй сервис отвечает 404 веб-сервера. Файлы публикации оказались в порядке, второго сервиса не было в самой конфигурации.
Одна оговорка. В августе неопубликованный сервис MCP в публикации с поимённым списком дал нам 500, после дописывания строки ответ сменился на 401. В сентябре на том же сервере такой адрес отвечал 404, и откуда тогда взялся 500, мы не знаем.
500 без текста. Так отвечает сервис, модуль которого не компилируется. Попытка в модуле его не ловит: до выполнения дело не доходит. 6 сентября мы потратили время на подозрения в метке порядка байтов, зарезервированных именах и порядке функций, а точную строку за минуту дал конфигуратор в пакетном режиме:
1cv8.exe DESIGNER /S сервер/база /N Пользователь /P Пароль
/CheckModules -Extension ИмяРасширения -Server
/Out C:/temp/check.log /DisableStartupDialogs
В логе лежит модуль, строка, колонка и “Переменная не определена” с именем. Запускать лучше скрытым процессом с ограничением по времени, зависший конфигуратор держит базу. Проверка ловит не всё: у нас проскакивали переменные с именами, совпадающими со словами языка, и ошибки модуля формы.
500 с текстом “Ошибка инициализации модуля”. Случай 22 сентября: типовая база, сервис MCP отвечает 405, список методов приходит, а каждый вызов падает на втором сервисе. Его модуль разбирал тело запроса через общий модуль библиотеки КоннекторHTTP, которой в типовой нет. Замена на платформенный разбор:
// Было: общий модуль библиотеки, которой в этой конфигурации нет
// Аргументы = КоннекторHTTP.JsonВОбъект(Запрос.ПолучитьТелоКакСтроку());
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(Запрос.ПолучитьТелоКакСтроку());
// Истина - вернуть Соответствие: обработчики методов читают его через Получить()
Аргументы = ПрочитатьJSON(ЧтениеJSON, Истина);
ЧтениеJSON.Закрыть();
Второй параметр Истина обязателен: обработчики звали Аргументы.Получить(...), у структуры такого метода нет, и без него падение переехало бы на строку ниже.
Когда код спрятан от вас
Два места, где настоящего кода не видно без специальных усилий.
Индикатор в приложении. Он зелёный при 401, при 409 и при пустом списке методов. Индикатор показывает, что процесс клиента запустился, про базу он не знает ничего.
Мост между клиентом и базой. Мы проверили свой мост 26 сентября:
| Что сделали | Что вернул мост |
|---|---|
| рукопожатие MCP с неверным паролем | 200, список инструментов пришёл, базу мост не трогал |
| вызов инструмента с тем же паролем | 200, isError: false, внутри текста “Client error ‘401 Unauthorized‘“ |
| вызов по базе с опечаткой в имени публикации | 200, внутри текста “404 Not Found” |
| вызов по базе с 409 | 200, внутри текста “409 Conflict” |
| рукопожатие по базе с 502 | ответа нет 30 секунд, клиент отвалился по таймауту |
По спецификации MCP ошибка инструмента должна приходить с isError: true, так что это особенность нашего моста. Но у последней строки цена самая высокая: со стороны это выглядит ровно как “сервер MCP не запускается”, и человек идёт переустанавливать клиент. Почему мост ждёт базу уже на рукопожатии, если при неверном пароле не ждёт, мы не разобрали.
У самого моста свои коды, и путать их с кодами публикации нельзя. В схеме один MCP-сервер на десять баз 404 от прокси значит “такой базы нет в реестре”, а 404 от публикации значит “нет сервиса”.
Скрипт, который проходит ступени сам
Всё выше мы собрали в proverka-mcp-1c.mjs: Node 18 и выше, без зависимостей, только GET-запросы, мосту рукопожатие и по желанию один инструмент без параметров. Учётку берёт из переменных среды и в вывод не печатает.
set MCP_1C_USER=mcp_check
set MCP_1C_PASSWORD=...
node proverka-mcp-1c.mjs --pub http://server/base --exec hs/api
node proverka-mcp-1c.mjs --pub http://server/base --bridge http://bridge/mcp/ --tool list_methods
Ключевая ступень вторая, запрос к выдуманному сервису. Разбор ответа в скрипте выглядит так:
const r = await запрос(PUB + '/hs/zz_proverka_' + Date.now().toString(36) + '/x', { headers: AUTH })
if (r.код === 404 && /404\.2|0x800704ec/i.test(r.тело)) итог(2, 'модуль 1С и кластер', 'stop', 'модуль 1С не разрешён в "Ограничениях ISAPI и CGI" IIS', r)
else if (r.код === 404) итог(2, 'модуль 1С и кластер', 'ok', 'модуль загружен, кластер отвечает, учётка принята (' + r.мс + ' мс)', r)
else if (r.код === 401) итог(2, 'модуль 1С и кластер', 'stop', 'логин или пароль не подходят к ЭТОЙ базе', r)
else if (r.код === 409) итог(2, 'модуль 1С и кластер', 'stop', 'версия модуля веб-сервера разошлась с версией кластера', r)
else if (r.код === 502) итог(2, 'модуль 1С и кластер', 'stop', 'модуль не достучался до кластера или не получил рабочий процесс', r)
На четвёртой ступени тот же 404 читается иначе, и скрипт отличает его по телу: JSON с отказом значит, что ответил сам модуль сервиса, то есть он жив и компилируется. Голый 404 веб-сервера значит, что сервиса нет.
const json = /^\s*[{[]/.test(r.тело)
if (json && r.код < 500) итог(4, 'сервис ' + EXEC, 'ok', 'модуль сервиса компилируется и сам отвечает на неизвестный метод', r)
А на пятой код ищется внутри текста ответа моста, потому что статус там 200 при любой беде:
const внутри = (c.тело.match(/(?:error|ошибк)[^"]{0,60}?\b([1-5]\d\d)\b/i) || [])[1]
Вывод по базе с обновлённым кластером:
[ OK ] 1. сеть до веб-сервера 200 публикация отвечает (66 мс). О базе это ещё ничего не говорит
[СТОП] 2. модуль 1С и кластер 409 версия модуля веб-сервера разошлась с версией кластера:
переопубликовать нужной версией (8.3.27.1606 - 8.3.27.2325)
Сломано на ступени 2
Код возврата равен номеру сломанной ступени, поэтому скрипт можно поставить в планировщик и получать уведомление, только когда есть что чинить. Мы прогнали его по девяти сценариям на живых базах: четыре поломки устроили сами (чужой пароль, пароль не передан, опечатка в имени публикации, опечатка в пути сервиса), три были настоящими (409, 502, нет второго сервиса), плюс контрольный прогон и прогон через мост. Во всех семи поломках скрипт остановился на той ступени, где было сломано.
Проверить, что попали именно в ту базу, скрипт намеренно не пытается: это уже выполнение кода в базе. Если метод исполнения кода у вас есть, одна строка вернёт имя машины с рабочим процессом:
ЛокальныйРезультат = ИмяКомпьютера();
Ложные следы, на которые мы потратили время
| Подумали | Как оказалось |
|---|---|
| сервер не ответил за 10 секунд, значит лежит | через несколько минут та же база отвечала за 29-989 мс; одиночный таймаут сначала повторяем |
| 403 на исполнении кода, значит учётке не хватает ролей | переключение вызова на POST сняло 403 сразу |
| 405 на сервисе MCP, значит всё работает | второй сервис при этом был мёртв, из этого случая выросла четвёртая ступень скрипта |
| сервер MCP не виден, значит опечатка в JSON конфига | JSON был верный, настольное приложение переписало файл своей копией через 4 секунды после ручной правки |
Когда подключение заработает, следующим встанет вопрос, что учётка MCP видит в базе: аудит прав доступа через нейросеть помогает ответить на него без полудня в конфигураторе.
Чего мы не проверяли
Всё снято на IIS. На Apache мы ожидаем тех же 409, 502 и 405, раз их отдаёт модуль платформы, но не проверяли. Подкоды 401.5 и 404.2 бывают только у IIS. Платформа 8.3.27, одна публикация на 8.3.20. Мост у нас один, и его поведение на рукопожатии может оказаться особенностью именно его: если сервер MCP живёт прямо в расширении, ступени 1-4 скрипта остаются теми же, а пятую стоит проверить у себя.
Открытым остаётся 403 на исполнении кода. Прямой GET на тот же адрес без параметров отвечает 200 с текстом “Не указан параметр code”, а 403 появлялся, похоже, когда код ехал внутри адреса GET-запроса. Кто именно его отдаёт, веб-сервер или модуль, мы так и не выяснили. Если вы докопались, расскажите.