Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ You can now issue commands from your MCP client.
> [!NOTE]
> Only one Editor instance can be connected to the MCP server at a time.

> [!IMPORTANT]
> Chromium gates a public page's connection to `127.0.0.1` behind a local access permission (Chrome 142+, extended to WebSockets in Chrome 147) granted **per origin**, so allow it when prompted. In Chrome's site settings it is `Apps on device` (loopback) — `Local network` covers LAN addresses and is not required. Only the Editor needs it: the launch page is bridged through the Editor rather than opening a socket of its own. If the Editor sits on `Connecting`, open its site settings and allow it — a blocked connection fails silently and looks exactly like a server that isn't running.

## Editor Driver Coverage

All tools act on the project open in the connected Editor. The server does not discover, select, create, delete, transfer, or administer projects, and project IDs are not tool inputs.
Expand All @@ -107,7 +110,7 @@ All tools act on the project open in the connected Editor. The server does not d

Asset transfers over 20 MiB use 1 MiB chunks. The server reads and writes local files incrementally, while the Editor spools uploads to browser storage and consumes downloads as streams instead of buffering the entire transfer in memory.

The Runtime tools drive a real Launch instance (the Editor's Launch button) so an agent can verify that a scene actually *runs*: screenshot the running app, read its console output, query live entity state, and inject keyboard/mouse/touch input. Allow pop-ups for the editor origin so `launch_start` can open the launch window — it reuses your existing PlayCanvas login session.
The Runtime tools drive a real Launch instance (the Editor's Launch button) so an agent can verify that a scene actually *runs*: screenshot the running app, read its console output, query live entity state, and inject keyboard/mouse/touch input. Allow pop-ups for the editor origin so `launch_start` can open the launch window — it reuses your existing PlayCanvas login session. The Editor relays `runtime:*` calls to that window, so it needs no local access permission of its own. Calling `launch_start` with no options adopts an app that is already running (`adopted: true` in the response) instead of restarting it; pass any option to force a fresh launch.

Every tool returns a consistent `{ data, meta }` envelope: `meta.status` is `ok` or `error` (with an actionable message), list tools paginate via `limit`/`offset` and `meta.nextCursor`, and mutating tools return the resulting entity/asset summaries so follow-up list calls are rarely needed.

Expand Down
7 changes: 4 additions & 3 deletions src/tools/runtime.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { z } from 'zod';

import { LAUNCH_HINT } from '../wss.ts';
import type { WSS } from '../wss.ts';

const DEFAULT_READY_TIMEOUT = 20_000;
Expand All @@ -11,8 +12,8 @@ export const register = (server: McpServer, wss: WSS) => {
{
description: [
'Start a real Launch runtime instance of the current scene (the editor\'s Launch button) so scripts, physics, animation and input actually run.',
'Opens the launch page in a new browser window with debug logging on; that page connects back automatically as the runtime peer.',
'Returns { url, sceneId, ready } where ready=true means the runtime is connected and capture_runtime / read_runtime_logs are usable.',
'Opens the launch page in a new browser window with debug logging on; the editor bridges it automatically.',
'Returns { url, sceneId, ready, adopted } where ready=true means the runtime is usable by capture_runtime / read_runtime_logs, and adopted=true means it attached to an app that was already running instead of starting a new one (which happens only when no options are passed, so pass an option to force a fresh launch).',
'This is the prerequisite for all runtime tools. If ready=false, the page may still be loading or popups were blocked; poll read_runtime_logs or retry.',
'When NOT to use: to screenshot the editor (use capture_viewport); to change the scene (edit-time tools).'
].join(' '),
Expand Down Expand Up @@ -45,7 +46,7 @@ export const register = (server: McpServer, wss: WSS) => {
return wss.ok(
'launch:start',
data,
ready ? undefined : { hint: 'Runtime did not connect in time. The launch page may still be loading (poll read_runtime_logs), or popups are blocked for the editor origin.' }
ready ? undefined : { hint: `Runtime did not connect in time. The launch page may still be loading (poll read_runtime_logs). ${LAUNCH_HINT}` }
);
} catch (err) {
return wss.fail('launch:start', err instanceof Error ? err.message : String(err));
Expand Down
Loading