Skip to content

feat(components): add folder parameter to transformations, apps and flows#438

Merged
Matovidlo merged 18 commits intomainfrom
AI-2344-add-folder-parameter
Apr 15, 2026
Merged

feat(components): add folder parameter to transformations, apps and flows#438
Matovidlo merged 18 commits intomainfrom
AI-2344-add-folder-parameter

Conversation

@Matovidlo
Copy link
Copy Markdown
Contributor

Description

Linear: AI-2344

Change Type

  • Major (breaking changes, significant new features)
  • Minor (new features, enhancements, backward compatible)
  • Patch (bug fixes, small improvements, no new features)

Summary

Adds an optional folder parameter to create_sql_transformation and update_sql_transformation tools so transformations can be organized into Keboola UI folders.

How it works:

  • Folder is stored as KBC.configuration.folderName configuration metadata (standard Keboola convention)
  • New component_configurations_search() storage client method uses the /search/component-configurations endpoint to efficiently find existing folders by metadata key
  • New get_transformation_folders() helper returns total transformation count and distinct folder names already in use
  • New set_transformation_folder_metadata() helper sets the folder metadata (errors are swallowed — non-fatal)
  • Tool docstrings instruct the model to always assign a folder when there are 20+ transformations in the project, by first checking existing folder names via get_configs

Testing

  • Tested with Cursor AI desktop (Streamable-HTTP transports)

Optional testing

  • Tested with Cursor AI desktop (all transports)
  • Tested with claude.ai web and canary-orion MCP (SSE and Streamable-HTTP)
  • Tested with In Platform Agent on canary-orion
  • Tested with RO chat on canary-orion

Checklist

  • Self-review completed
  • Unit tests added/updated (if applicable)
  • Integration tests added/updated (if applicable)
  • Project version bumped according to the change type (if applicable)
  • Documentation updated (if applicable)

@Matovidlo Matovidlo requested a review from Copilot March 24, 2026 15:18
@linear
Copy link
Copy Markdown

linear bot commented Mar 24, 2026

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds support for organizing SQL transformations into Keboola UI folders by introducing an optional folder parameter on the SQL transformation create/update tools and persisting it as configuration metadata.

Changes:

  • Add folder parameter to create_sql_transformation and update_sql_transformation, persisting it via configuration metadata (KBC.configuration.folderName).
  • Add Storage API client support for searching configurations by metadata keys (/search/component-configurations) plus helper utilities for folder discovery/setting.
  • Add/update unit tests and generated tool documentation (TOOLS.md) for the new parameter.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/keboola_mcp_server/tools/components/tools.py Adds folder parameter to SQL transformation create/update and writes folder metadata after config creation/update.
src/keboola_mcp_server/tools/components/utils.py Introduces get_transformation_folders and set_transformation_folder_metadata helpers.
src/keboola_mcp_server/clients/storage.py Adds component_configurations_search() client method for searching configs by metadata keys.
src/keboola_mcp_server/config.py Adds MetadataField.CONFIGURATION_FOLDER_NAME constant (KBC.configuration.folderName).
tests/tools/components/test_utils.py Adds tests for folder discovery helper and folder metadata update helper behavior.
tests/tools/components/test_tools.py Adds tests asserting folder metadata update is (or isn’t) called based on the folder parameter.
TOOLS.md Updates tool schema/docs to include the new folder parameter and guidance.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/keboola_mcp_server/tools/components/utils.py Outdated
Comment thread src/keboola_mcp_server/tools/components/utils.py Outdated
Comment thread src/keboola_mcp_server/clients/storage.py
Comment thread src/keboola_mcp_server/tools/components/tools.py Outdated
Comment thread src/keboola_mcp_server/tools/components/tools.py
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/keboola_mcp_server/tools/components/utils.py Outdated
Comment thread src/keboola_mcp_server/tools/components/tools.py Outdated
Comment thread src/keboola_mcp_server/tools/components/tools.py Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/keboola_mcp_server/tools/components/tools.py Outdated
Comment thread src/keboola_mcp_server/tools/components/tools.py Outdated
Comment thread TOOLS.md Outdated
Comment thread TOOLS.md Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/keboola_mcp_server/tools/components/tools.py Outdated
Comment thread src/keboola_mcp_server/tools/components/utils.py Outdated
Comment thread src/keboola_mcp_server/tools/components/utils.py
Comment thread src/keboola_mcp_server/clients/storage.py Outdated
Comment thread src/keboola_mcp_server/tools/components/tools.py Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/keboola_mcp_server/tools/components/tools.py Outdated
@Matovidlo Matovidlo marked this pull request as ready for review March 27, 2026 11:39
Comment thread tests/tools/components/test_utils.py Outdated
Comment thread src/keboola_mcp_server/preview.py
Comment thread src/keboola_mcp_server/tools/flow/tools.py Outdated
Comment thread TOOLS.md Outdated
Comment thread TOOLS.md
Comment thread TOOLS.md Outdated
Comment thread src/keboola_mcp_server/tools/data_apps.py
@Matovidlo Matovidlo requested a review from cjayyy April 2, 2026 09:01
Comment thread tests/tools/components/test_utils.py
Comment thread src/keboola_mcp_server/tools/components/tools.py
Comment thread src/keboola_mcp_server/tools/components/utils.py
Comment thread src/keboola_mcp_server/tools/components/tools.py
Comment thread src/keboola_mcp_server/tools/data_apps.py
@Matovidlo Matovidlo force-pushed the AI-2344-add-folder-parameter branch from 83b16a3 to 30dd263 Compare April 3, 2026 08:47
Comment thread integtests/project_lock.py Outdated
@Matovidlo Matovidlo changed the title feat(components): add folder parameter to SQL transformation tools [AI-2344] feat(components): add folder parameter to transformations, apps and flows Apr 3, 2026
@cjayyy

