Load the God's Eye View panel through the MCP server

Hosts serve panels from their own sites and may refuse other addresses;
Codex refuses any address on the user's machine. The panel now never
requests the app's server: it loads the app's panel build and data
through panel_request, a tool only the panel may call, which requests
the path from the app's server. One path in every host; only map
providers load directly.

npm run build:panel writes the panel build to dist/panel, served at
/panel/: one app script, one stylesheet, Cesium's script, and Cesium's
workers as one script Cesium runs from memory. Tools may now be marked
app-only. The panel CORS rules are gone.
This commit is contained in:
Sameh Khamis committed 2026-10-02 18:29:42 -07:00
1 parent b11d54d8b8
commit 996b95eb45
20 files changed
+1265 -437

No files matched your search

+52
View File
@@ -0,0 +1,52 @@
#!/usr/bin/env node
/**
* Build the MCP Apps panel: the app under dist/panel, served at /panel/.
* See build/panel.js.
*/
import { readdir, rename, rm, writeFile } from 'node:fs/promises';
import { join } from 'node:path';
import { fileURLToPath } from 'node:url';
import { build as esbuild } from 'esbuild';
import { build } from 'vite';
import standaloneConfig from '../server/standalone/vite.config.js';
import {
PANEL_BASE,
PANEL_OUT_DIR,
PANEL_WORKERS_PATH,
panelBuildConfig,
workersEntrySource,
} from '../build/panel.js';
const root = fileURLToPath(new URL('../', import.meta.url));
const outDir = join(root, PANEL_OUT_DIR);
const cesiumWorkers = join(root, 'node_modules/cesium/Build/Cesium/Workers');
const config = standaloneConfig({ command: 'build', mode: 'production' });
await build({
configFile: false,
root,
...panelBuildConfig(config),
});
// Cesium's plugin copies its files under the base path inside outDir.
const nested = join(outDir, PANEL_BASE, 'cesium');
await rm(join(outDir, 'cesium'), { recursive: true, force: true });
await rename(nested, join(outDir, 'cesium'));
await rm(join(outDir, PANEL_BASE.split('/')[1]), { recursive: true });
const names = (await readdir(cesiumWorkers))
.filter((file) => file.endsWith('.js') && !file.startsWith('chunk-'))
.map((file) => file.slice(0, -3));
const entry = join(outDir, 'cesium', 'workers-entry.js');
await writeFile(entry, workersEntrySource(names, cesiumWorkers));
await esbuild({
entryPoints: [entry],
bundle: true,
format: 'iife',
minify: true,
outfile: join(outDir, PANEL_WORKERS_PATH),
logLevel: 'warning',
});
await rm(entry);
console.log(`Panel build written to ${PANEL_OUT_DIR}`);
+4 -2
View File
@@ -31,7 +31,8 @@
"modules": [
"build/vite.js",
"build/application-html.js",
"build/embed-framing.js"
"build/embed-framing.js",
"build/panel.js"
],
"external": ["vite-plugin-cesium"]
},
@@ -3140,7 +3141,8 @@
"src/data/installationFeedback.js",
"src/view/index.js",
"src/tools/views.js",
"src/tools/globePanel.js"
"src/tools/globePanel.js",
"src/tools/queries/panelRequest.js"
],
"external": ["satellite.js"]
},