Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,10 @@ jobs:
image-tag: canary-orion-${{ github.sha }}
github-app-private-key: ${{ secrets.GITOPS_KBC_STACKS_TRIGGER_APP_PVK }}

# - name: Trigger image tag update for production
# uses: ./.github/actions/trigger-image-tag-update
# if: startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '-dev.')
# with:
# helm-chart: "mcp-server"
# image-tag: production-${{ github.sha }}
# github-app-private-key: ${{ secrets.GITOPS_KBC_STACKS_TRIGGER_APP_PVK }}
- name: Trigger image tag update for production
uses: ./.github/actions/trigger-image-tag-update
if: startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '-dev.')
with:
helm-chart: "mcp-server"
image-tag: production-${{ github.sha }}
github-app-private-key: ${{ secrets.GITOPS_KBC_STACKS_TRIGGER_APP_PVK }}
32 changes: 31 additions & 1 deletion integtests/test_flow_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
from fastmcp import Context

from integtests.conftest import ConfigDef
from keboola_mcp_server.client import KeboolaClient
from keboola_mcp_server.client import ORCHESTRATOR_COMPONENT_ID, KeboolaClient
from keboola_mcp_server.config import MetadataField
from keboola_mcp_server.tools.flow import (
FlowToolResponse,
create_flow,
Expand Down Expand Up @@ -55,6 +56,7 @@ async def test_create_and_retrieve_flow(mcp_context: Context, configs: list[Conf
tasks=tasks,
)
flow_id = created.flow_id
client = KeboolaClient.from_state(mcp_context.session.state)
try:
assert isinstance(created, FlowToolResponse)
assert created.description == flow_description
Expand All @@ -68,6 +70,19 @@ async def test_create_and_retrieve_flow(mcp_context: Context, configs: list[Conf
assert detail.phases[0].name == 'Extract'
assert detail.phases[1].name == 'Transform'
assert detail.tasks[0].task['componentId'] == configs[0].component_id

# Verify the metadata - check that KBC.MCP.createdBy is set to 'true'
metadata = await client.storage_client.configuration_metadata_get(
component_id=ORCHESTRATOR_COMPONENT_ID,
configuration_id=flow_id
)

# Convert metadata list to dictionary for easier checking
# metadata is a list of dicts with 'key' and 'value' keys
assert isinstance(metadata, list)
metadata_dict = {item['key']: item['value'] for item in metadata if isinstance(item, dict)}
assert MetadataField.CREATED_BY_MCP in metadata_dict
assert metadata_dict[MetadataField.CREATED_BY_MCP] == 'true'
finally:
client = KeboolaClient.from_state(mcp_context.session.state)
await client.storage_client.flow_delete(flow_id, skip_trash=True)
Expand Down Expand Up @@ -106,6 +121,7 @@ async def test_update_flow(mcp_context: Context, configs: list[ConfigDef]) -> No
tasks=tasks,
)
flow_id = created.flow_id
client = KeboolaClient.from_state(mcp_context.session.state)
try:
new_name = 'Updated Flow Name'
new_description = 'Updated description.'
Expand All @@ -123,6 +139,20 @@ async def test_update_flow(mcp_context: Context, configs: list[ConfigDef]) -> No
assert updated.description == new_description
assert updated.success is True
assert len(updated.links) == 3

# Verify the metadata - check that KBC.MCP.updatedBy.version.{version} is set to 'true'
metadata = await client.storage_client.configuration_metadata_get(
component_id=ORCHESTRATOR_COMPONENT_ID,
configuration_id=flow_id
)

assert isinstance(metadata, list)
metadata_dict = {item['key']: item['value'] for item in metadata if isinstance(item, dict)}
sync_flow = await client.storage_client.flow_detail(flow_id)
updated_by_md_key = f'{MetadataField.UPDATED_BY_MCP_PREFIX}{sync_flow["version"]}'
assert updated_by_md_key in metadata_dict
assert metadata_dict[updated_by_md_key] == 'true'

finally:
client = KeboolaClient.from_state(mcp_context.session.state)
await client.storage_client.flow_delete(flow_id, skip_trash=True)
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "keboola-mcp-server"
version = "1.0.0"
version = "1.0.1"
description = "MCP server for interacting with Keboola Connection"
readme = "README.md"
requires-python = ">=3.10"
Expand Down
17 changes: 16 additions & 1 deletion src/keboola_mcp_server/tools/flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from fastmcp import Context, FastMCP
from pydantic import AliasChoices, BaseModel, Field

from keboola_mcp_server.client import JsonDict, KeboolaClient
from keboola_mcp_server.client import ORCHESTRATOR_COMPONENT_ID, JsonDict, KeboolaClient
from keboola_mcp_server.errors import tool_errors
from keboola_mcp_server.links import Link, ProjectLinksManager
from keboola_mcp_server.mcp import with_session_state
Expand All @@ -20,6 +20,7 @@
FlowTask,
ReducedFlow,
)
from keboola_mcp_server.tools.components.tools import _set_cfg_creation_metadata, _set_cfg_update_metadata
from keboola_mcp_server.tools.validation import validate_flow_configuration_against_schema

LOG = logging.getLogger(__name__)
Expand Down Expand Up @@ -127,6 +128,13 @@ async def create_flow(
name=name, description=description, flow_configuration=flow_configuration # Direct configuration
)

new_flow = FlowConfigurationResponse.from_raw_config(new_raw_configuration)
await _set_cfg_creation_metadata(
client,
component_id=ORCHESTRATOR_COMPONENT_ID,
configuration_id=new_flow.configuration_id,
)

flow_id = str(new_raw_configuration['id'])
flow_name = new_raw_configuration['name']
flow_links = links_manager.get_flow_links(flow_id=flow_id, flow_name=flow_name)
Expand Down Expand Up @@ -190,6 +198,13 @@ async def update_flow(
change_description=change_description,
flow_configuration=flow_configuration, # Direct configuration
)
updated_flow = FlowConfigurationResponse.from_raw_config(updated_raw_configuration)
await _set_cfg_update_metadata(
client,
component_id=ORCHESTRATOR_COMPONENT_ID,
configuration_id=updated_flow.configuration_id,
configuration_version=updated_flow.version,
)

flow_id = str(updated_raw_configuration['id'])
flow_name = updated_raw_configuration['name']
Expand Down
Loading