Files
llm/docs/runbooks/adapter-1c-mcp.md
2026-08-14 09:40:51 +03:00

33 KiB

adapter-1c-mcp

Thin MCP proxy for the 1C REST adapter.

Target host:

docker.cin.su

Runtime URL:

http://docker.cin.su:8021

MCP endpoint for Codex:

http://docker.cin.su:8021/mcp

The server responds with MCP protocol 2025-06-18 and returns Mcp-Session-Id during initialize.

Legacy SSE endpoint:

http://docker.cin.su:8021/sse

Direct JSON-RPC endpoint for smoke tests:

http://docker.cin.su:8021/mcp

Codex config:

[mcp_servers.adapter-1c-mcp]
enabled = true
url = "http://docker.cin.su:8021/mcp"

Already running Codex Desktop windows can keep the MCP tool list from their startup time. Restart Codex Desktop, or start a fresh session, after changing MCP server configuration.

How The Adapter URL Is Passed

The MCP proxy does not hard-code the 1C adapter address. Pass it with:

ONEC_ADAPTER_URL=http://docker.cin.su:8011

Optional adapter bearer token:

ONEC_ADAPTER_TOKEN=

Timeout for adapter HTTP calls:

ONEC_ADAPTER_TIMEOUT_SECONDS=4

These variables are configured in:

core/deploy/docker/adapter-1c-mcp/.env.example

For real deployment, create a non-committed .env next to the compose file and set the actual adapter URL/token there.

REST adapter on docker.cin.su

The REST SQL adapter is deployed from:

core/deploy/docker/adapter-1c/compose.yaml

Its published port is set in a non-committed REST environment file:

ADAPTER_1C_HOST_PORT=8011

SQL-base administration is available in the REST adapter at:

http://docker.cin.su:<ADAPTER_1C_HOST_PORT>/admin

With the default port this is http://docker.cin.su:8011/admin. The page is used to add or update SQL connections for named bases. Do not put connection passwords in Git or documentation. If the port changes, use the new port both for this page and in ONEC_ADAPTER_URL.

If that port is occupied, select a free port there and set the MCP URL to the same value, for example ONEC_ADAPTER_URL=http://docker.cin.su:18011. Keep ONEC_SQL_BASES_JSON (or the mounted /data/onec-sql-bases.json) only in that external runtime configuration; never place SQL passwords in this repository.

Deploy

Deploy both REST adapter and MCP proxy, then run live verification when a test base is available:

powershell -NoProfile -ExecutionPolicy Bypass `
  -File scripts\deploy_1c_adapter_stack.ps1 `
  -RestEnvFile <path-to-non-committed-rest-env> `
  -McpEnvFile <path-to-non-committed-mcp-env> `
  -BaseId <base-id-from-project-context>

Multiple test bases can be verified in one deploy:

powershell -NoProfile -ExecutionPolicy Bypass `
  -File scripts\deploy_1c_adapter_stack.ps1 `
  -BaseId <base-id-1>,<base-id-2>

Duplicate base ids are rejected before verification starts, so persisted reports are not overwritten by an accidental repeated base value.

To make post-deploy checks deterministic, pass an explicit metadata object selector. This is optional; without it the smoke discovers a module-capable object automatically.

powershell -NoProfile -ExecutionPolicy Bypass `
  -File scripts\deploy_1c_adapter_stack.ps1 `
  -BaseId <base-id-from-project-context> `
  -ObjectGuid <metadata-object-guid> `
  -ObjectKind <metadata-kind>

Saved-state preparation defaults to ConfigSave for the base configuration save layer. Use -SavedStateTable ConfigCASSave when the strict smoke should target an extension/CAS save layer instead:

