Concrete scenarios for testing every local_ydb_* MCP tool in this repository.
These scenarios are intentionally opinionated and reflect what actually worked in this repo during local runs.
This document covers all public local_ydb_* tools currently registered by the MCP server:
local_ydb_inventorylocal_ydb_database_statuslocal_ydb_healthchecklocal_ydb_container_logslocal_ydb_destroy_stacklocal_ydb_status_reportlocal_ydb_tenant_checklocal_ydb_schemelocal_ydb_generate_schemalocal_ydb_apply_schemalocal_ydb_sqllocal_ydb_permissionslocal_ydb_nodes_checklocal_ydb_graphshard_checklocal_ydb_auth_checklocal_ydb_storage_placementlocal_ydb_add_storage_groupslocal_ydb_reduce_storage_groupslocal_ydb_storage_leftoverslocal_ydb_list_versionslocal_ydb_pull_imagelocal_ydb_pull_statuslocal_ydb_bootstrap_root_databaselocal_ydb_bootstraplocal_ydb_create_tenantlocal_ydb_start_dynamic_nodelocal_ydb_add_dynamic_nodeslocal_ydb_remove_dynamic_nodeslocal_ydb_restart_stacklocal_ydb_upgrade_versionlocal_ydb_list_dumpslocal_ydb_dump_tenantlocal_ydb_restore_tenantlocal_ydb_prepare_auth_configlocal_ydb_write_dynamic_auth_configlocal_ydb_apply_auth_hardeninglocal_ydb_set_root_passwordlocal_ydb_cleanup_storage
Use these profiles from examples/local-ydb.config.example.json:
ghcr261-clean: isolated clean stack onghcr.io/ydb-platform/local-ydb:26.1.1.6ghcr261-auth: same stack, but with auth artifacts enabledlocal: auth-enabled working stack on the default ports
Treat ghcr-rebuild-clean and ghcr-rebuild-auth as historical rehearsal profiles. Prefer the ghcr261-* pair for current testing.
- Run
local_ydb_check_prerequisitesfirst on a new host or profile. - If
local_ydb_check_prerequisitesreports installable packages, review its plan-only output and then useconfirm: trueto install supported host helpers before trying deeper checks. - Run read-only tools first.
- Use
local_ydb_list_versionsbeforelocal_ydb_upgrade_versionwhen you need to verify the exact registry tag to deploy. - If an image is not already present on the target host, use
local_ydb_pull_image(confirm=true)and polllocal_ydb_pull_statusbefore bootstrap or upgrade. - For mutating tools, call plan-only once before
confirm: trueunless you are deliberately smoke-testing an idempotent path. - Do not test
cleanup_storageagainst active volumes or paths. - Do not mix static and dynamic image tags inside one profile.
- For stable GHCR tests, use the exact patch tag
ghcr.io/ydb-platform/local-ydb:26.1.1.6.
dynamicNodeCountis the total configured tenant-node count, including primary, and defaults to1.- Configured node
1usesdynamicContainer; nodes2..NusedynamicContainer-<index>and base ports plusindex - 1. - Configured dynamic names must be distinct from the static container; bootstrap, add, and standalone primary start validate names and the complete shared-network port set before returning a plan.
- Static IC port
19001is reserved; all configured and one-off ports share the static node's network namespace and must not collide with it. - The static container publishes the static gRPC port and every configured dynamic gRPC port on loopback. One-off nodes do not change those bindings.
- Tenant bootstrap recreates configured containers in index order, even when a stale container is already running. Readiness requires a stable running exact container plus IC registration; a matching nodelist port alone is insufficient.
- Default
local_ydb_add_dynamic_nodesstarts atdynamicNodeCount + 1; an explicitstartIndexmust be greater thandynamicNodeCount, and higher suffixes are one-off runtime nodes. - Default
local_ydb_remove_dynamic_nodesconsiders only suffixes abovedynamicNodeCount; explicit selectors orstartIndexcan remove a configured suffix and create drift. - Before any restart mutation, the existing static container must pass the full profile check, including exact configured loopback bindings. A mismatch leaves all container IDs and states unchanged and requires destroy/bootstrap.
- Restart unconditionally recreates every configured container, including containers observed restarting. It reports missing configured and unexpected one-off containers, never removes unexpected containers, and attempts to restore every preflight-running unexpected container even when restart fails.
- Restart rollback uses restart or bootstrap reconciliation because inventory does not retain removed configured container definitions.
- Removal rollback restores configured nodes through restart or bootstrap and recreates one-off nodes through add; a mixed selection returns both instructions.
- Auth hardening runs the full static compatibility preflight before any config or container mutation, then recreates and verifies every configured node in index order, including profiles without a dynamic-node token file; rollback also uses restart or bootstrap reconciliation.
- Storage reduction and version upgrade inspect and preserve exact one-off gRPC, monitoring, and IC ports before dump or destroy; an incomplete container definition aborts the rebuild before destructive work.
Use only a disposable profile with unique container/network/volume names and non-overlapping contiguous port ranges. Keep cleanup in finally.
- Bootstrap with
dynamicNodeCount: 1. Save the static and primary container IDs, bindings, and running/stopped states. - Change the same profile to
dynamicNodeCount: 3. Restart plan-only must place the full static compatibility check before every mutation. Confirmed restart must reject the missing configured bindings without changing saved IDs/states or creating-2/-3; tenant bootstrap must reject the same shared compatibility contract. - Confirm destroy, then perform a fresh count-3 bootstrap. Inventory must contain the primary,
-2, and-3; the static container must publish exactly the static and all three configured dynamic gRPC ports on loopback; authenticatednodelistmust contain all three derived IC ports;scheme lsthrough every configured dynamic gRPC endpoint andlocal_ydb_tenant_checkmust pass. - Call
local_ydb_add_dynamic_nodeswithoutstartIndex. It must plan and create-4. Save its Docker ID and running state from inventory. - Remove configured container
-2explicitly. Call restart plan-only and requiremissingDynamicContainers=["<dynamicContainer>-2"]andunexpectedDynamicContainers=["<dynamicContainer>-4"]. The plan must not containdocker rm -f <dynamicContainer>-4. - Replace configured
-2with a same-name restart-looping fixture. Restart plan-only must contain an unconditional remove/run for-2; confirmed restart must give it a new Docker ID. The preflight-running-4must retain its saved Docker ID and running state. Exact configured IC ports and tenant metadata must pass again. - While
-4exists with non-default gRPC, monitoring, and IC ports, plan a storage reduction or version upgrade rebuild. Only-4may appear inextraDynamicNodes; its exact inspected ports must be reused, while configured-2and-3come from bootstrap/auth reconciliation. Withhold one inspected port as a negative control and require failure before dump or destroy. Final container/image and nodelist verification must cover configured nodes plus-4. - Confirm destroy, then bootstrap again. Inventory must contain exactly the three configured dynamic containers and no
-4. - In
finally, destroy the disposable stack and independently remove any leftover disposable containers, network, and volume.
Goal: exercise local_ydb_sql against the selected configured local-ydb profile. Use the official ydb-mcp server instead when the target is an arbitrary YDB endpoint rather than a toolkit-managed local-ydb profile.
Preparation:
- Create a disposable
managed_sql_smoketable withlocal_ydb_apply_schema. - Run every cleanup step from a
finallyblock, including after an assertion or preflight failure. - Never reuse a table that contains non-test data.
- For the authenticated Linux SSH fixture, keep static and dynamic gRPC ports unpublished, set
profile.networkto the static container's user-defined bridge, let the dynamic node share the static container namespace, and expose the root password file only as a read-only remote secret.
Calls:
{ "tool": "local_ydb_sql", "arguments": { "profile": "ghcr261-clean", "action": "query", "script": "SELECT $value AS value;", "parameters": { "value": { "type": { "kind": "primitive", "name": "Int32" }, "value": 42 } } } }
{ "tool": "local_ydb_sql", "arguments": { "profile": "ghcr261-clean", "action": "query", "script": "UPSERT INTO `managed_sql_smoke` (id, value) VALUES (1, \"blocked\");", "confirm": true } }
{ "tool": "local_ydb_sql", "arguments": { "profile": "ghcr261-clean", "action": "query", "script": "SELECT COUNT(*) AS count FROM `managed_sql_smoke`;" } }
{ "tool": "local_ydb_sql", "arguments": { "profile": "ghcr261-clean", "action": "explain", "script": "SELECT id, value FROM `managed_sql_smoke`;" } }
{ "tool": "local_ydb_sql", "arguments": { "profile": "ghcr261-clean", "action": "execute", "script": "UPSERT INTO `managed_sql_smoke` (id, value) VALUES (1, \"confirmed\");" } }
{ "tool": "local_ydb_sql", "arguments": { "profile": "ghcr261-clean", "action": "execute", "script": "UPSERT INTO `managed_sql_smoke` (id, value) VALUES (1, \"confirmed\");", "confirm": true } }
{ "tool": "local_ydb_sql", "arguments": { "profile": "ghcr261-clean", "action": "execute", "script": "THIS IS NOT VALID YQL;", "confirm": true } }
{ "tool": "local_ydb_sql", "arguments": { "profile": "ghcr261-clean", "action": "explain", "script": "ALTER TABLE `managed_sql_smoke` ADD COLUMN note Utf8;" } }
{ "tool": "local_ydb_sql", "arguments": { "profile": "ghcr261-clean", "action": "explain", "script": "CREATE TABLE `managed_sql_ctas_explain` (PRIMARY KEY (id)) WITH (STORE = COLUMN) AS SELECT id, value FROM `managed_sql_smoke`;" } }
{ "tool": "local_ydb_sql", "arguments": { "profile": "ghcr261-clean", "action": "query", "script": "SELECT value FROM AS_TABLE($items) ORDER BY value;", "maxRows": 2, "maxOutputBytes": 65536, "parameters": { "items": { "type": { "kind": "list", "item": { "kind": "struct", "fields": [{ "name": "value", "type": { "kind": "primitive", "name": "Int32" } }] } }, "value": [{ "value": 0 }, { "value": 1 }, { "value": 2 }] } } } }
{ "tool": "local_ydb_sql", "arguments": { "profile": "ghcr261-clean", "action": "query", "script": "SELECT $large AS first; SELECT $large AS second;", "maxOutputBytes": 256, "parameters": { "large": { "type": { "kind": "primitive", "name": "Utf8" }, "value": "<replace with an actual string of at least 4096 characters>" } } } }
{ "tool": "local_ydb_sql", "arguments": { "profile": "ghcr261-clean", "action": "query", "script": "SELECT $text AS text;", "parameters": { "text": { "type": { "kind": "primitive", "name": "Utf8" }, "value": "\ud800" } } } }
{ "tool": "local_ydb_sql", "arguments": { "profile": "ghcr261-clean", "action": "query", "script": "SELECT $record;", "parameters": { "record": { "type": { "kind": "struct", "fields": [{ "name": "\ud800", "type": { "kind": "primitive", "name": "Utf8" } }] }, "value": { "\ud800": "value" } } } } }
{ "tool": "local_ydb_sql", "arguments": { "profile": "ghcr261-clean", "action": "query", "script": "SELECT \"\ud800\" AS text;" } }
{ "tool": "local_ydb_sql", "arguments": { "profile": "ghcr261-clean", "action": "query", "script": "SELECT $path AS path;", "parameters": { "path": { "type": { "kind": "primitive", "name": "Utf8" }, "value": "<replace with this profile's configured rootPasswordFile path>" } } } }Expected:
queryuses SnapshotRO even whenconfirm=true; the attempted UPSERT fails and the following count remains zero.explainreturns a plan or AST without side effects.executealways performs mandatory EXPLAIN first. Withoutconfirm=trueit returnsoutcome=planned; with confirmation it sends one NoTx execution and performs no retries.- Invalid confirmed YQL is blocked by failed preflight with
executed=falseandconfirmationConsumed=false. - Parameter names are bare names, declarations are generated deterministically, and response metadata contains canonical parameter types with configured credential paths redacted but does not echo supplied parameter values. Selected result rows can still contain those values.
maxRowstruncates a result set only between complete rows; the first row-limit hit stops all further result capture (read-only execution cancels, confirmedNoTxdrains).maxOutputBytesis shared across captured issues, plan/AST, metadata, and rows.- The byte-limit call's placeholder is documentation only; replace it with an actual value of at least 4096 characters, or an equivalent fixture that reliably exceeds the 256-byte capture budget.
- All three lone-surrogate calls are rejected before Query Service execution: they probe an Utf8 parameter, a Struct field name, and the script itself. Replace the credential-path placeholder with the selected profile's exact configured path; the returned row string is
<redacted>. - Result rows are arrays aligned with
columns; their strings, nested object keys, and column names/types undergo recursive redaction for configured credential paths, the loaded root password, and recognized credential assignments. Colliding redacted keys retain every value through deterministic numeric suffixes, and redaction expansion remains charged tooutputBytes. Inspectoutcome, truncation flags, andoutputBytesrather than treating partial output as success. - On an authenticated Linux SSH profile with Docker-internal gRPC,
query,explain, plan-onlyexecute, andlocal_ydb_apply_schema action=validatesucceed without host port publication. Credential read, Docker target resolution, SSH listener setup, YDB readiness, session creation, session attach, and query execution failures return safe phase-specific diagnostics. - Cleanup drops
managed_sql_smokeeven when an earlier check fails.
Goal: verify the target host has the required base tools before any Docker or YDB checks.
Profile:
ghcr261-clean
Calls:
{ "tool": "local_ydb_check_prerequisites", "arguments": { "profile": "ghcr261-clean", "confirm": false } }Optional install path on supported apt-based hosts:
{ "tool": "local_ydb_check_prerequisites", "arguments": { "profile": "ghcr261-clean", "confirm": true } }Expected:
ready=trueonly when every prerequisite is usable- the check reports Docker CLI availability separately from the
dockerDaemonservice check - absent CLI/files appear in
missing; a present CLI with an unreachable daemon appears inunavailable - an unreachable SSH target reports
ready=false,missing=[],unavailable=["target"], no installable packages, and no install plan; it does not infer that Docker, curl, ruby, or the password file is missing - auth-enabled profiles also report whether
rootPasswordFileexists - plan-only output includes
apt-getinstall commands only for supported auto-install packages - after any confirmed
apt-getattempt,checks,ready,missing,unavailable, package-manager fields, and manual actions describe a fresh post-install snapshot;resultscontains the install attempt followed by those final probes - Docker installation and daemon startup remain manual;
confirm=truenever starts Docker
Avoid:
- treating
inventory = 0 containersas proof that Docker is installed on a remote host - proposing Docker or helper installation when the SSH target itself is unavailable
- using
confirm: trueblindly on a host whereapt-getshould not be touched
Goal: verify the selected profile is wired correctly and all read-only endpoints work.
Profile:
ghcr261-clean
Calls:
{ "tool": "local_ydb_inventory", "arguments": { "profile": "ghcr261-clean" } }
{ "tool": "local_ydb_storage_leftovers", "arguments": { "profile": "ghcr261-clean" } }
{ "tool": "local_ydb_status_report", "arguments": { "profile": "ghcr261-clean" } }
{ "tool": "local_ydb_healthcheck", "arguments": { "profile": "ghcr261-clean" } }
{ "tool": "local_ydb_scheme", "arguments": { "profile": "ghcr261-clean" } }
{ "tool": "local_ydb_scheme", "arguments": { "profile": "ghcr261-clean", "action": "list", "recursive": true, "onePerLine": true } }
{ "tool": "local_ydb_scheme", "arguments": { "profile": "ghcr261-clean", "action": "describe", "path": "/local/example", "stats": true } }
{ "tool": "local_ydb_permissions", "arguments": { "profile": "ghcr261-clean" } }Expected:
- successful
inventoryreturnsok=true,docker.cliAvailable=true,docker.daemonReachable=true, and the current containers/volumes. - Docker CLI, daemon, or inventory failures return
ok=falsewith a reason and omit inventory arrays; never interpret that response as an empty host. storage_leftoversreports candidate volumes/paths without mutating them.status_reportcontains every component independently: inventory, auth, tenant, nodes, or health rejection produces the existing component-shaped safe fallback and does not prevent later checks.- fallback diagnostics contain fixed summaries and empty command/output fields rather than raw exceptions, SSH/Docker stderr, credential paths, or
ENOENTdetails. healthcheckreturns the YDBselfCheckResult, issue counts, issue types, capped raw output, and truncatedissue_logentries when present.schemedefaults to the tenant root, returnscommand, cappedstdout/stderr, original uncapped byte counts, and truncation flags.permissionsdefaults to the tenant root for read-only ACL inspection and returns the owner, direct permissions, and effective permissions from the YDB CLI output.- recursive scheme listings should use
maxOutputByteswhen the tenant has many objects.
Avoid:
- Accessing
inventory.containersbefore checkinginventory.ok. - Treating
status_report.tenant=not-okas a transport failure. It often just means the stack is not bootstrapped yet. - Passing list-only flags such as
recursivetoaction=describe, orstatstoaction=list.
Goal: verify structured YDB table DDL generation, SDK validation, confirm-gating, application, inspection, and cleanup.
Profile:
ghcr261-auth
Calls:
{ "tool": "local_ydb_generate_schema", "arguments": { "profile": "ghcr261-auth", "validate": true, "statements": [{ "kind": "createTable", "tableName": "schema_apply_smoke", "columns": [{ "name": "id", "type": "Uint64", "notNull": true }, { "name": "value", "type": "Utf8" }], "primaryKey": ["id"], "indexes": [{ "name": "schema_apply_smoke_by_value", "columns": ["value"], "global": true }], "with": { "AUTO_PARTITIONING_BY_SIZE": { "token": "ENABLED" } } }] } }
{ "tool": "local_ydb_apply_schema", "arguments": { "profile": "ghcr261-auth", "action": "validate", "script": "CREATE TABLE `schema_apply_smoke` (\n `id` Uint64 NOT NULL,\n `value` Utf8,\n INDEX `schema_apply_smoke_by_value` GLOBAL ON (`value`),\n PRIMARY KEY (`id`)\n)\nWITH (\n AUTO_PARTITIONING_BY_SIZE = ENABLED\n);" } }
{ "tool": "local_ydb_apply_schema", "arguments": { "profile": "ghcr261-auth", "action": "apply", "script": "CREATE TABLE `schema_apply_smoke` (\n `id` Uint64 NOT NULL,\n `value` Utf8,\n INDEX `schema_apply_smoke_by_value` GLOBAL ON (`value`),\n PRIMARY KEY (`id`)\n)\nWITH (\n AUTO_PARTITIONING_BY_SIZE = ENABLED\n);", "confirm": false } }
{ "tool": "local_ydb_apply_schema", "arguments": { "profile": "ghcr261-auth", "action": "apply", "script": "CREATE TABLE `schema_apply_smoke` (\n `id` Uint64 NOT NULL,\n `value` Utf8,\n INDEX `schema_apply_smoke_by_value` GLOBAL ON (`value`),\n PRIMARY KEY (`id`)\n)\nWITH (\n AUTO_PARTITIONING_BY_SIZE = ENABLED\n);", "confirm": true } }
{ "tool": "local_ydb_scheme", "arguments": { "profile": "ghcr261-auth", "action": "describe", "path": "/local/example/schema_apply_smoke" } }
{ "tool": "local_ydb_apply_schema", "arguments": { "profile": "ghcr261-auth", "action": "apply", "script": "DROP TABLE schema_apply_smoke;", "confirm": true } }Expected:
local_ydb_generate_schemareturns generated DDL text, script SHA-256, statement kinds, official YDB references, warnings, risk, verification steps, and SDK validation status whenvalidate=true.- bare table
WITHtokens such asAUTO_PARTITIONING_BY_SIZE = ENABLEDare represented as{ "token": "ENABLED" }in the structured spec. action=validatereturns SDK validation status and never applies DDL.action=applywithoutconfirm=truevalidates and returns planned SDK validation/application steps only.- confirmed apply returns a script SHA-256, statement count/kinds, validation result, execution result, risk, rollback notes, and verification steps.
- the response does not echo the raw DDL script or configured credential paths.
DROP TABLEand destructiveALTER TABLE ... DROP ...actions are reported as high risk.CREATE TABLEnotNullis used only for columns that are part ofprimaryKey; non-key required business fields should be enforced by application validation or a later YDB feature path.partitionByHashis used only withstore: "column"and primary key columns; row tables use row partitioningWITHsettings instead.- column names with the reserved
__ydb_prefix, unsupported column-oriented table types,ALTER TABLE ADD COLUMNnotNull/default, duplicate add/drop column actions, and generated scripts over 1 MiB are rejected before validation/application. - If an index needs a newly added column, generate/apply the
addColumnfirst, then run a separate generate/apply call foraddIndex; do not add an index on a column dropped in the samealterTablespec. vector_kmeans_treeindexes includeglobal: true,sync: "sync", nounique, and completewithsettings:vector_dimension,vector_type, eitherdistanceorsimilarity,clusters, andlevels.- normal secondary indexes are global-only, do not accept creation-time
withsettings, unique indexes are synchronous, and creating a table with a vector index returns a warning that adding the vector index after loading representative data is preferred.
Avoid:
- assuming generated DDL was applied. Apply still goes through
local_ydb_apply_schemaand requiresconfirm=true. - using this tool for DML, user/auth DDL, ACLs, topics, transfers, or views; v1 supports only
PRAGMA,CREATE TABLE,ALTER TABLE, andDROP TABLE. - treating rollback notes as automatic rollback. Schema DDL needs explicit inverse DDL or restore from dump.
Goal: exercise the structured generator against common schema shapes before relying on it for a larger migration.
Profile:
ghcr261-auth
Probe specs:
{ "tool": "local_ydb_generate_schema", "arguments": { "profile": "ghcr261-auth", "validate": true, "statements": [{ "kind": "createTable", "tableName": "schema_probe_column_partition", "store": "column", "partitionByHash": ["tenant_id"], "columns": [{ "name": "tenant_id", "type": "Utf8", "notNull": true }, { "name": "ts", "type": "Timestamp", "notNull": true }, { "name": "value", "type": "Double" }], "primaryKey": ["tenant_id", "ts"], "with": { "AUTO_PARTITIONING_MIN_PARTITIONS_COUNT": 2 } }] } }
{ "tool": "local_ydb_generate_schema", "arguments": { "profile": "ghcr261-auth", "validate": true, "statements": [{ "kind": "createTable", "tableName": "schema_probe_vector", "store": "row", "columns": [{ "name": "id", "type": "Uint64", "notNull": true }, { "name": "user", "type": "String" }, { "name": "title", "type": "String" }, { "name": "embedding", "type": "String" }], "primaryKey": ["id"], "indexes": [{ "name": "schema_probe_vector_idx", "columns": ["user", "embedding"], "cover": ["title"], "global": true, "sync": "sync", "using": "vector_kmeans_tree", "with": { "distance": "cosine", "vector_type": "float", "vector_dimension": 3, "clusters": 2, "levels": 1 } }] }] } }
{ "tool": "local_ydb_generate_schema", "arguments": { "profile": "ghcr261-auth", "validate": true, "statements": [{ "kind": "createTable", "tableName": "schema_probe_defaults", "columns": [{ "name": "id", "type": "Uint64", "notNull": true, "default": 1 }, { "name": "label", "type": "Utf8", "default": "new" }, { "name": "created_on", "type": "Date", "default": "2026-05-27" }], "primaryKey": ["id"] }] } }
{ "tool": "local_ydb_generate_schema", "arguments": { "profile": "ghcr261-auth", "validate": true, "statements": [{ "kind": "alterTable", "tableName": "schema_probe_alter", "actions": [{ "kind": "addColumn", "column": { "name": "status", "type": "Utf8" } }] }] } }
{ "tool": "local_ydb_generate_schema", "arguments": { "profile": "ghcr261-auth", "validate": true, "statements": [{ "kind": "alterTable", "tableName": "schema_probe_alter", "actions": [{ "kind": "addIndex", "index": { "name": "schema_probe_alter_by_status", "columns": ["status"], "global": true } }] }] } }Expected:
- each positive generated script validates, then goes through
local_ydb_apply_schema action=apply confirm=falsebefore any confirmed apply. - created probe tables are described with
local_ydb_scheme action=describeand then cleaned up with validated/confirmedDROP TABLE. - generator-only negative probes reject row-table
partitionByHash, non-primary-keypartitionByHash, emptypartitionByHash/cover, column-store secondary indexes, unsupported column-store key/non-key types, local secondary indexes, secondary indexwithsettings, async unique indexes, unique vector indexes, same-spec add/drop column references from indexes, duplicate add/drop column/index actions,ALTER TABLE ADD COLUMNnotNull/default,with.STORE, reserved__ydb_column names, missing primary/index columns, invalid types, invalid setting names/tokens, and scripts over 1 MiB before rendering or validation.
Goal: verify ACL command construction and confirm-gating without accidentally changing an active stack.
Profile:
ghcr261-auth
Calls:
{ "tool": "local_ydb_permissions", "arguments": { "profile": "ghcr261-auth", "action": "list", "path": "/local/example" } }
{ "tool": "local_ydb_permissions", "arguments": { "profile": "ghcr261-auth", "action": "grant", "path": "/local/example", "subject": "testuser", "permissions": ["ydb.generic.read"], "confirm": false } }
{ "tool": "local_ydb_permissions", "arguments": { "profile": "ghcr261-auth", "action": "revoke", "path": "/local/example", "subject": "testuser", "permissions": ["ydb.generic.read"], "confirm": false } }
{ "tool": "local_ydb_permissions", "arguments": { "profile": "ghcr261-auth", "action": "set", "path": "/local/example", "subject": "testuser", "permissions": ["ydb.generic.read", "ydb.generic.list"], "confirm": false } }
{ "tool": "local_ydb_permissions", "arguments": { "profile": "ghcr261-auth", "action": "clear", "path": "/local/example", "confirm": false } }
{ "tool": "local_ydb_permissions", "arguments": { "profile": "ghcr261-auth", "action": "chown", "path": "/local/example", "owner": "root", "confirm": false } }
{ "tool": "local_ydb_permissions", "arguments": { "profile": "ghcr261-auth", "action": "clear-inheritance", "path": "/local/example", "confirm": false } }
{ "tool": "local_ydb_permissions", "arguments": { "profile": "ghcr261-auth", "action": "set-inheritance", "path": "/local/example", "confirm": false } }Expected:
action=listexecutes withoutconfirmand returns capped stdout/stderr plus byte counts.- mutating actions return
executed=false, planned command text, rollback notes, and verification steps whenconfirmis omitted or false. grant,revoke, andsetrender each permission as a separate-pargument.- authenticated profiles redact configured password-file paths in planned command text.
Avoid:
- using
confirm: trueforclear,chown, or inheritance changes unless the target path and rollback are already captured byaction=list. - passing a comma-separated permission string; use the structured
permissionsarray.
Goal: verify that the registry tag listing tool can discover concrete local-ydb image versions before an upgrade.
Calls:
{ "tool": "local_ydb_list_versions", "arguments": {} }
{ "tool": "local_ydb_list_versions", "arguments": { "image": "ghcr.io/ydb-platform/local-ydb", "pageSize": 50, "maxPages": 2 } }Version listing accepts only GHCR and Docker Hub images. Confirm that other registry hosts are rejected without a network request, and that cross-origin pagination links or bearer-token realms are rejected.
Expected:
- the response includes
image,registry,repository,tags,count, andtruncated - the default image resolves to
ghcr.io/ydb-platform/local-ydb tagsincludes concrete patch tags when the registry publishes them- numeric version tags are sorted newest first; mutable aliases such as
latest,nightly, andtrunkfollow the numeric versions truncatedbecomestrueonly when the configured page limit is reached before the registry finishes pagination
Avoid:
- assuming
latestis the only safe upgrade target - using a short major/minor tag in production-like checks when an exact patch tag is available
Goal: start slow registry downloads outside synchronous bootstrap or upgrade calls.
Calls:
{ "tool": "local_ydb_pull_image", "arguments": { "profile": "ghcr261-clean", "image": "ghcr.io/ydb-platform/local-ydb:26.1.1.6", "confirm": false } }
{ "tool": "local_ydb_pull_image", "arguments": { "profile": "ghcr261-clean", "image": "ghcr.io/ydb-platform/local-ydb:26.1.1.6", "confirm": true } }
{ "tool": "local_ydb_pull_status", "arguments": { "jobId": "<jobId-from-pull-image>" } }Expected:
- plan-only output includes
docker image inspectanddocker pull - with
confirm: true, the tool returns quickly withstatus: runningand ajobId, unless the image is already present - status polling eventually returns
completedorfailed - bootstrap and upgrade image preflight failures point back to
local_ydb_pull_imageinstead of hanging insidedocker run
Avoid:
- relying on
docker runto implicitly pull large images inside a synchronous MCP tool call - treating a 120-second MCP client timeout during image download as a YDB bootstrap failure
Goal: validate network/volume/static-node bring-up for plain /local without creating a CMS tenant or dynamic node.
Profile:
ghcr261-clean
Calls:
{ "tool": "local_ydb_bootstrap_root_database", "arguments": { "profile": "ghcr261-clean", "confirm": false } }
{ "tool": "local_ydb_bootstrap_root_database", "arguments": { "profile": "ghcr261-clean", "confirm": true } }
{ "tool": "local_ydb_scheme", "arguments": { "profile": "ghcr261-clean", "path": "/local" } }Expected:
- plan-only output starts the static container only
- no
admin database /local/... createcommand is planned - no dynamic-node container is created
scheme ls /localsucceeds through the static gRPC endpoint
Avoid:
- using the tenant bootstrap tool when the task only needs
/local - treating a missing configured tenant as a root database failure
Goal: verify bootstrap reuses a task-owned stopped static container only when its stored configuration remains compatible.
Precondition: bootstrap a disposable profile, then stop only that profile's static container.
Calls:
{ "tool": "local_ydb_bootstrap_root_database", "arguments": { "profile": "<disposable-profile>", "confirm": true } }
{ "tool": "local_ydb_healthcheck", "arguments": { "profile": "<disposable-profile>", "databasePath": "/local" } }Expected:
- bootstrap applies the same compatibility checks to running and stopped containers and never relies on
docker port - the exact image reference and current image ID, selected network,
/ydb_datavolume or bind source/type/RW, complete loopback gRPC and monitoring bindings without extras, required environment,unless-stoppedpolicy, and disabled healthcheck must all match - tenant bootstrap and restart additionally require the GraphShard feature flag plus the static gRPC binding and every configured dynamic gRPC binding
- a static container created for a smaller
dynamicNodeCountfails both bootstrap and restart compatibility before any configured dynamic container is mutated and requires destroy/rebootstrap - an inspect failure or mismatch returns only the incompatible aspect plus recreation guidance and leaves the container stopped; changing the profile volume is a useful live negative control
- a compatible static container starts exactly once and the root healthcheck succeeds
Avoid:
- stopping or reusing a persisted
/localstack owned by another workflow - starting, removing, or automatically recreating a container whose stored configuration does not match the selected operation
Goal: validate network/volume/static/dynamic bring-up on a clean profile.
Profile:
ghcr261-clean
Calls:
{ "tool": "local_ydb_bootstrap", "arguments": { "profile": "ghcr261-clean", "confirm": false } }
{ "tool": "local_ydb_bootstrap", "arguments": { "profile": "ghcr261-clean", "confirm": true } }Expected:
- Docker network and volume are created.
- Static container starts.
admin database /local/example statussucceeds;PENDING_RESOURCESis acceptable before the first dynamic node fully serves traffic.- Dynamic container is recreated with the current launch command if needed.
- Final checks succeed:
scheme ls /local/example, viewer capabilities, dynamic node registration.
What made this work:
- exact image tag
ghcr.io/ydb-platform/local-ydb:26.1.1.6 - dynamic launch sanitizes
grpc_config.ca/cert/keyfrom the generated config before calling/ydbd server - dynamic launch disables TLS with:
GRPC_TLS_PORT=YDB_GRPC_ENABLE_TLS=0
Avoid:
- using
ghcr.io/ydb-platform/local-ydb:26.1 - reusing a stale dynamic container with
docker startif its original launch command was broken
Goal: exercise tenant creation and dynamic start as separate tools.
Profile:
ghcr261-clean
Calls:
{ "tool": "local_ydb_create_tenant", "arguments": { "profile": "ghcr261-clean", "confirm": false } }
{ "tool": "local_ydb_create_tenant", "arguments": { "profile": "ghcr261-clean", "confirm": true } }
{ "tool": "local_ydb_database_status", "arguments": { "profile": "ghcr261-clean" } }
{ "tool": "local_ydb_start_dynamic_node", "arguments": { "profile": "ghcr261-clean", "confirm": false } }
{ "tool": "local_ydb_start_dynamic_node", "arguments": { "profile": "ghcr261-clean", "confirm": true } }
{ "tool": "local_ydb_tenant_check", "arguments": { "profile": "ghcr261-clean" } }Expected:
create_tenantwaits untiladmin database ... statusis readable. It should not insist onRUNNINGbefore the first dynamic node.database_statuscan showPENDING_RESOURCESbefore dynamic registration andRUNNINGafterwards.start_dynamic_noderecreates the container if it is stale or exited.tenant_checksucceeds only after the dynamic node is actually serving the tenant gRPC path.
Avoid:
- assuming
create OKalone means the tenant is resolvable by NodeBroker
Goal: cover the focused read-only diagnostics used when bootstrap fails.
Profile:
ghcr261-clean
Calls:
{ "tool": "local_ydb_database_status", "arguments": { "profile": "ghcr261-clean" } }
{ "tool": "local_ydb_healthcheck", "arguments": { "profile": "ghcr261-clean", "noCache": true } }
{ "tool": "local_ydb_container_logs", "arguments": { "profile": "ghcr261-clean", "target": "static", "lines": 120 } }
{ "tool": "local_ydb_container_logs", "arguments": { "profile": "ghcr261-clean", "target": "dynamic", "lines": 120 } }
{ "tool": "local_ydb_nodes_check", "arguments": { "profile": "ghcr261-clean" } }
{ "tool": "local_ydb_graphshard_check", "arguments": { "profile": "ghcr261-clean" } }
{ "tool": "local_ydb_storage_placement", "arguments": { "profile": "ghcr261-clean" } }Expected:
healthcheckgives the official YDB self-check status and issue hierarchy before falling back to narrower local heuristics.container_logs(dynamic)shows whether the node: registered, fetched config, crashed on TLS/cert, or failed tenant resolution.container_logs(static)showsNodeBrokerandSchemeShardevidence for create/resolve problems.nodes_checkandgraphshard_checkbecome useful after the stack is healthy or after auth is enabled with a valid viewer session path.storage_placementproves the tenant’s groups are on/ydb_data/pdisks/1.
Avoid:
- using generic
docker logsor shell-only inspection before tryinglocal_ydb_container_logs
Goal: confirm the restart tool is safe and uses the current launch command.
Profile:
ghcr261-clean
Calls:
{ "tool": "local_ydb_restart_stack", "arguments": { "profile": "ghcr261-clean", "confirm": false } }
{ "tool": "local_ydb_restart_stack", "arguments": { "profile": "ghcr261-clean", "confirm": true } }
{ "tool": "local_ydb_status_report", "arguments": { "profile": "ghcr261-clean" } }Expected:
- inventory and the full check-only static compatibility preflight run before any container stop, remove, or start command
- a static binding mismatch fails without changing configured or one-off container IDs/states and requires destroy/bootstrap
- after a successful preflight, the static node restarts first
- tenant status is checked before dynamic node is started again
- every configured dynamic node is unconditionally recreated, including a container observed in Docker's restarting state
- rollback uses
local_ydb_restart_stackorlocal_ydb_bootstrap, not an inventory claim about removed configured definitions - post-restart
status_reportreturnstenant=ok,nodes=ok
Avoid:
- trusting a plain
docker start <dynamic>path for a container created with old flags
Goal: prove backup/restore on a clean GHCR stack.
Profiles:
- source:
local - target:
ghcr261-clean
Calls:
{ "tool": "local_ydb_dump_tenant", "arguments": { "profile": "local", "confirm": true, "dumpName": "pre-auth-mcp-20260425" } }
{ "tool": "local_ydb_list_dumps", "arguments": { "profile": "ghcr261-clean" } }
{ "tool": "local_ydb_restore_tenant", "arguments": { "profile": "ghcr261-clean", "confirm": true, "dumpName": "pre-auth-mcp-20260425" } }
{ "tool": "local_ydb_tenant_check", "arguments": { "profile": "ghcr261-clean" } }
{ "tool": "local_ydb_graphshard_check", "arguments": { "profile": "ghcr261-clean" } }Path-level example:
{ "tool": "local_ydb_dump_tenant", "arguments": { "profile": "local", "confirm": true, "dumpName": "one-table-smoke", "path": "dir/table" } }
{ "tool": "local_ydb_restore_tenant", "arguments": { "profile": "ghcr261-clean", "confirm": true, "dumpName": "one-table-smoke", "path": ".", "describePaths": ["dir/table"], "countQueries": [{ "label": "dir/table rows", "query": "SELECT COUNT(*) FROM `dir/table`;" }] } }For dump, path is the source object or directory for ydb tools dump -p. For restore, path is the destination directory for ydb tools restore -p; restoring a single table dump back under the tenant root normally uses path: ".".
Expected:
- dump helper container runs with
--entrypoint /bin/bash - list-dumps reports dump directories that contain a
tenantfolder - restore helper container runs with
--entrypoint /bin/bash - restored tenant returns
.metadata .sys - GraphShard exists after restore
Avoid:
- assuming the helper image entrypoint can run arbitrary shell commands without
--entrypoint /bin/bash
Goal: test the two new preparation tools before mutating the running stack.
Profile:
ghcr261-auth
Calls:
{ "tool": "local_ydb_prepare_auth_config", "arguments": { "profile": "ghcr261-auth", "confirm": false } }
{ "tool": "local_ydb_prepare_auth_config", "arguments": { "profile": "ghcr261-auth", "confirm": true } }
{ "tool": "local_ydb_write_dynamic_auth_config", "arguments": { "profile": "ghcr261-auth", "confirm": false } }
{ "tool": "local_ydb_write_dynamic_auth_config", "arguments": { "profile": "ghcr261-auth", "confirm": true } }Expected:
prepare_auth_configwrites:/tmp/local-ydb-auth/config.auth.yaml/tmp/local-ydb-auth/root.password- generated auth config includes:
enforce_user_token_requirement: trueviewer_allowed_sidsmonitoring_allowed_sidsadministration_allowed_sidsregister_dynamic_node_allowed_sids - viewer/admin allowed SIDs include both
rootandroot@builtin write_dynamic_auth_configwrites:StaffApiUserToken: "root@builtin"NodeRegistrationToken: "root@builtin"
Avoid:
- assuming the viewer/admin SID is only
root@builtin - assuming the default root token identifies as
root@builtin; in our runwhoamireportedUser SID: root
Goal: turn a healthy clean stack into a working auth-enabled stack.
Profile:
ghcr261-auth
Calls:
{ "tool": "local_ydb_apply_auth_hardening", "arguments": { "profile": "ghcr261-auth", "confirm": false } }
{ "tool": "local_ydb_apply_auth_hardening", "arguments": { "profile": "ghcr261-auth", "confirm": true } }Expected:
- the full check-only static compatibility preflight runs before config copy or any container mutation; a mismatch leaves IDs/states unchanged and requires destroy/bootstrap
- the reviewed config is copied into the static container
- dynamic node is stopped
- static node is restarted
- tenant status remains readable via password
- dynamic node is recreated with:
--auth-token-file /run/local-ydb/dynamic-node-auth.pbsanitized dynamic config TLS disabled for local mode - rollback restores the static config and uses
local_ydb_restart_stackorlocal_ydb_bootstrapto recreate configured nodes, neverdocker startfor removed definitions
Avoid:
- restarting a stale dynamic auth container without recreation
- using a hardcoded login URL on
8765when the profile runs on another monitoring port
Goal: prove the auth rollout actually worked.
Profile:
ghcr261-auth
Calls:
{ "tool": "local_ydb_auth_check", "arguments": { "profile": "ghcr261-auth" } }
{ "tool": "local_ydb_status_report", "arguments": { "profile": "ghcr261-auth" } }
{ "tool": "local_ydb_nodes_check", "arguments": { "profile": "ghcr261-auth" } }
{ "tool": "local_ydb_graphshard_check", "arguments": { "profile": "ghcr261-auth" } }
{ "tool": "local_ydb_database_status", "arguments": { "profile": "ghcr261-auth" } }Expected:
auth_check.viewerWhoamiStatus == 401- authenticated tenant metadata still works
status_reportreturnstenant=ok,nodes=oknodes_checkreturns the dynamic nodegraphshard_checkreportsGraphShardExists=truedatabase_statusreturnsState: RUNNING
Avoid:
- treating a
401on/viewer/json/whoamias an error after auth; it is the expected anonymous result
Goal: change the root password through one MCP tool without exposing it in plan output.
Profile:
ghcr261-auth
Calls:
{ "tool": "local_ydb_set_root_password", "arguments": { "profile": "ghcr261-auth", "password": "<new-password>", "confirm": false } }Expected:
- plan-only output does not print the raw password
- the tool rotates the runtime password with
ALTER USER - the generated host auth config and
root.passwordfile are updated after the runtime password change - post-change anonymous
viewer/json/whoamishould still return401 - authenticated tenant checks should work with the new password
- empty passwords are an upstream YDB capability, but this MCP tool requires a non-empty
passwordargument - if the cluster config defines
auth_config.password_complexity, password rotation can fail until the supplied value matches that policy
Avoid:
- storing the password directly in committed config
- changing the password on a profile that lacks
authConfigPathorrootPasswordFile - assuming every punctuation mark is portable across builds; prefer letters, digits, and documented YDB special characters
!@#$%^&*()_+{}|<>?=unless the target image has already been rehearsed with a broader set
Goal: add multiple dynamic nodes to a healthy auth-enabled stack without creating extra profile entries.
Profile:
ghcr261-auth
Calls:
{ "tool": "local_ydb_add_dynamic_nodes", "arguments": { "profile": "ghcr261-auth", "count": 2, "confirm": false } }
{ "tool": "local_ydb_add_dynamic_nodes", "arguments": { "profile": "ghcr261-auth", "count": 2, "confirm": true } }
{ "tool": "local_ydb_add_dynamic_nodes", "arguments": { "profile": "ghcr261-auth", "startIndex": 2, "confirm": false } }
{ "tool": "local_ydb_nodes_check", "arguments": { "profile": "ghcr261-auth" } }
{ "tool": "local_ydb_tenant_check", "arguments": { "profile": "ghcr261-auth" } }
{ "tool": "local_ydb_container_logs", "arguments": { "profile": "ghcr261-auth", "target": "dynamic", "lines": 80 } }Expected:
- plan-only output creates one-off containers
ydb-dyn-example-ghcr261-4andydb-dyn-example-ghcr261-5 - default ports are derived from the profile:
2260/9069/19305and2261/9070/19306 - dynamic containers mount
/tmp/local-ydb-auth/dynamic-node-auth.pbwhen auth is enabled confirm=truestarts one node, verifies its exact container is stably running and its IC port appears innodelist, then starts the next- explicit
startIndex: 2is rejected before a mutating plan because configured indexes1..3cannot be used for one-off add; configured container IDs remain unchanged nodes_checkreports five dynamic nodes total: three configured nodes plus the two one-off nodes- tenant metadata remains reachable
Avoid:
- using any
startIndex <= 3; configured indexes belong to the declarative topology - adding many nodes at once on a live auth stack without first checking logs and
nodelist
Rollback:
docker rm -f ydb-dyn-example-ghcr261-4 ydb-dyn-example-ghcr261-5Goal: keep default removal inside one-off capacity while allowing deliberate configured-node drift fixtures.
Profile:
ghcr261-auth
Calls:
{ "tool": "local_ydb_remove_dynamic_nodes", "arguments": { "profile": "ghcr261-auth", "confirm": false } }
{ "tool": "local_ydb_remove_dynamic_nodes", "arguments": { "profile": "ghcr261-auth", "confirm": true } }
{ "tool": "local_ydb_nodes_check", "arguments": { "profile": "ghcr261-auth" } }Expected:
- immediately after Scenario 11, default plan-only output targets the highest one-off suffix,
ydb-dyn-example-ghcr261-5 confirm=trueremoves that container and verifies its IC port disappears from authenticatednodelist- rollback for the removed one-off node uses
local_ydb_add_dynamic_nodeswith matching suffixes and ports, not restart/bootstrap - configured containers
ydb-dyn-example-ghcr261,-2, and-3remain running with unchanged Docker IDs - after all one-off nodes are removed, another default call fails with
found 0and returns no destructive plan - tenant metadata remains reachable after removal
Explicit configured-node drift fixture:
{ "tool": "local_ydb_remove_dynamic_nodes", "arguments": { "profile": "ghcr261-auth", "confirm": false, "containers": ["ydb-dyn-example-ghcr261-2"] } }
{ "tool": "local_ydb_remove_dynamic_nodes", "arguments": { "profile": "ghcr261-auth", "confirm": false, "nodeIds": [50001] } }Configured suffix -2 is removable only through an explicit container, node ID, or startIndex: 2 selector. Its removal creates runtime drift; rollback uses local_ydb_restart_stack or local_ydb_bootstrap, never local_ydb_add_dynamic_nodes. Mixed configured and one-off selections return both rollback instructions in that order.
Avoid:
- treating the profile's main
dynamicContaineras removable through this tool - assuming default removal can select configured suffixes
- using
nodeIdsfor the base dynamic node; only IDs that resolve to suffix containers are removable - removing multiple extra nodes at once on a live stack without checking
nodelistafter each removal
Goal: increase NumGroups for a tenant storage pool by rereading and redefining the current pool shape.
Profile:
ghcr261-auth
Calls:
{ "tool": "local_ydb_add_storage_groups", "arguments": { "profile": "ghcr261-auth", "count": 1, "confirm": false } }
{ "tool": "local_ydb_add_storage_groups", "arguments": { "profile": "ghcr261-auth", "count": 1, "confirm": true } }
{ "tool": "local_ydb_storage_placement", "arguments": { "profile": "ghcr261-auth" } }
{ "tool": "local_ydb_tenant_check", "arguments": { "profile": "ghcr261-auth" } }Expected:
- plan-only output targets tenant pool
/local/example:hdd - the generated
DefineStoragePoolrequest preserves the current pool fields and increases onlyNumGroups confirm=truesucceeds without breaking tenant metadata- post-change
ReadStoragePoolreports a higherNumGroupsfor the tenant pool QueryBaseConfigreflects the updated group set on the current PDisk layout
Avoid:
- treating
DecommitGroupsorstorage_units_to_removeas a pool expansion path - using a partial
DefineStoragePoolshape that dropsPDiskFilter,ScopeId, orItemConfigGeneration
Goal: remove tenant metadata, local-ydb nodes, Docker network, and profile storage from one tool.
Recommended disposable profile:
ghcr-rebuild-clean
Calls:
{ "tool": "local_ydb_destroy_stack", "arguments": { "profile": "ghcr-rebuild-clean", "confirm": false } }Optional shared-host-path cleanup:
{ "tool": "local_ydb_destroy_stack", "arguments": { "profile": "ghcr-rebuild-clean", "confirm": false, "removeDumpHostPath": true, "removeAuthArtifacts": true } }Expected:
- plan-only output removes tenant metadata first when the static node is reachable
- extra dynamic nodes are removed before the profile's main dynamic container
- the static container, Docker network, and Docker volume are removed
- bind-mounted data is not deleted unless
removeBindMountPath: true - auth files and dump directories are not deleted unless explicitly requested
Avoid:
- enabling host-path deletion flags on shared paths without checking whether other profiles use them
- using this tool with
confirm=trueon a profile you still need without first taking a dump
Goal: reduce a tenant pool from a larger NumGroups back to a smaller one without relying on an unverified live shrink path.
Profile:
ghcr261-auth
Calls:
{ "tool": "local_ydb_reduce_storage_groups", "arguments": { "profile": "ghcr261-auth", "count": 1, "dumpName": "shrink-smoke", "confirm": false } }Expected:
- plan-only output starts with a tenant dump
- the stack is rebuilt with
admin database /local/example create hdd:1 - auth-enabled profiles re-run:
local_ydb_prepare_auth_configlocal_ydb_write_dynamic_auth_configlocal_ydb_apply_auth_hardening - extra dynamic-node suffixes are re-added after restore/auth reapply
- every one-off node keeps its inspected gRPC, monitoring, and IC ports; an incomplete inspect aborts before dump or destroy
Avoid:
- treating
DefineStoragePool { NumGroups: smaller }as a proven live shrink path - deleting auth artifacts during the rebuild path for an auth-enabled profile
Goal: upgrade a working profile to a specific image tag without reusing the old volume in place.
Profile:
ghcr261-auth
Calls:
{ "tool": "local_ydb_upgrade_version", "arguments": { "profile": "ghcr261-auth", "version": "26.1.1.6", "confirm": false } }Optional execution path on a disposable stack:
{ "tool": "local_ydb_upgrade_version", "arguments": { "profile": "ghcr261-auth", "version": "<target-tag>", "dumpName": "upgrade-smoke", "confirm": true } }Expected:
- the plan starts with source and target image preflight checks
- if either image is missing, run
local_ydb_pull_imagefirst and retry afterlocal_ydb_pull_statusreports completion - after image preflight, the upgrade path performs dump, destroy, bootstrap, restore, auth reapply, and extra dynamic-node recreation in that order
- before dump or destroy, every one-off node's exact gRPC, monitoring, and IC ports are inspected and retained; an incomplete definition aborts the rebuild
- auth-enabled profiles re-run:
local_ydb_prepare_auth_configlocal_ydb_write_dynamic_auth_configlocal_ydb_apply_auth_hardening - successful final inventory verifies the recreated containers' image tags and then persists
profiles.<name>.imagein the file-backed config - a verified image mismatch returns the accumulated history and leaves the profile image unchanged
- if final inventory is unavailable only after dump/rebuild/restore/auth/node phases succeed, the response appends a safe failed verification result, omits
imageVerification, preserves the full history, and persists the target profile image for subsequent operations
Avoid:
- using this tool against a profile pinned by image digest
- using this tool against a profile with
bindMountPath; automatic version upgrade only supports volume-backed rebuilds - treating it as an in-place rolling upgrade of the existing volume
- skipping the explicit target tag check from
local_ydb_list_versions
Goal: test the dangerous cleanup tool only on disposable targets.
Recommended disposable targets:
- stale rehearsal volumes discovered by
storage_leftovers - old test dump directories under
/tmp/local-ydb-dump/... - explicitly unused side-by-side rehearsal volumes such as
ydb-local-data-ghcr-cleanonly after you have decided they are no longer needed
Calls:
{ "tool": "local_ydb_storage_leftovers", "arguments": { "profile": "ghcr261-auth" } }
{ "tool": "local_ydb_cleanup_storage", "arguments": { "profile": "ghcr261-auth", "confirm": false, "volumes": ["<known-disposable-volume>"] } }
{ "tool": "local_ydb_cleanup_storage", "arguments": { "profile": "ghcr261-auth", "confirm": false, "paths": ["/tmp/local-ydb-dump/<known-disposable-dump>"] } }Expected:
- plan-only output includes the exact
docker volume rmorrm -rftarget - unsafe targets like
/tmp,/var/lib/docker, or unrelated names are rejected by validation
Avoid:
- using
cleanup_storage(confirm=true)against any active profile volume or the current auth stack
- Bootstrap and lifecycle:
local_ydb_bootstrap_root_database,local_ydb_bootstrap,local_ydb_create_tenant,local_ydb_start_dynamic_node,local_ydb_add_dynamic_nodes,local_ydb_remove_dynamic_nodes,local_ydb_restart_stack - Version discovery:
local_ydb_list_versions - Image pulls:
local_ydb_pull_image,local_ydb_pull_status - Storage-pool expansion:
local_ydb_add_storage_groups - Storage-pool reduction by rebuild:
local_ydb_reduce_storage_groups - Version upgrade by rebuild:
local_ydb_upgrade_version - Full teardown:
local_ydb_destroy_stack - Backup and restore:
local_ydb_list_dumps,local_ydb_dump_tenant,local_ydb_restore_tenant - Auth rollout:
local_ydb_prepare_auth_config,local_ydb_write_dynamic_auth_config,local_ydb_apply_auth_hardening,local_ydb_set_root_password,local_ydb_permissions,local_ydb_auth_check - Managed SQL:
local_ydb_sql - Read-only diagnostics:
local_ydb_inventory,local_ydb_database_status,local_ydb_healthcheck,local_ydb_container_logs,local_ydb_status_report,local_ydb_tenant_check,local_ydb_scheme,local_ydb_permissions,local_ydb_nodes_check,local_ydb_graphshard_check,local_ydb_storage_placement,local_ydb_storage_leftovers - Cleanup:
local_ydb_cleanup_storage
Field-proven successful stack in this repo:
- image:
ghcr.io/ydb-platform/local-ydb:26.1.1.6 - clean profile:
ghcr261-clean - auth profile:
ghcr261-auth - dump name used successfully:
pre-auth-mcp-20260425 - auth files:
/tmp/local-ydb-auth/config.auth.yaml/tmp/local-ydb-auth/root.password/tmp/local-ydb-auth/dynamic-node-auth.pb
Successful end state:
- anonymous
viewer/json/whoamireturns401 - authenticated
scheme ls /local/examplesucceeds - authenticated
nodelistreturns the dynamic node - authenticated
capabilitiesreportsGraphShardExists=true