Give an AI agent eyes into your 1C:Enterprise 8.3 base — read metadata & data, run queries, and diagnose why a document won't post — over one extension HTTP service.
Most 1C automation tooling either reads metadata or reads data. The thing an analyst actually gets stuck on — "this document won't post, why?" — needs both, plus the ability to run the posting logic and capture the error. 1c-mcp does exactly that.
It exposes your base as MCP tools through a thin HTTP service in a configuration extension. The MCP server stays a small, strict TypeScript client; the reasoning about how to fix a broken document is left to the agent (Claude) — no LLM baked into the server, no API keys to manage.
- 🔎 Metadata introspection — objects, attributes, tabular sections, register records
- 📄 Data & queries — read objects by ref, run 1C query-language, list documents, read register movements
- 🩺 Document diagnosis — test-post a document inside a rolled-back transaction, capture the fill errors, the exception text, the failing attribute, and the movements it tried to make — the whole context an agent needs to explain and fix it
- 🔒 Read-only by default — write tools (
object_update,document_post) exist but only register whenONEC_ALLOW_WRITE=1 - 🪶 TypeScript, ESM, MIT — 2 runtime deps (
@modelcontextprotocol/sdk,zod), no 1C secrets in the repo
document_diagnose(ref) is the headline. The extension runs, inside a transaction it always rolls back:
ПроверитьЗаполнение()— collects required-field / validation problemsЗаписать(…Проведение)in aПопытка/Исключение— captures the posting exception and everyСообщить()- reads back the register movements it would have made
…then returns one structured object. The agent gets the error text, the exact attribute/row that failed, the document data, the object's metadata, and the attempted movements — and works out the fix:
document_diagnose # ref → { filled, fillErrors, posts, errorText, messages, wouldMove, data, metadata }
# agent reads it, explains the cause, proposes the change
object_update # (if ONEC_ALLOW_WRITE=1) apply the fix
document_post # (if ONEC_ALLOW_WRITE=1) post for real
Because the transaction is always rolled back, diagnosis has zero side effects on the base.
- 1C:Enterprise 8.3 base published on a web server with HTTP services enabled.
- A configuration extension exposing the HTTP service
mcp(see The 1C side — this is the part you build, against a fixed contract). - A 1C user for the MCP to authenticate as (Basic Auth).
- Node ≥ 18.
npm install
cp .env.example .env # set ONEC_URL / ONEC_USER / ONEC_PASSWORD
npm run buildRegister it with your MCP client:
{
"mcpServers": {
"1c": {
"command": "node",
"args": ["D:/projects/1c-mcp/dist/index.js"],
"env": {
"ONEC_URL": "http://localhost/mybase/hs/mcp",
"ONEC_USER": "mcp",
"ONEC_PASSWORD": "secret",
"ONEC_ALLOW_WRITE": "0"
}
}
}
}| Env | Meaning |
|---|---|
ONEC_URL |
HTTP-service root: http://<host>/<base>/hs/<rootURL> |
ONEC_USER / ONEC_PASSWORD |
1C user for Basic Auth |
ONEC_ALLOW_WRITE |
1 registers the write tools; anything else = read-only |
The env prefix is
ONEC_(not1C_) on purpose — a var name starting with a digit breaks in POSIX shells.
| Tool | Purpose |
|---|---|
metadata_list |
List metadata objects (Catalogs / Documents / Registers …) with a filter. |
metadata_get |
Full structure of one object: attributes, tabular sections, register records. |
metadata_search |
Search objects by name/synonym across all kinds. |
object_get |
Read an object by GUID ref — attributes + tabular sections. |
query_run |
Run a 1C query-language query and return rows. |
document_list |
List documents by type / period / filter. |
register_records |
Register movements / balances by document or filter. |
document_diagnose |
Test-post in a rolled-back transaction → fill errors, exception text, failing attribute, movements, data, metadata. |
document_check_fill |
Fill check only (no test-post). |
object_update ⚑ |
Write an object's attributes / tabular sections. |
document_post ⚑ |
Post a document for real. |
⚑ — registered only when ONEC_ALLOW_WRITE=1.
The MCP talks to one HTTP service. You implement it in a configuration extension, against this contract.
Root: http://<host>/<base>/hs/mcp. Every method: POST, JSON body, Basic Auth. Errors: non-2xx with body { "error": { "code": string, "message": string } } (the client turns this into a tool error).
| Method | Request | Response (key fields) |
|---|---|---|
/metadata/list |
{ kind?, filter? } |
{ objects: [{ fullName, name, synonym, kind }] } |
/metadata/get |
{ fullName } |
{ fullName, synonym, attributes[], tabularSections[], registerRecords[] } |
/query/run |
{ text, params?, limit? } |
{ columns[], rows[][] } |
/object/get |
{ ref } |
{ ref, presentation, fields{}, tabularSections{} } |
/document/list |
{ type, period?, filter?, limit? } |
{ documents: [{ ref, number, date, presentation, posted }] } |
/register/records |
{ register, filter?, ref? } |
{ records[] } |
/document/diagnose |
{ ref } |
see below |
/document/checkfill |
{ ref } |
{ filled, fillErrors[] } |
/object/update ⚑ |
{ ref, fields{}, tabularSections? } |
{ ok, ref } |
/document/post ⚑ |
{ ref } |
{ ok, posts, errorText? } |
{
"ref": "guid",
"presentation": "Реализация 0001 от 01.01.2026",
"filled": false,
"fillErrors": [{ "field": "Организация", "message": "Поле не заполнено" }],
"posts": false,
"errorText": "Недостаточно 5 шт номенклатуры X на складе Y",
"messages": [{ "text": "...", "field": "Товары", "dataPath": "Товары[2].Количество" }],
"wouldMove": [{ "register": "ТоварыНаСкладах", "records": [{ "...": "..." }] }],
"data": { "Организация": null, "Товары": [{ "...": "..." }] },
"metadata": { "attributes": [], "tabularSections": [], "registerRecords": [] }
}-
Create a configuration extension, add an HTTP service with root URL
mcp. -
Implement the URL templates from the contract (method POST, JSON in/out).
-
The key handler
/document/diagnose— a side-effect-free test-post:Объект = Ссылка.ПолучитьОбъект(); Результат = Новый Структура("filled, fillErrors, posts, errorText, messages, wouldMove, data, metadata"); НачатьТранзакцию(); Попытка Результат.filled = Объект.ПроверитьЗаполнение(); // messages collected below Попытка Объект.Записать(РежимЗаписиДокумента.Проведение); Результат.posts = Истина; Исключение Результат.posts = Ложь; Результат.errorText = ОписаниеОшибки(); КонецПопытки; Результат.messages = ПолучитьСообщенияПользователю(Истина); Исключение Результат.errorText = ОписаниеОшибки(); КонецПопытки; ОтменитьТранзакцию(); // always roll back — the base is never changed
Fill
data/metadata/wouldMoveand return the JSON above. -
Publish the base on a web server, enable HTTP services, create the
ONEC_USERuser. -
Smoke test:
curl -u user:pass -X POST http://host/base/hs/mcp/metadata/list -d "{}".
npm test # vitest — config, HTTP client, write-tool gating (no live 1C needed)
npm run build # tsc → dist/
npx tsc --noEmit # typecheckThe design spec and implementation plan live in docs/superpowers/.
document_diagnosealways runs inside a rolled-back transaction — zero side effects.- Write tools register only when
ONEC_ALLOW_WRITE=1. - 1C credentials come from the environment only;
.envis git-ignored and never committed.
PRs welcome. Good first ideas:
- a bundled reference extension (
.xmlsources of the HTTP-service module) - OData transport as a read-only fallback (no extension required)
- richer
wouldMoveshaping / typed diagnose result - Russian README
- Fork and branch:
git checkout -b feature/my-change npm install;npm run buildandnpx tsc --noEmitmust pass;npm testgreen- Never commit secrets (
.env, passwords) or real base data - Open a PR describing what and why
MIT