powershell -NoProfile -ExecutionPolicy Bypass `
  -File scripts\deploy_1c_adapter_stack.ps1 `
  -BaseId <base-id-from-project-context> `
  -SavedStateTable ConfigCASSave

The deploy script prints Docker container summaries for both services, then the verify script prints /health status and contract_version before running the REST and MCP selector-chain smoke tests. The selector-chain smoke also checks, when a routine name is available from module metadata, that metadata.resolve_overrides returns write_plan_evidence.next_resolution for metadata.saved_state.modules.search with the same base_id and routine query, plus a public object ref/kind/name and semantic layer=base_saved_state|extension_saved_state; public follow-ups never require ConfigSave, ConfigCASSave, or owner_guid. The smoke then follows that resolver. If a saved-state stream exposes write_plan_target, the smoke composes it with write_plan_evidence.target and checks the resulting read-only metadata.write.plan; when the test base has no saved-state stream, that last composition step records skipped_no_saved_state_target. These selector-chain reports are written under reports/1c-sql/<base-id>/selector-chain-rest-smoke.json and reports/1c-sql/<base-id>/selector-chain-mcp-smoke.json. Each report includes a top-level coverage block summarizing whether override evidence was found, whether the saved-state resolver ran, whether a write_plan_target was available, and which steps were skipped. The verify script validates that both selector-chain report files are written, parse as JSON, pass, and include the expected coverage sections. Use -RequireSelectorChainWritePlanComposition when the test base is expected to contain a matching saved-state stream and the selector-chain smoke must fail instead of accepting skipped_no_saved_state_target. Verification also runs the read-only write-plan safety smoke through both REST and MCP onec_request; the MCP smoke also checks that live methods without payload.base_id are stopped by adapter_1c_mcp_policy.v1 with base_id_required, and that low-level storage.*/query.* fallback calls are blocked as diagnostic_method unless diagnostics are explicitly requested. The verify script validates the written write-plan safety reports after each smoke. Then verification runs REST saved-state form/module write-loop smoke tests through metadata.write; if the test base has no pending ConfigSave/ConfigCASSave rows, those saved-state checks record skipped_no_saved_state and pass by default. The saved-state report files are also parsed and checked after the smoke commands. Before those smoke tests, verification generates read-only saved-state-strict-readiness.json and saved-state-copy-plan.json reports for the selected -SavedStateTable. The copy plan is generated through scripts/plan_1c_saved_state_copy.py using the same object selector arguments, so the later persisted-report check has fresh copy-preparation evidence. At the end, verification runs scripts/check_1c_verify_reports.py against the persisted report set, so the same report validation can be repeated offline without calling the adapter. The offline validator checks that selector-chain coverage includes metadata.resolve_overrides evidence, the expected metadata.saved_state.modules.search next step, saved-state resolution, and attempted metadata.write.plan composition. It also verifies write-plan safety outcomes: effective form writes must route to metadata.write.plan, uncontrolled replacement must be blocked, controlled replacement must be planned through metadata.module.write_apply, drift must be blocked, and MCP policy checks must block missing base_id and diagnostic fallback. Saved-state write smoke reports are checked in both modes: empty-state skips must include successful preflight counts and skipped=true; real write-and-rollback runs must include allowed write plans, expected apply methods, and rollback evidence. The same persisted report validator also checks saved-state-strict-readiness.json and saved-state-copy-plan.json when saved-state write smoke reports are enabled. Readiness must match the requested base_id and selected save-layer table; in strict mode it must be ready=true. The copy plan must match the requested base_id, resolve a concrete object, list active source rows from the matching storage family, be plan_ready, and show clear target collision status for ConfigSave/ConfigCASSave. The family must match the target save layer: Config -> ConfigSave for base changes and ConfigCAS -> ConfigCASSave for extension/CAS changes. The validator also checks that readiness, copy-plan target table, saved-state form smoke table, and saved-state module smoke module_ref table are the same. scripts/check_powershell_scripts.py also guards the verify/deploy wiring for these strict flags and asserts that check_1c_verify_reports.py --self-test covers selector-chain, safety, saved-state, and copy-plan failure classes. Persisted report validation also pins the expected JSON schema value for each report type, so stale or unrelated report files fail before their contents are trusted. The same validator checks report identity: each persisted JSON must match the requested base_id, and REST/MCP reports must match their expected transport. When verification provides expected endpoints, REST/MCP reports must also match the configured endpoint_url.

To require an actual saved-state write-and-rollback instead of allowing the empty-state skip:

python scripts\check_1c_saved_state_strict_readiness.py `
  --base-id <base-id-from-project-context> `
  --saved-state-table ConfigSave `
  --report reports\1c-sql\<base-id>\saved-state-strict-readiness.json `
  --json

This readiness check is read-only. It checks REST adapter health, row counts in the selected save-layer table, and saved-state form/module discovery. Use --saved-state-table ConfigSave for the base save layer or --saved-state-table ConfigCASSave for the CAS/extension save layer. If it reports blocked_no_saved_state_rows, there are no unactivated Configurator changes in the selected save layer. To prepare a strict write test, copy the target object from the main configuration storage (Config/ConfigCAS) into the selected save layer through the approved saved-state workflow, then rerun readiness before enabling strict mode.

To produce a read-only copy preparation plan for a concrete object:

python scripts\plan_1c_saved_state_copy.py `
  --base-id <base-id-from-project-context> `
  --kind <metadata-kind> `
  --name <metadata-object-name> `
  --target-table ConfigSave `
  --report reports\1c-sql\<base-id>\saved-state-copy-plan.json `
  --json

The copy plan does not write SQL. It lists active storage rows for the selected object only from the matching source family, checks whether the intended ConfigSave/ConfigCASSave target already contains the same FileName values, and records the intended save-layer target. --target-table ConfigSave plans from Config; --target-table ConfigCASSave plans from ConfigCAS. Normal verification regenerates this file automatically before saved-state smoke tests and uses -SavedStateTable to pick the same target table for the copy plan, form smoke, and module smoke. Run the command manually when choosing a target object for strict readiness or when preparing evidence without the full deploy/verify flow. The offline persisted-report validator checks this file by default, so regenerate the plan whenever the chosen object, target table, or base changes.

To generate the reviewed SQL preparation script from that plan without executing SQL:

python scripts\prepare_1c_saved_state_copy_sql.py `
  --plan reports\1c-sql\<base-id>\saved-state-copy-plan.json `
  --expected-base-id <base-id-from-project-context> `
  --expected-target-table ConfigSave `
  --sql-out reports\1c-sql\<base-id>\prepare-saved-state-copy.sql `
  --report reports\1c-sql\<base-id>\prepare-saved-state-copy-sql.json `
  --json

This generator does not call the adapter and does not write SQL. It refuses plans that are not plan_ready, have target collisions, or mix storage families. The generated SQL is a manual review artifact: it starts a transaction, rechecks that the save-layer target has no planned FileName values, copies only the planned rows with INSERT ... SELECT, verifies the copied row count, and commits only if those guards pass.

To execute the reviewed preparation SQL, use the explicit SQL-write gate. This is not run by deploy/verify:

powershell -NoProfile -ExecutionPolicy Bypass `
  -File scripts\execute_1c_saved_state_copy_sql.ps1 `
  -Server <sql-server> `
  -Database <sql-database> `
  -User <sql-user> `
  -Password <sql-password> `
  -ExpectedBaseId <base-id-from-project-context> `
  -ExpectedTargetTable ConfigSave `
  -IUnderstandThisWritesToSql

The executor validates the generated SQL report, checks that the SQL file still looks like the reviewed saved-state copy artifact, records the SQL SHA1, runs the SQL through System.Data.SqlClient, and immediately calls the read-only post-copy verifier. Credentials can also be supplied with ONEC_SQL_SERVER, ONEC_SQL_DATABASE, ONEC_SQL_USER, and ONEC_SQL_PASSWORD. Do not commit credentials or execution reports containing environment-specific connection details.

After the SQL preparation has been executed, verify the saved-state copy read-only before enabling strict write smoke:

python scripts\verify_1c_saved_state_copy.py `
  --plan reports\1c-sql\<base-id>\saved-state-copy-plan.json `
  --expected-base-id <base-id-from-project-context> `
  --expected-target-table ConfigSave `
  --report reports\1c-sql\<base-id>\saved-state-copy-verify.json `
  --require-ready `
  --json

Before the SQL preparation is executed, this verifier is expected to report blocked_missing_target_rows. After preparation it must report ready=true by comparing the save-layer FileName, PartNo, byte sizes, and BinarySHA1 values against the reviewed active-source rows from the copy plan.

Also generate the guarded cleanup script before executing the preparation SQL, so there is a reviewed way to remove the prepared working-copy rows later:

python scripts\prepare_1c_saved_state_cleanup_sql.py `
  --plan reports\1c-sql\<base-id>\saved-state-copy-plan.json `
  --expected-base-id <base-id-from-project-context> `
  --expected-target-table ConfigSave `
  --sql-out reports\1c-sql\<base-id>\cleanup-saved-state-copy.sql `
  --report reports\1c-sql\<base-id>\cleanup-saved-state-copy-sql.json `
  --json

The cleanup SQL deletes only the planned FileName/PartNo rows from the selected save layer, and only when their current BinarySHA1 still matches the reviewed copy plan. It rolls back if the rows are missing, extra/mismatched, or if the deleted row count differs from the plan.

powershell -NoProfile -ExecutionPolicy Bypass `
  -File scripts\deploy_1c_adapter_stack.ps1 `
  -BaseId <base-id-from-project-context> `
  -RequireSavedStateWriteSmoke