This comment was marked as resolved.

Matovidlo and others added 17 commits April 15, 2026 10:21
- Add MetadataField.CONFIGURATION_FOLDER_NAME ('KBC.configuration.folderName')
- Add StorageClient.component_configurations_search() using the
  /search/component-configurations endpoint to find configs by metadata key
- Add get_transformation_folders() helper returning total config count and
  distinct folder names already in use
- Add set_transformation_folder_metadata() helper that sets
  KBC.configuration.folderName metadata (errors are swallowed, non-fatal)
- Add optional folder parameter to create_sql_transformation and
  update_sql_transformation; docstrings instruct the model to always assign
  a folder when 20+ transformations exist in the project
- Extend tests for folder set / not-set cases and new util helpers

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Strip whitespace from folder value in tools.py before branching (create + update)
- set_transformation_folder_metadata now strips folder name internally and returns early when result is empty, preventing blank/whitespace-only folder names in UI
- Wire get_transformation_folders into update_sql_transformation: surfaces change_summary folder hint when ≥20 transformations exist and no folder provided; merges with existing msg from internal update
- Consolidate test_create/update_sql_transformation_folder tests: merge separate "folder metadata" and "folder hint" test functions into single parametrized tests covering folder provided, whitespace stripping, few transformations, many with/without existing folders
- Consolidate test_set_transformation_folder_metadata: merge two separate test functions into one parametrized test covering normal, whitespace, empty, and whitespace-only inputs
- Fix isort: move get_transformation_folders import to alphabetical position

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…Python

The /search/component-configurations endpoint does not accept componentId
as a query parameter (returns 400 "This field was not expected."). Remove
it from the URL params and filter results by componentId in Python instead.

Update test_get_transformation_folders to include componentId in mock
search result items so the new Python filter keeps them.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Use set for O(1) deduplication in get_transformation_folders
- Wrap get_transformation_folders calls in try/except in both
  create_sql_transformation and update_sql_transformation so a
  transient API failure in the folder-hint path does not fail an
  already-successful transformation create/update

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Extract _build_folder_hint(total, existing_folders) helper to deduplicate
  the near-identical hint-building logic from both create and update tools
- Fix folder parameter description in both tools: removed the incorrect
  instruction to call get_configs to find folder names (get_configs list
  responses do not include KBC.configuration.folderName metadata); replaced
  with accurate guidance that existing folders are surfaced in change_summary
- Fix CONSIDERATIONS in create_sql_transformation docstring: same correction
- Regenerate TOOLS.md from updated docstrings

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Broaden exception catch in set_transformation_folder_metadata from HTTPStatusError
  to Exception so network errors (timeouts, DNS) are also handled gracefully; log as
  warning instead of exception to avoid noisy tracebacks for best-effort metadata
- Short-circuit get_transformation_folders when total < 20: return early without
  calling the search API, since _build_folder_hint returns None anyway below the threshold
- Add empty metadata_keys guard in component_configurations_search to prevent
  accidental unbounded project-wide fetches
- Fix contradictory folder param description: replace "always assign … leave empty"
  with "you should assign … create a new one that clearly reflects the purpose"
- Split test_get_transformation_folders into two tests to assert search API is NOT
  called when count < 20 (short-circuit) and IS called when count >= 20
- Regenerate TOOLS.md to reflect updated folder parameter description

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
preview.py passes all update_sql_transformation params through mutator_params
directly to the internal function; the internal function was missing folder
so any preview call with folder set raised TypeError.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The existing test omitted folder from toolParams so the TypeError introduced
by the missing param in update_sql_transformation_internal was never caught.
Adding folder to the fixture ensures the preview path is covered.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When the UI calls /preview/configuration with a folder param, the preview
response now includes folder in originalConfig and updatedConfig so the
diff viewer shows the folder change.

