Skip to content

fix(web, artifacts, mcp): port fallback, artifacts crash, MCP URL overrides#387

Closed
echandler-anl wants to merge 2 commits into
als-apg:mainfrom
echandler-anl:aps
Closed

fix(web, artifacts, mcp): port fallback, artifacts crash, MCP URL overrides#387
echandler-anl wants to merge 2 commits into
als-apg:mainfrom
echandler-anl:aps

Conversation

@echandler-anl

Copy link
Copy Markdown

Summary

  • osprey web: when no --port is given and the default port (8087) is busy, auto-bind to a free OS-assigned port instead of hard-exiting. Explicitly specified ports still error if taken.
  • osprey artifacts web: pass workspace_root to run_server() so the command doesn't crash with TypeError when launched standalone.
  • registry/mcp.py: apply the url field from claude_code.servers overrides to built-in framework servers, so stdio→HTTP switching via config works without osprey claude regen silently ignoring the key.

Test plan

  • osprey web with default port in use → confirms it picks a free port and prints the chosen port
  • osprey web --port <taken> → still errors as before
  • osprey artifacts web standalone → no longer crashes with TypeError
  • Set claude_code.servers.<name>.url in config for a framework server → URL is applied

🤖 Generated with Claude Code

…rrides for framework MCP servers

- artifacts_cmd.py: pass workspace_root to run_server() so osprey artifacts web
  does not crash with TypeError when launched standalone (auto-launch path via
  server_launcher.py was unaffected as it already resolved workspace_root)

- registry/mcp.py: apply url field from claude_code.servers overrides to built-in
  framework servers, enabling stdio→HTTP switching via config without osprey claude
  regen silently ignoring the url key
When no --port is specified and the default port (8087) is already in use,
bind to port 0 to let the OS pick a free port instead of exiting with an
error. Explicitly specified ports still error if taken.
@thellert

Copy link
Copy Markdown
Collaborator

Hi Elaine — thanks for these, and welcome! Three genuinely useful fixes here; let me take them one at a time, since they're at different levels of ready.

osprey web port fallback — nice quality-of-life win, and I like that you kept explicit --port fail-loud. Since you opened this, web_cmd.py gained a step that publishes the actual bound port to child processes via OSPREY_WEB_PORT (panel navigation depends on it), so the fallback needs to reassign port before that publish or the children keep talking to 8087. I've reworked it on top of current main with a test that threads the chosen port through — and I'd rather it land here, under your PR, than anywhere else. If you enable "allow edits from maintainers" (or it's fine to push to the branch), I'll drop the commit straight onto #387 so it stays yours; otherwise I'm happy to paste it here as a patch for you to apply.

osprey artifacts web — good to take. One note: run_server already defaults workspace_root=None on current main, so it no longer crashes with TypeError — your change is still an improvement (it passes the real root), just not a crash fix anymore. Mind trimming that from the description so the history stays accurate?

registry/mcp.py url override — this is the one I'd like to slow down on. main has since reworked resolve_servers so framework-server overrides honor only enabled, deliberately: letting config reshape a safety-configured server — the control-system connector, its approval hooks, its write posture — is exactly what that guard prevents. A url override would let claude_code.servers.controls.url swap the in-process connector for an arbitrary HTTP endpoint; the local approval hooks still fire, but the enforcement that lives in the connector moves off-box. On the hardware-write path, I don't think we want that as a silent, unguarded config knob. Could you say more about the use case? If there's a real need for stdio→HTTP on a framework server, let's design the gate together (allowlist? localhost-only? explicit opt-in?) rather than open it for every server.

Heads-up too that the branch is conflicting with main now, so it'll need a rebase regardless.

Really appreciate the contribution — the first two are close, and I'm glad to help get the third somewhere we're both comfortable.

@thellert

Copy link
Copy Markdown
Collaborator

Closing the loop on the three pieces here:

osprey web port fallback — landed, with you as co-author, via #420 (commit d58b2ce). It keeps exactly your design — no explicit port → auto-bind a free OS-assigned port; explicit --port still fails loud — reworked on top of the current web_cmd.py so the chosen port is reassigned before it's published to child processes via OSPREY_WEB_PORT, plus regression tests covering the busy-default and pinned-port paths. I'd offered to land it under this PR, but #420 was already rewiring the same code, and carrying the change in both places guaranteed a conflict on merge — so it rides along there instead. Thanks for the idea and the initial implementation, Elaine; the Co-Authored-By in the commit keeps the credit where it belongs.

osprey artifacts web — moot on current main: run_server now defaults workspace_root=None, so the standalone crash is already gone and there's nothing left to land.

MCP url override — as discussed above, we don't want an unguarded config knob that can move a safety-configured framework server (the control-system connector in particular) to an arbitrary HTTP endpoint. If the stdio→HTTP use case is still live for you, please open an issue describing it and we'll design a proper gate together — allowlist, localhost-only, explicit opt-in, whatever fits.

With all three threads resolved I'll close this one out. Really appreciate the contribution — hope to see more!

@thellert thellert closed this Jul 18, 2026
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