To require selector-chain evidence to resolve all the way to a concrete read-only metadata.write.plan composition:

powershell -NoProfile -ExecutionPolicy Bypass `
  -File scripts\deploy_1c_adapter_stack.ps1 `
  -BaseId <base-id-from-project-context> `
  -RequireSelectorChainWritePlanComposition

To skip saved-state write-loop checks entirely:

powershell -NoProfile -ExecutionPolicy Bypass `
  -File scripts\deploy_1c_adapter_stack.ps1 `
  -BaseId <base-id-from-project-context> `
  -SkipSavedStateWriteSmoke

To skip only the read-only write-plan safety smoke:

powershell -NoProfile -ExecutionPolicy Bypass `
  -File scripts\deploy_1c_adapter_stack.ps1 `
  -BaseId <base-id-from-project-context> `
  -SkipWritePlanSafetySmoke

To validate the latest persisted reports without contacting REST or MCP:

python scripts\check_1c_verify_reports.py --base-id <base-id-from-project-context>

Add --rest-adapter-url <url> --mcp-url <url> when the persisted REST/MCP reports should be pinned to specific endpoints. Add --saved-state-table ConfigSave or --saved-state-table ConfigCASSave when the persisted saved-state reports must be pinned to a specific save-layer table. Add --max-report-age-seconds <seconds> when the persisted reports must also be fresh enough for a deployment gate. Use --skip-saved-state-copy-plan only when intentionally validating an older report bundle that does not include saved-state-copy-plan.json.

To run the offline validator's synthetic soft/strict self-test:

python scripts\check_1c_verify_reports.py --self-test

To run the whole offline/static verification-stack preflight:

python scripts\check_1c_adapter_verification_stack.py --base-id <base-id-from-project-context>

The verification-stack preflight passes the default REST/MCP endpoint URLs to the persisted report validator. Override them with --rest-adapter-url and --mcp-url for non-default deployments. It also passes --saved-state-table, defaulting to ConfigSave, so persisted copy-plan/form/module reports must match the intended save-layer table. Pass multiple base ids after --base-id to validate several persisted report directories in one run. Use --max-report-age-seconds to reject stale report files during the verification-stack preflight.

To save a machine-readable verification-stack summary:

python scripts\check_1c_adapter_verification_stack.py `
  --base-id <base-id-from-project-context> `
  --json `
  --report reports\1c-sql\<base-id>\adapter-verification-stack-check.json

