Skip to content

fix(mcp): forward packaging mode in package and migrate - #158

Open
matthewmoorcroft wants to merge 16 commits into
mainfrom
fm/flowx-mcp-package-mode
Open

matthewmoorcroft wants to merge 16 commits into
mainfrom
fm/flowx-mcp-package-mode

Conversation

@matthewmoorcroft

@matthewmoorcroft matthewmoorcroft commented Oct 14, 2026 •

Copy link
Copy Markdown
Member

Intent

The hosted flowx MCP server's package call ignored the packaging mode: inputs package asks the agent for packaging_mode and group_spec, but package (and migrate's package step) dropped them and always wrote the per-pipeline layout while returning ok: true. This makes MCP honour the same modes the CLI does (from #73).

What changed

  • src/flowx/mcp/server.py: package and migrate forward packaging_mode, group_by and group_spec to the CLI's --packaging-mode/--group-by/--group-spec, so defaults and refusals of bad values match the CLI. A group_spec sent alone implies per-group + spec, as the inputs package text promises.
  • Tool description, inputs package text and the package skill document the parameters and note that group_spec must be a path the server itself can read (on the hosted server use group_by inferred or a server-local path).
  • Follow-up fixes: a packaging value that isn't a string (for example group_spec: false) is now refused before anything runs, in package and migrate, instead of reaching the CLI as the text "False". The migrate skill's recommended call now shows the packaging keys, and the skill, tool description and needs_input message say a migrate re-call must repeat them (they aren't remembered between calls) and that interactive=false belongs on the first call.

How it was tested

  • New tests/unit/test_mcp_package_modes.py: MCP package writes the same files as the CLI from the same converted state for default/per-pipeline, single, per-group (inferred, explicit spec, and spec without group_by); a bad packaging_mode/group_by is refused through MCP exactly as through the CLI; migrate forwards the flags. The parity and refusal tests fail on the old code.
  • Non-string values are refused before any adapter call, for both commands; the migrate re-call tests drive a real needs_input first call and then the re-call, across single, per-group inferred and a group_spec.
  • Full unit suite (MCP extra included), the make integration selection, ruff check, ruff format --check and mypy pass; uv.lock unchanged.

Notes

No inline or remote group_spec support, and no changes to dab_writer.py packaging logic, Airflow code or other MCP differences.

This pull request and its description were written by Isaac.

matthewmoorcroft and others added 16 commits October 14, 2026 13:29
The MCP package command and migrate's package step dropped packaging_mode,
group_by and group_spec, so hosted runs always wrote the per-pipeline layout
while reporting ok. Forward them to the adapter's --packaging-mode, --group-by
and --group-spec flags so MCP gets the CLI's defaults and refusals, and
document the parameters in the tool description.

Co-authored-by: Isaac <no-reply@databricks.com>
A packaging_mode or group_by of 0 or False was treated as unset, so MCP
package fell back to the per-pipeline layout with ok: true while the CLI
refuses the same value. Only a missing key, None or "" now counts as unset;
anything else is forwarded so argparse refuses it as on the command line.

Co-authored-by: Isaac <no-reply@databricks.com>
A packaging_mode, group_by or group_spec that is set but not a string
reached the CLI stringified, so group_spec false became the spec path
"False", which a multi-DAG Airflow migration never reads. MCP now
refuses such a value before anything runs, in package and migrate.

Co-authored-by: Isaac <no-reply@databricks.com>
The recommended Genie migrate call left out packaging_mode, group_by
and group_spec, so following it always packaged per-pipeline. Add them,
and say the answers re-call must repeat them.

Co-authored-by: Isaac <no-reply@databricks.com>
Re-applied from the validation run's review fix c171934 so the branch
stays a fast-forward from be231c4.

Co-authored-by: Isaac <no-reply@databricks.com>
The answers re-call test pre-seeded a report and made one call, so it
could not show that a first call's layout is not remembered. It now
makes the first call, then the re-call with and without the packaging
keys, and pins that a later interactive=false call starts over.

Co-authored-by: Isaac <no-reply@databricks.com>
Only an answers re-call reuses the report. An interactive=false call
after needs_input starts over, so it needs the source again and reruns
discover and convert; the skill, the needs_input message, the tool
description and the docstring now say so.

Co-authored-by: Isaac <no-reply@databricks.com>
Resolves one docstring conflict in the MCP tool description: keeps this
branch's migrate re-call ending and main's new profile entry.

Co-authored-by: Isaac <no-reply@databricks.com>

This branch has not been deployed

No deployments
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.

1 participant