galaxyproject / galaxyproject/loom
Orbit/Galaxy MCP: a configured Galaxy URL ending in `/api` regenerates the doubled `/api/api` 404 from config
- Dominant language
- TypeScript
- Stars
- 14
- Forks
- 12
- Avg merge
- 6d 5h
- Merged PRs (30d)
- 17
Description
Follow-up to #420, surfaced while fixing it and deliberately left out of that PR's scope.
#420 fixed the doubled `/api/api/...` path where it was hardcoded in the source (galaxy-mcp PR #99). But a user can regenerate exactly the same 404 from **configuration**, and that route is still open.
**What happens.** The only normalization applied to a user-supplied Galaxy URL is trailing-slash. In `mcp-server-galaxy-py/src/galaxy_mcp/server.py`:
```python
# module level, for GALAXY_URL
normalized_galaxy_url = (
raw_galaxy_url if not raw_galaxy_url or raw_galaxy_url.endswith("/") else f"{raw_galaxy_url}/"
)
# and again inside connect(), for the url argument
galaxy_url = use_url if use_url.endswith("/") else f"{use_url}/"
```
That value goes straight to `GalaxyInstance(url=galaxy_url, ...)`, and bioblend does:
```python
self.base_url = url.rstrip("/")
self.url = f"{self.base_url}/api"
```
So `GALAXY_URL=https://example.org/api` becomes `https://example.org/api/` becomes base `https://example.org/api` becomes `self.url = https://example.org/api/api`. Every subsequent call 404s with `No route for /api/api/...` -- the identical symptom #420 reported, from a different cause, and **not** covered by that fix.
Pointing a client at the API root is a reasonable thing for a user to do; it's what the Galaxy API docs URL looks like, and nothing in the config surface says not to. The failure gives no hint that the URL is the problem.
**Second variant, same root gap.** A scheme-less `GALAXY_URL` (`example.org`) isn't normalized either. Loom hit this exact class from its own side and fixed it there -- see #264, closed, `notebook_list_galaxy_pages` failing with "Failed to parse URL". The MCP server never got the equivalent treatment.
**Suggested fix.** Normalize user-supplied Galaxy URLs once, in a shared helper, and use it in both places that currently duplicate the trailing-slash logic. At minimum: add a scheme when missing, and strip a trailing `/api` (or `/api/`).
Worth an explicit decision rather than just picking one:
- **Strip and continue** is friendliest, and matches how most clients treat a pasted API root -- but it silently rewrites what the user configured, which is surprising if they meant something unusual.
- **Reject loudly at connect time** with a message naming the problem ("drop the trailing `/api` -- point me at the Galaxy root") is more honest and much easier to debug than a 404 forty calls later.
Either beats the current behavior. Leaning toward normalizing the common cases and erroring only on genuinely ambiguous input, but that's a maintainer call -- it changes `connect()` semantics, which is why it wasn't folded into #99.
**Note on repo.** The fix lands in `galaxyproject/galaxy-mcp`; filing here to match how the other `Orbit/Galaxy MCP:` reports are tracked.
Contributor guide
No contributing guide indexed for this repository
Research direction
The affected code is in mcp-server-galaxy-py/src/galaxy_mcp/server.py, where URL normalization is duplicated at module level and inside connect(). Start by tracing both values into GalaxyInstance(url=galaxy_url, ...), then confirm the maintainer decision between stripping /api and rejecting it. Done means both configuration paths consistently handle scheme-less URLs and URLs ending in /api without producing /api/api or a delayed 404.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100