The saved stack report keeps per-command return codes, compact parsed summaries for JSON-producing checks, and truncated stdout/stderr tails for diagnostics. For persisted verify-report checks, the parsed summary also includes per-base REST/MCP selector-chain composition status, write-plan safety check counts, and saved-state write smoke status, including the saved-state copy-plan target, source-row count, and target collision status.

To deploy without live verification:

powershell -NoProfile -ExecutionPolicy Bypass `
  -File scripts\deploy_1c_adapter_stack.ps1 `
  -SkipVerify

Low-level MCP-only deploy:

docker --host ssh://docker.cin.su compose `
  --env-file core\deploy\docker\adapter-1c-mcp\.env.example `
  -f core\deploy\docker\adapter-1c-mcp\compose.yaml `
  up -d --build

Container name:

adapter-1c-mcp

Health

Invoke-RestMethod http://docker.cin.su:8021/health
docker --host ssh://docker.cin.su ps --filter name=adapter-1c-mcp
docker --host ssh://docker.cin.su logs --tail 80 adapter-1c-mcp

Smoke test MCP initialize:

$body = @{
  jsonrpc = "2.0"
  id = 1
  method = "initialize"
  params = @{
    protocolVersion = "2025-06-18"
    capabilities = @{}
    clientInfo = @{ name = "smoke"; version = "1" }
  }
} | ConvertTo-Json -Depth 10

