the symptom, in your words

"The editor MCP port is one global setting: bump it by hand, let your agent discover it"

✓ verified on 26.07.15a
lane Tooling & environmentposted updated

▸ SYMPTOM

An MCP tool call that worked yesterday now hits the wrong editor, or nothing at all. A port you hardcoded (or remembered from a previous session) either answers with a different project's editor or times out. A second editor you just opened serves no MCP at all, and its Preferences page reads "Not running" with no reason given. Mutating calls, anything that changes a scene or asset, are the dangerous case: they land against whichever project happens to hold that port right now.

▸ CAUSE

The editor MCP port cannot be pinned per project. It is a single engine-global preference (Editor.EditorPreferences.McpServerPort, persisted in the engine's config/tools.json; stored via the engine-global editor cookie, so there is no per-project override by design). The engine default is 7269. Whichever project's editor launches first binds the configured port.

There is no auto-increment. When the configured port is already bound by another open editor, the second editor does not fall back to a neighbouring port. It fails the bind and starts no MCP server at all. The engine source wraps the listener start in a single try/catch: on failure it logs one warning and gives up, with no retry and no port search.

Confirmed with three editors live on build 26.07.15a: one project's editor held the configured port 7279; two more editors opened afterward, and a full identity-probe scan of ports 7200-7330 found only that first editor. The later editors exposed no MCP server on any port.

The console warning is the only diagnostic. On a bind conflict the editor logs (grep your console for this, tag MCP):

snippet
Couldn't start MCP server on port <port> (<reason>)

A clean start logs MCP server listening on <url> instead. The Preferences page (Edit > Preferences > MCP Server) shows only "Not running" on a failed bind, the same text it shows when the server is disabled, so the page alone will not tell you a conflict happened. Check the console.

Consequences:

  • Any hardcoded or remembered port goes stale on every restart or launch-order change.
  • A port that answered yesterday can be a different project today, the silent and dangerous failure, because a mutating call succeeds against the wrong editor.
  • A second editor opened on the same configured port serves nothing until you give it a free port by hand.

▸ FIX

Two parts: set the port by hand, and let agents discover it.

Set a free port by hand

The port is read at editor startup, so before launching an additional editor that needs MCP, open Edit > Preferences > MCP Server and set the "Mcp Server Port" field to a free number (increment it yourself), then launch the new editor.

Changing the port (or the enabled checkbox) restarts the server immediately, so you can also fix an editor that already failed its bind: open its Preferences and set a free port there, and its MCP server starts on the spot, no restart needed.

Discover, never pin

Because ports are launch-order and hand-set, don't hand a fixed port to your tooling each session. Discover the live port at run time:

  1. Scan the plausible range (e.g. 7200 to 7330) with a parallel, read-only editor_status probe per port. editor_status is safe to call against any project.
  2. Match the returned Project field to the project you mean to drive.
  3. Feed the found URL to all tooling via an env var, so every call targets the confirmed editor.

A ~130-port threaded scan completes in about a second.

Implementation caveats

Write the probe as a self-contained raw JSON-RPC POST (e.g. urllib). Do not reuse an interactive MCP client helper that prints guidance and calls sys.exit() on an unreachable port:

  • SystemExit is not an Exception, so it slips past a normal try/except Exception and kills your scan.
  • contextlib.redirect_stdout is process-global and not thread-safe, so it corrupts output under a parallel scan.

A minimal per-port probe that opens a socket, POSTs an editor_status request, reads the Project, and returns the URL is all you need.

▸ WHY IT WORKS

Because the port is assigned by launch order and set by hand, never auto-negotiated, the only reliable identifier is the Project field the editor reports about itself. Scanning and matching that field targets the editor by identity instead of by a number that drifts, so tooling always talks to the intended project, and a mutating call can never silently land on the wrong one.

Verified on engine 26.07.15a: seen in a real project.
s&box moves fast; an undated fix is a liability. Spot a stale detail?
changelog
  • Corrected: the editor does not auto-increment; the port must be bumped manually before launching another editor
  • Published

Want to know when new guides or fixes drop? Join the community to help build this out. Report gotchas, flag outdated fixes, or just lurk.

Join the Discord