Skip to main content
Glama

1C配置结构MCP服务器

多份1C配置的元数据、平台语法和查询语言参考手册——面向编写BSL代码的代理。提供最小充分切片:将人类表述解析为精确对象名、所需详细级别的对象结构、其关联、平台方法说明结合具体配置的版本以及查询语言结构。

不能替代对项目源码的grep:代码存在于文件中,服务器负责的是变化缓慢的配置知识。边界在docs/data-sources.md中明确。

状态——截至2026-08-18

阶段

状态

1C卸载处理

✅ 20种元数据,8.3.5和8.3.23,XML和JSON

卸载格式

schema v1

加载器、模型、关联图、渲染

✅ 5个配置,20 522个对象,322千条边

平台帮助

✅ 三个版本合并索引,25 691个元素,since/until边界

查询语言

shquery_ru.hbk,127页,独立无版本来源

搜索

✅ 97.1%帮助,94.7%查询语言,90.5%元数据——见「已测量」

寄存器虚拟表

✅ 现成查询字段名(КоличествоОстаток

旧平台替换表

✅ 不可用的不只是禁止,而是用配方替换

来源注册表、版本映射

MCP服务器,7个工具

✅ streamable-http和stdio

Docker

✅ 单容器,354 MB

搜索索引缓存

✅ 12 MB,替代重新解析启动

测量台

python -m mcp1c.bench,P@k,MRR,差距,标记核对

测试

pytest,371

仪表板

✅ 注册表、来源、查询运行、关联图、卡片、词典

授权

API_TOKEN读权限,ADMIN_TOKEN写权限

.cf索引模块

目录

  1. 启动 — Docker,仪表板关联图,无Docker

  2. 代理连接MCP如何工作如果无法连接,令牌,客户端 配置:Claude CodeCodex CLICursorVS CodeQwen Codestdio

  3. 工具调用顺序来源查询语言平台版本帮助合并替换

  4. 数据管理 — 来源, 词典和搜索键CLI测量台手动服务器数据来源

  5. 结构说明 — 模块, 测量测试

  6. 安全 — 令牌,无令牌时开放什么

  7. 文档


1. 启动

Docker(主要方式)

# 1. Положить исходные данные
mkdir -p data/bootstrap
cp ВыгрузкаКонфигурации.zip                     data/bootstrap/
cp /opt/1cv8/8.3.27.2130/shcntx_ru.hbk          data/bootstrap/

# 2. Поднять
docker compose up -d --build

# 3. Проверить
curl http://localhost:5001/health
{"status":"ok",
 "configurations_total":2,
 "syntax_loaded":true,
 "query_language_loaded":true,
 "configurations":["РозницаДляКазахстана","ЮвелирныйТорговыйДомДляКазахстана"],
 "syntax":["8.3.5.1570","8.3.23.1997","8.3.27"]}

平台帮助和查询语言是不同来源、不同字段:syntax_loaded仅指前者,syntax列出已加载帮助的版本。配置名称和帮助版本仅返回给通过读权限检查的请求;无令牌时保留status、计数器和两个标志。

data/bootstrap/中的所有内容在启动时被索引:*.zip——配置卸载,*.hbk——平台帮助。同一文件不会重复解析:按哈希核对。

./data目录挂载到容器中为/data。服务器在其中保存源文件、索引、缓存和registry.json;注册表中的路径是相对的,因此目录可以在开发机器和容器之间移动。

data/完全在git之外——它是卷,不是仓库的一部分。通过复制目录迁移。因此克隆后需要自行放置帮助文件:仓库不包含也不能包含它,这是1C公司的内容。

修改代码后需要重新创建容器,而不是重启:

docker compose up -d --build --force-recreate

restart会在旧镜像上启动旧容器,修改不会生效。

**关于端口。**对外服务器监听5001,容器内监听8000——docker-compose.yml中映射5001:8000。本文所有地址都是外部的,即5001。被其他服务占用——修改映射左侧,右侧不要动:EXPOSE和镜像的healthcheck依赖它。

仪表板

http://localhost:5001/ — 六个页面:

页面

内容

概览

已加载内容:对象、关联、平台版本、清单中的警告

来源

已加载列表,上传.zip.hbk,删除

查询

运行表述列表,带评分和排序原因

关联

对象邻域图(图片形式)

卡片

对象组成或平台元素说明——与代理看到的一致

词典

带来源的规则;创建别名或同义词组

关联——对象图

/graph绘制对象邻域:颜色按类型,箭头按链接方向,悬停显示边标签。点击节点围绕它构建图,拖拽移动,滚轮缩放。邻居限制在页面上选择(15…400),裁剪以数字表示——「显示30/102」。

回答「动了会坏什么」:被橙色文档包围的寄存器立即告诉你谁在动它。

**深度始终一步。**从常用参考手册两步就能到达一千个对象,三步——配置的三分之一;再远就通过公共机制如附加属性连接,它们几乎连接一切。无法用关联数阈值切断:这样的节点有34条边,而有意义的Справочник.Пользователи有323条。因此由人展开节点,而非启发式——人能看到哪里不该去。

**代理有意没有这个工具。**分析和返回条件见docs/TASKBOARD.md「已推迟」部分。

失误无需离开浏览器即可修复:查询页面上每个短语都有「不对——创建别名」链接,指向已填入该短语的词典。修改立即生效——索引不重建,无需重启。

**读取由API_TOKEN保护,写入由ADMIN_TOKEN保护。**API_TOKEN未设置时,任何能访问地址的人都可以读取——包括配置结构和定制。对localhost可接受,对网络服务器则不行。

令牌分离是因为读令牌存在于每个MCP客户端配置中并随其泄露;代理不应有删除来源的权限。管理员令牌也可用作读令牌——无需保留两个头。

// .mcp.json — как клиент передаёт токен
{"mcpServers": {"1c": {"type": "http", "url": "http://localhost:5001/mcp",
                       "headers": {"X-Api-Token": "..."}}}}

仅ASCII:HTTP头以latin-1编码,西里尔字母无法传输。/health对healthcheck保持开放,但配置名称仅按令牌返回。

上传、删除和词典编辑需要ADMIN_TOKEN——与/admin/reload相同;没有它这些端点不存在,而非「被关闭」。令牌在表单中输入一次,浏览器收到的是会话标识符而非令牌。

通过docker-compose.yml旁的.env设置——包含所有变量的模板在.env.example中:

cp .env.example .env
python3 -c "import secrets; print(secrets.token_urlsafe(32))"   # значение
docker compose up -d --force-recreate

结果中的名称是卡片链接:对象显示带类型的属性、表格部分和移动,平台元素显示签名、参数、可用性和出现版本。与代理收到的文本相同,带brief / fields / full切换。属性没有自己的卡片——链接指向所属对象。

「查询」页面回答「服务器为什么返回这个」:每个命中旁边有原因——精确匹配词典中的别名查询的所有词。可以看出如何修复失误——用同义词、别名或权重。

帮助解析需要几秒:页面在解析后响应,但MCP客户端不受影响——索引在单独线程中进行。

无Docker

python3 -m venv .venv && .venv/bin/pip install -r requirements.txt
PYTHONPATH=src .venv/bin/python -m mcp1c.server --host 0.0.0.0 --port 5001

2. 代理连接

服务器通过官方SDK的标准传输实现MCP协议,因此适用于任何MCP客户端。无需HTTP包装。

传输

适用场景

地址

streamable-http

服务器在Docker或独立机器上

http://地址:5001/mcp

stdio

客户端本地启动进程

sse

仅用于旧客户端

--transport sse

两种主要传输均已通过官方MCP客户端验证:initialize握手、tools/listtools/call,协议2025-11-25

这是如何工作的

在连接失败之前理解这一点很有用。**地址唯一——/mcp**没有按工具的路由;调用哪个工具写在请求体中,而非路径中。

接下来是两种不同的机制,不应混淆:

工具描述

数据

时机

连接时一次

每次调用

发起方

客户端,自行,无需模型参与

模型,按决策

方法

POST initialize,然后POST tools/list

POST tools/call

去向

模型系统提示词

对话体

成本

一次性,整个会话占用

每次调用

连接时客户端执行POST initialize——服务器返回名称、版本和instructions文本,并在头中返回mcp-session-id。然后POST tools/list一次性返回工具:名称、描述、参数JSON模式。所有这些在人类输入第一个词之前就放入模型上下文。模型不会在需要时去获取描述——它已经有了。

由此得出一个编辑描述时重要的推论:它们在整个会话中占用窗口空间,无论模型是否调用任何工具。

3. 工具

工具始终是七个,无论加载了什么。工具集是契约而非变量:工具之间相互关联,工作服务器上加载了全部三个来源——配置、平台帮助、查询语言。tools/list 契约加上 instructions——约 3 900 个令牌,这个数字与注册表状态无关。

由此得出一个必须提前知道的直接后果:如果来源未加载,您仍然要为其工具付费。 没有平台帮助时,search_syntaxget_syntax 躺在上下文中,花费 1 185 个令牌,回答「帮助未连接」;compare_configurations 在只有一个配置时——262 个令牌只为回答「至少需要两个」。解决办法是加载来源,而不是筛选工具:筛选在 2026-08-19 试过并已取消——详情和数字见「已推迟」

因此描述写得很紧凑,细节则移入工具自身的输出中:只有需要时才为它付费。

GET /mcp 不是「错误的 POST」,而是同一地址上的第三种方法:它打开从服务器到客户端的消息流,并要求已获取的 mcp-session-idDELETE /mcp 关闭会话。

如果客户端无法连接

日志中的响应代码(docker logs -f mcp1c)说明原因:

代码

问题

406

客户端未发送 Accept: application/json, text/event-stream——两种类型都需要

400 Missing session ID

客户端未返回在 initialize 时获得的 mcp-session-id

首次 GET /mcp 时返回 400

客户端以 GET 开始握手——它使用的是旧的 HTTP+SSE 传输,而此地址是 streamable-http

/sse 返回 404

同样的问题:旧传输未对外暴露

401

在设置了 API_TOKEN 的情况下未传递 X-Api-Token

日志中为空

客户端根本没有发送请求——问题出在它的配置中,请求未到达服务器

真实案例:Qwen Code 无法连接,因为其配置中有 url 键——在 Gemini CLI 系列中(Qwen 继承了该格式)它表示旧的 SSE 传输,客户端以 GET 开始,收到 400。使用 httpUrl——即 streamable-http——连接立即成功。

令牌:在客户端设置中添加什么

如果服务器上设置了 API_TOKEN,每个客户端都必须通过请求头发送它。没有该头,/mcp 返回 401,代理将看不到任何工具。

两个请求头中的任意一个都可以——服务器都接受:

X-Api-Token: <токен>
Authorization: Bearer <токен>

三件容易绊倒的事情:

  • 仅限 ASCII。 HTTP 头使用 latin-1 编码,西里尔字母令牌无法通过。生成方式: python3 -c "import secrets; print(secrets.token_urlsafe(32))"

  • 客户端中放置的是 API_TOKEN,而不是 ADMIN_TOKEN 管理员令牌也能被接受,但客户端配置会进入 git 和备份:泄露的只读令牌允许查看,泄露的管理员令牌则允许删除来源。

  • stdio 完全不需要令牌。 那里客户端自己启动进程,不涉及网络,无需验证。如果客户端不支持设置请求头——这是一个可行的变通方案。

在配置任何客户端之前,检查服务器是否能看到令牌:

curl -s -o /dev/null -w '%{http_code}\n' -X POST \
  -H 'x-api-token: ВАШ_ТОКЕН' \
  -H 'content-type: application/json' \
  -H 'accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"probe","version":"1"}}}' \
  http://localhost:5001/mcp

200 — 令牌已接受。401 — 令牌错误或请求头未送达。

如何不提交密钥

.mcp.json 及类似文件通常位于仓库中。方案:

  1. 变量替换 — 如果客户端支持(Claude Code 支持): "X-Api-Token": "${MCP1C_API_TOKEN}",变量本身放在 ~/.zshrc 中。 进入 git 的是变量名,而不是值。

  2. 将文件移出 git 管理: git rm --cached .mcp.json && echo ".mcp.json" >> .gitignore

  3. 将设置放在项目之外的用户级客户端配置中 — 这样与仓库完全无关。

Claude Code

项目根目录下的 .mcp.json 文件:

{
  "mcpServers": {
    "1c": {
      "type": "http",
      "url": "http://localhost:5001/mcp",
      "headers": { "X-Api-Token": "${MCP1C_API_TOKEN}" }
    }
  }
}

仅当服务器上设置了 API_TOKEN 时才需要 headers 块。值从环境变量中获取,以便文件可以放在仓库中:

echo 'export MCP1C_API_TOKEN=ваш_токен' >> ~/.zshrc && source ~/.zshrc

或者使用命令:

claude mcp add --transport http 1c http://localhost:5001/mcp \
  --header "X-Api-Token: $MCP1C_API_TOKEN"

Codex CLI

~/.codex/config.toml 或项目中的 .codex/config.toml

[mcp_servers.mcp1c]
url = "http://localhost:5001/mcp"

# Только если задан API_TOKEN. Имя ключа для заголовков у Codex менялось между
# версиями — сверьтесь со своей (`codex --help`, раздел MCP). Не подхватилось —
# используйте stdio, там токен не нужен вовсе.
[mcp_servers.mcp1c.http_headers]
X-Api-Token = "ваш_токен"

Cursor

.cursor/mcp.json

{
  "mcpServers": {
    "1c": {
      "type": "streamable-http",
      "url": "http://localhost:5001/mcp",
      "headers": { "X-Api-Token": "ваш_токен" }
    }
  }
}

VS Code (Copilot)

.vscode/mcp.json — 这里的键名为 servers

{
  "servers": {
    "1c": {
      "type": "http",
      "url": "http://localhost:5001/mcp",
      "headers": { "X-Api-Token": "ваш_токен" }
    }
  }
}

Qwen Code

格式来自 Gemini CLI,键选择传输方式——这是唯一的微妙之处:

{
  "mcpServers": {
    "1c": {
      "httpUrl": "http://localhost:5001/mcp",
      "headers": { "X-Api-Token": "ваш_токен" }
    }
  }
}

httpUrl — streamable-http,即我们的情况。此格式中的 url 表示旧的 SSE 传输:客户端将以 GET /mcp 开始握手,收到 400 Missing session ID 后无法连接。

其他客户端

Windsurf、Antigravity、Cline、Roo Code、控制台代理——写法相同:传输类型、URL,以及如果设置了 API_TOKEN,还有请求头块。区别仅在于文件名和顶层键名(mcpServersservers)——请查阅具体客户端的文档。

客户端不支持设置请求头——这不是死胡同:通过 stdio 连接,那里不需要令牌,因为没有网络。

通过 stdio 本地启动

当客户端需要自行启动服务器时。这里不需要令牌:进程由客户端启动,通信通过进程管道进行,而非网络——无需验证,也无需防范任何人。

{
  "mcpServers": {
    "1c": {
      "command": "python3",
      "args": ["-m", "mcp1c.server", "--transport", "stdio", "--data", "/путь/к/data"],
      "env": { "PYTHONPATH": "/путь/к/проекту/src" }
    }
  }
}

3. 工具

工具集是固定的,并且有意保持精简:每个工具都常驻在代理的上下文中。新的数据源丰富的是现有工具的回答,而不是添加自己的工具。

工具

用途

list_configurations

加载了什么,每个配置可用哪些提供程序

search_objects(query, config, kind, limit)

人类表述 → 对象的精确名称

get_object(full_name, config, detail)

对象组成;detailbrief / fields / full

get_related(full_name, config)

流转、引用、依赖——仅直接

compare_configurations(full_name, configs)

两个配置中的同一个对象

search_syntax(query, config, kind, limit)

在平台帮助和查询语言中搜索

get_syntax(name, config, detail)

签名、参数、可用性、版本、旧平台替代方案

当加载了多个配置时,config 为必填:服务器有意不静默地猜测——否则代理会根据错误的数据库编写代码,而无人知晓。

一个名称可以同时存在于两个域中:СтрНайти 既在平台中(自 8.3.6 起),也在查询语言中。此时 get_syntax 会列出所有同名项,并附上每个的现成地址,可以用输出中的一行重复调用:

get_syntax("СтрНайти")                    → Одноимённых элементов: 2
                                            - `Глобальный контекст.СтрНайти` — Метод, с 8.3.6
                                            - `Запрос.СтрНайти` — Функция запроса
get_syntax("Запрос.СтрНайти")             → карточка функции языка запросов

限定符 Запрос. 是必需的,因为查询语言元素没有所有者:无法像平台元素那样通过 Объект.Член 来限定。

调用顺序——以及违反它会失去什么

list_configurations → search_objects → get_object → search_syntax → get_syntax

不能跳过 get_object 步骤。 搜索只返回名称和计数器;代码所依赖的一切都存在于对象卡片中:

  • 注册表的类型和周期。 СрезПоследних 仅存在于周期信息注册表中,而 603 个中有 566 个是非周期的;

  • 虚拟表字段的现成名称。 在查询中,资源 Количество 被称为 КоличествоОстатокКоличествоОборотКоличествоПриход——这些名称在设计器中任何地方都看不到,它们由平台生成;

  • 子分析限额、对应关系、图表资源 — 没有它们,СубконтоДт1 之类的字段无法命名;

  • 不定长字符串。 直接在类型中标记:Строка (неогр. — только через ПОДСТРОКА) 对比 Строка(200)。这样的字段不能直接放入查询——平台不允许比较、分组或排序。在真实配置中,这类字段占字符串字段的 23% 到 38%,因此在包含它们的卡片上(20 522 张中的 2 474 张),在字段列表之前会打印带配方的说明。

search_objects 之后立即编写的查询看起来正确,却报「字段未找到」。以下示例仅来自 get_object

## Таблицы запроса
- `РегистрНакопления.ТоварыНаСкладах.Остатки`
  измерения: Склад, Номенклатура, Характеристика
  ресурсы: КоличествоОстаток, РезервОстаток

第二个同样的例子——这是 2026-08-18 一次真实的失误。代理按无长度限制的字符串分组;我们返回了正确的数据,但差异只能通过括号中缺少数字来识别:

> **Строки неограниченной длины** помечены `(неогр.)`. Платформа не даёт их
> сравнивать, группировать и упорядочивать и не пускает в РАЗЛИЧНЫЕ,
> ОБЪЕДИНИТЬ и агрегатные КОЛИЧЕСТВО, МИНИМУМ, МАКСИМУМ. Ограничивайте
> длину — одинаково в списке выборки и в группировке:
>
>     ПОДСТРОКА(КодСкидки, 1, 100) КАК КодСкидки
>
> Длину подбирайте по смыслу поля: 100 — не универсальное число.

## Реквизиты

- `КодСкидки` — Строка (неогр. — только через ПОДСТРОКА) // Код скидки
- `КодМаркировки` — Строка(200) // Код маркировки

配方既在说明中,也在字段字符串本身中,这并非冗余。 第一版将说明打印在卡片的最后一段。2026-08-18 一个真实代理调用了 get_object 并传入 detail=fields,完整获取了它——却仍然按该字段分组。说明位于字段字符串之后 721 个令牌处,而决策是在复制名称的地方做出的。同样的教训已经写在工具描述上:规则在人们阅读它的地方起作用,而不是在人们认为更合适放置它的地方。

每个禁止项都经过验证:聚合函数——引用自帮助,其余五项——在真实数据库上运行并记录了错误文本。帮助只知道六个聚合函数中三个的限制,对分组、排序、РАЗЛИЧНЫЕОБЪЕДИНИТЬ 和比较只字不提——也就是说,即使代理诚实地阅读了帮助,也无法得知这些。按来源分类见 docs/data-sources.md 中「卡片中的说明」一节。

在旧配置上调用平台函数之前——先调用 get_syntax 不可用的会被标记,如果已记录,那里也有替换配方。

来源相互独立

共有三个,每个单独连接:

来源

文件

提供什么

没有它

配置元数据

СтруктураКонфигурации_*.zip

对象、属性、关系、流转

search_objectsget_object 不响应

平台帮助

shcntx_ru.hbk

方法、属性、签名、可用性、版本

search_syntax 返回「来源未连接」

查询语言

shquery_ru.hbk

ВЫБРАТЬЛЕВОЕ СОЕДИНЕНИЕИТОГИ ПОРАЗНОСТЬДАТ

查询语言结构无法找到

已加载内容

可用的功能

全部三个

全部

仅配置

元数据;语法返回「来源未连接」

仅帮助

语法不过滤版本,config 不需要

list_configurations 说明要加载什么

查询语言——独立来源

shquery_ru.hbk 来自平台安装目录。127 页:52 个函数、67 个关键字、8 篇文章。作为普通来源加载,并进入与平台帮助相同的搜索索引——无需用单独的工具搜索,search_syntax 两者都能找到。

文件本身没有版本——已检查全部 129 页:零处提及「8.3.x」和「自版本起」。但查询语言在变化:8.3.20 版本添加了 25 个函数,包括 СтрНайтиЛевПравВРегНРегСтрЗаменитьОкрЦел 以及全部三角函数。

Взять версию неоткуда: справка платформы функций языка запросов не описывает вовсе (ПОДСТРОКА — ноль совпадений на 25 511 элементов). Поэтому версии задаёт курируемая таблица query_versions.py — по списку 1С «Функции, добавленные в язык запросов начиная с релиза 8.3.20». Остальным 27 функциям версия не приписывается: они были всегда.

Дальше работает обычный фильтр: конфигурация на 8.3.5 этих функций не увидит, на 8.3.23 увидит.

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

python3 tools/lab/compare_query_help.py <старая.hbk> <новая.hbk>

Прогон 2026-08-19, 8.3.5.1570 против текущей: появилось 29, покрыто 29, ложных срабатываний 0. Ложное срабатывание — худшая из ошибок: элемент, который был уже в старой справке, но помечен версией, спрячется от конфигурации, где он есть.

Экземпляр один на сервер: повторная загрузка заменяет прежний.

Таблицы страниц показываются, но не ищутся. В этой справке ячейки таблиц размечены абзацами внутри <TD>, и без отдельного разбора карточка печатала таблицу столбцом значений: «Товар / Количество / Номер / Сантехника / 104 / …» два десятка строк подряд. Теперь таблицы разбираются отдельным полем — 51 таблица на 31 странице из 127 — и печатаются на своих местах в тексте: страница с двумя примерами показывает каждый результат под своим примером. В поисковый индекс содержимое таблиц не попадает.

Таблицы в этой справке двух разных природ, и разбираются они по-разному:

Что

Сколько

Как выглядит в карточке

таблица данных — результат запроса-примера

51 на 31 странице

markdown-таблицей

рисованная синтаксическая диаграмма — грамматика конструкции

21 на 17 страницах

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

Различаются по разметке, а не по классу CSS: class=SimplyTable стоит не на всех — 7 настоящих таблиц идут без него. Признак — геометрия: у таблицы данных все строки одной ширины, у диаграммы ширины рваные и есть ячейки из одной вертикальной черты (это нарисованная линия, а не значение).

Испорченная разметка называется вслух. Страница с незакрытой <TABLE> разбирается без таблиц, но не теряется, и её имя попадает в предупреждения источника: строкой в выводе загрузки (mcp1c.cli reg-add) и отдельной строкой на странице «Источники» дашборда. Молча отдать карточку беднее обычного нельзя: от справки, в которой этого просто нет, такое неотличимо.

Половина имён совпадает с именами платформы (57 из 127) — ГОД, МЕСЯЦ, ПРЕДСТАВЛЕНИЕ есть и там и там. Чтобы вопрос про запрос не уводил к методу платформы, обороты вроде «в запросе», «в тексте запроса», «в выборке» дают элементам языка запросов мягкий подъём. Мягкий намеренно: при уверенном отрыве платформенный элемент остаётся первым — «как задать параметр в запросе» может быть и про Запрос.УстановитьПараметр.

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

Ответ зависит от версии платформы

Один и тот же вызов, две конфигурации:

get_syntax("СтрШаблон", config="Розница")          → 8.3.23
# Метод: Глобальный контекст.СтрШаблон
с версии платформы 8.3.6
Доступность: ТонкийКлиент, ВебКлиент, Сервер, ТолстыйКлиент, …

get_syntax("СтрШаблон", config="Ювелирный")        → 8.3.5
# `Глобальный контекст.СтрШаблон` недоступен в этой конфигурации
Элемент существует, но появился в 8.3.6, а конфигурация работает на 8.3.5.1570.
Использовать нельзя — код не скомпилируется.

Для платформы 8.3.5 из выдачи убрано 6 539 элементов, для 8.3.23 — 874. Не предупреждением, а фильтрацией: предупреждение агент пропустит, отсутствующий в выдаче метод — нет.

Поле Доступность (сервер / тонкий клиент / веб-клиент / мобильные) читать обязательно: вызов серверного метода из клиентского контекста не компилируется.

Справки нескольких версий сливаются в один индекс

Одна свежая справка на старой конфигурации врёт. Замерено на 8.3.5: 199 элементов сервер объявил бы несуществующими, 117 отдал бы с чужой сигнатурой (ЗаписьXML.ОткрытьФайл на 8.3.5 берёт два параметра, в 8.3.27 — три), 410 — с чужой доступностью. Всё это ошибки компиляции, а не неточности.

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

Цена измерена и мала: слияние трёх версий даёт 25 691 ключ против 24 777 у одной, то есть меньше процента. Отдельный контейнер на версию тоже работает и остаётся аварийным путём, но как основной проигран по цифрам — 300–450 МБ и свой адрес на каждую версию.

Сервер сам называет, каких справок не хватает и какие лишние, — в выдаче list_configurations.

Замена вместо запрета

Сказать «функции нет» — половина ответа. Вторая половина — чем её заменить, и из справки она не выводится: пометка об устаревании стоит на 15 страницах из 25 тысяч.

Поэтому есть таблица замен (replacements.py), сейчас 6 записей — строковые функции, появившиеся в 8.3.6. Вместо запрета get_syntax отдаёт рецепт:

get_syntax("СтрРазделить", config="Ювелирный")     → 8.3.5
# `СтрРазделить` недоступна: появилась в 8.3.6

Замена: РазложитьСтрокуВМассивПодстрок(<Строка>, <Разделитель>)
Оговорка: разделитель у `СтрРазделить` — набор символов, каждый из которых
самостоятельный разделитель; у замены это одна строка целиком.

Оговорка обязательна. Замена почти никогда не эквивалентна, и молча подсунуть похожую функцию — хуже, чем не подсказать ничего.

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


4. Управление данными

Добавить источник

# в Docker
docker compose exec mcp1c python -m mcp1c.cli reg-add /data/bootstrap/Выгрузка.zip --data /data
docker compose exec mcp1c python -m mcp1c.cli reg-add /data/bootstrap/shcntx_ru.hbk --data /data

# без Docker
PYTHONPATH=src python3 -m mcp1c.cli reg-add Выгрузка.zip

Проще: положить файл в data/bootstrap/ — он подхватится при следующем старте.

Применить изменения без перезапуска

Работающий сервер держит реестр в памяти, поэтому после reg-add его нужно подтолкнуть. Либо перезапуск (docker compose restart mcp1c, около 2 секунд), либо админ-ручка:

# включается переменной ADMIN_TOKEN; без неё маршрут отключён
ADMIN_TOKEN=секрет docker compose up -d
curl -X POST -H "x-admin-token: секрет" http://localhost:5001/admin/reload

Словарь: как говорят против того, как названо

Главная сложность поиска — разрыв между словами человека и именами в конфигурации. «Заказ клиента» — а объект называется ЗаказПокупателя. Словарь лежит в data/dictionary.json, правится без пересборки образа.

Два механизма, и они разные.

Синонимы слов — общие для всех конфигураций:

python3 -m mcp1c.cli dict-synonyms клиент покупатель заказчик

Псевдонимы объектов — прямое указание «когда я говорю так, я имею в виду вот эти объекты», вес выше любого текстового совпадения. Два десятка типовых фраз («файлы», «товары», «клиенты», «сотрудники», «задачи») встроены и работают сразу; если объекта в конфигурации нет, псевдоним не применяется. Свои добавляются с привязкой к конфигурации:

python3 -m mcp1c.cli dict-alias "справочник физлиц" \
    Справочник.ФизическиеЛица Справочник.Пользователи \
    --config РозницаДляКазахстана
«справочник физлиц»
    Справочник.ФизическиеЛица     псевдоним из словаря
    Справочник.Пользователи       псевдоним из словаря

Существование объектов проверяется при добавлении — псевдоним на опечатку бесполезен. Посмотреть содержимое: dict-show, удалить: dict-alias «фраза» --remove.

Изменения применяются перезапуском контейнера или POST /admin/reload — пересобирать образ не нужно.

Поисковые ключи языка запросов — третий механизм, и правится он только в коде (search_keys.py, в git с ревью). Разрыв тут другой природы: человек не называет конструкцию чужим словом, а описывает задачу. «Количество дней между двумя датами» против РАЗНОСТЬДАТ, «убрать повторы» против РАЗЛИЧНЫЕ — общих слов ноль, и синоним не поможет, заменять нечего.

Поэтому к 116 страницам из 127 приписаны формулировки, которыми их спрашивают, и попадают в поисковый индекс отдельным полем. В рантайме не весят ничего. Результат на живом наборе: 57,9% → 94,7% первым местом, без регресса на 61 тысяче автоматических запросов.

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

  • живут отдельным слоем в git, а не приписываются разобранному элементу;

  • в ответ агенту не попадают — ответ по-прежнему собирается только из справки, ключи работают исключительно на попадание в нужную статью;

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

Правило целиком — в docs/data-sources.md, раздел «Сгенерированные слои поверх источников».

Посмотреть, что загружено

docker compose exec mcp1c python -m mcp1c.cli reg-list --data /data
РозницаДляКазахстана  2.3.10.5  платформа 8.3.23.1997
  объектов 5637, связей 44034, загружено 2026-08-18T12:22:16+00:00
  метаданные : да
  синтаксис  : справка 8.3.27, новее конфигурации, скрыто 874
  модули     : не подключены
  язык запросов: подключён, 127 страниц

Конфигураций может не быть вовсе — сервер при этом работает, если загружена хоть одна справка: отвечают search_syntax и get_syntax, config указывать не нужно. reg-list в этом случае перечисляет подключённое и возвращает 0:

Конфигурации не загружены. Подключено:
  язык запросов, 127 страниц
Работают search_syntax и get_syntax, без фильтра по версии.

На полностью пустом реестре — «Ничего не загружено.» и код возврата 1. Любая команда, которой нужна конфигурация, там же скажет, чего именно не хватает и чем каждое берётся.

Отладка без агента — mcp1c.cli

CLI ходит в тот же реестр и те же функции, что и инструменты MCP. Если он отвечает верно — дело в настройке клиента, а не в сервере.

Команды делятся на три группы. По реестру — то же, что видит агент:

PYTHONPATH=src python3 -m mcp1c.cli reg-list  [--data data]
PYTHONPATH=src python3 -m mcp1c.cli reg-add   Выгрузка.zip     [--data data]
PYTHONPATH=src python3 -m mcp1c.cli reg-add   shcntx_ru.hbk    [--data data]
PYTHONPATH=src python3 -m mcp1c.cli reg-search "чек ккм"  --config РозницаДляКазахстана
PYTHONPATH=src python3 -m mcp1c.cli reg-search "разделить строку" --syntax --limit 5

reg-search без --syntax ищет по метаданным, с ним — по справке и языку запросов.

Прямо по файлу, без реестра — посмотреть выгрузку до того, как она поедет в сервер:

PYTHONPATH=src python3 -m mcp1c.cli info    Выгрузка.zip
PYTHONPATH=src python3 -m mcp1c.cli stats   Выгрузка.zip
PYTHONPATH=src python3 -m mcp1c.cli show    Выгрузка.zip Документ.ЧекККМ --detail full
PYTHONPATH=src python3 -m mcp1c.cli related Выгрузка.zip Документ.ЧекККМ --depth 2
PYTHONPATH=src python3 -m mcp1c.cli find    Выгрузка.zip реализация --limit 10

Путь — ZIP или распакованный каталог, формат определяется по манифесту.

Словарь поиска — синонимы общие, псевдонимы привязаны к конфигурации:

PYTHONPATH=src python3 -m mcp1c.cli dict-show                       # правила и их происхождение
PYTHONPATH=src python3 -m mcp1c.cli dict-show --all --config Розница...
PYTHONPATH=src python3 -m mcp1c.cli dict-synonyms чек ккм касса     # группа взаимозаменяемых слов
PYTHONPATH=src python3 -m mcp1c.cli dict-synonyms чек ккм --remove
PYTHONPATH=src python3 -m mcp1c.cli dict-alias "справочник физлиц" Справочник.ФизическиеЛица
PYTHONPATH=src python3 -m mcp1c.cli dict-alias "справочник физлиц" --remove

dict-show показывает происхождение каждого правила — с этого начинается разбор «почему поиск так себя ведёт».

Замер качества поиска — mcp1c.bench

Отдельный стенд, потому что «стало лучше» без цифр — мнение.

PYTHONPATH=src .venv/bin/python -m mcp1c.bench \
    --data data --config РозницаДляКазахстана \
    --auto --sets query-language,roznica-metadata --check-notes

Ключ

Что делает

--sets имя,имя

ручные наборы из tests/queries/*.json, без расширения

--auto

автоматические наборы по справке: точные имена и одноимённые

--config

конфигурация; обязательна, если загружено несколько

--limit

глубина выдачи, по умолчанию 10

--save путь

записать прогон для сравнения; по уговору data/bench/ГГГГ-ММ-ДД.json

--baseline путь

сравнить с прошлым прогоном — назовёт поимённо, кто сменил место

--check-notes

сверить пометки в наборе с тем, какое место запрос занял

Печатает P@1/P@3/P@5/P@10, MRR, долю «чужой домен первым» и медианный отрыв первого результата от второго. Порогов в assert нет намеренно: наборы запросов — не тесты, проценты ломались бы от каждой правки словаря. Ненулевой код возврата бывает только на расхождении пометок — это не качество поиска, а враньё в файле.

Сравнение двух прогонов выглядит так (ухудшения первыми):

=== сравнение с прошлым прогоном ===
  - «как прибавить месяц к дате в запросе»: 1 -> промах
  - «как отсортировать результат запроса»: 1 -> 5
  + «в чем разница между внутренним и левым соединением»: 5 -> 4

Наборы в образ не входят (tests/ в .dockerignore) — запускать из рабочей копии, не из контейнера.

Сервер вручную — mcp1c.server

PYTHONPATH=src python3 -m mcp1c.server --data data          # streamable-http на :8000/mcp
PYTHONPATH=src python3 -m mcp1c.server --transport stdio    # локальному клиенту
PYTHONPATH=src python3 -m mcp1c.server --host 0.0.0.0 --port 5001

--transport sse в коде есть и работает, но наружу не выведен: SDK поднимает один транспорт на процесс, а всё состояние у нас в памяти — второй транспорт стоил бы примерно столько же, сколько первый. Сам SSE в MCP объявлен устаревшим в пользу streamable-http.

Откуда берутся исходные данные

Структура конфигурации — обработкой из exporter-1c/. Четыре варианта модуля под обычную и управляемую форму, XML и JSON; XML-варианты совместимы с 8.3.5. Две обработки лежат уже собранными и открываются как есть: ВыгрузкаСтруктурыКонфигурации_ОбычнаяФорма_XML.epf (8.3.5 и выше) и ВыгрузкаСтруктурыКонфигурации_УправляемаяФорма_XML_JSON.epf (8.3.6 и выше, формат выбирается на форме).

Справка платформы — файл shcntx_ru.hbk из каталога установки 1С:

/opt/1cv8/<версия>/shcntx_ru.hbk
C:\Program Files\1cv8\<версия>\bin\shcntx_ru.hbk

Имя должно совпадать целиком. В том же каталоге лежат сотни файлов .hbk — 38 разных справок, каждая на два десятка языков. Похожие на нужный:

文件

这是什么

为什么不合适

shcntx_root.hbk

同一份帮助,语言无关部分

25 508 个元素,但没有任何描述:只有页面树和英文标识符,没有出现版本

shlang_ru.hbk

内置语言描述

根本不是 1C 容器

shquery_ru.hbk

查询语言

同上

config_ru.hbk

配置器帮助

是容器,但内部没有语法助手页面

1cv8_ru.hbk

用户手册

不是容器

按大小无法区分:shcntx_root.hbk 为 33 MB,而目标文件为 39 MB。后缀 _ru 表示语言,_root 表示无文本的公共部分。

文件不对——服务器会解释具体原因,并保留原有帮助文件不动。

只需要一份来自最新可用平台的帮助:每个元素都带有出现版本,对于旧配置,多余的内容会被过滤掉。如果路径中没有版本,则从数据本身推断。

旧平台的帮助文件同样被接受——它们的标记方式不同(章节用 div 而不是 p),这一点已考虑在内。如果为旧部署搭建独立服务器,这会很有用:来自 8.3.5 的帮助提供 18 936 个元素,且不包含 СтрНайтиСтрРазделитьЗаписьJSON——这些在 8.3.5 中本来就不存在。但此类帮助不会报告自身版本:其中没有“从版本开始”的标记,因为当时一切都是当前的。因此,版本取自文件名或目录名——请将其命名为 8.3.5.1570.hbk 或放入 data/hbk/8.3.5.1570/,否则与配置的匹配将无法工作。


5. 工作原理

src/mcp1c/
  v8container.py     контейнер 1С — общий для .hbk, .cf, .epf
  syntax_parser.py   разбор справки платформы
  syntax_model.py    модель элемента справки, виды, границы версий
  syntax_merge.py    слияние справок разных версий в один индекс
  query_parser.py    разбор справки по языку запросов (shquery_ru.hbk)
  replacements.py    чем заменить функцию, которой нет в старой платформе
  virtual_tables.py  таблицы запроса регистров и имена их полей
  loader.py          чтение выгрузок, XML и JSON в одну модель
  model.py           модель конфигурации
  graph.py           граф связей
  graph_view.py      окрестность объекта для картинки на дашборде
  search.py          лексический поиск
  search_keys.py     формулировки, которыми спрашивают язык запросов
  synonyms.py        встроенный словарь: как говорят против того, как названо
  dictionary.py      локальный словарь поверх встроенного
  index_cache.py     кэш поисковых индексов, расходный
  store.py           чтение и запись разобранных справок
  render.py          markdown-карточки объектов и элементов
  registry.py        реестр источников, сопоставление версий
  tools.py           семь инструментов, без зависимости от MCP
  server.py          протокольный слой (единственная внешняя зависимость)
  dashboard.py       веб-интерфейс: реестр, запросы, словарь
  cli.py             отладочный CLI
  bench.py           стенд замеров качества поиска

一种模型,两种格式。 XML 和 JSON 是同一模式的不同序列化;加载器将两者转换为相同的字典。已验证:两种导出产生相同的 30 个键的集合。

图由加载器构建,而不是 1C。 边从属性类型、文档移动、输入依据、所有者、订阅处理程序和计划任务方法中推导。规则可以在不重新导出的情况下更改。

弱边。ЗначениеДоступа 这样的属性枚举了数百种类型,并将几乎所有东西与所有东西关联。这些关联被标记为弱关联,默认隐藏——否则有用的关联会被淹没。

详细程度。 Документ.ЧекККМ 的完整描述(50 个属性,17 个表格部分)会完全消耗上下文。brief 是几行,fields 是组成,full 是带关联的。

无外部数据库。 五个配置及其帮助保存在一个进程的内存中——628 字节,从磁盘启动 9.4 秒。Elasticsearch、向量存储和图数据库都经过考虑并被否决,附有数据:分析见 docs/TASKBOARD.md 的“已推迟”部分。简而言之:50 万文档对 ES 来说太少,而向量的全部成本不在存储,而在运行时的编码器模型(+185–620 MB 到镜像,torch 的编码请求 16–32 毫秒,而当前整个搜索为 0.18–1.4 毫秒)。

在真实数据上测量——2026-08-18

工作服务器上加载的内容:

配置

平台

对象

哈萨克斯坦会计

8.3.27.1936

3 492

84 426

文档流 КОРП

8.3.27.1936

4 596

50 554

薪资与人力资源管理

8.3.27.1936

5 181

100 136

哈萨克斯坦零售

8.3.23.1997

5 637

58 345

珠宝贸易公司

8.3.5.1570

1 616

29 288

总计

20 522

322 749

加上平台帮助——三个版本(8.3.5、8.3.23、8.3.27)的合并索引,25 691 个元素,以及查询语言——127 页作为独立来源。

从缓存启动——所有这些需要 9.4 秒。首次启动更慢:解析源文件,构建索引并存储到 data/index/cache/(12 MB),解析的帮助存储到 data/index/syntax/(11 MB)。之后从那里加载。

缓存是派生的且可消耗的:绑定到 Python 版本、包代码的指纹和源的哈希。如果任何一项不匹配——索引将重新构建。目录可以随时删除,它会自动重建。

活动容器的内存——628 MB。索引发布以 numpy 数组形式存储;填充保持字典形式,并在冻结后立即释放。镜像——354 MB

模块文本——侦察,尚无提供者

modules 提供者尚未实现,服务器不提供代码工具。成本已提前测量,在“零售”2.3.10.5 导出到文件(2 063 MB,33 188 个文件,7 878 个模块,136 909 个过程):

在磁盘上

在内存中

过程签名和地址

18.1 MB

65 MB

搜索所有过程

473 MB

仅搜索导出过程(49 068)

156 MB

表单:3 194 个文件,69 769 个元素

5.8 MB

44 MB

搜索延迟——0.4–1.2 毫秒。语料库解析——7–10 秒。

存在两种不同的文件导出,第二种单独测量——“珠宝贸易公司”10.5.1.3 在 8.3.5 上:平面布局,模块在 .txt 中,普通表单的代码在二进制容器 .Form 内。2 603 个模块,33 555 个过程,解析 1.1 秒,搜索所有 94 MB,中位数 0.2 毫秒。此格式不包含表单结构,部分通用模块以编译形式提供——其中根本没有源代码。

测量脚本位于 tools/lab/,它们是探索性的,将在真正的提供者出现时被丢弃。目前,它们可以重现上述每个数字:

python3 tools/lab/measure_modules.py <каталог выгрузки в файлы>
python3 tools/lab/measure_resident.py <каталог> <файл индекса> собрать
python3 tools/lab/measure_search.py <файл индекса> [экспортные]
python3 tools/lab/measure_forms.py <каталог>
python3 tools/lab/measure_flat.py <каталог плоской выгрузки>

完整解析,包括配置扩展的结构,——docs/modules-and-extensions-2026-08-18.md

搜索质量

通过测试台测量,一条命令即可重现:

PYTHONPATH=src .venv/bin/python -m mcp1c.bench \
    --data data --config РозницаДляКазахстана \
    --auto --sets query-language,roznica-metadata --check-notes

数据集

查询数

P@1

P@3

P@5

MRR

差距

查询语言

19

94.7%

94.7%

100%

0.958

35.0%

零售元数据

21

90.5%

95.2%

95.2%

0.934

94.0%

帮助中的精确名称

50 926

97.1%

98.3%

98.7%

0.978

91.7%

同名

10 544

98.8%

99.8%

99.9%

0.993

93.8%

前两个数据集是手动的,来自真实失败。后两个是从数据本身构建的:元素名称作为查询,它本身作为预期答案。

“差距”——第一个结果与第二个结果的差距,以中位数衡量。回答“是自信命中还是侥幸”的问题:查询语言 35% 对比帮助 91.7% 意味着这些胜利的强度弱三倍,排名调整可以翻转它们,而不移动 P@1 的一个百分点。

搜索延迟——0.18–1.4 毫秒/查询,取决于数据集。

查询集不包含在镜像中tests/.dockerignore 中):测量应从工作副本进行,而不是从容器中。

测试

.venv/bin/pip install -r requirements-dev.txt
.venv/bin/python -m pytest          # 371 тест, ~2 с

不依赖 data/ 的内容:仓库中没有专有导出,所有需要的内容在 tests/conftest.py 中合成生成。

搜索质量不通过测试检查——它通过测试台测量(mcp1c.bench,见“测量”)。百分比阈值会因每次字典编辑而破坏,因此测试台打印数字,而决策由人做出。pytest 检查可观察的行为:“索引未重建”、“结果匹配”、“启动未崩溃”。


6. 安全

两个令牌,都由环境变量设置。只要令牌未设置,相应的访问权限就对所有能访问该地址的人开放。

变量

保护什么

未设置时

API_TOKEN

读取:MCP 工具和仪表板页面

配置结构对所有人生效

ADMIN_TOKEN

写入:加载和删除源、编辑字典、/admin/reload

这些路由被禁用,返回 404

“开放”和“禁用”之间的区别是有意为之。没有令牌的读取是有效的——在您自己的机器上这很方便且没有风险。没有令牌的写入完全无效:一次失败的字典编辑会静默破坏所有连接到共享服务器的用户的搜索。

令牌通过标头传递——要么 X-Api-Token,要么 Authorization: Bearer <token>。管理员令牌也适用于读取:否则所有者必须在客户端中保留两个标头而不是一个。

令牌必须使用拉丁字母。 HTTP 标头以 latin-1 编码,西里尔令牌无法到达服务器:通过浏览器中的登录表单它可以工作,通过客户端标头则不行。

两个路径绕过检查:/health(容器健康检查使用它,并且它不提供超出读取权限的信息)和 /login——否则登录表单会被它自己提供的授权所保护。

还有两条规则,与令牌无关:

  • MCP 端点返回完整的配置结构。 在您的机器之外部署时,请设置 API_TOKEN,网络访问是不够的。

  • data/ 目录完全在 .gitignore——包括 .hbk 和导出文件,以及解析后的索引。帮助索引是 1C 公司的相同内容,只是解包了。它曾经被提交并存在了 20 个提交;历史被 git filter-repo 重写,规则被重新表述为按目录而不是按扩展名:要检查的不是“这是 .hbk 吗?”,而是“这位于 data/ 中吗?”。


7. 文档

文件

关于什么

AGENTS.md

项目工作规则

CHANGELOG.md

已完成的工作和关于 1C 的发现

docs/TASKBOARD.md

计划、优先级和已拒绝的提案及原因

docs/schema-v1.md

导出格式的契约

docs/data-sources.md

我们从哪个来源获取什么

docs/query-language-design.md

查询语言来源的结构

docs/dashboard-design.md

仪表板的结构

docs/market-review-2026-08-17.md

类似产品的回顾以及从中借鉴的内容

exporter-1c/README.md

1C 的导出处理

任务板中的“已推迟”部分——被拒绝的提案及数据:外部数据库、向量、图数据库、外部 SSE、惰性加载。在重新提出这些建议之前,值得阅读:这些决定被新的测量推翻,而不是被新的考虑推翻。

-
license - not tested
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/AzeevAN/mcp-1c'

If you have feedback or need assistance with the MCP directory API, please join our Discord server