- update_sql_transformation_internal fetches current KBC.configuration.folderName
  metadata and returns {'original_folder': old, 'updated_folder': new} as a 4th
  return value when the folder differs from the current value
- preview.py uses next(...isinstance(x, dict)...) instead of mutator_preview[0]
  so the str msg (3rd value) is skipped and the folder dict (4th value) is picked up
- Outer update_sql_transformation call site updated to unpack 4-tuple with *_
- Preview test extended: mocks configuration_metadata_get and asserts folder diff
  appears in originalConfig/updatedConfig

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…_internal

A transient SAPI error in configuration_metadata_get would have aborted
the real update_sql_transformation call, not just the preview path. The
folder diff is best-effort: wrap in try/except Exception and log a warning,
proceeding with folder_preview=None on failure.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
/v2/storage/branch/default/components returns 400; the correct endpoint
for listing all components with configs is /v2/storage/components.
- Rename get_transformation_folders → get_config_folders (already generic)
- Move _build_folder_hint → build_folder_hint in utils.py (generalized)
- Add folder param to create_flow, create_conditional_flow, update_flow, modify_flow
- Add folder param to modify_data_app (create and update paths)
- Add FlowToolOutput.change_summary and ModifiedDataAppOutput.change_summary fields
- Add 22 parametrized tests covering folder metadata for flows and data apps
- Regenerate TOOLS.md
- Bump version to 1.50.0

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove the try/except from set_transformation_folder_metadata so that
failures when the user explicitly sets a folder are surfaced as errors.
The non-critical hint-building path (get_config_folders) is already
wrapped in try/except at each call site — that remains unchanged.

Remove the corresponding test that validated the (now removed) swallow
behavior.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…er description

- Add folder: str = '' to update_flow_internal and modify_data_app_internal so the
  preview dispatcher (which spreads all tool_params verbatim) no longer crashes with
  TypeError when folder is present in the request
- Fix modify_flow folder hint label: replace f'{flow_type} flows' with
  'legacy flows'/'conditional flows' to match the labels used by the create paths
- Extract folder_field_description(singular, plural) helper to utils.py; replace 7
  duplicated Field description strings across components/tools.py, flow/tools.py, and
  data_apps.py with calls to the helper
- Fix curly/smart quotes in create_conditional_flow docstring (left by the binary
  replace that fixed the SyntaxError) — replaced U+201C/U+201D with straight ASCII "
- Soften create_sql_transformation CONSIDERATIONS: 'always assign a folder' →
  'consider organizing with a folder ... or create a new one'
- Regenerate TOOLS.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…data_app_internal

- update_flow_internal: fetch current folderName metadata and build
  folder_preview dict, merged with schedule mutator_preview so the
  preview endpoint shows folder changes in the diff
- modify_data_app_internal: same pattern; return type extended to
  tuple[DataApp, JsonDict, dict | None] so caller and preview endpoint
  receive the folder preview
- update caller (deploy_data_app) to unpack 3-element tuple
- update test mock return value from 2-tuple to 3-tuple to match new
  return type

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…remove redundant internal folder call

- create_sql_transformation, create_flow, create_conditional_flow,
  _apply_folder (data app create): wrap set_transformation_folder_metadata
  in try/except so a transient metadata API failure doesn't orphan an
  already-created resource or hide its ID from the caller
- build_folder_hint: use ', '.join(existing_folders) instead of raw
  list interpolation so the LLM hint reads as natural language, not
  Python syntax like ['Analytics', 'Sales']
- update_sql_transformation: remove folder=folder from the internal
  function call; the internal function fetched metadata only for preview
  purposes and the result was discarded — folder is already applied
  separately via set_transformation_folder_metadata afterwards
- test_set_transformation_folder_metadata docstring: "swallows errors"
  → "propagates errors" after commit 5bfbf02 removed the try/except

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ck cleanup

The c5d5800 commit correctly switched the endpoint from
/v2/storage/branch/default/components to /v2/storage/components, but
simultaneously changed the include query parameter from 'configuration'
(singular, valid) to 'configurations' (plural, invalid). The Storage API
only accepts 'configuration' as per ComponentResource = Literal['configuration',
'rows', 'state']. With the invalid value the API returns components without
embedded configuration data, so component.get('configurations', []) always
returns [] and no configs are ever deleted during integration test cleanup.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@Matovidlo Matovidlo force-pushed the AI-2344-add-folder-parameter branch from 007f3bb to 2bfdd61 Compare April 15, 2026 08:23
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@Matovidlo Matovidlo merged commit 73fe24c into main Apr 15, 2026
21 checks passed
@Matovidlo Matovidlo deleted the AI-2344-add-folder-parameter branch April 15, 2026 09:42
@Matovidlo Matovidlo mentioned this pull request Apr 15, 2026
14 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants