diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index b41e6e88..288e0ee4 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -10,7 +10,7 @@ "plugins": [ { "name": "kbagent", - "version": "0.79.0", + "version": "0.80.0", "source": "./plugins/kbagent", "description": "AI-friendly interface to Keboola Connection projects — explore configs, jobs, lineage, call MCP tools, manage dev branches, and debug SQL in workspaces", "category": "development" diff --git a/CLAUDE.md b/CLAUDE.md index 8dcab441..ada602fa 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -425,7 +425,9 @@ kbagent tool call TOOL_NAME [--project NAME] [--input JSON|@file|-] [--branch ID # prints a cli_equivalent column, tool call warns with the exact replacement (stderr; --json adds # an additive "deprecation" key). Parity map = src/keboola_agent_cli/mcp_parity.py; weekly # mcp-parity-canary workflow (make parity-check) diffs it against upstream TOOLS.md. The group -# (and `agent --type mcp_tool`) will be removed after the deprecation window. +# (and `agent --type mcp_tool`) is REMOVED in v0.85.0, scheduled for the end of August 2026 +# -- epic #390 phase 3. `agent --type mcp_tool` tasks persist in agents.json, so they need +# migrating to `--type cli_command` before that release or they fail on their next cron tick. kbagent branch list [--project NAME] kbagent branch create --project ALIAS --name "..." [--description "..."] diff --git a/plugins/kbagent/.claude-plugin/plugin.json b/plugins/kbagent/.claude-plugin/plugin.json index 83ab0d2d..7f9a7a9f 100644 --- a/plugins/kbagent/.claude-plugin/plugin.json +++ b/plugins/kbagent/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "kbagent", - "version": "0.79.0", + "version": "0.80.0", "description": "AI-friendly interface to Keboola Connection projects — explore configs, jobs, lineage, call MCP tools, manage dev branches, and debug SQL in workspaces", "author": { "name": "Keboola", diff --git a/plugins/kbagent/agents/keboola-expert.md b/plugins/kbagent/agents/keboola-expert.md index a075247f..abacff04 100644 --- a/plugins/kbagent/agents/keboola-expert.md +++ b/plugins/kbagent/agents/keboola-expert.md @@ -49,7 +49,8 @@ a critical failure. 4. **PREFER CLI OVER MCP**. If a `kbagent ` native subcommand exists, use it. Only fall back to `kbagent tool call ...` (MCP) when - the native command does not cover the operation. When an MCP + the native command does not cover the operation -- the `tool` group is + REMOVED in v0.85.0 (end of August 2026), so never build a new workflow on it. When an MCP `tool call` returns `isError: true`, DO NOT retry with reformatted inputs. Fall back to the `kbagent serve` REST API for the equivalent operation. diff --git a/plugins/kbagent/skills/kbagent/references/commands-reference.md b/plugins/kbagent/skills/kbagent/references/commands-reference.md index 5c372aa3..e1075d74 100644 --- a/plugins/kbagent/skills/kbagent/references/commands-reference.md +++ b/plugins/kbagent/skills/kbagent/references/commands-reference.md @@ -209,7 +209,7 @@ Lifecycle for `keboola.data-apps`. Combines Storage API (config body, git block, - `data-app git-credentials-create --project NAME --app-id ID --type ssh_key|http_token --permissions readOnly|readWrite [--public-key KEY | --public-key-file PATH] [--name LABEL] [--yes]` (since 0.63.3) -- mint a git credential for the app's MANAGED git repo. `ssh_key` requires a public key; `http_token` returns a ONE-TIME secret (shown once, never retrievable again -- mirrors `data-app password`). Needs an admin storage token. Apps from `data-app create --git-repo` are EXTERNAL => 409 `no managed Git repository`. Confirmation unless `--yes`/`--json`. For a managed-repo app this credential authenticates YOUR `git push` of the code; the deploy itself uses the platform's injected clone credentials -- no further wiring needed. ## MCP Tools (DEPRECATED since v0.74.0 -- epic #390) -Every catalog tool has a native command; `tool list` prints a `cli_equivalent` column and `tool call` warns with the exact replacement. The group will be removed after the deprecation window. Prefer native commands in all new workflows. +Every catalog tool has a native command; `tool list` prints a `cli_equivalent` column and `tool call` warns with the exact replacement. The group is REMOVED in v0.85.0, scheduled for the end of August 2026. Prefer native commands in all new workflows. - `tool list [--project NAME] [--branch ID]` -- list available MCP tools (multi_project annotation + `cli_equivalent` since 0.74.0) - `tool call TOOL_NAME [--project NAME] [--input JSON|@file|-] [--branch ID]` -- call MCP tool (read = all projects, write = single). `--input` accepts inline JSON, `@file.json`, or `-` (stdin). Emits a deprecation warning naming the native equivalent (stderr in human mode, additive `deprecation` key in `--json`) diff --git a/plugins/kbagent/skills/kbagent/references/gotchas.md b/plugins/kbagent/skills/kbagent/references/gotchas.md index 84fa8c09..370feebb 100644 --- a/plugins/kbagent/skills/kbagent/references/gotchas.md +++ b/plugins/kbagent/skills/kbagent/references/gotchas.md @@ -11,7 +11,7 @@ Versioning convention: behavior; the inline `(updated vX.Y.Z)` records when the refinement landed. --> -## MCP passthrough is DEPRECATED; parity map + canary (since v0.74.0) +## MCP passthrough is DEPRECATED; REMOVED in v0.85.0 (since v0.74.0) - **`tool call` / `tool list` / `agent --type mcp_tool` are on a removal track** (epic #390 phase 2). `tool call` warns with the exact native @@ -25,9 +25,15 @@ Versioning convention: (also `make parity-check`) diffs the live keboola-mcp-server `TOOLS.md` against it, so a new upstream tool turns the canary red instead of silently widening the gap. -- **`agent --type mcp_tool` tasks keep working** through the deprecation - window -- creation just warns; migrate to `--type cli_command` with the - native command at your own pace before the removal release. +- **Removal is scheduled: v0.85.0, end of August 2026** (epic #390 phase 3, + announced in 0.80.0). Before 0.80.0 the notice said only "a future + release"; it now names the version everywhere. +- **`agent --type mcp_tool` tasks keep working** until then -- creation just + warns. Migrate to `--type cli_command` with the native command BEFORE + v0.85.0. These tasks are persisted in `/agents.json`, so + unlike an interactive `tool call` they get no warning at removal time: a + scheduled task simply starts failing on its next cron tick. Use the + `cli_equivalent` from `kbagent tool list` to rewrite each one. ## MCP tool classification is FAIL-CLOSED; parity commands replace `tool call` (since v0.73.0) diff --git a/pyproject.toml b/pyproject.toml index 60c4419e..e91a2b63 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "keboola-cli" -version = "0.79.0" +version = "0.80.0" description = "AI-friendly CLI for managing Keboola projects" readme = "README.md" requires-python = ">=3.12" diff --git a/src/keboola_agent_cli/changelog.py b/src/keboola_agent_cli/changelog.py index 2fa5abb5..4801fac0 100644 --- a/src/keboola_agent_cli/changelog.py +++ b/src/keboola_agent_cli/changelog.py @@ -24,6 +24,25 @@ # Ordered newest-first. Each value is a list of brief one-line descriptions. CHANGELOG: dict[str, list[str]] = { + "0.80.0": [ + "Note (#390): the MCP passthrough now has a named removal date -- `kbagent tool " + "list` / `tool call` and `agent --type mcp_tool` are REMOVED in **v0.85.0**, " + "scheduled for the **end of August 2026**. Deprecated since 0.74.0, the notice " + 'until now said only "a future release", which gives nobody anything to plan ' + "against. Every surface that mentions the deprecation -- the `tool call` warning, " + "the `tool list` banner, `kbagent context`, the skill references and the agent " + "prompt -- quotes the same two constants, so the version and the date cannot drift " + "apart. All 39 upstream tools already have a native command (`make parity-check` " + "verifies it against the live catalogue on every canary run), so nothing is lost " + "by migrating early: `kbagent tool list` prints the replacement per tool in its " + "`cli_equivalent` column.", + "Note (#390): if you have scheduled agent tasks of `--type mcp_tool`, migrate them " + "to `--type cli_command` before v0.85.0. Unlike an interactive `tool call`, these " + "are persisted in `/agents.json` and get no warning at removal time -- " + "they simply start failing on their next cron tick. `kbagent agent list` shows the " + "action type of each task, and `kbagent tool list` gives the native command to " + "replace each tool with.", + ], "0.79.0": [ "Fix: the standalone `kbagent` binary no longer tries to update itself with " "`uv tool install`. kbagent ships both as a Python distribution and as a " diff --git a/src/keboola_agent_cli/commands/agent.py b/src/keboola_agent_cli/commands/agent.py index 752181e2..fe95b466 100644 --- a/src/keboola_agent_cli/commands/agent.py +++ b/src/keboola_agent_cli/commands/agent.py @@ -23,6 +23,7 @@ import typer from ..errors import ConfigError, ErrorCode +from ..mcp_parity import MCP_REMOVAL_TARGET_DATE, MCP_REMOVAL_VERSION from ..output import OutputFormatter, write_machine_output from ..server.agents_store import AgentAction, Trigger from ..services.agent_service import AgentService @@ -35,10 +36,17 @@ # stderr warning in human mode, additive "deprecation" envelope key in # JSON mode. Creation is never blocked; agents.json / REST payloads are # unchanged. +# The deadline matters MORE here than on `tool call`. An interactive `tool call` +# warns on every invocation right up to removal; a scheduled task is written to +# agents.json once and then runs unattended, so creation time is the only moment +# its owner is present to hear the date. Removing the action type without this +# turns those tasks into a silent cron failure. MCP_TOOL_ACTION_DEPRECATION = ( "agent action type 'mcp_tool' is deprecated (epic #390); prefer --type " "cli_command with the native kbagent command (see `kbagent tool list` " - "cli_equivalent column)." + f"cli_equivalent column). It is REMOVED in kbagent v{MCP_REMOVAL_VERSION} " + f"({MCP_REMOVAL_TARGET_DATE}) -- migrate scheduled tasks before then or they " + "will start failing on their next run." ) diff --git a/src/keboola_agent_cli/commands/context.py b/src/keboola_agent_cli/commands/context.py index 9a477c9b..ac7e14a9 100644 --- a/src/keboola_agent_cli/commands/context.py +++ b/src/keboola_agent_cli/commands/context.py @@ -1276,8 +1276,10 @@ See agent-tasks-cli-workflow.md skill reference for full walkthroughs. -### MCP Tools (Multi-Project) -- DEPRECATED since 0.74.0 +### MCP Tools (Multi-Project) -- DEPRECATED since 0.74.0, REMOVED in 0.85.0 + The `tool` group and `agent --type mcp_tool` are REMOVED in kbagent + v0.85.0, scheduled for the end of August 2026. Migrate before then. The MCP passthrough is on a removal track (epic #390): every catalog tool has a native command. Prefer the native command in ALL new work -- `tool list` prints the replacement in the cli_equivalent column and `tool call` diff --git a/src/keboola_agent_cli/commands/tool.py b/src/keboola_agent_cli/commands/tool.py index d6333ff7..43d72214 100644 --- a/src/keboola_agent_cli/commands/tool.py +++ b/src/keboola_agent_cli/commands/tool.py @@ -17,7 +17,12 @@ from ..config_store import ConfigStore from ..errors import ConfigError, ErrorCode, PermissionDeniedError -from ..mcp_parity import deprecation_message, native_equivalent +from ..mcp_parity import ( + MCP_REMOVAL_TARGET_DATE, + MCP_REMOVAL_VERSION, + deprecation_message, + native_equivalent, +) from ..output import OutputFormatter, format_tool_result, format_tools_table from ._helpers import ( EXIT_PERMISSION_DENIED, @@ -35,7 +40,8 @@ # messages for `tool call` come from mcp_parity.deprecation_message(). TOOL_LIST_DEPRECATION = ( "The MCP passthrough is deprecated (epic #390); every tool has a native " - "command -- see the cli_equivalent column." + "command -- see the cli_equivalent column. The `tool` group is REMOVED in " + f"kbagent v{MCP_REMOVAL_VERSION} ({MCP_REMOVAL_TARGET_DATE})." ) diff --git a/src/keboola_agent_cli/constants.py b/src/keboola_agent_cli/constants.py index 266518b3..4122d01f 100644 --- a/src/keboola_agent_cli/constants.py +++ b/src/keboola_agent_cli/constants.py @@ -305,6 +305,7 @@ def _resolve_app_name() -> str: MCP_UV_PRERELEASE_FLAG: str = "--prerelease=allow" MCP_PIP_PRERELEASE_FLAG: str = "--pre" + # --- Auto-Update --- ENV_AUTO_UPDATE: str = "KBAGENT_AUTO_UPDATE" ENV_SKIP_UPDATE: str = "KBAGENT_SKIP_UPDATE" diff --git a/src/keboola_agent_cli/mcp_parity.py b/src/keboola_agent_cli/mcp_parity.py index 480a6ea0..7563025c 100644 --- a/src/keboola_agent_cli/mcp_parity.py +++ b/src/keboola_agent_cli/mcp_parity.py @@ -20,6 +20,21 @@ from dataclasses import dataclass +# Removal target for the MCP passthrough (epic #390 phase 3). Deprecated since +# 0.74.0; until 0.80.0 the notice said only "a future release", which gives a +# user nothing to plan against -- especially for `agent --type mcp_tool`, whose +# tasks live in `/agents.json` on disk and would simply start +# failing on their next cron tick. Every surface that mentions the deprecation +# quotes these two so they cannot drift apart. +# +# Deliberately NOT in constants.py, which is otherwise the home for values like +# these: this module must stay stdlib-only and standalone-importable so +# `scripts/check_mcp_parity.py` can load it on a bare python3 in the canary +# workflow, and constants.py imports httpx. Moving them there turns the canary +# red -- verified. +MCP_REMOVAL_VERSION: str = "0.85.0" +MCP_REMOVAL_TARGET_DATE: str = "end of August 2026" + @dataclass(frozen=True) class ParityEntry: @@ -135,10 +150,12 @@ def deprecation_message(tool_name: str) -> str: return ( f"MCP passthrough is deprecated (epic #390) and tool {tool_name!r} has " f"no native equivalent yet -- please report it at " - f"https://github.com/keboola/cli/issues/390." + f"https://github.com/keboola/cli/issues/390 before the group is " + f"removed in v{MCP_REMOVAL_VERSION} ({MCP_REMOVAL_TARGET_DATE})." ) suffix = f" ({entry.note})" if entry.note else "" return ( f"MCP passthrough is deprecated (epic #390); use `kbagent {entry.command}` " - f"instead{suffix}. The `tool` group will be removed in a future release." + f"instead{suffix}. The `tool` group is REMOVED in kbagent " + f"v{MCP_REMOVAL_VERSION} ({MCP_REMOVAL_TARGET_DATE})." ) diff --git a/tests/test_mcp_deprecation_warnings.py b/tests/test_mcp_deprecation_warnings.py index 7e0a9af3..fdf1410e 100644 --- a/tests/test_mcp_deprecation_warnings.py +++ b/tests/test_mcp_deprecation_warnings.py @@ -403,3 +403,60 @@ def test_update_cli_command_task_has_no_warning(self, tmp_path: Path) -> None: ) assert updated.exit_code == 0, updated.output assert "deprecation" not in json.loads(updated.stdout)["data"] + + +class TestRemovalTargetIsNamedEverywhere: + """Every deprecation surface must quote the same removal version and date. + + Until 0.80.0 the notices said only "a future release". A deprecation + without a date is not a window -- users have nothing to plan against, and + `agent --type mcp_tool` tasks are persisted in agents.json, so their owner + is only present to hear the deadline at creation time. + """ + + def test_constants_agree_with_the_announced_target(self) -> None: + from keboola_agent_cli.mcp_parity import ( + MCP_REMOVAL_TARGET_DATE, + MCP_REMOVAL_VERSION, + ) + + assert MCP_REMOVAL_VERSION == "0.85.0" + assert MCP_REMOVAL_TARGET_DATE == "end of August 2026" + + def test_every_warning_names_the_version(self) -> None: + from keboola_agent_cli.commands.agent import MCP_TOOL_ACTION_DEPRECATION + from keboola_agent_cli.commands.tool import TOOL_LIST_DEPRECATION + from keboola_agent_cli.mcp_parity import ( + MCP_REMOVAL_VERSION, + MCP_TOOL_PARITY, + deprecation_message, + ) + + surfaces = { + "tool list banner": TOOL_LIST_DEPRECATION, + "agent mcp_tool warning": MCP_TOOL_ACTION_DEPRECATION, + "tool call (mapped)": deprecation_message(sorted(MCP_TOOL_PARITY)[0]), + "tool call (unmapped)": deprecation_message("no_such_upstream_tool"), + } + for name, text in surfaces.items(): + assert MCP_REMOVAL_VERSION in text, f"{name} does not name the removal version" + + def test_mcp_parity_stays_stdlib_only(self) -> None: + """The canary loads this module by path on a bare python3. + + `scripts/check_mcp_parity.py` bypasses the package (constants.py pulls + in httpx), so a third-party or relative import here turns the weekly + canary red -- which is exactly what happened while writing this. + """ + import ast + from pathlib import Path + + source = Path("src/keboola_agent_cli/mcp_parity.py").read_text(encoding="utf-8") + for node in ast.walk(ast.parse(source)): + if isinstance(node, ast.ImportFrom): + assert node.level == 0, f"relative import of {node.module!r} breaks the canary" + assert (node.module or "").split(".")[0] in { + "dataclasses", + "typing", + "__future__", + }, f"non-stdlib import {node.module!r} breaks the canary" diff --git a/uv.lock b/uv.lock index f207b4f7..c4786d8f 100644 --- a/uv.lock +++ b/uv.lock @@ -590,7 +590,7 @@ wheels = [ [[package]] name = "keboola-cli" -version = "0.79.0" +version = "0.80.0" source = { editable = "." } dependencies = [ { name = "croniter" },