Conversation
Adds an opt-in remote mode so a workspace can target an FXServer on another machine. When StudioConfig.remote is unset (the default), every existing code path runs unchanged. The loopback policy is not relaxed; it is satisfied honestly on both ends. The runtime binds 127.0.0.1 on the host and reaches RCON at 127.0.0.1, so the Quake3-style UDP packets that carry rcon_password in plaintext never leave that machine. The app connects to 127.0.0.1 on a forwarded port. SSH provides encryption, authentication, and host-key verification in between. networkPolicy.ts and fivem-mcp-server are unchanged. The runtime is already remote-capable: it binds from MCP_HOST/MCP_PORT and always prints its listening port to stderr, which remote mode parses in place of the IPC ready message that is unavailable over SSH. Notes: - No new dependencies. The system OpenSSH client is invoked directly, which also inherits the user's ~/.ssh/config, agent, and key handling. - The launch script is delivered over SSH stdin (sh -s), so no value appears in argv, where other users on the host could read it via ps. - rcon_password is read out of server.cfg by the remote script itself, so it is never transmitted to the client. - RemoteHostSettings holds no secrets, since StudioConfig reaches the renderer. Verified against a live FXServer: initialize, tools/list, and tools/call all succeed through the tunnel, and list_resources returns real started/stopped state.
drgost1
force-pushed
the
feat/remote-ssh-host
branch
from
August 31, 2026 08:07
6048acb to
afa0b6e
Compare
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.
Summary
Adds an opt-in remote mode so a workspace can target an FXServer on another machine over SSH. When
StudioConfig.remoteis unset — the default — every existing code path runs unchanged.Opening this as a concrete proposal rather than a request; entirely understood if the direction isn't one you want, and happy to close it or rework it.
The loopback policy is not relaxed
The obvious version of this feature — let
RCON_HOSTaccept a public address — deserves rejection. FXServer RCON is Quake3-style UDP with the password in plaintext in every packet, so that would leakrcon_passwordon every command.networkPolicy.tsis correct as written and this PR does not touch it.Instead the policy is satisfied honestly on both ends:
127.0.0.1127.0.0.1127.0.0.1assertLoopbackHost()passes on both sides truthfully and unmodified. The RCON password never touches the network at all.Why the change is small
managedRuntime.tsalready spawns the runtime with a clean contract — environment variables in, authenticated HTTP on a port out — with no local-only coupling. Remote mode reuses it exactly, swappingspawn()forsshplus a port forward.fivem-mcp-serveris unchanged. It is already remote-capable: it binds fromMCP_HOST/MCP_PORT, andhttpServer.tsalways prints the listening port to stderr. Remote mode parses that line in place of the IPCreadymessage, which isn't available over SSH (process.sendis correctly guarded, so nothing breaks).Implementation notes
DEPENDENCY_POLICY.md's review gate is unaffected, and~/.ssh/config, agent, and key handling come for free.BatchMode=yesprevents interactive prompts from hanging the UI.sh -s), so nothing is visible viapsto other users on the host.rcon_passwordis never transmitted. The remote script reads it out of the sameserver.cfgthe runtime is given, on the host.StudioConfig. That object reaches the renderer, soRemoteHostSettingsholds only a host alias and paths.MCP_PORT=0, host picks a free port), one forwards once that port is known. This avoids reserving a fixed remote port.remoteSettingsOrNull()validates in the style of the surrounding code: absolute POSIX paths with no traversal, a conservative host-alias charset that cannot start with-, port range, and the runtime's own both-or-neither txAdmin pairing plus itsserver.cfg-inside-workspace rule.Scope
This is stage 1 of the smallest useful split:
No settings UI yet — deliberately kept out to keep this reviewable. Happy to add it if the approach looks right.
Verification
npm run typecheckandnpm run check:staticboth pass.Verified end-to-end against a live FXServer (Linux host, Node 24.20.0, Windows client): the bundled
runtime.cjsdeployed unmodified,initialize+tools/list+tools/callall succeed through the tunnel,list_resourcesreturns real started/stopped state, andget_runtime_identityreports the host's workspace path.Not run here:
npm test,npm run dist, andnpm run verify:package, since those need the full release toolchain on the pinned Node 24.20.0 / npm 11.19.0 — worth running before merge.