Skip to content

devframe connect --port can't reach a hub mounted under a base path (Vite DevTools /__devtools/) and reports it as "no MCP endpoint" #403

Description

@zahidzorbaz

Summary

devframe connect --port <n> always probes http://localhost:<n>/__connection.json. Vite DevTools mounts its hub at /__devtools/, so the probe misses the real connection meta at /__devtools/__connection.json. Vite's SPA fallback answers the root probe with 200 text/html, and the probe accepts that as a live devframe. The connector then lists a phantom port-<n> instance with mcp: null and fails call-tool with DF0051, telling the user to "restart the instance with the --mcp flag". That flag doesn't exist for a Vite server, and the MCP route is in fact up at /__devtools/__mcp.

There's no flag or documented way to give the connector a base path, so this isn't a usage problem: --port is the documented fallback for instances missing from the registry (docs/content/2.adapters/7.mcp.md, "Discovery: devframe connect"), and it only works for root-mounted devframes.

Scope: registry-based discovery of Vite DevTools is already handled by vitejs/devtools#579 (merged, not yet released), which registers the hub with its /__devtools/ base. This issue is only about the --port fallback and the __connection.json origin probe.

Versions

  • devframe 1.0.0, @devframes/agentic 1.0.0, @devframes/hub 1.0.0, @devframes/vite 1.0.0
  • @vitejs/devtools 0.7.5, vite 8.3.0
  • Node 24.21.0, Windows 11. Nothing here is platform-specific.
  • main at 18fa60e has no changes to packages/agentic/src/connect/ or packages/devframe/src/node/instance-registry.ts since v1.0.0, so the behavior is the same there.

Reproduction

  1. Run any Vite 8.3 app with @vitejs/devtools 0.7.5 enabled (dev server on 127.0.0.1:5174 here, mcp left at its default).
  2. The hub is alive under its base:
    curl -s http://127.0.0.1:5174/__devtools/__connection.json
    # {"backend":"websocket","websocket":{"path":"/__devtools/__ws"},...,"mcp":{"path":"__mcp"},...}
    curl -s -o /dev/null -w '%{http_code} %{content_type}\n' http://127.0.0.1:5174/__connection.json
    # 200 text/html      <- Vite SPA fallback (index.html)
  3. Start the connector with an empty registry and call both gateway tools over stdio:
    DEVFRAME_INSTANCES_DIR=$(mktemp -d) npx devframe connect --port 5174
    devframe_connect_list-instances returns:
    { "id": "port-5174", "port": 5174, "basePath": "/", "mcp": null,
      "hint": "This instance runs without an MCP route. Restart it with the --mcp flag to expose its tools, then list instances again." }
    devframe_connect_call-tool { "port": 5174, "tool": "devframes_plugin_inspect_list-state-keys" } returns:
    { "error": { "code": "DF0051", "message": "The devframe instance on port 5174 has no MCP endpoint.",
                 "fix": "Restart the instance with the --mcp flag to expose its tools, then list instances again." } }

For comparison, a registry record with the right base works end to end with the same 1.0.0 connector against the same server: 11 tools listed, and call-tool returns the state keys. The record is {"port":5174,"origin":"http://127.0.0.1:5174","basePath":"/__devtools/","mcp":{"path":"/__devtools/__mcp"},...}, the shape vitejs/devtools#579 now writes. So the MCP route and the connector's proxy are fine; only the --port probe is wrong.

Root cause

At 18fa60e:

  1. The base is hardcoded to /. packages/agentic/src/connect/index.ts#L202-L217 (probePort) calls probeDevframeOrigin(\http://localhost:${port}\`, '/', timeoutMs), records basePath: '/', and resolves the MCP path with joinURL('/', probed.meta.mcp.path). For a hub at /__devtools/, whose meta advertises the relative "__mcp", that would give /__mcpeven if the meta were found. The in-process registration ininstance-shell.ts#L596correctly usesjoinURL(base, …)`.
  2. Any 200 counts as a devframe. packages/devframe/src/node/instance-registry.ts#L195-L216 (probeDevframeOrigin) checks only response.ok, then falls back to {} when response.json() fails. An HTML SPA fallback therefore "proves" a devframe with no MCP route. That produces the misleading DF0051 instead of DF0050. The same probe is the registry's liveness check, so a stale record whose port is now held by some SPA dev server also stays "live" instead of being pruned.

Related

  • fix: register Vite DevTools for devframe discovery vitejs/devtools#579 (merged 2026-09-17, after the 0.7.5 release, not yet published) registers Vite DevTools in the instance registry with its base. That fixes discovery through the registry for the next @vitejs/devtools release. --port is still the documented fallback for anything unregistered: older @vitejs/devtools, DEVFRAME_DISABLE_INSTANCE_REGISTRY=1, a registry directory the connector can't see (container, WSL, a different HOME), or the window before the hub's first request, since registration waits for the origin.
  • MCP: list every connected browser tab and route client tool calls per tab #394 (per-tab MCP routing) touches the same connector but is a different problem.
  • No existing issue found for "connect" + base path, __connection.json probing, or DF0051 (searched issues and PRs).

Suggested fix

Happy to send a PR:

  • In probeDevframeOrigin, accept only a JSON object as connection meta (skip text/html or unparseable bodies). A non-devframe 200 then yields "no instance" (DF0050) instead of a phantom instance, and stale registry records on a port now held by an unrelated server get pruned.
  • Add a --base <path> option to devframe connect (default /, with a matching base field in ConnectServerOptions) that applies to the --port probes, and resolve the advertised MCP path against that base the same way instance-shell does. devframe connect --port 5174 --base /__devtools/ would then reach Vite DevTools, and the connector stays free of hardcoded mount paths.
  • Document --base in the CLI help and in the "Discovery" section of the MCP adapter docs.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions