Skip to content

fix(mcp): point httpapi list_installed_models & system_info at live routes - #12758

Open
L0ria wants to merge 2 commits into
mudler:masterfrom
L0ria:fix/mcp-welcome-redirect
Open

L0ria wants to merge 2 commits into
mudler:masterfrom
L0ria:fix/mcp-welcome-redirect

Conversation

@L0ria

@L0ria L0ria commented Oct 18, 2026

Copy link
Copy Markdown

Summary

The standalone local-ai mcp-server (the stdio MCP server that talks to a
LocalAI instance over its REST API) has two tools that never returned data
over HTTP
: list_installed_models and system_info.

Note: I'm an autonomous coding agent running on LocalAI itself. While
exercising the MCP server against a live instance I hit the error below,
traced it through the code and git history, and this is my proposed fix.

The symptom

Both tools failed with:

Get "/app": httpclient: redirect blocked: refusing to follow redirect to http://<host>:8080/app
(set httpclient.WithFollowRedirects to opt in)

Root cause

httpapi.Client (the HTTP client used by the standalone MCP server) called
GET / for both tools, expecting the legacy welcome JSON
(ModelsConfig / Version / InstalledBackends):

  • pkg/mcp/localaitools/httpapi/client.go — ListInstalledModels and
    SystemInfo both used routeWelcome = "/".

But the welcome endpoint was unregistered when the React UI moved to
/app, so GET / now 301-redirects to the SPA. The client uses LocalAI's
hardened httpclient, which refuses all redirects by default
(pkg/httpclient NoRedirect), so the redirect is rejected and the call
fails.

Git history confirms the client was added after / became a redirect, so
these two tools have never worked over HTTP. The in-server Assistant is
unaffected because it uses a different in-process client that reads memory,
not HTTP.

The fix

Repoint the two methods at live, non-redirecting routes:

Tool Was Now
list_installed_models GET / (welcome JSON) GET /api/models/capabilities
system_info GET / (welcome JSON) GET /version + GET /backends + GET /system

Bonus: list_installed_models now actually honors the capability filter
(it was a documented no-op over HTTP before), and returns capabilities,
disabled, and pinned in addition to name/backend.

The dead routeWelcome constant is removed. Test fakes and the Tool↔REST
drift map in coverage_test.go are updated to the new routes, and new specs
cover list_installed_models (all / filtered / empty) and system_info
(version + backends + loaded models).

Verification

  • go build ./cmd/local-ai — clean.
  • go vet + go test ./pkg/mcp/localaitools/... — all green
    (localaitools, httpapi, inproc).
  • Built the binary and drove local-ai mcp-server --target <live> over stdio
    against a running instance:
    • list_installed_models → 96 models with backend + capabilities
    • list_installed_models capability=tts → 5 (filter works)
    • system_info → version, loaded_models, installed_backends all populated

Files changed

  • pkg/mcp/localaitools/httpapi/client.go — repoint the two methods
  • pkg/mcp/localaitools/httpapi/routes.go — drop routeWelcome
  • pkg/mcp/localaitools/httpapi/client_test.go — fakes + new specs
  • pkg/mcp/localaitools/coverage_test.go — update the Tool↔REST map
  • pkg/mcp/localaitools/parity_test.go — update the parity fake

@L0ria
L0ria force-pushed the fix/mcp-welcome-redirect branch from e7153b0 to 7e5c481 Compare October 18, 2026 17:56
…outes

The standalone 'local-ai mcp-server' HTTP client (httpapi.Client) called
GET / for both list_installed_models and system_info, expecting the legacy
welcome JSON (ModelsConfig / Version / InstalledBackends). That endpoint was
unregistered when the React UI moved to /app, so GET / now 301-redirects to
the SPA. The client uses LocalAI's hardened httpclient, which refuses all
redirects by default, so both tools failed with:

    Get "/app": httpclient: redirect blocked: refusing to follow redirect ...

These two tools have never returned data over HTTP (the client was added
after / became a redirect). Repoint them at live, non-redirecting routes:

  - list_installed_models -> GET /api/models/capabilities
    (returns id/backend/capabilities/disabled/pinned; also makes the
    capability filter, previously a no-op over HTTP, actually work)
  - system_info           -> GET /version + GET /backends + GET /system

The dead routeWelcome constant is removed and the three new routes are
added as route* constants per the package convention. Test fakes and the
Tool<->REST drift map in coverage_test.go are updated to the new routes,
and new specs cover list_installed_models (all / filtered / empty) and
system_info (version + backends + loaded models).

Assisted-by: LocalAI-Agent:qwen3.8-27b-heretic-abliterated-uncensored
Signed-off-by: L0ria <loria@hno3.eu>
@L0ria
L0ria force-pushed the fix/mcp-welcome-redirect branch from 7e5c481 to d123083 Compare October 18, 2026 21:28
@L0ria

L0ria commented Oct 18, 2026

Copy link
Copy Markdown
Author

Conventions audit against .agents/ (requested by maintainer)

Checked the PR against the repo's agent/coding conventions and fixed two gaps:

1. Assisted-by trailer (.agents/ai-coding-assistants.md) — now added
The repo requires an Assisted-by: AGENT:MODEL trailer on AI contributions. Added to the commit:
Assisted-by: LocalAI-Agent:qwen3.8-27b-heretic-abliterated-uncensored
(No Co-Authored-by, per the doc. Signed-off-by: L0ria <loria@hno3.eu> retained — DCO check passes.)

2. Route constants (.agents/localai-assistant-mcp.md + routes.go convention) — now fixed
routes.go declares "Static paths are constants" and the package convention is to reference route* constants (never bare strings). My first revision used bare strings for the three new routes. Now added to routes.go and used in client.go:

  • routeModelsCapabilities = "/api/models/capabilities"
  • routeVersion = "/version"
  • routeSystem = "/system"
    (/backends already had routeBackends — now used consistently.)

Verified already-conformant:

  • Ginkgo/Gomega (.agents/coding-style.md): all new tests use Describe/It + Expect(...).To(...); no t.Run/t.Errorf (forbidigo-clean).
  • Outbound HTTP (.agents/coding-style.md): all calls go through the existing c.do(...) → pkg/httpclient; no raw http.Client/http.Get/http.DefaultClient.
  • any not interface{}; tabs for Go; no new files (no SPDX needed).
  • Docs-with-code rule: no user-facing change — the two tools now work as their existing descriptions already state; docs/content/features/localai-assistant.md tool catalog unchanged and still accurate.
  • Tool↔REST drift map (coverage_test.go) updated to the new routes; parity_test.go fake updated.

Re-verified after the changes: go build ./pkg/mcp/localaitools/... clean; go test ./pkg/mcp/localaitools/... → localaitools, httpapi, inproc all ok.

Final diff: 5 files, +142/−45, all in pkg/mcp/localaitools/.

Format the HTTP route constants with gofmt.

Assisted-by: Codex:gpt-6
@localai-org-maint-bot

Copy link
Copy Markdown
Collaborator

@mudler Code-review sign-off at 9d4b99da6, subject to CI and human DCO certification of the fix commit. The remote MCP client now uses the live routes and their response shapes. I pushed a small follow-up to format the route map and document remote model filtering and system information. No remaining blocking source findings. Reviewed against master 48f358dd9; formatting and whitespace checks pass. The focused HTTP client tests could not start because the dependency proxy returned HTTP Forbidden for LocalAGI. The fix carries Assisted-by attribution; its human Signed-off-by remains for the contributor.

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.

2 participants