Invoke-WebRequest `
  -Uri "http://docker.cin.su:8021/mcp" `
  -Method Post `
  -ContentType "application/json" `
  -Headers @{ Accept = "application/json, text/event-stream" } `
  -Body $body

Tools

The MCP proxy exposes a small stable tool surface:

onec_health
onec_help
onec_request
onec_job_get
onec_job_cancel
access_role_users
access_role_profiles
access_role_audit_export
access_role_audit_analyze
access_user_explain
access_users_search
access_object_explain
access_keys_query
access_object_keys_resolve
access_object_roles
access_object_subjects
access_rls_discover

Use onec_request(method, payload) for uncommon or newly added adapter methods until a dedicated alias is useful enough to keep stable. The access_* tools are lightweight aliases for common access-audit workflows; they only forward to REST adapter methods such as access.role.users and keep all BSP/access-rights logic in the REST adapter.

For object access checks, pass object names/public refs first; the REST adapter resolves GUIDs, SQL numbers, BSP identifiers, synonyms, and readable role-rights names internally. Example:

python scripts\smoke_1c_access_object.py `
  --base-id upo_test `
  --ref "РегистрСведений.УОП_АктуальныеСпецификации" `
  --action write

Use access_object_roles or access_object_subjects for the question "which roles/users can read or write this metadata object". Do not depend on metadata.objects.list kind=Role: some live bases do not expose roles as regular metadata objects through that route.

For BSP data-access keys, keep the metadata object and concrete data record separate:

{
  "base_id": "upo_test",
  "kind": "object",
  "object_ref": "Справочники.Номенклатура",
  "record_ref": "00112233445566778899AABBCCDDEEFF"
}

Here kind=object is the access_keys_query area, not the metadata kind. object_ref is resolved to the internal BSP SQL number and record_ref to the record id. The same public pair works with access_object_keys_resolve and access_object_explain; do not invent object_sql_number in MCP code.

For BSP role-right checks, action=write means add or modify rights. Read-only roles must not be returned for write; query action=read separately when you need visibility roles. Returned permissions keep source_fields from ПраваРолей so suspicious mappings can be verified against the live base.

access.snapshot.extract also supports this access graph and defaults to the BSP extractor preset when queries are not supplied. Passing preset=bsp explicitly is still fine, but the old "No extractor queries were provided" discovery response should not appear for a normal BSP base.

When access_object_subjects is called with include_access_key_scope=true, the regular limit only trims returned roles/profiles/groups/users. Scope diagnostics use separate controls: access_key_scope_subject_limit limits how many matched groups/users are checked, and access_key_scope_limit limits rows read from each BSP access-key extractor. Check access_key_scope.coverage and access_key_scope.truncated before treating the scope sample as complete.

For local audit artifacts, use the workspace script:

