Skip to main content
Glama

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
QA_MCP_HTTP_HOSTNoHTTP bind host. Defaults to loopback. Example: 127.0.0.1.
QA_MCP_HTTP_PORTNoHTTP bind port. Example: 8000.
QA_MCP_TRANSPORTNoSet to 'http' to enable authenticated streamable-HTTP transport. Defaults to stdio.
QA_MCP_BEARER_TOKENNoBearer token for authenticated HTTP transport. Generate a strong project-owned token.

Instructions

Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.

This server publishes no instructions, or was last inspected before Glama recorded them.

Capabilities

Features and capabilities supported by this server

Protocol revision2025-11-25

CapabilityDetails
tools
{
  "listChanged": true
}
logging
{}
prompts
{
  "listChanged": false
}
resources
{
  "subscribe": false,
  "listChanged": false
}
extensions
{
  "io.modelcontextprotocol/ui": {}
}
experimental
{}

Tools

Functions exposed to the LLM to take actions

NameDescription
activate_windowB

Bring a buried top-level window to the front natively. activate and close are the SAME window-level command …SecondaryFrame[<window>] 88 82 81; the effect is contextual on z-order — applied to a BACKGROUND window it activates (brings forward), applied to the active window it closes it (see close_window). This faithfully replays the genuine navigation from capture (open the fixture form -> open the catalog list -> drill a row, so other windows cover the target) then the window-level command that raises the buried target (window_ref, default the fixture form's app ref); GUID rebinder rebinds the window GUIDs as they appear (first-appearance, same machinery as open_card / close_window). Confirmed by the target becoming the ACTIVE (last-reported) window — its (live, rebound) SecondaryFrame is the one in the final window-bearing client response (activated), the inverse of close_window. Returns {window_ref, window_sf, live_window_sf, accepted, activated, target_in_activate_resp}.

add_table_rowB

Add a persistent row to the fixture table natively. The standard «add row» discards an uncommitted empty row, so the fixture exposes a PF_ADD_ROW command that server-side appends a MARKED row (PF_ROW_ADDED_<n> / PF_ADDED_TEXT), activates it, and sets PF_LAST_ACTION. This clicks PF_ADD_ROW capture-free (= click_command('PF_ADD_ROW')). Verify via assert_form_value('PF_LAST_ACTION')=='PF_ADD_ROW' / 'PF_SELECTED_ROW_MARKER' or capture_screenshot. Returns {base_button, target_button, accepted}.

advanced_searchA

Filter a dynamic list via the «Расширенный поиск» (advanced-search) DIALOG natively. The reusable "drive a MODAL dialog" pattern: replay the genuine flow — open the form -> click «Расширенный поиск» (opens the standard UniversalListFindExtForm in a NEW window) -> SET its Pattern field -> click Find — with GUID rebinder rebinding the dialog window (the answer_dialog / open_card machinery) and the Pattern re-targeted to value (UTF-16 buffer, fixed-width, bounded by the captured length). Searches the dialog's default field (the capture left FieldSelector at «Код»; targeting another field is a refinement). No clean value read-back — the list narrows (verify with capture_screenshot). Returns {search_command, value, echoed}.

answer_dialogA

Answer a 1C modal dialog (ПоказатьВопрос / ПоказатьПредупреждение) natively. Unlike a popup choice list (which reuses the form window), a real dialog opens a NEW top-level window — a fresh SecondaryFrame GUID per open. The genuine answer is a WINDOW-LEVEL command on that dialog frame (…SecondaryFrame[<dlg>] 88 82 81 = the window's default action = ОК/Да), NOT a Button activate. This faithfully replays the genuine dialog session from capture (open form -> click raise_command -> the dialog opens -> the window-level answer); GUID rebinder learns the LIVE dialog GUID from the live open response and rebinds the captured one in the close command (the same first-appearance rebinding as the form window). Commit is confirmed by result_marker (the fixture's answer field, e.g. PF_V4_WARNING_ACK) appearing in the post-answer read-back. Returns {raise_command, result_marker, dialog_sf, committed}. NOTE: the WARNING (ОК) path is the default — the QUESTION (Да/Нет) answer is the same window-level mechanism with the appropriate raise_command/marker once captured.

assert_com_countA

Assert a numeric result from a read-only host-side COM query.

Use for file infobases where OData is not published. query should return a single row whose first value, or count_field when supplied, is numeric. op is one of eq/ne/gt/lt/ge/le.

assert_dataA

DEPRECATED for a test-client-held base — see below. Assert a value in the DATA LAYER via read-only 1C OData. Locate a record in entity_set (e.g. 'Catalog_Товары') by an OData filter (e.g. "Description eq 'Обувь'") or a key (Ref_Key guid / code), then assert field against expected with match = equals|contains|regex. Connection from params or env (QA_MCP_ODATA_URL/USER/PASSWORD). Returns {ok, actual, expected, record_count, deprecated, deprecation, …}.

DEPRECATION: an infobase opened by a «Клиент тестирования» is EXCLUSIVELY LOCKED, so OData cannot read it — an OData read-back of what the running test client just did is impossible on that base. Verify UI writes through the SAME client's protocol value-read (write_form_fields_by_label returns a value-read committed; read_record / read_form_descriptor read committed values). This tool is valid ONLY against a SEPARATELY published, non-exclusive OData endpoint.

assert_data_countA

DEPRECATED for a test-client-held base — a «Клиент тестирования» holds the infobase under an EXCLUSIVE lock, so OData cannot read it; verify via the same client's protocol value-read (read_record / read_form_descriptor) instead. Assert the NUMBER of records matching a filter in the DATA LAYER. op = eq|ne|gt|lt|ge|le; e.g. assert a posting created exactly N register rows, or that no orphan remains (op='eq', expected=0). Read-only OData; valid only against a separately published, non-exclusive endpoint. Returns {ok, count, expected, op, deprecated, deprecation, ...}.

assert_form_valueC

First-class ASSERT on a form field's live value.

attach_test_clientA

Attach to an already-listening /TESTCLIENT endpoint without owning its process.

This is for clients started out-of-band, for example with a custom environment or by a host-side launcher. The returned handle status records attached=true and owns_process=false. The MCP server also records the endpoint as the active attached context for replay-backed tools that are called with default host/port.

capture_screenshotA

Capture an OS-level PNG screenshot of the TestClient's X display (Linux).

display is the one from launch_test_client(display=…) status (e.g. ":101"). Optional window is a title substring (xdotool) to capture a single window instead of the whole display; if no window matches, falls back to the full display (matched_window_id=null). Captures with scrot (fallback ImageMagick import). Returns {path, display, window, matched_window_id, size_bytes, tool}; read the PNG at path.

choose_from_listA

Pick a value from a ПоказатьВыборИзСписка modal natively. The flow: open the form, click the command that raises the choice list (base_command), then PICK value (a list-item VALUE NAME, e.g. PF_CHOICE_A/B/C). The pick is the choose tag e0 4b 53 + the length-prefixed value at the ManagedForm path — the same e0 4b 53 family as a radio set_choice, but addressed at the FORM (the popup reuses the window, so NO new SecondaryFrame to bind); only the value is re-targeted (captured_value -> value). Opens the form by replaying the genuine setup from capture (which clicked base_command and picked captured_value). The result is a user message Сообщить(<message_prefix> + value), so commit is verified by scanning the responses for that ASCII marker. Returns {captured_value, value, accepted, committed, message}.

choose_from_menuA

Pick an item from a ПоказатьВыборИзМеню popup menu natively. The popup menu is the wire TWIN of the choice list (choose_from_list): clicking base_command raises it, and the pick is the SAME e0 4b 53 choose tag + the length-prefixed item VALUE NAME at the ManagedForm path (the popup reuses the form window — no new SecondaryFrame). Only the value is re-targeted (captured_value -> value, e.g. PF_MENU_1 -> PF_MENU_2). Opens the form by replaying the genuine setup from capture (which clicked base_command and picked captured_value). The result is a user message Сообщить("PF_MENU=" + value), confirmed on the wire. Returns {captured_value, value, accepted, committed, message}.

click_commandA

Click a form-command BUTTON natively. A command click activates the …Group[<bar>].Button[NAME] element (88 81 81 e1 command-execute) — the Button twin of switch_page / toggle_checkbox. Opens the form (replays the genuine setup from capture, which clicked base_button) and sends the genuine click re-targeted to target_button (the Button leaf; defaults to base_button). A click has no value read-back — verify via a side-effect field (PF_LAST_ACTION) or capture_screenshot. Returns {base_button, target_button, accepted}.

close_windowB

Close a top-level window natively. close (and activate) are window-level commands: …SecondaryFrame[<window>] 88 82 81 — the SAME family as the dialog close in answer_dialog, applied to any top-level window. This faithfully replays the genuine navigation from capture (open form -> open the catalog list -> drill a row -> the record card opens in a new window) then the window-level close on the active card; GUID rebinder rebinds the list/card window GUIDs as they appear (first-appearance, same machinery as open_card / answer_dialog), and the replay is truncated just before any subsequent close so ONLY the target window (window_ref, default the card's record data ref) is closed. Confirmed by the closed window's (live, rebound) SecondaryFrame being reported by the client BEFORE the close but gone AFTER it (closed), and the window behind it becoming active (active_window_after). Returns {window_ref, window_sf, live_window_sf, accepted, closed, active_window_after}. NOTE: replays the captured open-card->close flow, so it closes that card window; to close a different window, capture that flow (the window-level close mechanism is identical).

com_connector_doctorA

Diagnose Windows V83.COMConnector registration and optional read smoke.

Calls the authenticated host-agent COMConnector doctor on the Windows host. The doctor checks 64-bit registration state, TypeLib presence, COM creation, file-infobase connection, and an optional read-only query. If the TypeLib is missing, the result includes the elevated C:\Windows\System32\regsvr32.exe remediation command.

copy_table_rowB

Copy the ACTIVE table row natively. Clicks the fixture's PF_COPY_ROW command (ДанныеФормыКоллекция.Вставить a copy of the active row right below it, marker suffixed _COPY, made active), capture-free, by replaying the genuine PF_COPY_ROW click (the identity case — no Button-leaf retarget). Example: baseline active row 1 -> PF_TABLE_SNAPSHOT=PF_TABLE[4]=PF_ROW_001|PF_ROW_001_COPY|PF_ROW_002|PF_ROW_003. Session-local form state — verify in the SAME session via assert_form_value('PF_TABLE_SNAPSHOT') / ('PF_LAST_ACTION'=='PF_COPY_ROW'). Select the target row first with select_table_row. Returns {base_button, target_button, accepted}.

delete_table_rowA

Delete the ACTIVE table row natively. Clicks the fixture's PF_DELETE_ROW command (ДанныеФормыКоллекция.Удалить on the active row of PF_TABLE_ITEMS), capture-free, by replaying the genuine PF_COPY_ROW click (its form-open setup) retargeted to the PF_DELETE_ROW Button leaf. Example: baseline [PF_ROW_001|PF_ROW_002|PF_ROW_003], active row 1 -> PF_TABLE_SNAPSHOT=PF_TABLE[2]=PF_ROW_002|PF_ROW_003. The deletion is session-local form state (reset on a fresh form-open), so verify in the SAME session via assert_form_value('PF_TABLE_SNAPSHOT') / ('PF_LAST_ACTION'=='PF_DELETE_ROW') or capture_screenshot. Select the target row first with select_table_row. Returns {base_button, target_button, accepted}.

get_stateA

Snapshot the native QA engine's session/run state. Aggregates three views: connection (the TestClient TPort liveness, + pid aliveness if given), run_session (the scenarios run this server session — counts + the last scenario/status, from the same log as get_test_results), and infobase (the configured target identity, password-redacted, from the .ai1c profile). Returns {engine {default_capture, value_read_templates}, connection {pid, alive, host, port, listening}, run_session {…aggregate…, last_scenario, last_status}, infobase {…redacted…}}.

get_test_resultsA

Aggregate the scenarios run in THIS MCP-server session natively. Every run_scenario / run_step / run_write_scenario_tool call records its outcome; this returns the roll-up: {scenarios, passed, failed, total_steps, step_status_counts {ok|assert_failed|error: n}, results:[{scenario, status, step_count, steps:[{kind, name, status}]}]}. The log is process-lifetime, in-memory; pass clear=true to report the current roll-up AND reset it (adds cleared = how many were dropped). Use it after a batch of scenarios to get a single pass/fail report instead of eyeballing each ScenarioResult.

get_window_listA

Enumerate the visible OS windows on the TestClient's X display natively. Lists the window-manager's top-level windows on display (the one from launch_test_client(display=…) status, e.g. ":101") via xdotool — id + title (+ geometry {x, y, width, height} unless geometry=false). Use to see what the client has open (main window, an opened list/card, a modal dialog) at the OS level; address an individual window programmatically with activate_window / close_window. Requires xdotool + a launched display. Returns {display, count, windows:[{id, title, geometry?}]}. (The protocol-level "windows known to the test client" list is get_window_list_testclient.)

get_window_list_testclientA

Enumerate the 1C-internal windows/tabs open in the TestClient natively. This is the protocol-level list (the 1C windows the client tracks — main desktop, an open form/list/card tab, a dialog), DISTINCT from get_window_list which lists OS top-level X windows (1C opens forms as MDI tabs inside ONE X window, so the OS list does not see them). Replays the genuine window-list query on a live session (grafted onto a live value-read header so the session GUIDs match — a raw replay is rejected) and decodes each window's caption + frame kind (SecondaryFrame | MainFrame | HomePage). Each window record's caption is the window title (Cyrillic-aware). SCOPE: like read_form_descriptor, each call is a FRESH session, so it lists the windows of the session it opens (the fixture form + desktop + home page); address an individual window with activate_window / close_window. If you only need to prove MCP-to-TestClient connectivity without a form target, run qa_mcp_doctor and inspect its testclient_smoke check. Form-level reads that need a target should pass open_link such as e1cib/list/<metadata>. Returns {count, windows:[{kind, guid, caption}]}. Decoded + validated against a genuine analysis oracle (4 windows).

infobase_infoA

Report the configured TestClient infobase / connection metadata natively. Reads the local .ai1c/*.env profile (INFOBASE_PATH / PLATFORM_ROOT / TEST_CLIENT_KIND / TEST_CLIENT_USER) into a target descriptor — the password is never echoed (only password_set) — and reports whether the TPort at host:port is live. Override the profile with infobase_path / env_file. Returns {env_file, env_present, infobase {host, port, kind, user, target, headless, display, password_set}, platform_root, client_bin, listening}. Richer config name/version metadata (from the handshake) is a decode follow-up.

launch_test_clientA

Launch a 1C /TESTCLIENT and wait for its TPort to listen.

Loads the local .ai1c/*.env profile (INFOBASE_PATH / PLATFORM_ROOT / TEST_CLIENT_USER/KIND/PASSWORD), overridden by any args given. Boots 1cv8 ENTERPRISE /IBConnectionString File="…"; /N<user> /TESTCLIENT -TPort <port>. The client OUTLIVES this call — connect with run_scenario/write_form_value(port=…), then tear down with stop_test_client(pid, xvfb_pid). Set manage_apache=true for an Apache-served infobase (stops apache2 for the boot, restart on stop_test_client).

Display (for screenshots): pass display=":101" (or "auto") to OWN an Xvfb on that display and run the client with DISPLAY=:N — then capture_screenshot(display) works. Default (None) uses xvfb-run -a (no screenshots). Returns {pid, alive, listening, display, xvfb_pid, connection (password-redacted), out_dir, launch_environment}. The password is never echoed back. For an explicitly authorized Windows hardware/network-license contour, set use_hardware_licenses=true; when omitted, ignored runtime state may opt in with QA_MCP_TESTCLIENT_USE_HW_LICENSES=1.

move_table_rowA

Move the ACTIVE table row up or down natively. direction in {"up","down"} clicks the fixture's PF_MOVE_ROW_UP / PF_MOVE_ROW_DOWN command (ДанныеФормыКоллекция.Сдвинуть(±1) on the active row, no-op at the table boundary), capture-free, by replaying the genuine PF_COPY_ROW click retargeted to the move Button leaf. Example: baseline active row 1 + "down" -> PF_TABLE_SNAPSHOT=PF_TABLE[3]=PF_ROW_002|PF_ROW_001|PF_ROW_003. Session-local form state — verify in the SAME session via assert_form_value('PF_TABLE_SNAPSHOT') / ('PF_LAST_ACTION'). Select the target row first with select_table_row. Returns {base_button, target_button, accepted}.

open_cardA

Open a record CARD by drilling into a catalog list row natively. Drilling into a list item opens the record's form in a NEW top-level window (a fresh SecondaryFrame, like a dialog). This faithfully replays the genuine navigation from capture (open the fixture form -> open the catalog list via a nav link -> «Изменить» the active row -> the card form opens). Each new window's per-open SecondaryFrame GUID is rebound by GUID rebinder automatically (first-appearance, like the dialog window — the same new-window machinery as answer_dialog). Opening is confirmed by result_marker (a card-specific UTF-16 string, e.g. the card form id "ФормаГруппы") reading back. Returns {result_marker, opened}. Opens the captured active row's card; to open a SPECIFIC row, precede with a row-select (compose with select_table_row).

open_external_processorA

Open an EXTERNAL data processor/report (.epf/.erf) in the running client the 1C-NATIVE way. NO external input component, NO config object: drives «Главное меню (≡, top-right) -> Файл -> Открыть» (located on-screen via locate_text) -> the GTK file chooser -> Ctrl+L -> types path Unicode-safe (xtest_type_unicode — plain typing drops Cyrillic) -> Enter. The Gherkin step «Я открываю внешнюю обработку или отчет '' (Расширение)» maps to this. PREREQ (as for write_form_value_xtest): the client was launched with an Xvfb display + a window manager (matchbox). Pass expect_caption (e.g. a substring of the processor's window title) to verify the form opened. Returns {path, opened, caption_found, dialog_closed, screenshot, located}.

open_listA

Open a catalog/list window natively through e1cib/list/<path>.

Omitting capture (or passing a blank value) uses the released, version-selected bundled bootstrap and value-read navigation templates. All assets are loaded and structurally checked before a TestClient session opens; missing assets return open-list-navigation-unavailable with protocol_write_attempted=false.

A non-blank capture preserves the explicit capture-replay compatibility path. navigation_templates optionally selects a controlled value-read template JSON for the default template-backed path. Returns the requested base_link/target_link, the navigation method, and whether the target form resolved. A list-open has no business-data mutation or value read-back.

qa_mcp_doctorA

Run the secret-safe end-to-end qa-mcp setup doctor.

The doctor returns one ordered pass/fail/skipped chain for project-owned bearer-token env presence, host-agent HTTP reachability, container-to-host route, TestClient TPort reachability, an open-link-free TestClient smoke and login/access-dialog state. Platform, COM and private-suite diagnostics are intentionally outside the standalone route. When require_bearer_token is omitted, bearer auth is required for HTTP transports and skipped for stdio.

query_comA

Run a read-only 1C query through the Windows host-agent COM bridge.

This is the file-infobase data path for model-B installs without OData: qa-mcp sends an authenticated host-agent /com/execute WorkerRequest to the bundled ai-com-worker.exe on the Windows host. Obvious write-shaped query text is rejected locally before host transport. Configure QA_MCP_HOST_AGENT and QA_MCP_HOST_AGENT_TOKEN; the host install must have ai-com-worker.exe available for /com/execute.

read_form_descriptorB

Introspect a live form into a full element descriptor natively — the get_form_analysis equivalent. Opens the form then replays the genuine form-analysis QUERY sweep (a per-field value-read of every element) on one connection, decoding each element's name->value with extract_form_field_values (the canonical «стал равен» value; markers fa/9a single-byte, 97 UTF-16 checkbox Да/Нет, 8b short-number, 81 empty; ASCII + Cyrillic field names). Returns {fields {name: value}, field_count, queried}; with gherkin (default) also a Gherkin state block (И элемент формы с именем 'X' стал равен "V"). Both ASCII-named (PF_*) and Cyrillic-named fields are swept — Cyrillic group/leaf paths ride the 0x97 UTF-16 envelope, so e.g. the fixture's Контрагент / ПолеСоСпискомВыбораСтрока are read. SCOPE (honest): captures the EditField value surface — form DECORATIONS (static Label captions) are not field values and are omitted (the 3 PF_DECORATION_LABEL* are a separate Label-kind gap). The fixture descriptor is validated against a genuine analysis oracle.

enumerate_live: by default the field list comes from capture_dir's value-read query paths (the one-time per-form capture). With enumerate_live=True the field list is enumerated LIVE off the open form by splice-replaying the genuine get_form_analysis descriptor query (_enumerate_live_fields -> extract_descriptor_fields), so introspection needs NO per-form capture for the field list. With open_link the engine OPENS that form by nav-link (e.g. "e1cib/list/Справочник.Контрагенты") — navigate + resolve its SecondaryFrame.ManagedForm, point the session at it — and introspects IT (no per-form capture at all): introspect ANY form by its nav-link. The descriptor query enumerates EditFields + Buttons/Tables/Groups; a list form has its content in a dynlist Table (few form-level EditFields).

The open_link open is CONFIG-AGNOSTIC (no fixture required): the engine bootstraps to the bare desktop, window-lists the LIVE desktop MainFrame, and navigates straight to the target form — it does NOT open the suite fixture first. Every splice rides a header built with NO form open (_splice_header_no_form: the header's only live fields are the bootstrap ack_guid + sequence; the form GUIDs are after the marker the splice discards), and the navigate is retargeted onto the live desktop. So open_link introspects any form on ANY real config that has no suite fixture. Live-verified (fixture config: 46 EditFields incl. Cyrillic; Контрагенты opened + introspected to 79 elements with NO fixture open).

read_list_columnA

Read the CURRENT (first) ROW's value of a dynamic-list (dynlist) column natively — the «Я открываю основную форму списка справочника … + перехожу к первой строке + я запоминаю значение поля с именем 'X'» equivalent for a catalog LIST form. Opens the list at open_link (e.g. e1cib/list/Справочник.Товары), positions to the first row, and reads column (e.g. Наименование / Код) of the resolved dynlist table. By default the table is resolved from the live descriptor (single table -> that table; metadata-name/legacy Список matches when needed); pass table to select explicitly. Returns {table, column, nav_link, value, captured_value, list_refresh, table_resolution}.

MECHANISM: a FAITHFUL FULL-SEQUENCE replay of a genuine list-form read (navigate -> activate -> render/data-load -> position -> read), with GUID rebinder rebinding the per-session window GUIDs and the nav-link + column re-targeted in-frame. (A piecemeal splice does NOT work — the dynlist needs the interaction-ready open state a splice cannot reach; use read_table_cell for FORM tables, where row 1 is current on open.) Live-verified (against OData): Товары/Наименование->«Обувь», Товары/Код->«000000001», Контрагенты/Наименование->«Покупатели», Валюты/Наименование->«EUR». CURRENCY: a dynamic list is async/eventually-consistent, so refresh=True (default) forces an «Обновить»/F5 requery and polls-until-stable before reporting, so a value=None only ever means a genuinely empty cell — never a not-yet-loaded list; refresh=False opts out (records "no refresh applied") for absence assertions. list_refresh records the refresh method + poll outcome. Table-resolution failures return structured list-table-* diagnostics and do NOT run a wrong-table replay or call the list genuinely empty.

read_list_gridA

Read MANY ROWS × columns of a dynamic list (the whole visible grid) in ONE call. Opens the list at open_link (e.g. e1cib/list/Справочник.Товары), reads the first row's columns (e.g. ["Код", "Наименование"] of the resolved dynlist table), then steps «перехожу к следующей строке» and reads again, up to max_rows rows or end-of-list. By default the table is resolved from the live descriptor; pass table to select explicitly. Returns {table, nav_link, row_count, rows: [{column: value}, …], list_refresh, table_resolution}.

flat (default False) reads the list's CURRENT view/sort order. A HIERARCHICAL catalog (e.g. Товары) defaults to a grouped view, so the grid then exposes only the TOP-LEVEL folders (Обувь/Продукты/…). Set flat=True to first switch the list to flat «Список» view (the standard catalog-list-form «ФормаСписок» view-mode command, baked into the genuine capture) so NESTED items are read too — live-verified on Товары (flat -> Bosch1234/Sony К3456P/Босоножки/… nested rows, codes vs OData). flat selects the capture; pass capture_dir to override explicitly.

CURRENCY: a 1C dynamic list is async/eventually-consistent, so refresh=True (default) forces an «Обновить»/F5 requery and polls-until-stable before reporting — a freshly-created record shows up and a reported 0 rows only ever means a genuinely empty list. refresh=False opts out (records "no refresh applied") for an absence assertion. wait_for_rows=N blocks until at least N rows are read or the bounded poll timeout elapses (list_refresh.wait_for_rows_met reports which). list_refresh records the refresh method + poll outcome. Table-resolution failures return structured list-table-* diagnostics and do NOT run a wrong-table replay or call the list genuinely empty.

Mechanism: a genuine next-row capture replayed cold (faithful full-replay through the first read — which for the flat capture also replays the view-switch — then the genuine go-to-next-row block, the decoded next-row action GUID d267315b…, replayed + the reads, all on the one materialised socket, message-id kept + sequence bumped). Live-verified the cursor advances. One grid read per fresh launch_test_client (the cold-client boundary). Use read_list_row for a single row (or a row by value), read_list_column for a single cell, read_table_cell for FORM tables.

read_list_rowA

Read SEVERAL columns of a dynamic-list row in ONE call. Opens the list at open_link (e.g. e1cib/list/Справочник.Товары) and reads each name in columns (e.g. ["Код", "Наименование"]) of the standard dynlist table Список. Returns {table, nav_link, row: {column: value}, list_refresh} (+ where when given).

where selects the ROW: omit it to read the FIRST (current) row; pass a single {column: value} (e.g. {"Наименование": "Молоко"}) to position the list to the row WHERE column == value first — the «в таблице "Список" я перехожу к строке: | col | value |» equivalent — then read THAT row. The where-row path is a faithful full-sequence replay of a genuine DYNLIST go-to-row-by-value capture (a splice of the FORM-table «перехожу к строке» onto a live dynlist did NOT reposition; the full-sequence replay does), value retargeted in-frame; live-verified on Товары (Наименование=Молоко -> Код 000000026 vs OData). Matching by «Наименование» is the verified path. One row read per fresh launch_test_client (the cold-client boundary), reading all requested columns inside the one materialised session (message-id kept, sequence bumped). CURRENCY: refresh=True (default) forces an «Обновить»/F5 requery + poll-until-stable so an all-None row is only ever a genuinely empty row, not a not-yet-loaded list; refresh=False opts out. For iterating every row use read_list_grid; read_list_column for a single cell; read_table_cell for FORM tables.

read_recordA

Read the actual object-attribute VALUES of an EXISTING POPULATED catalog/document RECORD natively (no per-form capture). Opens the record's form by its reference navigation link (e1cib/data/<record_type>?ref=<ref>) and value-reads every object attribute, decoding the canonical «стал равен» value (string / number / date / enum-presentation / UTF-16; ASCII + Cyrillic). record_type is the metadata full name (e.g. Справочник.Товары); ref is the object's reference UUID — pass the natural dashed form (the OData Ref_Key / УникальныйИдентификатор, e.g. a7a30aaf-321b-11dd-8d3a-000d8843cd1b) and it is auto-encoded to the e1cib hex token, or pass the 32-hex token directly. Returns {opened, record_type, ref, fields {name: value}, field_count, elements, element_count} (+ a Gherkin state block when gherkin).

Live-verified (against OData): Товары/«Доставка» -> {Наименование: «Доставка», Код: «000000037», Вид: «Услуга», Родитель: «Услуги», …} (12 attribute values); Контрагенты/«Покупатели» -> {Наименование: «Покупатели», Код: «000000002»}. The reference-link ref encoding (UUID groups g4·g5·g3·g2·g1) was decoded from the genuine open-card capture.

COLD-CLIENT BOUNDARY: small / catalog-group (ФормаГруппы) record forms read reliably on a freshly launched client. A LARGE item form (e.g. an 80-element Товар card) materialises its attribute DATA only once the client PROCESS has fully opened a form at least once — the first cold open enumerates the element tree but the per-field reads echo with no value (field_count 0 with element_count > 0). To read a large record cold, WARM the client first with one read of a DIFFERENT record (any small/group record), then read the target; re-opening the SAME record does not help (a 2nd same-caption window breaks newest-window detection). This is the same cold-client boundary the dynlist reads observe.

read_spreadsheet_cellB

Read a spreadsheet (ТабличныйДокумент) CELL by address natively. Reading a cell is an IN-CLIENT method on the live object, NOT a binary .mxl wire-decode: the manager NEVER receives the cell text in the binary form-render (only a 20-byte handle); a TARGETED read («перейти к ячейке ») makes the client evaluate the cell and return its value as a small PLAIN string. Replays the genuine flow (open form -> run the report -> navigate to the cell) re-targeting the address (R1C1 notation, ANY length — the navigate frame resizes) and parses the value from the client response with the value-read path (the cell value rides the SAME 0x9a<len><utf-8> shape). Live-verified across address lengths (R1C1->PF_RPT_R1C1, R1C12->PF_RPT_R1C12, R12C12->PF_RPT_R12C12). Returns {field, address, value}.

read_table_cellA

Read the CURRENT ROW's value of a form-TABLE cell natively — the ТаблицаФормы … ТекущиеДанные / «я запоминаю значение поля с именем …» equivalent. Addresses the table by name (table, e.g. PF_TABLE_ITEMS)

  • the column BY NAME (column, e.g. PF_TABLE_TEXT) and decodes the canonical «стал равен» value (string / number / date / UTF-16; ASCII + Cyrillic). Opens the suite fixture form by default; pass open_link (e1cib/list|data/…) to read a cell on ANY form config-agnostically (the table's enclosing groups are discovered from the live descriptor). Returns {table, column, value, groups, opened?}. SCOPE: reads the CURRENT ROW — a form table populated on open has row 1 current (live-verified: fixture PF_TABLE_ITEMS -> PF_TABLE_TEXT="PF_ROW_001_TEXT", PF_TABLE_NUMBER="1,10"). A DYNLIST freshly opened by nav-link may have NO active current row yet (value None) — see read_list_column.

read_user_messagesA

Read the user messages (Сообщить text / the "messages to user" panel) a form emits. This is the capture-free ASSERTION read for «нет сообщений пользователю» and for reading Сообщить output. The client reports the message panel in its responses as the envelope cb 53 9a <byte-len> <UTF-8>; this faithfully replays the genuine flow from capture (whatever raises the message — e.g. the choose-from-list / choose-from-menu callbacks) and decodes every message. Returns {messages, count, expected_found}. Pass expected to assert a specific message is present. NOTE: byte-length-prefixed UTF-8 — proven on ASCII and on a synthetic multibyte string; a real Cyrillic Сообщить should decode the same.

role_data_matrixA

DEPRECATED for a test-client-held base — a «Клиент тестирования» holds the infobase under an EXCLUSIVE lock, so OData cannot read it; this matrix is valid only against a SEPARATELY published, non-exclusive endpoint. Run the SAME data-layer read under several credentials/ROLES and report per-role access + count. Each role = {label, user, password} + optional expectation {expect_access: "read"|"denied", min_count: N}. Returns {ok, roles: [{label, access ('read'|'denied'|'error'), count, http, ok}], deprecated, deprecation}. NOTE: a genuine role-DIFFERENCE matrix needs restricted infobase users provisioned out-of-band (admin-mcp) — outside qa-mcp's read-only scope.

run_reportB

Run a report / fill a ТабличныйДокумент natively. A report-run is a standard FORM-COMMAND click (the click_command family, …Button[<command>] 88 82 81 20 20 20); clicking PF_RUN_REPORT fills the form's spreadsheet attribute ON THE SERVER (cells PF_RPT_R1C1…R2C2) and sets PF_LAST_ACTION="PF_RUN_REPORT". Replays the genuine setup from capture + the command click. NOTE: the SPREADSHEET CELL CONTENT rides the wire as a 1C-packed BINARY ТабличныйДокумент (.mxl) blob — NOT plain strings, NOT zlib/deflate. So reading individual cells capture-free is a deep .mxl-format decode (deferred — the in-client testing API's domain, e.g. «табличный документ … равен»); verify the produced spreadsheet with capture_screenshot (the cells render) or by reading the PF_LAST_ACTION marker. Returns {command, accepted}.

run_scenarioA

Run a scenario (from feature_text or scenario_json) through the native Python TestManager against a running 1C /TESTCLIENT at host:port. When feature_text carries several scenarios, the first runs and the rest register as callees for any run_subscenario («я выполняю сценарий 'X'») step.

OPEN steps (open_main_form / open_list) EXECUTE LIVE with no capture: the form is opened by its e1cib nav-link via the splice_navigate sequence on the bootstrapped session (config-agnostic, fixture-free — the same mechanism read_form_descriptor uses). The step passes when the form actually opens (window-resolved), so «Я открываю основную форму справочника 'Валюты'» drives a real client open + state change. Other ACTION steps (click/select/input/close/…) re-target a CAPTURED command frame, so to EXECUTE those pass action_capture — the capture dir holding those command frames; each action step's frame is located by its marker and replayed GUID-rebound to the live session. action_input_value is the value baked into the capture's input frame (so a .feature input_text retargets correctly), and action_ordinals ("marker=ordinal,marker=ordinal") pins a frame when a marker is not unique. Without action_capture only read/assert/data/skip/subscenario/open steps run; other action steps report unsupported. Returns the ScenarioResult.

run_stepC

Run a single read step (read_active_window / read_form_summary / read_element) natively.

run_write_scenario_toolB

Run a WRITE scenario (Gherkin «в поле с именем 'F' я ввожу текст 'V'» / scenario_json) natively: each input_text step is routed through the COMMIT-capable NativeWriteSession, so the value actually commits — verified by read-back. Steps may target DIFFERENT fields (step.marker) on one session via capture-free element addressing off the base_field capture (same enclosing group); non-write steps are reported unsupported. Returns the ScenarioResult (per-step committed/read-back preview).

search_for_stepsA

Discover the supported Gherkin step vocabulary. Returns the qa-mcp step library: each recognized step's canonical phrasing, a concrete example, its native Step kind, category (read | action | navigation) and a description, optionally filtered by keywords (each whitespace-separated token must appear, case-insensitive; empty returns all). The library is derived from the transpiler's STEP_PATTERNS, so it exactly matches what transpile / run_scenario execute. Use it to author features for qa-mcp; transpile then flags any unmapped lines. Returns {count, total, steps:[{phrase, example, kind, category, description}]}.

search_listA

Filter a dynamic list by a SEARCH STRING natively. Types value into a dynamic list's search-string addition (search_field); the list filters incrementally (searchOnInput). A dynlist search rides the SAME UTF-16 value-SET buffer as a reference-name input (e0 41 81 81 b7 <char-count><utf-16le><space pad>) addressed at the SearchStringAddition element, so it composes from the same full-replay machinery as set_reference_field: open the form (replay the genuine setup from capture, which typed captured_value into the search box) -> activate the dynlist -> SET the search string, re-targeting the UTF-16 string to value (fixed-width, bounded by the captured length). A list-filter has no clean value read-back — confirm with capture_screenshot (the visible rows narrow); echoed reports the search value echoed in the client responses. CURRENCY: refresh=True (default) forces an «Обновить»/F5 requery first so the search runs against a current list (a just-created record is filterable); refresh=False opts out. A search reports no row count, so this is refresh-only (no poll-until-stable); list_refresh records the refresh method. Returns {search_field, value, echoed, list_refresh}.

select_all_table_rowsB

Select ALL rows of the table natively (multi-select). Multi-row select IS protocol-drivable: the genuine «выделяю все строки» step is a TABLE-level command invoke addressed at the …Table[PF_TABLE_ITEMS] element (tail 88 82 81 20 20 20, the same command family as the row-op buttons / window commands — NOT OS input), so it replays from a connect+open+select-all capture and fires (accepted). CAVEAT — read-back boundary: the multi-selection (Элементы.PF_TABLE_ITEMS.ВыделенныеСтроки) is TRANSIENT table-focus UI state. Any SEPARATE focus-changing protocol command (e.g. clicking PF_REFRESH_SELECTION to read it) collapses it back to the active row — confirmed identically in genuine AND replay (both read PF_SEL[1]=<active>), i.e. standard 1C focus behaviour, not a replay defect. So a live multi-selection is NOT capture-free-readable across commands; the non-collapsing read is the in-session testing API (ТестируемаяТаблицаФормы.ПолучитьВыделенныеСтроки), and composing select-then-act must capture the whole flow in ONE session. Returns {base_button, target_button, accepted}. (Arbitrary multi-select via Ctrl-toggle / deselect-all are the same Table-command family — capture on demand.)

select_table_rowB

Position the active row of a table to the row whose column equals row_match natively. A native row-select is "find the row where = " (both length-prefixed strings in the genuine command); re-targeting the VALUE (fixed-width) selects a different row. Replays the capture setup (which selected a row by captured_row_match) with the search value re-pointed to row_match so that row becomes ACTIVE. Returns {row_match, accepted}. Verify via assert_form_value('PF_SELECTED_ROW_MARKER') -> PF_ROW_IDX_<n>:<marker> (fixture OnActivateRow handler), or chain set_table_cell(row_match=…) to WRITE into the selected row.

send_keysA

Send raw OS keystrokes (Enter / Esc / Tab / arrows / shortcuts) to the focused 1C client window. 1C keyboard input is OS-LEVEL (the key is in NO manager->client protocol frame), so raw keys are delivered via XTEST (xdotool) into the client window. Same primitive as write_form_value_xtest's DB-verified Tab/Ctrl+S.

keys is a sequence of xdotool key specs sent in order (["Down", "Down", "Return"], ["Escape"], ["ctrl+s"], ["Tab"]…). Keys go to the FOCUSED window (the launched client is the lone app window), so PREREQ: launch the client with launch_test_client(display=":89", port=…) + a window manager (matchbox); display must be that Xvfb. Most keyboard INTENTS already have a protocol tool — confirm/cancel dialogs (answer_dialog), field commit (Tab / focus-change), row navigation (select_table_row / read_list_grid), save (click_command «Записать») — use those first; send_keys is the raw-key escape hatch for controls that need genuine OS keys. Returns {keys, display, sent}.

set_choiceB

Set a radio (Переключатель) to variant natively. A choice ACTIVATES the EditField and carries the selected variant as a length-prefixed string (…EditField[NAME] … e0 4b 53 <0x9a><len><variant>); variant is the value NAME (e.g. PF_CHOICE_C). Opens the form (replays the genuine setup from capture, which set base_field to captured_variant) and sends the genuine choose block re-targeted: the EditField leaf to target_field (defaults to base_field) + the variant string to variant (same-length swap). Returns {base_field, target_field, variant, accepted}.

set_list_viewA

Switch a dynamic list's VIEW MODE / grouping natively — the «Режим просмотра» toggle. mode is Список (flat) / Дерево (tree) / Иерархический (hierarchy) — also list/tree/hierarchical. The «Режим просмотра» entries are standard FORM BUTTONS (<dynlist>Список / …Дерево / …ИерархическийСписок); clicking one is the …Button[<name>] 88 82 81 20 20 20 command family (the same invoke as the row ops / close-window) with the Button leaf encoded UTF-16LE (Cyrillic name — so this also exercises the UTF-16-aware command-click path that generalizes click_command to real configs). Replays the genuine click from capture (which clicked Список + ИерархическийСписок), re-targeting the Button leaf (Дерево = same-char-length UTF-16 retarget of Список; Список / Иерархический = verbatim). No value read-back — the list REPRESENTATION changes (verify with capture_screenshot). Returns {mode, button, accepted}.

set_reference_fieldA

Set a CatalogRef field to value (a catalog element NAME, e.g. "Пантера АО") natively. A reference InputField resolves a TYPED name to a ref (выбор по строке) on focus-change; the typed name rides the wire as e0 41 81 81 b7 <char-count><utf-16le name><space pad> (the value-SET family with a UTF-16 choice value). This faithfully replays the genuine reference-input session from capture (open form -> type captured_value into field -> focus-change commit -> read-back), re-targeting the UTF-16 name to value. Commit is confirmed by the resolved presentation reading back. Returns {field, value, committed}. CONSTRAINT: value must currently be the SAME character length as captured_value (the field's edit buffer is length-fixed — same fixed-width limit as the string write; a variable-length ref name does not commit yet). Re-capture with a same-length name for other lengths.

set_table_cellA

Write value into a table cell on the ACTIVE row natively. A table-cell SET is byte-identical to a plain string-field SET; only the element path differs — the column is the EditField leaf inside a Table[<table>] segment, with NO row index (the edit hits the active/selected row). Opens the form (replays the genuine setup from capture, which added a row and edited base_column to captured_value), then re-targets the cell SET to table/column + the value and commits via the synthesized focus-change (commit_partner_field — same machinery as the number field). The fixture's editable table is PF_TABLE_ITEMS (PF_TABLE_TEXT string, PF_TABLE_NUMBER number; PF_TABLE_MARKER read-only). The NUMBER cell uses the SAME value buffer as the string cell — the genuine PF_TABLE_NUMBER SET is byte-identical (e0 41 81 81 ba <len> <ascii>, value as text), so set_table_cell(value, column="PF_TABLE_NUMBER") just works (readback "999"). A grid DATE cell is NOT drivable this way: the date control rejects text input («Неподходящий тип элемента управления»); use set_table_date_cell. Returns {requested_value, readback_value, committed, column, table}. The cell read-back IS reliable: the SET response echoes the committed value via the column EditField + value-SET tag — so readback_value/committed reflect the actual write (no screenshot needed).

ROW ADDRESSING: by default the write hits the captured active row. To write into a SPECIFIC row, use a capture whose setup selected a row (with base_column=PF_TABLE_TEXT, captured_value=R2WROT, commit_partner_value=C90RC) and pass row_match = the target row's base_column value — the genuine row-select's search value (captured_row_match, default PF_ROW_002_TEXT) is re-targeted in the setup so the row whose column equals row_match becomes active (row_match=PF_ROW_003_TEXT writes into row 3).

set_table_date_cellA

Set a grid DATE cell to date (DD.MM.YYYY) on the ACTIVE row natively, with the cell located ON SCREEN (no hardcoded coordinates). A 1C date grid cell rejects text/keystroke SET (masked editor); it is settable only by MOUSE through the calendar picker. This tool: (1) protocol-activates the cell (the shipped table-cell write_block — activate+SET, no commit — so the inline date editor and its calendar dropdown button appear), (2) screenshots and LOCATES the calendar button by template-matching the shipped glyph (ImageMagick compare -subimage-search via locate_calendar_button), (3) drives the calendar by mouse — click the dropdown, then the month, then the day — using the popup month-list / day-grid origins DERIVED from the localized button center (fixed deltas, calendar_month_cell / calendar_day_cell geometry), then commits (Return). Returns {column, requested_date, localized, button_xy, month_origin, day_origin, status, verified_by, screenshot, activation_screenshot}. When the button cannot be located it returns status="blocked" and does NOT click guessed coordinates; status="set" when the pick committed (the calendar closed) and "set_calendar_open" if the calendar is still visible after the pick.

YEAR is navigated when the target year differs from the cell's CURRENT year (the calendar opens on it): the ‹/› arrows step the month, so the year uses the « ▼» dropdown (current at the top, current+k below; clicked by row, chained in steps of 3 for larger forward offsets). The current year = from_year if given, else today (correct for an EMPTY cell, which opens on today) — pass from_year for a populated cell whose year differs from today. Backward years (target < current) are not yet supported (the dropdown lists forward only) and return status="blocked".

VERIFICATION is the SCREENSHOT: a mouse-set date cell has no protocol SET echo (the value enters via the calendar, not a wire SET) and the in-form value is not protocol-readable without a save, so the active cell showing the picked date in screenshot is the proof.

REQUIRES an X display with the client laid out by a window manager (matchbox; started here when manage_wm) so the cell/calendar geometry is stable, plus xdotool (XTEST mouse) and ImageMagick.

CONFIG-AGNOSTIC path — pass open_link (a document's e1cib/data/Документ.X?ref=… ref) to set the date on ANY real document form's tabular date cell with NO per-form capture (no capture / write_block). The engine brings the form FOREGROUND, activates the cell ON SCREEN by double-clicking it — located from the date column's on-screen header column_title (e.g. "Дата", subimage-search; the form descriptor has no pixel bounds) or the explicit cell_x/cell_y — and reuses the same calendar pick. row_offset (≈ one grid row, 28 px) steps from the header to the first data row; column is the date column NAME (for the result).

foreground selects how the form is brought to the active tab: "listreplay" (DEFAULT, fixture-FREE, config-agnostic) replays a genuine cold catalog-list-open sequence retargeted to open_link (no bundled fixture — works on any config); "fixture" is the legacy primer (the bundled fixture render-push frames + prime). prime only applies to foreground="fixture".

stop_test_clientA

Tear down a TestClient launched by launch_test_client.

Local mode stops by PID/process group. Remote-client mode requires the host-agent lifecycle handle returned by launch_test_client, so stale or recycled PIDs cannot target a newer process.

switch_pageA

Switch the active tab page (закладку) natively. Opens the form (replays the genuine setup from capture, which switched to base_page) and sends the genuine page-switch command re-targeted to target_page (the page-Group leaf). Returns {base_page, target_page, accepted}. (A page-switch has no value read-back — use capture_screenshot to confirm visually.)

test_client_statusA

Report a launched TestClient's health: whether pid is alive (if given) and whether its TPort at host:port is listening (connectable). Use after launch_test_client / before driving a scenario.

toggle_checkboxB

Toggle a Boolean checkbox (флаг) natively. A checkbox commits with NO value buffer: the wire only ACTIVATES the EditField (the value-free e0 4b 55 toggle, identical for set & clear) and the server flips the Boolean + fires ПриИзменении — the EditField twin of switch_page. Opens the form (replays the genuine setup from capture, which toggled base_field) and sends the genuine toggle re-targeted to target_field (the EditField leaf). Returns {base_field, target_field, accepted}. (A toggle has no ASCII value read-back — the Boolean reads as Да/Нет; confirm via a side-effect field or capture_screenshot.)

transpileA

Transpile a .feature (Gherkin, ru/en) into the native Scenario model without executing it. Returns the scenario steps and any unmapped (unsupported) step lines.

wait_for_form_valueC

Poll a form field's live value until it matches or the timeout elapses.

write_form_dateC

Set a FORM-LEVEL managed-form date EditField (DD.MM.YYYY), distinct from grid date-cell writing.

With open_link this uses the config-agnostic foreground label writer against the target form. Without open_link it falls back to the capture-backed field writer with date-prefix readback acceptance.

write_form_fields_by_labelA

Write values into form fields located by their on-screen LABEL — CONFIG-AGNOSTIC, no per-field capture (generalizes write_form_value_xtest beyond a single fixed field). Foregrounds the form by open_link (e.g. e1cib/data/Справочник.Валюты create form), then TWO-PASS: pass 1 locate_text's every label and records its right edge; pass 2 clicks each field into the SHARED input column (rightmost label edge + input_column_gap) — so a short reference label like «Владелец» hits the same right-aligned column as the longest label instead of under-reaching into a neighbour — types the value Unicode-safe (xtest_type_unicode — Cyrillic-safe) -> Tab. (A field_mode="date" field clicks its own input mask at date_input_offset and types digit keys, never the calendar button; with 0/1 located labels the column falls back to the legacy label-center + input_offset.) Pairs with autofill_required_fields (feed its resolved {label->value} plan). save -> Ctrl+S (creates a record).

HONEST verification: after typing, the open form is value-READ on a fresh manager connection (readback, default on) and each item's committed is set True ONLY when the requested value is actually read back from the form model (the «стал равен» value-read) — a field targeted on screen but not read back is committed=False (no false positives). OData cannot verify here: a test-client-held file/server base is exclusively locked, so the protocol value-read of the SAME client is the verification, not assert_data.

PREREQ: client launched with an Xvfb display + matchbox. all_targeted = every label located + typed; all_committed = every targeted value read back. Returns {open_link, foregrounded, results:[{label, value, click_xy, targeted, committed, readback_value, geometry}], all_targeted, all_committed, readback:{opened, field_count, verified, fields}, screenshot}.

write_form_valueA

Write an arbitrary VALUE into a form field and COMMIT it natively.

Replays the genuine INPUT capture capture for base_field (auto-derived template) to establish an input-authorized session, retargets the captured value to value (variable-length, fixed-width aware), and verifies by read-back. When field differs from base_field, the element-address path leaf is re-targeted to field (same enclosing group). commit_partner (+ commit_partner_value): for a field whose genuine input had no trailing focus-change (e.g. base_field="PF_EDIT_NUMBER", captured_value="777,77"), pass another field with a genuine input (e.g. commit_partner="PF_EDIT_STRING", commit_partner_value="QAGENUINE2026"); its ACTIVATE is appended as the synthesized focus-change so the value COMMITS. Returns committed/readback_value/field.

open_link switches to the config-agnostic foreground write route: the target form is opened by nav-link and the on-screen field label is targeted with XTEST text input. That route is explicit in the result as write_mode="open_link_label_xtest" and retains a screenshot path.

write_form_value_xtestA

Write a value into a form field via the protocol+XTEST HYBRID — for OBJECT-attribute fields (Объект.* on catalog/document forms) that the pure protocol replay cannot commit.

The pure write_form_value only sets a field's edit-text; an object attribute commits only on a genuine user edit + blur, which a programmatic SetEditText does not trigger (and 1C exposes no AT-SPI elements). The 1C window IS OS-accessible, so this replays the capture's open+focus prefix (protocol, addresses field by name), then injects value via xdotool type (Unicode/Cyrillic-aware) into the focused client window on display, blurs (Tab -> commit), optionally saves (save=True -> Ctrl+S -> DB), and reads the value back by replaying the capture's read sequence. PREREQ: launch the client with launch_test_client(display=":89", port=…) (and a window manager so the form lays out — matchbox); display must be that Xvfb. Defaults match the demo capture (Справочник.Валюты.Наименование). Returns {field, value, committed, value_in_readback, readback_value, diverged_at, blurred, saved, display}.

write_form_valuesB

Batch value-write: open the form ONCE and COMMIT several values in sequence on one connection (NativeWriteSession multi-write). Same as write_form_value (incl. capture-free field addressing via base_field) but for values in order.

write_test_reportA

Write machine-readable test reports for the scenarios run THIS MCP-server session so qa-mcp slots into an existing CI pipeline. formats (default both): "junit" -> <out_dir>/junit.xml (CI test-result panels); "allure" -> <out_dir>/allure-results/*.json (renderable by the Allure CLI, with per-step status/timing and any screenshot attachments). Uses the same session log as get_test_results; pass clear=true to reset it after writing. Returns the output paths + scenario count.

Prompts

Interactive templates invoked by user choice

NameDescription

No prompts

Resources

Contextual data attached and managed by the client

NameDescription

No resources

TDQS

B3.2/5.0

Scored across 64 tools

Disambiguation3/5

Many tools have overlapping purposes, especially the write_form_value variants (write_form_value, write_form_value_xtest, write_form_values, write_form_fields_by_label), the read_list_* family (column/row/grid), and several assert/read tools. The very detailed descriptions help differentiate them, but an agent still faces non-trivial selection risk across 64 tools with similar naming.

Naming Consistency4/5

The vast majority of tools use consistent snake_case verb_noun naming (run_scenario, read_record, write_form_value, open_list, select_table_row). A few exceptions are noun-only or diagnostic names (advanced_search, com_connector_doctor, infobase_info, qa_mcp_doctor, role_data_matrix, test_client_status), and one has a suffix (get_window_list_testclient), but the overall pattern is predictable.

Tool Count2/5

64 tools is far above a typical well-scoped set and exceeds the 25+ threshold for 'too many'. The domain is broad (1C client lifecycle, UI automation, scenario running, diagnostics), so some count is justified, but many tools are granular variants of the same underlying operations, making the surface heavier than necessary.

Completeness4/5

Coverage is extensive: client launch/attach/stop, form and list reads, form/table/cell writes, dialogs, menus, choices, checkboxes, pages, reports, scenario execution, and diagnostics. A few boundaries remain (multi-select read across commands, backward year navigation in date cells, spreadsheet cell decode deferred), but these are minor workarounds rather than glaring gaps.