skills/calling-1c-rest-api-via-curl/SKILL.md
Access a 1C:Enterprise database through the 1C MCP Toolkit REST API using curl. Provides 12 endpoints under /api/ for querying data (execute_query), exploring metadata (get_metadata), reading event logs (get_event_log), checking access rights (get_access_rights), finding object references (find_references_to_object), navigating objects by link (get_object_by_link, get_link_of_object), executing 1C code (execute_code), looking up BSL language reference (get_bsl_syntax_help), submitting text for de-anonymization (submit_for_deanonymization, when anonymization is enabled), and session management (restart_1c_session, close_1c_session). Use when the agent needs to interact with a 1C database via HTTP but does not speak MCP. Supports channel isolation for multi-database routing.
npx skillsauth add roctup/1c-mcp-toolkit calling-1c-rest-api-via-curlInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
REST API under /api/* mirrors the MCP tools. No authentication required. All endpoints use the same channel routing and validation logic as MCP.
BASE_HOST=localhost
BASE_URL="http://$BASE_HOST:6003"
CHANNEL="default"
J='-H Content-Type:application/json'
# Health check
curl -sS --noproxy $BASE_HOST "$BASE_URL/health"
Set curl --max-time above the proxy timeout (default 180s), e.g. --max-time 200.
Every response is JSON with this structure:
{"success": true, "data": <result>}
{"success": false, "error": "description"}
Most endpoints follow this pattern. Exception: submit_for_deanonymization returns {"received": true} on success (no data field).
Some endpoints add extra fields: count, truncated, has_more, last_date, next_same_second_offset, configuration, schema.
Controlled by server env RESPONSE_FORMAT (default: toon):
data is a TOON-encoded string inside the JSON envelope (saves 30–60% tokens)data is a normal JSON value (array/object/primitive)The outer envelope (success, error, extra fields) is always standard JSON regardless of format.
A JSON structure that identifies a 1C object reference. It flows between tools:
{
"_objectRef": true,
"УникальныйИдентификатор": "ba7e5a3d-1234-5678-9abc-def012345678",
"ТипОбъекта": "СправочникСсылка.Контрагенты",
"Представление": "ООО Рога и Копыта"
}
execute_query results, find_references_to_object hitsget_link_of_object, find_references_to_object, get_event_log (object filter)See references/object-description-format.md for full specification.
Pass ?channel=<name> in the URL query string. Regex: ^[a-zA-Z0-9_-]{1,64}$. Default: default.
curl -sS --noproxy $BASE_HOST "$BASE_URL/api/execute_query?channel=dev" $J -d '{"query":"ВЫБРАТЬ 1"}'
Full parameter tables, all curl variations, and complete response examples: references/tools-full-reference.md
GET/POST /api/get_metadataExplore database structure. Five modes:
| Mode | Params | Returns |
|------|--------|---------|
| Summary | none | Root types with counts + configuration info |
| List | meta_type and/or name_mask | Array of {ПолноеИмя, Синоним} with pagination |
| Detail | filter = full object name | Full object structure (attributes, dimensions, tabular sections) |
| Collection element | filter = full path to element | Single element info (e.g., Справочник.Контрагенты.Реквизит.ИНН) |
| Attribute search | attribute_mask | Array of {ПолноеИмя, Синоним} for all matching attributes across all objects |
Key params: filter, meta_type (string or array, "*" for all types), name_mask, attribute_mask, sections (requires filter, incompatible with attribute_mask): properties/forms/commands/layouts/predefined/movements/characteristics (movements only for Документ), limit (default 100, max 1000), offset, extension_name.
Request rules:
?channel=<id>Notes:
--data-urlencode for each parameter (except channel). To list extensions via GET, pass an explicit empty value: --data-urlencode "extension_name=".extension_name="MyExtension" (specific extension, not ""), responses include a top-level extension field in all modes (summary/list/details).# Summary
curl -sS -G --noproxy $BASE_HOST "$BASE_URL/api/get_metadata?channel=$CHANNEL"
# List documents matching "реализ"
curl -sS -G --noproxy $BASE_HOST "$BASE_URL/api/get_metadata?channel=$CHANNEL" \
--data-urlencode "meta_type=Документ" \
--data-urlencode "name_mask=реализ"
# Detail with sections (POST mode)
curl -sS --noproxy $BASE_HOST "$BASE_URL/api/get_metadata?channel=$CHANNEL" $J \
-d '{"filter":"Справочник.Номенклатура","sections":["properties"]}'
# Collection element filter (Mode 3a)
curl -sS --noproxy $BASE_HOST "$BASE_URL/api/get_metadata?channel=$CHANNEL" $J \
-d '{"filter":"Справочник.Контрагенты.Реквизит.ИНН","sections":["properties"]}'
# Attribute search — find all attributes whose name/synonym contains "контраг"
curl -sS --noproxy $BASE_HOST "$BASE_URL/api/get_metadata?channel=$CHANNEL" $J \
-d '{"attribute_mask":"контраг"}'
# Attribute search scoped to one object
curl -sS --noproxy $BASE_HOST "$BASE_URL/api/get_metadata?channel=$CHANNEL" $J \
-d '{"attribute_mask":"дата","filter":"Документ.Реализация"}'
POST /api/execute_queryExecute 1C query language queries. For query language syntax, table naming, and optimization rules consult the composing-1c-queries skill.
Key params: query (required), params (key-value), limit (default 100, max 1000), include_schema (boolean, adds column types).
curl -sS --noproxy $BASE_HOST "$BASE_URL/api/execute_query?channel=$CHANNEL" $J \
-d '{"query":"ВЫБРАТЬ Ссылка, Наименование ИЗ Справочник.Контрагенты","limit":5}'
Response:
{
"success": true,
"data": [
{
"Ссылка": {"_objectRef": true, "УникальныйИдентификатор": "ba7e5a3d-...", "ТипОбъекта": "СправочникСсылка.Контрагенты", "Представление": "ООО Рога и Копыта"},
"Наименование": "ООО Рога и Копыта"
}
],
"count": 1
}
Tip: Use "ВЫБРАТЬ ПЕРВЫЕ 0 * ИЗ ..." with include_schema: true to inspect table structure without loading data.
POST /api/execute_codeExecute arbitrary 1C code. Must assign result to Результат variable. Cannot declare Процедура/Функция or use Возврат.
Parameters: code (required), execution_context (optional: "server" (default) or "client").
"server" (default) — runs in &НаСервереБезКонтекста: full DB access, 1C objects, queries. Use for data operations."client" — runs in &НаКлиенте: access to form attributes and UI functions (ОткрытьФорму, etc.), no DB queries.Dangerous keywords blocked by default: Удалить, Delete, Записать, Write, УстановитьПривилегированныйРежим, SetPrivilegedMode, COMОбъект, COMObject, УдалитьФайлы, DeleteFiles, and others (see references/tools-full-reference.md).
CRITICAL: Query text inside execute_code must be a single line. Always write the entire query in one line without line breaks. Do not use multiline formatting.
// CORRECT:
Запрос.Текст = "ВЫБРАТЬ Ссылка, Наименование ИЗ Справочник.Контрагенты ГДЕ НЕ ПометкаУдаления";
# Simple code (server context, default):
curl -sS --noproxy $BASE_HOST "$BASE_URL/api/execute_code?channel=$CHANNEL" $J \
-d '{"code":"Результат = ТекущаяДата();"}'
# Code with query — single line:
curl -sS --noproxy $BASE_HOST "$BASE_URL/api/execute_code?channel=$CHANNEL" $J \
-d '{"code":"Запрос = Новый Запрос;\nЗапрос.Текст = \"ВЫБРАТЬ Ссылка, Наименование ИЗ Справочник.Контрагенты ГДЕ НЕ ПометкаУдаления\";\nРезультат = Запрос.Выполнить().Выгрузить().Количество();"}'
# Client context — open a form:
curl -sS --noproxy $BASE_HOST "$BASE_URL/api/execute_code?channel=$CHANNEL" $J \
-d '{"code":"ОткрытьФорму(\"Справочник.Номенклатура.ФормаСписка\"); Результат = \"OK\";","execution_context":"client"}'
Response: {"success": true, "data": "2024-01-15T10:30:00"}
POST /api/get_object_by_linkRetrieve complete object data by navigation link.
Link format: e1cib/data/Type.Name?ref=<32 hex chars>
curl -sS --noproxy $BASE_HOST "$BASE_URL/api/get_object_by_link?channel=$CHANNEL" $J \
-d '{"link":"e1cib/data/Справочник.Контрагенты?ref=80c6cc1a7e58902811ebcda8cb07c0f5"}'
Response: {"success": true, "data": {"_type": "Справочник.Контрагенты", "Код": "001", "Наименование": "ООО Рога и Копыта", ...}}
POST /api/get_link_of_objectGenerate a navigation link from an object_description (from execute_query results).
Note: on success, data is a string (navigation link), not an object.
curl -sS --noproxy $BASE_HOST "$BASE_URL/api/get_link_of_object?channel=$CHANNEL" $J \
-d '{"object_description":{"_objectRef":true,"УникальныйИдентификатор":"ba7e5a3d-1234-5678-9abc-def012345678","ТипОбъекта":"СправочникСсылка.Контрагенты"}}'
Response: {"success": true, "data": "e1cib/data/Справочник.Контрагенты?ref=ba7e5a3d12345678..."}
POST /api/find_references_to_objectFind all references to an object across the database.
Key params: target_object_description (required, see object description), search_scope (required, array from: documents, catalogs, information_registers, accumulation_registers, accounting_registers, calculation_registers), meta_filter ({names, name_mask}), limit_hits (default 200), limit_per_meta (default 20), timeout_budget_sec (default 30).
curl -sS --noproxy $BASE_HOST "$BASE_URL/api/find_references_to_object?channel=$CHANNEL" $J \
-d '{
"target_object_description": {
"_objectRef": true,
"УникальныйИдентификатор": "ba7e5a3d-1234-5678-9abc-def012345678",
"ТипОбъекта": "СправочникСсылка.Контрагенты"
},
"search_scope": ["documents"],
"limit_hits": 50
}'
Response:
{
"success": true,
"data": {
"hits": [
{"found_in_meta": "Документ.РеализацияТоваровУслуг", "found_in_object": {"_objectRef": true, "...": "..."}, "path": "Контрагент", "match_kind": "attribute", "note": "Реализация №001"}
],
"total_hits": 1, "candidates_checked": 5, "timeout_exceeded": false, "skipped_names": []
}
}
Quick check — is an object used at all? Set limit_hits: 1.
POST /api/get_access_rightsGet role permissions for a metadata object, optionally with effective user rights.
Key params: metadata_object (required, format Type.Name), user_name (case-insensitive search by IB user or Пользователи catalog), rights_filter, roles_filter.
Limitations: effective_rights = sum of roles (RLS, contextual restrictions NOT considered). Admin rights required.
curl -sS --noproxy $BASE_HOST "$BASE_URL/api/get_access_rights?channel=$CHANNEL" $J \
-d '{"metadata_object":"Справочник.Контрагенты","user_name":"Иванов"}'
Response:
{
"success": true,
"data": {
"metadata_object": "Справочник.Контрагенты",
"roles": [{"name": "Менеджер", "rights": {"Чтение": true, "Изменение": true, "Удаление": false}}],
"user": {"name": "Иванов", "roles": ["Менеджер"], "effective_rights": {"Чтение": true, "Изменение": true, "Удаление": false}}
}
}
POST /api/get_event_logRead event log entries with cursor-based pagination.
Key params: start_date, end_date (ISO 8601: YYYY-MM-DDTHH:MM:SS), levels (Information/Warning/Error/Note), events, limit (default 100, max 1000), user, metadata_type, application, computer, comment_contains, transaction_status (Committed/RolledBack/NotApplicable/Unfinished), object_description/link (filter by object).
Pagination: use last_date → start_date and next_same_second_offset → same_second_offset for next page. Stop when has_more=false.
curl -sS --noproxy $BASE_HOST "$BASE_URL/api/get_event_log?channel=$CHANNEL" $J \
-d '{"start_date":"2024-01-01T00:00:00","levels":["Error","Warning"],"limit":100}'
Response:
{
"success": true,
"data": [{"date": "2024-01-15T10:30:00", "level": "Error", "event": "_$Data$_.Update", "comment": "...", "user": "Иванов", "metadata": "Документ.РеализацияТоваровУслуг"}],
"count": 1, "last_date": "2024-01-15T10:30:00", "next_same_second_offset": 1, "has_more": false
}
POST /api/get_bsl_syntax_helpSearch the built-in BSL language reference: functions, methods, types, language constructs. Returns candidates (breadcrumb paths) and, when exactly one matches, Markdown content. Requires SyntaxHelpReader component loaded on the 1C side.
Key params: keywords (required, string[]) — search terms or exact path/link; match ("all"/"any", default "all"); limit/offset for candidate pagination; content_page for content pagination.
# Search by keyword
curl -sS --noproxy $BASE_HOST "$BASE_URL/api/get_bsl_syntax_help?channel=$CHANNEL" $J \
-d '{"keywords":["Найти","Массив"]}'
# Exact lookup by candidate path
curl -sS --noproxy $BASE_HOST "$BASE_URL/api/get_bsl_syntax_help?channel=$CHANNEL" $J \
-d '{"keywords":["Массив/Методы/Найти"]}'
# Next content page
curl -sS --noproxy $BASE_HOST "$BASE_URL/api/get_bsl_syntax_help?channel=$CHANNEL" $J \
-d '{"keywords":["Запрос"],"content_page":2}'
Response (multiple candidates): {"success": true, "data": {"candidates": [...], "total": N, "content": null, ...}}
Response (one match): {"success": true, "data": {"candidates": [...], "content": "...", "content_page": 1, "content_total_pages": N, "content_has_more": false, ...}}
Content pagination: fields content_page, content_total_pages, content_has_more appear only when content is not null. If content_has_more is true — call again with content_page + 1.
Links in content: Markdown links have format [Title](topic:Path). To follow — pass the full target including topic: prefix as a keyword.
POST /api/submit_for_deanonymizationSubmit the final user-facing response for de-anonymization display. Available only when anonymization is enabled. Returns {"received": true} on success (not {"success": true, "data": ...}).
When to use: MUST call if, and only if, your final response contains anonymization tokens [CATEGORY-NNNNN] (e.g., [ORG-00001], [PER-00042], [INN-00001]). Call exactly once, immediately before the final response. Do NOT call for intermediate steps.
Key params: text (required, string) — the complete final response text containing anonymization tokens.
curl -sS --noproxy $BASE_HOST "$BASE_URL/api/submit_for_deanonymization?channel=$CHANNEL" $J \
-d '{"text":"Компания [ORG-00001], ИНН [INN-00001], директор: [PER-00001]"}'
Response: {"received": true}
Error: {"success": false, "error": "Tool is not available: anonymization is disabled"}
POST /api/restart_1c_sessionRestart the current 1C session (picks up configuration changes). No parameters. New session starts automatically with same settings; anonymization state preserved. Old session shuts down after new one is ready.
IMPORTANT: Only call when explicitly instructed by the user or pipeline spec — never autonomously.
Use --max-time 200 (startup can take up to 120 s).
curl --max-time 200 -sS --noproxy $BASE_HOST "$BASE_URL/api/restart_1c_session?channel=$CHANNEL" $J -d '{}'
Response: {"success": true, "data": "Session restarted successfully. Note: the first MCP request to the new session may fail - retry once if it does."}
POST /api/close_1c_sessionClose the current 1C session and receive a launcher script command to start a new one. Use when exclusive DB access is needed (e.g., configuration update). No parameters.
IMPORTANT: Only call when explicitly instructed — never autonomously.
On success, data is a string containing the shell command to launch a fresh session. Run it synchronously: exit 0 = session ready; non-zero = startup failed. On Windows, run in PowerShell (not cmd.exe).
curl --max-time 200 -sS --noproxy $BASE_HOST "$BASE_URL/api/close_1c_session?channel=$CHANNEL" $J -d '{}'
Response: {"success": true, "data": "Session closed. To start a new session, run:\npowershell -ExecutionPolicy Bypass -File 'C:\\...\\launcher.ps1'\n..."}
Full curl commands and responses at each step: references/workflow-examples.md
Trigger: "what's in this database", "show me the structure"
GET /api/health — verify connectionGET /api/get_metadata — get root summary (types + counts) and configuration infoGET /api/get_metadata?meta_type=Документ — list objects of a specific type (use --data-urlencode for params)POST /api/get_metadata with filter + sections — get detailed structure of an objectPOST /api/execute_query — sample real dataTrigger: "where is this object used", "can I delete this"
POST /api/execute_query — find the object, extract object_description from resultPOST /api/find_references_to_object — find all references (tip: limit_hits: 1 for quick yes/no)POST /api/get_access_rights — check who can modify/deletePOST /api/get_event_log with object_description — check recent change historyTrigger: "what errors happened", "investigate recent problems"
POST /api/get_event_log with levels: ["Error"] and date range — fetch errorslast_date + next_same_second_offset until has_more=falsePOST /api/get_object_by_link or execute_query — examine objects mentioned in errorsPOST /api/execute_query — gather context data around problematic objects| Status | Meaning | Action |
|--------|---------|--------|
| 200 + success:true | OK | Use data |
| 200 + success:false | Business error / timeout from 1C | Read error string |
| 400 | Invalid JSON | Fix request body |
| 415 | Wrong Content-Type for POST | Add -H Content-Type:application/json |
| 422 | Validation error | Read error and details, fix params |
| 500 | Server error | Check proxy logs |
curl -sS --noproxy $BASE_HOST "$BASE_URL/api/execute_query?channel=$CHANNEL" $J -d '{"query":"ВЫБРАТЬ 1"}' \
| jq -r 'if .success then .data else ("ERROR: " + .error) end'
Default proxy timeout is 180s. Set curl --max-time slightly above (e.g., 200). For execute_code with long operations, increase both.
When building curl commands with JSON payloads containing 1C code and queries, multiple quoting levels are involved. Follow these rules to avoid errors.
-d payload (recommended)Single quotes prevent bash from interpreting $, !, &, backticks and other special characters inside the payload. Double quotes also work but require extra care with special characters.
# Recommended — single quotes, bash doesn't touch anything inside:
curl ... -d '{"query":"ВЫБРАТЬ 1"}'
# Also works, but bash interprets special characters — be careful:
curl ... -d "{\"query\":\"ВЫБРАТЬ 1\"}"
Instead of embedding string literals directly in query text (which requires complex escaping), always pass them as query parameters. This avoids nested quoting entirely.
# GOOD — value passed as parameter, no nested quoting:
curl ... -d '{"query":"ВЫБРАТЬ Ссылка ИЗ Справочник.Контрагенты ГДЕ Статус = &Статус", "params":{"Статус":"Активный"}}'
# GOOD — same for execute_code:
curl ... -d '{"code":"Запрос = Новый Запрос;\nЗапрос.Текст = \"ВЫБРАТЬ Ссылка ИЗ Справочник.Контрагенты ГДЕ Статус = &Статус\";\nЗапрос.УстановитьПараметр(\"Статус\", \"Активный\");\nРезультат = Запрос.Выполнить().Выгрузить();"}'
! in string valuesBash interprets ! as history expansion even inside some quote contexts. Never use ! in string literals. Replace with safe alternatives.
# BAD — ! triggers history expansion:
-d '{"code":"...ТОГДА \"!!! ВЫСОКАЯ\"..."}'
# GOOD — no exclamation marks:
-d '{"code":"...ТОГДА \"ВЫСОКАЯ\"..."}'
If you absolutely must embed a string literal in query text without a parameter, the escaping depends on context:
execute_query — one level of JSON escaping (\"):
curl ... -d '{"query":"ВЫБРАТЬ Ссылка ИЗ Справочник.Контрагенты ГДЕ Наименование ПОДОБНО \"%Рога%\""}'
execute_code — the 1C string "" escaping + JSON escaping (\"\"):
curl ... -d '{"code":"Запрос.Текст = \"ВЫБРАТЬ Ссылка ИЗ Справочник.Контрагенты ГДЕ Наименование ПОДОБНО \"\"%Рога%\"\"\";"}'
Prefer Rule 2 (parameters) over this whenever possible.
| Character | Problem | Solution |
|-----------|---------|----------|
| " inside query string | Nested escaping | Pass value as parameter (Rule 2) |
| ! | Bash history expansion | Avoid completely |
| & | Bash interprets in double quotes | Safe inside single-quoted -d payload |
| \n | Line break in JSON string | Use for separating 1C statements, NOT inside query text |
object_description structure and how it flows between toolsdevelopment
Compose correct and optimized 1C:Enterprise query language queries. Covers ВЫБРАТЬ/ИЗ/ГДЕ structure, table naming (catalogs, documents, registers, virtual tables), field selection, joins, grouping, totals, temporary tables, and parameter usage. Use when the agent needs to compose a 1C query for execute_query, or when the user asks to query, filter, aggregate, or analyze data from a 1C database. Triggered by requests involving 1C data retrieval, report building, or query debugging.
tools
Use when work should span one or more detached tasks but still behave like one job with a single owner context. TaskFlow is the durable flow substrate under authoring layers like Lobster, ACPX, plugins, or plain code. Keep conditional logic in the caller; use TaskFlow for flow identity, child-task linkage, waiting state, revision-checked mutations, and user-facing emergence.
tools
# Lobster Lobster executes multi-step workflows with approval checkpoints. Use it when: - User wants a repeatable automation (triage, monitor, sync) - Actions need human approval before executing (send, post, delete) - Multiple tool calls should run as one deterministic operation ## When to use Lobster | User intent | Use Lobster? | | ------------------------------------------------------ | --------------------------
tools
# Lobster Lobster executes multi-step workflows with approval checkpoints. Use it when: - User wants a repeatable automation (triage, monitor, sync) - Actions need human approval before executing (send, post, delete) - Multiple tool calls should run as one deterministic operation ## When to use Lobster | User intent | Use Lobster? | | ------------------------------------------------------ | --------------------------