python scripts\export_1c_access_role_audit.py `
  --base-id upo_test `
  --role "запись изменение номенклатура поставщиков" `
  --user-threshold 30

It writes CSV, JSON export, analysis JSON, and a summary file under reports/1c-access/<base_id>/. By default it also writes a self-contained HTML report with findings, counters, artifact links, and a filterable user table; pass --no-html to skip it.

Architecture contract:

  • The REST adapter owns 1C behavior, payload validation, decoding, owner resolution, RAG/tool-facing data shape, and method documentation through help.methods.
  • MCP is a transport proxy: JSON-RPC/MCP framing, adapter URL/token handling, generic onec_request, job polling/cancellation helpers, and lightweight agent-safety checks such as requiring base_id for live database methods.
  • Do not add method-specific 1C business logic to MCP. Put it in the adapter, expose it through /rpc, and make it discoverable via help.methods.
  • Do not register an MCP unified/composite handler with the same name as an adapter method; onec_request(method=...) must call the adapter method, not shadow it inside MCP.
  • When adding a new adapter method, verify it through MCP with onec_request({"method": "...", "payload": {...}}). MCP should not require a schema edit for ordinary adapter growth.
  • Run python scripts/check_1c_mcp_adapter_contract.py before release; it verifies that onec_request stays generic and that every method listed by the REST adapter is forwarded through /rpc.

Example:

{
  "method": "metadata.object.get",
  "payload": {
    "base_id": "<base_id-from-project-context>",
    "kind": "document",
    "name": "ПриходнаяНакладная",
    "view": "merged"
  }
}

Do not copy placeholder or sample base_id values from documentation into real requests. For live database methods, get base_id from the current project, user request, environment, or another authoritative context.

Agent Request Policy

The MCP proxy blocks live database methods without payload.base_id before calling the REST adapter. This is intentional: agents must not probe metadata, modules, extensions, queries, storage, or code without a concrete target base.

Affected method families include:

metadata.*
modules.*
code.*
templates.*
diagnostics.*
extensions.*
query.*
storage.*
schema.*
codec.*

Allowed without base_id:

onec_help / help.methods
onec_health without a base for generic service health
adapter.job.get / adapter.job.cancel

Agent rules:

  • If base_id is unknown, ask for it or obtain it from project context.
  • For object-scoped calls, use one of the public selector shapes supported by the adapter: ref, kind + name, guid, or MCP-friendly object_type/object_name/object_guid. Do not add MCP-side conditions for concrete object names.
  • If a prior result contains module_ref, module_id, GUID, or read selector, use direct read methods before global search.
  • If a search result contains read_selector.method, call that method with the selector payload. code.search selectors point to code.read; modules.search selectors point to modules.read.
  • If a result contains related_selectors, prefer those payloads for the next object-scoped call. They preserve kind/name/guid and include ref when the adapter knows the canonical object kind and name.
  • When modules.search or code.search resolves a module owner, keep both the public owner selector (ref, kind, name, guid) and the opaque module_ref in the next read payload. module_ref is the direct read handle; ref makes the owner clear to the agent and later calls.
  • When narrowing code.search to one module, pass module_ordinal together with the object selector. The adapter response should remain a public onec_code_search.v1 object with item.read_selector, not a low-level tuple or storage result.
  • For BSL edits, prefer high-level metadata.write with a 1C canonical path, routine_text, and routine_operation. Do not ask the user for SQL/save gates: the adapter prepares saved-state when needed, writes only to the saved-state working layer, and does not activate changes. Use metadata.form.command_button.write for the complete form command + visible button + handler workflow. code.write remains a compatibility shortcut for simple module edits.
  • For a metadata object's standard synonym or comment, call generic onec_request with method=metadata.object.property.write, a public ref/kind + name, and allow_saved_state_write=true. Prefer execution_mode=plan first. The adapter resolves GUIDs and serialized paths; MCP callers must not pass SQL tables or file names. Object rename and adding a new synonym locale are intentionally unsupported.
  • For an existing requisite, tabular section, dimension, or resource, add a public member_ref such as Catalog.Номенклатура.Attribute.Артикул. When only member_kind + member_name is used and several identities match, preserve the adapter's ambiguous result and retry with the full member path.
  • To add a requisite, call metadata.object.member.add through onec_request with a full template_member_ref from the same object and the new public name/synonym. Never invent a GUID, Config table, collection path, or type descriptor in MCP code; the new requisite inherits type/settings from the named template.
  • The same method adds a tabular-section column when template_member_ref contains the full ...TabularSection.<name>.Attribute.<column> path. Keep the complete path so duplicate checks and generated identity remain scoped to that table part.
  • For unresolved module owners, inspect diagnostics.owner_resolution and counts.owner_scan_limit_hit; narrow by kind/name/guid or increase owner_scan_limit before falling back to broader searches.
  • Do not treat not_found from metadata.definition.find or scoped search as proof that code is absent in extensions or ConfigCAS.
  • Treat partial, truncated=true, scan limits, and timeouts as incomplete evidence.

Offline selector-chain smoke:

python scripts\smoke_1c_mcp_selector_chain.py --json --no-report

Saved-state BSL write smoke:

python scripts\smoke_1c_code_write_saved_state.py `
  --adapter-url http://docker.cin.su:8011 `
  --base-id <base-id-from-project-context> `
  --extension <extension-name> `
  --object-type CommonForm `
  --object-name <form-name> `
  --routine-name <routine-name> `
  --json

This smoke performs idempotent code.write mode=apply checks with the current routine text, a unique old/new fragment, and the current full module_text. It then verifies code.read state=working, code.read state=both, marker-hiding for saved form modules, and saved-state form indexing. Every write step must report write_mode.target=saved_state and activation_state=not_activated.

Agent working-view report:

python scripts\report_1c_agent_working_view.py `
  --adapter-url http://docker.cin.su:8011 `
  --base-id <base-id-from-project-context> `
  --extension <extension-name> `
  --object-type CommonForm `
  --object-name <form-name> `
  --routine-name <routine-name> `
  --json

This read-only report shows the form names that an agent sees in the working/save layer and verifies that code.read state=working and state=both prefer saved_state when saved code exists.

The concise agent-facing coding rules are kept in docs/runbooks/1c-agent-coding-contract.md.

Run this with the contract checks before release. It validates generic agent routes through onec_request and rejects concrete object names in selector examples.

Optional live selector-chain smoke against a real adapter/base:

python scripts\smoke_1c_mcp_selector_chain.py `
  --live `
  --transport rest `
  --adapter-url http://docker.cin.su:8011 `
  --base-id <base-id-from-project-context> `
  --json `
  --no-report

