Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
3055221
feat(mcp): add MCP servers for Babylon.js graph editors
RaananW Apr 20, 2026
3cc2e4f
formatting
RaananW Apr 20, 2026
0a7a506
fix(mcp): resolve CI test failures
RaananW Apr 20, 2026
8a58870
lint part 1
RaananW Apr 20, 2026
4ccd8f9
fix: resolve all lint errors on mcp/graph-servers branch
RaananW Apr 20, 2026
91973b8
formatting
RaananW Apr 20, 2026
acd5771
fix(mcp/nrge): fix 5 className casing bugs and add 3 missing blocks
RaananW Apr 20, 2026
470c2ff
fix(mcp): add missing blocks to Flow Graph (24) and NGE (1) registries
RaananW Apr 20, 2026
bbf3554
fix(mcp): resolve CI failures — TS baseUrl deprecation, lint errors, …
RaananW Apr 20, 2026
c618f4d
revert: undo unrelated barrel-import lint fixes in dev/core and dev/l…
RaananW Apr 20, 2026
52a55ee
revert: undo remaining unrelated lint fixes in dev/ packages
RaananW Apr 20, 2026
a0b6250
chore: remove .vscode/mcp.json from PR
RaananW Apr 20, 2026
0fb8b33
Merge remote-tracking branch 'upstream/master' into mcp/graph-servers
RaananW Apr 29, 2026
3559554
fix(playground): remove MCP session UI integration
RaananW Apr 29, 2026
5bf0086
Merge remote-tracking branch 'upstream/master' into mcp/graph-servers
RaananW Apr 29, 2026
3f39437
feat(mcp): add shared editor session server
RaananW May 20, 2026
7af701d
feat(mcp): share editor session connector
RaananW May 20, 2026
7a72a2f
feat(mcp): add node particle sessions
RaananW May 20, 2026
e00c453
feat(mcp): add shared session controller
RaananW May 20, 2026
543de9e
feat(mcp): add node render graph sessions
RaananW May 20, 2026
e867c74
feat(mcp): add gui editor sessions
RaananW May 20, 2026
56010d3
feat(mcp): add flow graph sessions
RaananW May 20, 2026
63fd3d1
feat(mcp): add smart filter sessions
RaananW May 20, 2026
57441e4
feat(mcp): add session server discovery helpers
RaananW May 20, 2026
4fa133a
feat(mcp): add session server identity metadata
RaananW May 20, 2026
42955a6
test(mcp): cover session server reuse decisions
RaananW May 20, 2026
9851914
fix(mcp): restrict session server cors
RaananW May 20, 2026
b2c1b0e
feat(mcp): expose session conflict metadata
RaananW May 20, 2026
170f573
feat(mcp): add session server diagnostics
RaananW May 20, 2026
f223c6d
chore(mcp): quiet server build warnings
RaananW May 20, 2026
53ce2bb
Merge remote-tracking branch 'upstream/master' into mcp/graph-servers
RaananW May 20, 2026
c88dbb8
chore(mcp): remove gltf server
RaananW May 20, 2026
cd0387d
feat(mcp): add idle timeout feature to editor session server
RaananW May 21, 2026
7d7aa8f
feat(mcp): add public servers package
RaananW May 21, 2026
4e681df
Merge remote-tracking branch 'upstream/master' into mcp/graph-servers
RaananW May 21, 2026
6f883d8
feat(mcp): update server block coverage
RaananW May 21, 2026
5e89121
feat(mcp): update server block coverage
RaananW May 21, 2026
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
19 changes: 19 additions & 0 deletions .github/instructions/mcp-server-coverage.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
applyTo: "packages/dev/core/src/{FlowGraph,Materials/Node,Meshes/Node,FrameGraph,Particles/Node}/**/*.{ts,tsx},packages/dev/smartFilterBlocks/src/**/*.ts,packages/dev/gui/src/2D/controls/**/*.ts,packages/tools/{flow-graph-mcp-server,nme-mcp-server,nge-mcp-server,nrge-mcp-server,npe-mcp-server,smart-filters-mcp-server,gui-mcp-server}/**/*.{ts,tsx}"
---

# MCP Server Coverage

When adding, removing, or renaming a graph block or GUI control, update the matching MCP server registry or catalog in the same change:

