Кратко
Пошаговое руководство по режиму кода AnythingMCP: запусти code runner, включи режим кода и сохрани code tool, который за один вызов инструмента читает последние заказы из ERP (weclapp), а также аккаунт и открытые сделки из CRM (HubSpot). Только чтение, с правами вызывающего, с аудитом.
Кратко: перед звонком клиенту менеджер по продажам просит ассистента составить обзор: последние заказы из ERP, а также владельца аккаунта и открытые сделки из CRM. Без режима кода это четыре-пять вызовов инструментов, и модель полностью читает результат каждого. С сохранённым code tool вызов один: customer_overview(customer) запускает короткую программу на JavaScript, которая делает нужные вызовы, оставляет только важное и возвращает одну компактную сводку. В этом руководстве мы создаём такой инструмент на self-hosted AnythingMCP (v0.52.1 или новее) с weclapp в роли ERP и HubSpot в роли CRM; тот же подход работает с любыми двумя коннекторами.
Что тебе понадобится
- Self-hosted AnythingMCP v0.52.1 или новее. Режим кода скоро появится в AnythingMCP Cloud.
- Два коннектора с инструментами для чтения, здесь это weclapp и HubSpot, установленные и работающие.
- Права администратора в рабочем пространстве.
Впервые слышишь об этой идее? В статье Что такое режим кода MCP? объясняется, почему одна программа лучше множества вызовов инструментов.
Шаг 1 — Запусти code runner
Код никогда не выполняется внутри самого AnythingMCP. Он работает в отдельном контейнере code-runner, и без него любой запуск кода отклоняется. Добавь в свой .env:
COMPOSE_PROFILES=code-runner
CODE_RUNNER_URL=ws://code-runner:8777
Если ты уже используешь профили, перечисли их вместе, например COMPOSE_PROFILES=files,code-runner. Затем выполни:
docker compose up -d
Runner не хранит секретов, не публикует портов и не имеет выхода в интернет; с ним общается только бэкенд, по внутренней сети Docker. Как изолируется каждый запуск: Безопасное выполнение кода для ИИ-агентов.
Шаг 2 — Включи режим кода для MCP-сервера
По умолчанию режим кода выключен для каждого MCP-сервера, а сохранённые code tools отклоняются на сервере, где режим кода равен off. Установи для сервера, которым пользуется твоя команда продаж, режим кода tools (только сохранённые code tools). Режим inline дополнительно предлагает агенту code_execute и code_propose_tool; для этого руководства он не нужен.
В дашборде открой MCP Servers, затем нужный сервер. В карточке Server settings вверху выбери для Code mode значение Saved code tools only и нажми Save. После этого переподключи ИИ-клиент.
Удобнее через API? PUT /api/mcp-servers/<id> с {"codeMode": "tools"} делает то же самое. Настройка появилась в v0.52.1; на v0.52.0 сначала обнови AnythingMCP.
Шаг 3 — Запиши id двух коннекторов
Code tool объявляет, какие коннекторы может вызывать его программа. Открой каждый коннектор в дашборде: его id — это последняя часть адреса, /connectors/<id>. Скопируй id коннекторов weclapp и HubSpot.
Шаг 4 — Создай code tool
Открой коннектор weclapp, перейди в MCP Tools и нажми Add Tool. Установи Tool Type в Code Tool, затем заполни поля:
- Tool Name:
customer_overview - Description: «Обзор одного клиента перед звонком: последние 10 заказов из ERP, аккаунт в CRM и его открытые сделки. Передай название компании или его часть». По описанию ИИ решает, когда вызывать инструмент, поэтому укажи, что он возвращает.
- Input Parameters: один параметр,
customer, тип string, обязательный.