To verify both deployed layers with one command:

powershell -NoProfile -ExecutionPolicy Bypass `
  -File scripts\verify_1c_adapter_deployment.ps1 `
  -BaseId <base-id-from-project-context>

By default this also writes reports/1c-sql/<base>/code-write-saved-state-rest-smoke.json and reports/1c-sql/<base>/code-write-saved-state-mcp-smoke.json when the default saved-state code-write target exists. The REST verification also writes reports/1c-sql/<base>/agent-working-view.json to pin the save-first working view that agents should use for coding. Use -RequireCodeWriteSavedStateSmoke to make that smoke mandatory, or -SkipCodeWriteSavedStateSmoke to skip it for bases where the scenario is not available.

Pass multiple base ids to run the same REST and MCP checks against each base:

powershell -NoProfile -ExecutionPolicy Bypass `
  -File scripts\verify_1c_adapter_deployment.ps1 `
  -BaseId <base-id-1>,<base-id-2>

Use -ObjectRef, or -ObjectKind with -ObjectName/-ObjectGuid, to verify a specific module-capable metadata object instead of auto-discovery. Use -SavedStateTable ConfigSave or -SavedStateTable ConfigCASSave to choose which save-layer table is used by the copy plan and saved-state write smokes. Add -RequireSelectorChainWritePlanComposition when the selected base/object must have a saved-state stream that lets the selector-chain smoke compose a concrete read-only metadata.write.plan. The same strict mode also requires the write-preflight smoke to discover both an extension form and an extension module by public names (extension/ref/form/member and extension/ref/form/module/stream_ordinal), compose allowed plans, and prove that the repository and support gates use the same resolved extension:<GUID> layer. Module search restores the public extension name from ConfigCASSave; it never returns the storage GUID as the caller-facing selector. The smoke then submits each public selector with a deliberately different GUID and requires a read-only blocked / extension_selector_conflict result, so a legacy permissive repository profile cannot authorize a mismatched layer. Run both checks directly with scripts/smoke_1c_write_preflight.py --require-name-first-extension-form --require-name-first-extension-module.

To exercise the MCP proxy itself, switch transport and URL:

python scripts\smoke_1c_mcp_selector_chain.py `
  --live `
  --transport mcp `
  --mcp-url http://docker.cin.su:8021 `
  --base-id <base-id-from-project-context> `
  --json `
  --no-report

Live mode discovers a module-capable object from metadata lists and then checks adapter.help.methods -> metadata.definition.find -> related_selectors.modules -> metadata.object.modules -> modules.read -> code.search -> item.read_selector -> code.read using the returned selector and a token derived from module text or routine metadata. The adapter.help.methods step verifies live REST contract_version and selector_capabilities, so stale REST adapter images fail before the longer chain. MCP transport also performs initialize, checks tools/list for the same contract_version and the generic onec_request selector schema, keeps Mcp-Session-Id, and sends adapter calls through tools/call + onec_request. This catches stale MCP proxy images where REST works but agents still see old tool descriptions. Do not commit real base ids or captured reports from live runs.

  • Avoid increasing global search limits when a direct selector is already available.
  • Do not request include_storage=true merely to read a module found by search; use the public read_selector first.

The request is proxied to the REST adapter through POST /rpc:

{
  "method": "metadata.object.get",
  "payload": {}
}

The MCP proxy intentionally does not know adapter-specific 1C methods. Add new methods in the REST adapter and expose them through help.methods; MCP stays unchanged unless the MCP transport itself changes.