- Flow Graph blocks: `packages/tools/flow-graph-mcp-server/src/blockRegistry.ts`
- Node Material blocks: `packages/tools/nme-mcp-server/src/blockRegistry.ts`
- Node Geometry blocks: `packages/tools/nge-mcp-server/src/blockRegistry.ts`
- Node Render Graph blocks: `packages/tools/nrge-mcp-server/src/blockRegistry.ts`
- Node Particle blocks: `packages/tools/npe-mcp-server/src/blockRegistry.ts`
- Smart Filters blocks: `packages/tools/smart-filters-mcp-server/src/blockRegistry.ts`
- GUI controls: `packages/tools/gui-mcp-server/src/catalog.ts`

Keep the MCP metadata aligned with the runtime block/control class name, serialized class name, public inputs, public outputs, configurable properties, and default serialized properties. If a block/control is intentionally omitted because it is abstract, a base class, editor-internal, or non-creatable, leave the omission clear in nearby registry comments or tests.

After changing coverage, run the affected MCP server tests or build and also rebuild `@babylonjs/mcp-servers` so the public package stays current.
22 changes: 22 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
"build:umd:tools": "nx run-many --outputStyle=static --target=build --parallel --maxParallel=2 --projects=babylonjs-inspector-legacy,babylonjs-node-editor,babylonjs-node-geometry-editor,babylonjs-node-render-graph-editor,babylonjs-node-particle-editor,babylonjs-gui-editor,babylonjs-inspector,create-babylonjs",
"build:es6": "npm run build:assets:smart-filters && npm run build:es6:libs && npm run build:es6:tools && npm run check:treeshaking-all",
"build:es6:libs": "nx run-many --outputStyle=static --target=build --parallel --maxParallel=6 --projects=@babylonjs/core,@babylonjs/gui,@babylonjs/loaders,@babylonjs/materials,@babylonjs/serializers,@babylonjs/post-processes,@babylonjs/procedural-textures,@babylonjs/viewer,@babylonjs/shared-ui-components,@babylonjs/addons,@babylonjs/accessibility,@babylonjs/ktx2decoder,@babylonjs/smart-filters,@babylonjs/smart-filters-blocks,@babylonjs/lottie-player",
"build:es6:tools": "nx run-many --outputStyle=static --target=build --parallel --maxParallel=2 --projects=@babylonjs/node-editor,@babylonjs/node-geometry-editor,@babylonjs/node-render-graph-editor,@babylonjs/node-particle-editor,@babylonjs/inspector-legacy,@babylonjs/gui-editor,@tools/smart-filters-editor-control,@tools/smart-filters-debugger,@tools/smart-filters-editor,@babylonjs/inspector",
"build:es6:tools": "nx run-many --outputStyle=static --target=build --parallel --maxParallel=2 --projects=@babylonjs/node-editor,@babylonjs/node-geometry-editor,@babylonjs/node-render-graph-editor,@babylonjs/node-particle-editor,@babylonjs/inspector-legacy,@babylonjs/gui-editor,@tools/smart-filters-editor-control,@tools/smart-filters-debugger,@tools/smart-filters-editor,@babylonjs/inspector,@babylonjs/mcp-servers",
"watch:shaders": "build-tools -c build-shaders --global --watch",
"watch:assets": "build-tools -c pa --global --watch",
"watch:assets:smart-filters": "npm run build:assets:smart-filters:prerequisites && node ./packages/dev/smartFilters/dist/utils/buildTools/watchShaders.js ./packages/dev/smartFilterBlocks/src/blocks smart-filters core",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
const DocumentRoute = "document";

/**
* Options used to open an MCP editor session event stream.
*/
export interface IMcpEditorSessionEventSourceOptions {
/** Base session URL, such as `http://localhost:3001/session/<id>`. */
sessionUrl: string;
/** Called whenever the server sends a document update. */
onDocument: (document: unknown) => void;
/** Called when the server explicitly closes the session. */
onSessionClosed: (reason: string) => void;
/** Called when the EventSource reports a connection error. */
onConnectionError: () => void;
}

/**
* Normalize a user-provided MCP editor session URL.
* @param sessionUrl - The URL entered by the user or returned by an MCP tool.
* @returns The URL without trailing slash characters.
*/
export function NormalizeMcpEditorSessionUrl(sessionUrl: string): string {
return sessionUrl.replace(/\/+$/, "");
}

/**
* Open an EventSource for server-to-editor MCP session updates.
* @param options - Event stream options and callbacks.
* @returns The opened EventSource. Call `CloseMcpEditorSessionEventSource` to disconnect it.
*/
export function OpenMcpEditorSessionEventSource(options: IMcpEditorSessionEventSourceOptions): EventSource {
const normalizedUrl = NormalizeMcpEditorSessionUrl(options.sessionUrl);
const eventSource = new EventSource(`${normalizedUrl}/events`);

eventSource.onmessage = (event) => {
try {
options.onDocument(JSON.parse(event.data));
} catch {
// Ignore malformed document updates and keep the live session open.
}
};

eventSource.addEventListener("session-closed", (event) => {
options.onSessionClosed(ReadSessionClosedReason(event));
eventSource.close();
});

eventSource.onerror = () => {
options.onConnectionError();
eventSource.close();
};

return eventSource;
}