Шаг 5 — Напиши программу
Program — это тело асинхронной функции JavaScript. Входные данные инструмента находятся в args; amcp.run(name, args) вызывает другой инструмент и возвращает его результат как разобранный JSON (и выбрасывает ошибку, если инструмент завершился сбоем). Всё, что ты вернёшь через return, получит ИИ.
// Input: args.customer, a company name or part of it.
const name = String(args.customer ?? '').trim();
if (!name) return { error: 'Pass a customer name.' };
// ERP (weclapp): the customer, then its latest sales orders.
const parties = await amcp.run('weclapp_list_customers', {
filter: `company-ilike=%${name}%`,
pageSize: 5,
});
const customer = (parties.result ?? [])[0];
if (!customer) return { error: `No customer matching "${name}" in the ERP.` };
const orders = await amcp.run('weclapp_list_sales_orders', {
filter: `customerId-eq=${customer.id}`,
sort: '-orderDate',
pageSize: 10,
});
// CRM (HubSpot): the company record and its open deals.
const companies = await amcp.run('hubspot_search_objects', {
object_type: 'companies',
query: customer.company,
properties: ['name', 'domain', 'hubspot_owner_id', 'lifecyclestage'],
limit: 1,
});
const company = companies.results?.[0];
let deals = [];
if (company) {
const found = await amcp.run('hubspot_search_objects', {
object_type: 'deals',
filter_groups: [{ filters: [
{ propertyName: 'associations.company', operator: 'EQ', value: company.id },
{ propertyName: 'hs_is_closed', operator: 'EQ', value: 'false' },
] }],
properties: ['dealname', 'amount', 'dealstage', 'closedate'],
limit: 20,
});
deals = found.results ?? [];
}
// Only this goes back to the model.
return {
customer: { number: customer.customerNumber, name: customer.company },
lastOrders: (orders.result ?? []).map((o) => ({
number: o.orderNumber, date: o.orderDate, status: o.status, net: o.netAmount,
})),
crm: company
? { owner: company.properties.hubspot_owner_id, stage: company.properties.lifecyclestage }
: null,
openDeals: deals.map((d) => ({
name: d.properties.dealname, amount: d.properties.amount,
stage: d.properties.dealstage, close: d.properties.closedate,
})),
};
Названия полей — те, что возвращают API weclapp и HubSpot. Прежде чем полагаться на поле, запусти нужный инструмент один раз в его панели Test и посмотри на результат; внутри программы await amcp.describe('weclapp_list_sales_orders') возвращает схему входных данных инструмента.
Замечание о связывании. Эта программа сопоставляет компанию в CRM по названию, чего достаточно для брифинга. Если ты храните номер клиента из ERP в свойстве HubSpot, фильтруй по нему, и совпадение будет точным.
Шаг 6 — Объяви, что может использовать программа
Uses (connectors) перечисляет коннекторы и, при необходимости, конкретные инструменты, которые программа может вызывать. Вставь два id из шага 3:
[
{ "connectorId": "<weclapp connector id>", "tools": ["weclapp_list_customers", "weclapp_list_sales_orders"] },
{ "connectorId": "<hubspot connector id>", "tools": ["hubspot_search_objects"] }
]
Указывать инструменты необязательно (без "tools" разрешён весь коннектор), но короткий список упрощает проверку инструмента. Принимаются только коннекторы того же рабочего пространства. Инструмент вне этого списка завершается ошибкой, даже если пользователь мог бы вызвать его напрямую.
Шаг 7 — Run as invoker, только чтение
- Run as: Invoker (собственные права вызывающего). Каждый внутренний вызов проверяется по роли того, кто использует инструмент. Менеджер без доступа к HubSpot получит ошибку в части HubSpot, точно так же, как если бы вызвал HubSpot напрямую. (Definer выполняется с правами, настроенными автором, как хранимая процедура; он предназначен для администраторов и Enterprise.)
- Allow write tools: выключено. Тогда программа может вызывать только инструменты для чтения;
weclapp_list_*иhubspot_search_objectsотносятся к чтению. Code tools с записью требуют Enterprise.
Нажми Create Tool.
Шаг 8 — Проверь в Claude или ChatGPT
Сначала проверь программу кнопкой Test у инструмента в дашборде: она запускает код в code runner по тем же правилам, что и настоящий вызов. Затем протестируй из ИИ-клиента, подключённого к MCP-серверу. Инструмент доступен на каждом сервере, где есть коннектор weclapp и включён режим кода. Переподключись или обнови инструменты в своём ИИ-клиенте и спроси:
«Через десять минут я звоню Lindenhof Bau. Что они заказывали в последнее время, кто ведёт аккаунт и есть ли открытые сделки?»
Ассистент один раз вызывает customer_overview и пишет брифинг по компактному результату, вместо того чтобы читать полные списки заказов и записи CRM. Если что-то не так, результат инструмента подскажет, что именно: вызов вне Uses ('hubspot_search_objects' is not a tool this code tool can use), ошибка, возвращённая API, или тайм-аут. Исправь программу, сохрани и спроси снова.
Что происходит при каждом вызове
- Один запуск, одна запись. Каждый вызов инструмента записывается как запуск кода, а каждый вызов инструмента, который делает программа, попадает в журнал аудита, как и любой другой вызов, с указанием пользователя.
- Лимиты. Запуск может длиться до 10 секунд, делать до 500 вызовов инструментов (по 16 одновременно) и возвращать до 1 МБ. Программа, превысившая лимит, останавливается с понятной ошибкой и ничего больше не затрагивает.
- Без вложенности. Code tool не может вызывать другой code tool.
- Только на твоих серверах. Code tools отдаются на собственных MCP-серверах рабочего пространства, но никогда на общем эндпоинте
/mcp.
Тарифы
Сохранённые code tools по редакциям, как объявлено в v0.52: Community 3, Starter 5, Team 20, Enterprise без ограничений. Code tools с записью и «run as definer» доступны в Enterprise. Сравнить тарифы.
FAQ
Нужно ли знать JavaScript?
Достаточно базового JavaScript: await, объекты, map и filter. Ты также можешь поручить агенту набросать программу и предложить её как инструмент, чтобы ты её проверил.
Может ли программа напрямую вызывать внешний API? Нет. У неё нет доступа к сети. Она может вызывать только MCP-инструменты, перечисленные в Uses; чтобы обратиться к другому API, сначала добавь его как коннектор.
На каком коннекторе должен находиться code tool? На любом из тех, которые он использует; инструмент появляется везде, где назначен этот коннектор. Выбери тот, чья аудитория должна получить инструмент.
Связанные материалы
- Что такое режим кода MCP?
- Безопасное выполнение кода для ИИ-агентов: как работает изолированный runner
- Рецепты режима кода: выручка по месяцам, сверка счетов, 100 запросов цен
- Агент предлагает code tool, администратор одобряет его
- Управляй своим ERP через ИИ: weclapp
- Развёртывание AnythingMCP с Docker Compose
- Подключи weclapp и HubSpot к Claude
Это руководство помогло?