Skip to content

Revive the gxy CLI as a human/AI scripting surface#56

Open
dannon wants to merge 10 commits into
galaxyproject:mainfrom
dannon:feature/gxy-cli
Open

Revive the gxy CLI as a human/AI scripting surface#56
dannon wants to merge 10 commits into
galaxyproject:mainfrom
dannon:feature/gxy-cli

Conversation

@dannon

@dannon dannon commented Jun 4, 2026

Copy link
Copy Markdown
Member

This brings the gxy command-line tool from the old cli-exploration branch onto current main, packaged properly and with a working credential path. gxy is a thin Typer adapter -- one of three surfaces over the same ~37 @mcp.tool functions in server.py (alongside full-MCP and code-mode), so there's no duplicated Galaxy logic. It's JSON-first, for humans, shell scripts, and CI; the headline feature is IWC workflow discovery (search/recommend/import), which needs no Galaxy account and makes it a real successor to the unmaintained parsec.

The one structural fix beyond packaging is server.connect_global(): the multi-user connect() tool deliberately stopped writing module-global state (#50), so a single-user in-process client had no way to seed a connection from resolved creds. connect_global() does exactly that, with an explicit contract that it's single-user-only and must never run inside the multi-tenant HTTP server.

Positioning is deliberate: agents should probably continue to use the MCP server / code-mode, not this CLI. Agent-grade output hardening (mandatory --json, deterministic status strings, an exit-code contract, output-contract tests) is intentionally deferred to a follow-up (Option C). This PR keeps the existing JSON output and adds no agent guarantees.

What's here

  • Imports the CLI source (src/galaxy_mcp/cli/) unchanged, then packages it: declares typer/tomli, adds the gxy console script, relocks.
  • connect_global() for single-user CLI connections (TDD'd).
  • Wires --url/--api-key/--profile into an actual connection via a best-effort callback (IWC discovery still works with zero creds; connect/--help skip it).
  • Drops the vestigial _fn tool-unwrap helper -- FastMCP 3 returns plain functions from @mcp.tool, so the CLI calls them directly.
  • Docs in both READMEs with config precedence, runnable examples, and the "agents -> MCP/code-mode" positioning.

Verification

200 tests pass (server + CLI), mypy and lint clean. Smoke-tested with no credentials: gxy iwc recommend ... returns ranked workflows (exit 0), and a data command like gxy history list fails cleanly with a JSON "not connected" error (exit 1, no traceback).

dannon added 10 commits June 4, 2026 10:32
This is the Typer CLI that wraps the MCP server's tool functions for shell
use. Pulled in unchanged; packaging, the connection path, and cleanup follow
in subsequent commits.
The CLI hard-imports typer and config.py needs tomli on 3.10, but neither was
declared, so a clean install couldn't run gxy. Adds both plus the gxy entry
point and relocks.
The multi-user connect() tool no longer writes the module-global state, so an
in-process single-user client (gxy) has no way to seed a connection from
resolved creds. connect_global does exactly that, with a clear contract that
it's single-user-only and must not run inside the multi-tenant server.
The callback resolved --url/--api-key/--profile into ctx.obj but never seeded
the server's connection state, so only env-var auth worked for data commands.
Now the callback best-effort connect_globals when creds are present (skipping
connect/help, swallowing failures so credential-free IWC discovery still
works), and the connect command uses connect_global too.
FastMCP 3 returns the plain function from @mcp.tool, so _fn only ever worked
via its else-fallback. Call the server functions directly and flip the test
mocks from mock.fn to the mock itself.
iwc recommend/search/list/details hit the IWC manifest, not Galaxy, so they
must work with no creds. Test guards that.
Adds a CLI section with config precedence and runnable examples, and states
plainly that agents should use the MCP server / code-mode for now -- gxy is the
human/CI/scripting surface.
A bare print() at import time put 'Loaded environment variables from ...' on
stdout. For the gxy CLI that's the JSON data channel, so any 'gxy ... | jq'
pipeline broke whenever a .env was present -- which is exactly how CLI users
configure creds. It's also a latent hazard for the MCP stdio transport
(JSON-RPC over stdout). Route it through the logger like the other diagnostics.
The config layer already supported gxy + planemo profiles, but nothing exposed
list_profiles() so there was no way to discover what's configured. Adds a
'gxy profile list' command (no connection needed) over the existing tested
function. Also removes get_config_path/ensure_config_dir, which were dead.
A subprocess test asserts the dotenv message lands on stderr, not stdout --
the in-process CliRunner can't catch it because the message is emitted at
server-import time. Plus a unit test for the new profile list command.
@dannon dannon changed the title Revive the gxy CLI as a human/CI scripting surface Revive the gxy CLI as a human/AI scripting surface Jun 4, 2026
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