Revive the gxy CLI as a human/AI scripting surface#56
Open
dannon wants to merge 10 commits into
Open
Conversation
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This brings the
gxycommand-line tool from the oldcli-explorationbranch onto currentmain, packaged properly and with a working credential path.gxyis a thin Typer adapter -- one of three surfaces over the same ~37@mcp.toolfunctions inserver.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 unmaintainedparsec.The one structural fix beyond packaging is
server.connect_global(): the multi-userconnect()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
src/galaxy_mcp/cli/) unchanged, then packages it: declarestyper/tomli, adds thegxyconsole script, relocks.connect_global()for single-user CLI connections (TDD'd).--url/--api-key/--profileinto an actual connection via a best-effort callback (IWC discovery still works with zero creds;connect/--helpskip it)._fntool-unwrap helper -- FastMCP 3 returns plain functions from@mcp.tool, so the CLI calls them directly.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 likegxy history listfails cleanly with a JSON "not connected" error (exit 1, no traceback).