Repository navigation
Remote gpu server - #35
Merged
Merged
Conversation
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The Origin check only allowed loopback origins, so a browser reaching a --host 0.0.0.0 server by LAN IP got 403 on every POST. An Origin whose hostname matches the request's own Host is now accepted; a rebinding attack still differs from Host and is still refused. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
dw-mcp exits 2 when --url is not loopback and no token is set, and makes one GET /api/health before serving so a wrong URL or token is reported once with a message rather than as a 401 on every tool call. --no-probe skips the check. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
create_app(mcp=True) mounts the dw_mcp tool surface inside the HTTP server, behind the same bearer token as /api. The tools call back to the REST API over loopback, so dw_mcp stays a pure HTTP client. An agent on another machine needs no local install: one URL and a token. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Refused on a non-loopback bind without a token: an MCP endpoint can write and run workflows and has no UI-style token prompt in front of it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
stdout is block-buffered when it is not a terminal, so under the systemd unit (StandardOutput=journal) or nohup the banner - including whether MCP is mounted - was withheld until the server shut down. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Adds #/server: status (hostname, version, device, worker, queue, current job), the bind and what it means, the machine's interface addresses with the URL each makes, whether MCP is mounted and where, whether a token is required, copy-paste snippets for a browser and for `claude mcp add`, and the workflow/output/prompt directories. The token is never rendered - the mcp command carries the literal placeholder <token> - and nothing derived from it is shown either. URL and command composition lives in lib/serverinfo.ts so it is testable on its own; the page reads GET /api/server for the static detail and polls /api/health for the live half. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The Server page has to answer "what URL and command do I give the other machine?", and the only half of that the server knows is its own bind address, port, whether a token is required, whether MCP is mounted, and which non-loopback addresses its interfaces carry. It reports those and stops there - URL composition is the UI's job. The token is never reported in any form, only auth_required; a test asserts the value, a prefix of it and its length are all absent from the body. Address enumeration prefers psutil (the only method that can name the interface) but never requires it - psutil is transitive here, not a declared dependency - and falls back to getaddrinfo plus the connectionless UDP outbound-address trick, which matters on a host whose name resolves to 127.0.1.1. Enumeration failure yields [], not a 500. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- Updated `build_mcp_app` to accept host parameter for correct client base URL. - Added `client_base_url` function to determine the server address for mounted tools. - Enhanced same-origin checks in the server to reject opaque origins. - Added tests for address handling in mounted tools and server configurations. - Updated address labeling logic to handle unknown interfaces gracefully.
dkackman
added a commit
that referenced
this pull request
Sep 5, 2026
* docs: move scoping notes from superpowers/scope to docs/proposals Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(server): accept same-origin browser requests on a non-loopback bind The Origin check only allowed loopback origins, so a browser reaching a --host 0.0.0.0 server by LAN IP got 403 on every POST. An Origin whose hostname matches the request's own Host is now accepted; a rebinding attack still differs from Host and is still refused. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat(mcp): refuse an unauthenticated remote server and probe at startup dw-mcp exits 2 when --url is not loopback and no token is set, and makes one GET /api/health before serving so a wrong URL or token is reported once with a message rather than as a 401 on every tool call. --no-probe skips the check. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat(server): report hostname, device and mcp in /api/health Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat(server): mount MCP over Streamable HTTP at /mcp create_app(mcp=True) mounts the dw_mcp tool surface inside the HTTP server, behind the same bearer token as /api. The tools call back to the REST API over loopback, so dw_mcp stays a pure HTTP client. An agent on another machine needs no local install: one URL and a token. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat(serve): --mcp serves the tool surface at /mcp Refused on a non-loopback bind without a token: an MCP endpoint can write and run workflows and has no UI-style token prompt in front of it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs: remote GPU server guide, systemd unit, MCP security rewrite Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs: quickref no longer says MCP is localhost only Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * delete * fix(serve): flush the startup banner stdout is block-buffered when it is not a terminal, so under the systemd unit (StandardOutput=journal) or nohup the banner - including whether MCP is mounted - was withheld until the server shut down. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat(ui): Server page with the details needed to connect from elsewhere Adds #/server: status (hostname, version, device, worker, queue, current job), the bind and what it means, the machine's interface addresses with the URL each makes, whether MCP is mounted and where, whether a token is required, copy-paste snippets for a browser and for `claude mcp add`, and the workflow/output/prompt directories. The token is never rendered - the mcp command carries the literal placeholder <token> - and nothing derived from it is shown either. URL and command composition lives in lib/serverinfo.ts so it is testable on its own; the page reads GET /api/server for the static detail and polls /api/health for the live half. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat(server): GET /api/server describes how to reach this machine The Server page has to answer "what URL and command do I give the other machine?", and the only half of that the server knows is its own bind address, port, whether a token is required, whether MCP is mounted, and which non-loopback addresses its interfaces carry. It reports those and stops there - URL composition is the UI's job. The token is never reported in any form, only auth_required; a test asserts the value, a prefix of it and its length are all absent from the body. Address enumeration prefers psutil (the only method that can name the interface) but never requires it - psutil is transitive here, not a declared dependency - and falls back to getaddrinfo plus the connectionless UDP outbound-address trick, which matters on a host whose name resolves to 127.0.1.1. Enumeration failure yields [], not a 500. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat(server): enhance MCP app configuration and improve address handling - Updated `build_mcp_app` to accept host parameter for correct client base URL. - Added `client_base_url` function to determine the server address for mounted tools. - Enhanced same-origin checks in the server to reject opaque origins. - Added tests for address handling in mounted tools and server configurations. - Updated address labeling logic to handle unknown interfaces gracefully. * fix(tests): update HEAD request assertion to handle 404 and 405 status codes --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.