galaxyproject / galaxyproject/loom

Orbit/Galaxy MCP: a configured Galaxy URL ending in `/api` regenerates the doubled `/api/api` 404 from config

Open
#454 0 comments 0 reactions 0 assignees View on GitHub
bug
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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.