/**
* Close an MCP editor session EventSource if one is active.
* @param eventSource - EventSource to close.
*/
export function CloseMcpEditorSessionEventSource(eventSource: EventSource | null | undefined): void {
eventSource?.close();
}

/**
* Post a document JSON payload to an MCP editor session.
* @param sessionUrl - Base session URL, such as `http://localhost:3001/session/<id>`.
* @param document - Serialized JSON document to send to the MCP server.
* @param legacyDocumentRoute - Optional compatibility route to try when `/document` is unavailable.
* @returns The final fetch response from the standard or compatibility route.
*/
export async function PostMcpEditorSessionDocumentAsync(sessionUrl: string, document: string, legacyDocumentRoute?: string): Promise<Response> {
const normalizedUrl = NormalizeMcpEditorSessionUrl(sessionUrl);
const response = await PostDocumentToRouteAsync(normalizedUrl, DocumentRoute, document);
if (response.ok || !legacyDocumentRoute || (response.status !== 404 && response.status !== 405)) {
return response;
}

return await PostDocumentToRouteAsync(normalizedUrl, legacyDocumentRoute.replace(/^\//, ""), document);
}

async function PostDocumentToRouteAsync(sessionUrl: string, route: string, document: string): Promise<Response> {
const headers = new Headers();
headers.set("Content-Type", "application/json");

return await fetch(`${sessionUrl}/${route}`, {
method: "POST",
headers,
body: document,
});
}

function ReadSessionClosedReason(event: Event): string {
try {
const data = JSON.parse((event as MessageEvent).data);
return typeof data.reason === "string" ? data.reason : "Session closed by MCP server";
} catch {
return "Session closed by MCP server";
}
}
48 changes: 48 additions & 0 deletions packages/public/@babylonjs/mcp-servers/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"name": "@babylonjs/mcp-servers",
"version": "9.8.0",
"description": "Bundled Model Context Protocol servers for Babylon.js authoring workflows",
"type": "module",
"bin": {
"mcp-servers": "dist/babylonjs-mcp-servers.js",
"babylonjs-mcp-servers": "dist/babylonjs-mcp-servers.js",
"babylonjs-flow-graph-mcp-server": "dist/flow-graph-mcp-server.js",
"babylonjs-gui-mcp-server": "dist/gui-mcp-server.js",
"babylonjs-nge-mcp-server": "dist/nge-mcp-server.js",
"babylonjs-nme-mcp-server": "dist/nme-mcp-server.js",
"babylonjs-npe-mcp-server": "dist/npe-mcp-server.js",
"babylonjs-nrge-mcp-server": "dist/nrge-mcp-server.js",
"babylonjs-smart-filters-mcp-server": "dist/smart-filters-mcp-server.js"
},
"files": [
"dist/**/*.*",
"readme.md"
],
"scripts": {
"build": "npm run clean && npm run build:servers && npm run copy:servers",
"build:servers": "npm run build -w @tools/mcp-server-core && npm run build -w @tools/nme-mcp-server && npm run build -w @tools/npe-mcp-server && npm run build -w @tools/nge-mcp-server && npm run build -w @tools/nrge-mcp-server && npm run build -w @tools/gui-mcp-server && npm run build -w @tools/flow-graph-mcp-server && npm run build -w @tools/smart-filters-mcp-server",
"clean": "rimraf dist",
"copy:servers": "node scripts/copyMcpServers.mjs"
},
"engines": {
"node": "^20.19.0 || >=22.13.0 <23.0.0"
},
"keywords": [
"3D",
"javascript",
"html5",
"webgl",
"babylon.js",
"mcp",
"model-context-protocol"
],
"license": "Apache-2.0",
"homepage": "https://www.babylonjs.com",
"repository": {
"type": "git",
"url": "https://github.com/BabylonJS/Babylon.js.git"
},
"bugs": {
"url": "https://github.com/BabylonJS/Babylon.js/issues"
}
}
73 changes: 73 additions & 0 deletions packages/public/@babylonjs/mcp-servers/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Babylon.js MCP Servers

`@babylonjs/mcp-servers` packages the Babylon.js Model Context Protocol servers as executable Node.js binaries. MCP-compatible clients can use these servers to create, edit, validate, import, export, and live-sync Babylon.js authoring graphs.

## Included Servers

| Server | Dispatcher name | Direct binary | Purpose |
| ------------------------ | --------------- | ------------------------------------ | ------------------------------------------------------------------------ |
| Node Material Editor | `nme` | `babylonjs-nme-mcp-server` | Node Material graph authoring and import/export workflows. |
| Node Geometry Editor | `nge` | `babylonjs-nge-mcp-server` | Node Geometry graph authoring and export/import workflows. |
| Node Render Graph Editor | `nrge` | `babylonjs-nrge-mcp-server` | Node Render Graph authoring and render-pipeline export/import workflows. |
| Node Particle Editor | `npe` | `babylonjs-npe-mcp-server` | Node Particle graph authoring and export/import workflows. |
| GUI Editor | `gui` | `babylonjs-gui-mcp-server` | Babylon.js GUI authoring, layout, export/import, and snippet flows. |
| Flow Graph Editor | `flow-graph` | `babylonjs-flow-graph-mcp-server` | Flow Graph authoring and coordinator JSON export/import workflows. |
| Smart Filters Editor | `smart-filters` | `babylonjs-smart-filters-mcp-server` | Smart Filters graph authoring and export/import workflows. |

## Run With npx

Use the dispatcher when you want a compact command:

```sh
npx -y @babylonjs/mcp-servers nme
```

Use direct binaries when your MCP client expects a command name:

```sh
npx -y -p @babylonjs/mcp-servers babylonjs-nme-mcp-server
```

## MCP Client Configuration

Most MCP clients accept a command plus arguments. This example starts the Node Material Editor MCP server through the dispatcher:

```json
{
"mcpServers": {
"babylonjs-node-material": {
"command": "npx",
"args": ["-y", "@babylonjs/mcp-servers", "nme"]
}
}
}
```

This equivalent form uses the direct binary:

```json
{
"mcpServers": {
"babylonjs-node-material": {
"command": "npx",
"args": ["-y", "-p", "@babylonjs/mcp-servers", "babylonjs-nme-mcp-server"]
}
}
}
```

## Live Editor Sessions

The graph MCP servers can start a local editor session server and return a session URL. Paste that URL into the matching Babylon.js editor's MCP session panel to see live updates from the MCP server and to push editor changes back to the MCP server.

The local editor session server binds to `127.0.0.1` by default. It stops when the MCP process exits, when the `stop_session_server` MCP tool is called, or after 15 minutes without MCP/editor activity.

## Local Development

From the Babylon.js repository, build the package with:

```sh
npm run build -w @babylonjs/mcp-servers
```

The build compiles the private MCP server workspaces and copies their bundled `dist/index.js` outputs into this package's `dist/` directory.
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#!/usr/bin/env node

import { spawn } from "node:child_process";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";

const serverAliases = new Map([
["flow-graph", "flow-graph-mcp-server.js"],
["flowgraph", "flow-graph-mcp-server.js"],
["gui", "gui-mcp-server.js"],
["nge", "nge-mcp-server.js"],
["node-geometry", "nge-mcp-server.js"],
["nme", "nme-mcp-server.js"],
["node-material", "nme-mcp-server.js"],
["npe", "npe-mcp-server.js"],
["node-particle", "npe-mcp-server.js"],
["nrge", "nrge-mcp-server.js"],
["node-render-graph", "nrge-mcp-server.js"],
["smart-filters", "smart-filters-mcp-server.js"],
["sfe", "smart-filters-mcp-server.js"],
]);

const [, , serverName, ...serverArguments] = process.argv;

if (!serverName || serverName === "--help" || serverName === "-h") {
printUsage();
process.exit(serverName ? 0 : 1);
}

const serverFile = serverAliases.get(serverName.toLowerCase());
if (!serverFile) {
console.error(`Unknown Babylon.js MCP server "${serverName}".`);
printUsage();
process.exit(1);
}

const distDirectory = dirname(fileURLToPath(import.meta.url));
const child = spawn(process.execPath, [join(distDirectory, serverFile), ...serverArguments], { stdio: "inherit" });

child.on("exit", (code, signal) => {
if (signal) {
process.kill(process.pid, signal);
return;
}

process.exit(code ?? 0);
});

child.on("error", (error) => {
console.error(error.message);
process.exit(1);
});

function printUsage() {
console.error(`Usage: babylonjs-mcp-servers <server>

Servers:
nme Node Material Editor
nge Node Geometry Editor
nrge Node Render Graph Editor
npe Node Particle Editor
gui GUI Editor
flow-graph Flow Graph Editor
smart-filters Smart Filters Editor
`);
}
Loading