fix(storage): write column descriptions where the MCP server reads them (#624) - #628
Draft
padak wants to merge 1 commit into
Draft
fix(storage): write column descriptions where the MCP server reads them (#624)#628padak wants to merge 1 commit into
padak wants to merge 1 commit into
Conversation
`storage describe-column` / `describe-batch` stored each description as a
flat `KBC.column.{name}.description` entry on the TABLE's metadata, on the
documented assumption that Keboola exposes no user-writable column-metadata
endpoint. That assumption is wrong: the same
`POST /v2/storage/tables/{id}/metadata` kbagent already calls accepts a
`columnsMetadata` payload with `provider: user`, and that native
`columnMetadata` store is what the Keboola UI and the Keboola MCP server
(`get_table_detail`, `search`) read.
Nothing read the flat keys, so column descriptions written by kbagent were
invisible to every AI client using the MCP server -- the exact audience they
are written for. The failure was silent in both directions: `table-detail`
read back kbagent's own convention, so the descriptions were reported as
correctly applied.
- client: new `set_table_column_metadata()` posting a JSON `columnsMetadata`
payload (the nested per-column shape has no form-encoded equivalent).
- service: `describe_columns()` writes `KBC.description` per column there;
`get_table_detail()` reads it from `columnMetadata` first and keeps the flat
keys as a fallback so older descriptions stay visible, with `columnMetadata`
winning when both carry a value.
- the repetitive per-column metadata elif chain becomes a `_COLUMN_META_FIELDS`
mapping, keeping the file inside its grandfathered line budget.
There is no bulk migration: re-running `describe-column` on an affected table
rewrites it into the right place.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
storage describe-column/describe-batchnow write column descriptions asKBC.descriptioninside the table's nativecolumnMetadatastore, instead of asflat
KBC.column.{name}.descriptionentries on the table's metadata.Why
Two incompatible conventions never met:
KBC.column.{name}.descriptionKBC.descriptioncolumnMetadata[{name}]The
client/storage_tables.pydocstring justified the flat convention with "KeboolaStorage API does not expose a user-writable column-metadata endpoint". That is not
correct. The same
POST /v2/storage/tables/{id}/metadatakbagent already calls acceptsa
columnsMetadatapayload withprovider: user;keboola/mcp-server'sStorageClient.table_metadata_update()does exactly that, and its read paths(
tools/storage/tools.py,tools/storage/search.py) resolve column descriptions onlyfrom
columnMetadata.So every column description kbagent ever wrote was invisible to every AI client using
the Keboola MCP server — precisely the audience those descriptions are written for.
The failure was silent in both directions:
storage table-detailread backkbagent's own convention, so the descriptions were reported as correctly applied.
Changes
client/storage_tables.py) — newset_table_column_metadata()posting aJSON
{provider, columnsMetadata}payload. It sends JSON rather than form databecause the nested per-column shape has no form-encoded equivalent; the table-level
set_table_metadata()is untouched and still form-encoded. Entries carry theredundant
columnNamekey, mirroring what the platform's own clients send.services/storage_service.py::describe_columns) — writesKBC.descriptionper column through the new client method.describe_batchpicksthis up for free via its
columns:section.services/storage_service.py::get_table_detail) — readsKBC.descriptionfromcolumnMetadataas the primary source, keeping the flatKBC.column.*keys as a fallback so descriptions written by an older kbagent stayvisible here. When both carry a value,
columnMetadatawins.storage_service.pyis a grandfathered file that may not grow, sothe repetitive five-branch per-column
elifchain became a_COLUMN_META_FIELDSmapping. Adding a pass-through field is now a one-line data change, and the file
stays at its 1733 ceiling.
describe-columncommand help,AGENT_CONTEXT,storage-describe-workflow.md,commands-reference.md, and a rewrittengotchas.mdentry tagged(since v0.87.1).Migration
There is no bulk migration command. Re-running
describe-column(ordescribe-batch) on an affected table rewrites the description into the right place;until then those tables stay invisible to MCP clients. The read fallback means nothing
disappears from kbagent's own output in the meantime.
A dedicated migration command was left out deliberately — it would be a new CLI surface
(with the full set of drift surfaces to update) for a one-shot operation that re-running
an existing command already performs. Happy to add one if you would rather have it.
Version
Bumped to 0.87.1 with a changelog entry. This changes where data is written and
carries a migration note, so shipping it without a changelog entry would leave users
unaware they need to re-run
describe-column. Renumber freely if it should land under adifferent version.
Testing
make checkgreen: lint, format, typecheck, skill-check, version-check,command-sync-check, changelog-check, error-codes, sentinel-guards, loc-check, and
5703 tests passed.
KBC.descriptionread fromcolumnMetadata;columnMetadatabeating the legacy flat key when both are present.
columnsMetadatabody and theapplication/jsoncontent type, plus the branch-scoped endpoint.set_table_metadatacall no longer happensfor columns; the pre-existing flat-key read tests now stand as legacy-fallback
regression cover.
endpoint contract is corroborated by the issue author's live reproduction on project
9432 and by
keboola/mcp-server's implementation.Fixes #624