Serveur MCP SSWorld
Commit 19 oct. 2026Permet aux agents IA de concevoir, compiler, rendre et inspecter des scènes géographiques 3D via WebGPU avec une illumination globale par lancer de rayons.
Aussi connu sous DataArche/SSWorld
- Étoiles
- 5
- Outils
- 13
- Téléchargements, 30 jours
- —
- Dernière version
- —
- Dernier commit
- 19 oct. 2026
- Licence
- Apache-2.0
Qu'est-ce que SSWorld MCP ?
SSWorld est un serveur MCP. Permet aux agents IA de concevoir, compiler, rendre et inspecter des scènes géographiques 3D via WebGPU avec une illumination globale par lancer de rayons. Il expose 13 outils, comme ssworld_catalog, ssworld_project_list, ssworld_project_create.
Résumé généré à partir du README du projet
À propos du MCP server SSWorld
SSWorld permet de créer et d'inspecter des scènes géographiques 3D via un agent IA. Ce MCP server permet aux développeurs d'utiliser des agents tels que Claude Code, Cursor ou Codex pour concevoir, compiler et rendre des environnements complexes en utilisant le SSDL, un langage de description de scène similaire au QML. Le système fonctionne sur le runtime WebGPU de SSEngine, offrant une illumination globale par lancer de rayons en temps réel, des ciels atmosphériques et des ombres au sein d'un aperçu par navigateur.
Les utilisateurs interagissent avec le serveur localement en l'installant via npm, ce qui enregistre le serveur auprès de l'application agent choisie et télécharge le moteur nécessaire. Contrairement aux simples générateurs de scènes, ce serveur fournit une boucle de rétroaction permettant à l'agent de réellement voir son travail. Grâce à l'outil ssworld_capture_frame, l'agent reçoit des données visuelles incluant les percentiles de luminance, la couverture de couleurs et les écarts de pose de la caméra. Cela permet à l'IA de détecter des problèmes, comme un ciel mal teinté, et de les corriger de manière autonome sans intervention humaine.
Ce que vous pouvez faire avec
- 1Débogage visuel automatiséUn agent peut inspecter une image rendue pour détecter des erreurs de couleur et corriger automatiquement le code de la scène.
- 2Génération procédurale de villesLes développeurs peuvent ordonner à un agent de reconstruire des paysages urbains entiers en utilisant les données OpenStreetMap.
- 3Ancrage de scènes géographiquesCréez des modèles 3D positionnés précisément sur un terrain mondial en utilisant la longitude et la latitude.
- 4Ajustements d'éclairage en temps réelUn agent peut manipuler l'horloge du moteur pour simuler différents moments de la journée et observer les changements de luminosité.
Extrait du README du projet. Chaque cas d'utilisation est vérifié par rapport à une citation du document.
Outils MCP SSWorld 13
Détectés depuis le READMEssworld_catalogssworld_project_listssworld_project_createssworld_source_patchssworld_source_batchssworld_scene_inspectssworld_compilessworld_previewssworld_capture_framessworld_environment_readssworld_geo_readssworld_geometry_read
| ssworld_catalog | — | |
| ssworld_project_list | — | |
| ssworld_project_create | — | |
| ssworld_source_patch | — | |
| ssworld_source_batch | — | |
| ssworld_scene_inspect | — | |
| ssworld_compile | — | |
| ssworld_preview | — | |
| ssworld_capture_frame | — | |
| ssworld_environment_read | — | |
| ssworld_geo_read | — | |
| ssworld_geometry_read | — |
Afficher les 13 outilsAfficher moins d'outils
ssworld_engine_status
| ssworld_engine_status | — |
Vérifications automatisées
Exécuté le 14 nov. 2026Rapport complet →Pas encore vérifié. Un serveur nécessite un score de 80, aucune faille sérieuse et suffisamment de données pour que nous puissions effectuer les vérifications. Fonctionnement des vérifications · Ce qu'il faut corriger pour gagner des points
- Dépôt source lié et accessibledataarche/ssworld is public and reachablegithub.com/dataarche/ssworld ↗Réussi
- Le nom du package correspond au dépôt sourceNon vérifié
- Provenance du build (attestation Sigstore)Non vérifié
- Licence open source (OSI)Apache-2.0spdx.org/licenses/Apache-2.0.html ↗Réussi
- Commit ou version publiée au cours de l'année écouléeLast commit or release 2026-10-19github.com/dataarche/ssworld ↗Réussi
- OpenSSF ScorecardNon vérifié
- Nom du package non proche d'un package populaireNon vérifié
- Aucun avis critique dans le package ou ses dépendancesNon vérifié
- Aucune instruction cachée destinée au modèle13 tool descriptions and the README read; no override phrases, credential paths or hidden charactersRéussi
- Les outils destructifs sont étiquetésNo tool named like delete, drop or execRéussi
- Le point de terminaison distant répond à la poignée de main MCPNon vérifié
README
Voir sur GitHubSSWorld — WebGPU ray tracing and global illumination (GI)
Agents can't see what they render. SSWorld closes the loop.
An MCP server that lets any MCP-capable agent app (Claude Code, Codex, Hermes, Cursor …) author, compile, render and inspect 3D geographic scenes — written in SSDL, a QML-like scene description language — on the SSEngine WebGPU runtime. The picture above is Lumen Gallery: an interactive architectural courtyard with sunlit timber vaults, metal reflections and ray-traced global illumination (GI). Its English interface lets visitors compare GI on/off, switch between 16:00 and 22:00, and explore three views. Lumen Gallery is this project's showcase name; it is not an integration of Unreal Engine Lumen.
Why this is not another scene generator
- A real engine, not a preview. Deferred rendering, atmospheric sky, shadows, post-processing, glTF assets, GPU instancing. Scenes stand on a real globe: terrain, imagery layers, 3D Tiles and GeoJSON, anchored by longitude and latitude. 60 fps with hundreds of thousands of instanced objects.
- Ray-traced GI in the browser. WebGPU software ray tracing adds indirect light and reflections to the scene. Compare it against raster lighting without changing the camera or materials; the gallery also uses the engine clock to move the sun and transition to night.
- The agent gets the frame back.
ssworld_capture_framerenders through the engine and returns luma percentiles, exposure tails, colour coverage per 3×3 region, top colours, the camera pose it actually used and the deviation from the one requested — plus a receipt binding the frame to the source digest and the answering page. An agent can tell that its sky came out orange-brown, and fix it, without a human looking. - Traps that cost a real session become compile errors. Every failure below was first hit on real
hardware, where it showed up as a blank page with nothing in the log. Each one now names the node
and the member at compile time: a sky tinted through
rayleighScattering, aLatheradius of 0, anormalMapon geometry without tangents, aheightslist counted as cells instead of corners.
Examples
| Lumen Gallery | GuanlanRoadTemplate0924 | SkylineGarden0919 | DaxiongHall0924 |
|---|---|---|---|
| An English interactive gallery: ray-traced GI on/off, sunlit architecture, reflections, furnished close-ups and an engine-clock day/night transition. | Real streets rebuilt from OpenStreetMap by a reusable pipeline: point it at another bbox and it builds that site. | An original procedural city with traffic, signals, a train, park life, fountains and a day–night cycle. | A Chinese temple hall — double eaves, bracket sets, marble terrace, incense smoke — with a cinematic camera tour. |
Start with Lumen Gallery: its editable SSDL, English interface and about 6.7 MB of model and
texture assets are included, with no asset-generation step. The other three examples carry sources
and generators and are each under 400 KB. The gallery includes CC0 Poly Haven textures; Guanlan
fetches © OpenStreetMap contributors' street data under
ODbL. See examples/ for setup and credits.
Install (one command)
npx -y ssworld-mcp install
This installs the package globally, registers the ssworld MCP server with every agent app it finds
(--client=claude,codex,hermes,cursor,dsh to choose), and downloads the pinned engine (≈54 MB) into ~/.ssworld/engine/.
Requirements: Node.js ≥ 22, npm, a WebGPU browser (Chrome/Edge) to look at previews.
Or install as a native plugin
Claude Code and Codex both read plugin manifests straight out of this repository, so one command registers the MCP server and the SSDL authoring skill with no global npm install. The pinned engine still downloads on the first preview.
# Claude Code
/plugin marketplace add DataArche/SSWorld
/plugin install ssworld@ssworld
# Codex
codex plugin marketplace add DataArche/SSWorld
codex plugin add ssworld --marketplace ssworld
Hermes, Cursor and DSH have no plugin package that can carry an MCP server — each registers servers
in its own config — so ssworld-mcp install is the native path there and writes exactly what that
host reads: mcp_servers: in ~/.hermes/config.yaml, mcpServers in ~/.cursor/mcp.json, and an
@deepseek-ai/dsh-mcp-client row in DSH's user patch layer ~/.dsh/cordis.patch.yml. Hermes and DSH
also get the skill copied into their own skills/ directory, which is the whole registration.
npx -y ssworld-mcp install --client=hermes,dsh
Manual registration for any other client:
{ "mcpServers": { "ssworld": { "command": "node", "args": ["<npm root -g>/ssworld-mcp/bin/ssworld-mcp.mjs"] } } }
Tools
| tool | purpose |
|---|---|
ssworld_catalog |
component index / one contract / components: [...] in one call (detail: compact hoists shared members); catalog_digest + if_digest for cache hits; units and rotation conventions annotated per member |
ssworld_project_list |
projects in ~/.ssworld/projects |
ssworld_project_create |
new runnable project (anchored at lon/lat/height), compiled |
ssworld_source_read / ssworld_source_write |
bounded reads (max_chars, offset/limit with has_more/next_offset; mode: metadata for digests, sizes and compile staleness without text; node: "<id>" for one block; file: "*" for all files) and whole-file writes of .ssdl sources; editing the files on disk with any tool also works (ssworld_compile rebuilds from disk) but bypasses the digest lock |
ssworld_source_patch |
exact-span edit (old_string → new_string, uniqueness checked, replace_all opt-in) with the same digest guard |
ssworld_source_batch |
atomic multi-edit: text patches and node-level {node_id, set, unset} across files; all validated in memory before anything is written; validate: compile + rollback restores the previous sources on a failed compile |
ssworld_scene_inspect |
compiled-scene facts without rendering: budget ratio, subtrees by size, leaf children by type, nodes per source file, primitive extent, the requested camera (lookAt-derived heading/pitch); render stats honestly unavailable |
ssworld_compile |
SSDL 0.3 compiler with real diagnostics, node_count, budget usage and logic (declared properties, states, host calls); catalog/runtime mismatches are compile errors (Label without a font, material animations on a Group/Model, undeclared host calls) |
ssworld_preview |
starts the local preview server, returns http://127.0.0.1:8880/projects/<name>/index.html, whether the page is open, page.clients (every browser syncing the page: id, visibility, canvas, user agent) and a structured next (open_webgpu_viewer / capture_frame / bring_page_to_front) |
ssworld_capture_frame |
screenshot of the open preview through the engine (saveImage2Base64); stats with luma percentiles, exposure tails, colour-class coverage overall and per 3×3 region, top colours; runtime errors deduplicated and mapped to scene.ssdl:line:column; camera pose with `source: scene |
ssworld_environment_read |
ask the engine what it actually received for the environment: the adopted sun's direction read back from the native sun and converted to azimuth/elevation at the anchor (with the deviation from the scene's request), which DirectionalLight drives the atmosphere, and every environment component's live native values. The probe lives in the project's index.html, which is project-owned, so a page created before 0.9.8 answers page_probe_unavailable and the error names the handler to paste in |
ssworld_geo_read |
ask the engine what it holds for the geographic layers: whether the terrain provider loaded, anchor_above_terrain_m (how far the scene's local z: 0 sits above the ground under the anchor, because terrain moves the ground and not the scene), the imagery stack in real draw order with each layer's native_index, and every Tileset / GeoJsonLayer's readiness, extent and feature count. Same project-owned probe as the environment read, so an older index.html answers page_probe_unavailable |
ssworld_geometry_read |
measure the scene from the engine instead of a screenshot: every geometry node's and Model's dimensions (object axes, metres), world position/rotation/scale composed through the live scene graph, axis-aligned world_bounds (tight or an envelope), ground contact (on / buried / above z = 0, and a Box is centred on its position so z: 0 buries half of it), mesh facts the engine measured (vertex/triangle counts, closed, manifold, area_m2 / volume_m3); Groups and GeoAnchors as the union of their descendants, Instances as the native union, the scene as its whole extent; overlaps: true lists intersecting boxes with the overlap volume, ids narrows, detail: brief trims. Same project-owned probe, so an older index.html answers page_probe_unavailable |
ssworld_logic_read / ssworld_logic_write |
read the open page's scene logic (and whether the scene module actually mounted: runtime.state plus errors mapped to scene.ssdl:line) without a screenshot, or set declared properties in one transaction ({set: {p: 0.4, pace: 0.0025}}) to put a game into a situation before capturing; a refused value rolls the whole set back and names the failing binding |
ssworld_engine_status |
engine pair installed? (install: true to download) |
How big a scene, measured
Budgets are per-project values in showcase.manifest.json; the defaults and the ceilings come from
src/ssdl/tools/probe_engine_limits.py (which asks every facade for its own capabilities()) and
src/ssdl/tools/probe_scale_limits.py (which raises the budgets and builds a scene past them on real
hardware). Defaults: 4096 native objects / 4096 material shells / 32 distinct images / 4096 bindings
/ 2048 handlers / 256 timers / 256 timelines / 1024 Group locators / 1024 Prefabs / 524288 instance
rows. Four of those are the engine's own and a manifest cannot raise them (resolveBudgets clamps
distinct images, timers, timelines and Group locators), because a scene past them compiles and then
fails to mount.
What actually runs out, in order:
- Not rendering. 6401 native objects with 409 600 instance rows across 200 prefabs compiled in 1.2 s, mounted in 4.0 s and ran at 61 fps with no runtime errors.
ssworld_capture_framefirst. The offscreen readback dies of a wasm "memory access out of bounds" somewhere between 4001 native objects (captures,render_verified, ~21k distinct colours) and 5001 (does not). Past roughly 4000 nodes a scene runs and cannot be screenshotted, which is whynative_objectssits just under that and why instancing — 409 600 rows for 200 native objects — is the way to build something large. The capture timeout is now the caller's to set: the page used to give the readback a fixed 8 s whatevertimeout_mssaid, so a scene big enough to be worth a screenshot always timed out.- Bindings used to be the hard wall, and are not any more.
AnimationFacade.captureBatchrefuses a batch of more than 64 items and refuses it whole, so a scene whose first frame carried 65 bindings failed to mount with a receipt that said "evaluated 65, committed 0, failed 65" and named nothing — while the shipped budget said 256. The runtime now flushes bindings in chunks of 64 and restores the chunks that already landed if a later one fails, so the flush stays all-or-nothing to the author. Measured after the fix: 1500 bindings + 600 handlers + 914 locators mount in 2.2 s at 44 fps.
Three engine ceilings have no budget dimension and are compile errors of their own:
scene_depth_exceeded (SceneGraphFacade.max_depth, 16 levels of nesting), model_budget
(ModelFacade.max_model_instances, 256 Model mounts, 1 GiB of distinct glb bytes — use one as a Prefab source instead of a copy
per placement) and texture_budget (MaterialFacade.max_texture_bytes_total, 64 MiB of GPU texture
memory: each distinct image resized to a power of two, block-compressed with its mips -- about 1 MiB per
1024² image, whatever the file size -- and no side above 4096 px).
Authoring reference
Colours are authored as sRGB
#rrggbb is read as sRGB — the value a colour picker gives you. The runtime converts it to linear before handing it to
the engine, so the frame shows the colour that was picked and reading the value back returns the same hex. Before 0.9.8
that conversion was missing and every flat colour rendered roughly three times too bright (#16260f came out as a light
green). Native materials keep 8 bits of linear light per channel, so very dark colours quantise: #16260f reads back
as #16260d, and anything below about #0a0a0a collapses towards black. Verified on real hardware with
src/ssdl/tools/probe_color_space.py (headless Chromium + WebGPU, frames captured through the engine).
What the compiler refuses
Several failures that used to surface only as a dead page are now compile errors naming the node and the member:
sky_scattering_refused—SkyAtmosphere'srayleighScattering,mieScattering,mieAbsorption,otherAbsorptionandskyLuminanceFactorare normalised direction vectors, not colours (their magnitude lives in the neighbouring*Scale). Writing a "neutral-looking" vector raises red and turns the whole sky orange-brown. Tint through the sun'slightColorinstead; the error text carries each member's real engine default.cloud_kilometres_expected—VolumetricCloud'slayerBottomAltitude,layerHeight,tracingStartMaxDistance,tracingMaxDistanceandshadowTracingDistanceare in kilometres, the unit UE uses for this component, while the rest of SSDL is in metres. Metre values do not merely misplace the deck: the ray-march sample count is fixed (min(96 x viewSampleCountScale, 768)) and does not grow with the tracing distance, so a ray stretched a thousandfold aliases the cloud noise into vertical white streaks across the sky. A deck islayerBottomAltitude: 1.8; layerHeight: 0.5.mesh_degenerate— a radius of 0 in aLatheprofile, exactly repeated adjacent points, aTubeorSweeppath that doubles back or repeats a point, two identical adjacentLoftrings, aMeshface with zero area, a ring with no area. These producedGeometryFacade.createMesh: triangle is degenerateand took the entire scene module down without naming a node. (A vertical firstTubesegment is fine: the parallel-transport frame switches reference axis at|tangent.z| >= 0.9.)mesh_invalid— a parameter outside its range or a shape the generator cannot build: aSweepprofile or anExtrudedPolygonoutline that crosses itself, ataper/bevelthat eats an edge (the message names the edge), aMeshface index out of range, aRooffootprint that crosses itself or whose skeleton cannot be closed (the message names the edge to simplify),ridgeon a polygonRooforgables/lowEdgeon a quadrilateral one,Capsulewithheight <= 2 * radiusor a segment count not divisible by four,sampleswithoutsmooth: "catmullrom",capon a closedLoft.placement_invalid—Instancesmembers that belong to another placement mode, aringwithout a positiveradius,along_pathwith both or neither ofstep/count, more than 512 instances in one batch, orfaceCenter/alignToPathnext to an explicit rotation member.spawnable_invalid— apragma spawnablecomponent that cannot be one: a root that is not a singleGroup, apropertyoutsidereal/bool/string/length/degrees/durationor one without a default (the default is what the fragment's budget and mesh limits are checked against), a scene singleton (Camera,Environment,Globe, a light that owns the sun, a geographic layer), aKeyHandlerorPointerHandler(both claim the whole window), or aModel(it loads asynchronously, andapi.scene.spawnreturns a live handle in the same turn). The entryscene.ssdlitself cannot be spawnable.spawn_budget/spawn_parameter_invalid/spawn_parameter_immutable/spawn_handle_unknown/spawn_placement_invalid— runtime refusals fromapi.scene.spawn_budgetnames the dimension and shows static + already-spawned + this copy against the manifest limit, and nothing is built.spawn_parameter_immutablemeans the parameter feeds acreate_onlymember, so changing it isdispose+spawn, notset.spawn_replay_failed— a hot reload replayed the spawn log into the new generation and one entry no longer fits the component as it was edited. It does not stop the mount; the entries are inssworld_logic_readunderdynamic.spawn_failures, and the objects they named are simply gone.runtime_unsupported—Label(no font),sunAzimuth/sunElevationwithoutatmosphereSunLight: true, and the members a light may not write in the mode it is in.multiple_writer/environment_duplicate— anEnvironmentowns the sun direction, so aDirectionalLightthat also pinssunAzimuth/sunElevation, or aSunSkybeside it, is refused rather than left to a last-writer-of-the-frame race; and the scene-globalEnvironmentslot takes exactly one claimant.sky_light_capture_owned—SkyLight.realTimeCapture: falsebeside anEnvironment. TheEnvironmentowns the sky light capture and keeps it running, so thefalsewould be a no-op; it is refused with the reason instead.material_requires_tangent— anormalMapon geometry without tangents (onlyHeightField/Lathe/Tube/Lofthave them).value_out_of_range—emissiveColoroutside its[r, g, b]0..16 range.
List values may span lines since 0.9.8: a newline after sections: [, one ring per line and comments inside the
brackets all compile. A property still ends at a newline or ;, so this only applies inside [ ].
Procedural geometry
Four parametric generators compile to constant parameters and are tessellated by the runtime (MeshData/v1, ccw outward,
≤ 65535 vertices per node, mesh_budget beyond): HeightField { width; depth; columns; rows; heights }
(columns/rows count cells, heights counts the (columns+1)*(rows+1) corners around them — row-major from -depth/2),
Lathe { profile: [[radius, 0, height] …]; segments; closed }, Tube { path; radius; segments; closed },
Loft { sections: [[ring] …]; cap }. ssworld_compile reports their cost as usage.mesh. There are no per-vertex
functions: arbitrary meshes are managed assets (Model).
Geographic layers
Every scene already stands on the globe at its manifest anchor; four components let it reach the globe
itself, all of them direct children of Scene with no transform of their own (geographic longitude/latitude
and the scene's local ENU metres are two different worlds, and SSDL does not pretend otherwise):
Globe { id: earth; terrain: "default"; lighting: false }
ImageryLayer { id: base; source: "https://<your tile service>/{z}/{x}/{y}.png"; webMercator: true }
Tileset { id: city; source: "https://<host>/tileset.json"; offset: [0, 0, -12] }
GeoJsonLayer { id: parks; source: "assets/parks.geojson"; geometry: "polygon"; fillColor: "#2e7d32" }
Globe— terrain, ground colour, opacity and lighting; at most one, and the last scene to write it hands the globe back as it found it on unload.ImageryLayer—kind: "xyz" | "wms" | "arcgis" | "single". Draw order is declaration order, the first layer being the base map;visibleandalphacan be bound and animated by scene logic. At most 8.Tileset— 3D Tiles, or a Gaussian splat set withsplat: true.offset/rotation/scaletransform the tileset's own root (offset.zis the height correction most datasets need). This engine has nomaximumScreenSpaceError;geometricErrorScale(0.2–12) is the LOD dial. At most 4.GeoJsonLayer— one layer draws one kind of feature (geometry: "polygon" | "line" | "point"). The document is a managedassets/*.geojsonwhose geometry is checked againstgeometryat compile time, or a remoteurlthe page fetches — a cross-origin server withoutAccess-Control-Allow-Originreportsgeojson_fetch_failedinstead of leaving a silently empty layer. Polygons are filled: withextrudeHeightFieldthey become solid blocks, without it a flat plane. At most 8.
Terrain moves the ground, not the scene: local z: 0 stays at the anchor's ellipsoid height, so a scene built
flat can end up buried in a hillside the moment terrain loads. ssworld_geo_read answers with
anchor_above_terrain_m, the imagery stack in real draw order and each layer's readiness. No basemap ships
with this server — a tile service carries terms and often a key, and neither is ours to accept for you;
"template": "geo" lays out the scene with the ImageryLayer line commented out, waiting for a URL.
Questions sur SSWorld MCP
Quels outils SSWorld MCP fournit-il ?
Il expose 13 outils, dont ssworld_catalog, ssworld_project_list, ssworld_project_create, ssworld_source_patch, ssworld_source_batch.
Que peut faire un agent avec SSWorld ?
Un agent peut concevoir, compiler, rendre et inspecter des scènes géographiques 3D écrites en SSDL sur le runtime WebGPU de SSEngine.
Comment l'agent sait-il si le rendu est correct ?
L'agent peut utiliser l'outil capture frame pour recevoir les percentiles de luminance, les queues d'exposition, la couverture de couleurs et les données de pose de la caméra afin de vérifier le résultat visuel.
SSWorld prend-il en charge les données géographiques réelles ?
Oui, les scènes peuvent être ancrées par longitude et latitude et inclure du terrain, des couches d'imagerie, des 3D Tiles et du GeoJSON.
Quels sont les prérequis système pour l'installation ?
Vous avez besoin de Node.js version 22 ou supérieure, de npm et d'un navigateur compatible WebGPU comme Chrome ou Edge pour visualiser les aperçus.
