accueil / serveurs / Médias / info.3dcms/mcp
info.3dcms/mcp
serveur MCP (Model Context Protocol) · 3dcms 1.3.0
Référencé dans l'annuaire. Seul le pentest comportemental fait foi, et il n'a pas encore été exécuté sur ce serveur.
Est-ce que info.3dcms/mcp est sûr ?
Au dernier audit MCP Hub, le serveur MCP « info.3dcms/mcp » est classé « Non encore testé ». Référencé dans l'annuaire. Seul le pentest comportemental fait foi, et il n'a pas encore été exécuté sur ce serveur. Le verdict est réévalué en continu ; consultez la fiche pour l'état à jour.
Méthode : MCP Hub analyse la description de chaque outil (couche 1) et, pour le verdict fort, exécute le serveur dans une micro-VM isolée avec leurres et réseau bloqué (couche 2). On publie des noms et des compteurs, jamais le contenu brut renvoyé par un outil.
Les 13 outils
- apply_ops≈ 14938 tokens
Use this to build or change a 3D scene: add rooms, text, pictures, links, models, lights, pages. Edit a scene by applying a batch of operations ATOMICALLY (all-or-nothing). Call this for any add / move / edit / delete / duplicate / group / reparent / re-material. Reference existing nodes ONLY by the id shown in get_scene — never guess ids. To create a node and then modify or parent it in the same batch, put a `tempId` on the add op and use that same string as the id/parentId of later ops. Each call is atomic and checkpointed: the owner can roll back in the editor (File > Version history). There is no undo over MCP; to reverse a call, apply the inverse ops. LARGE SCENES: ~40-50 objects per call; get_scene between batches. The result names what it CREATED (id, type, name) and may carry `warnings` (advisory lint and design fails): act on them next batch. READ FIRST: the `operations` field description opens with METHOD (ten steps every build follows, indoors and out: the person's own pictures first, library sets before flat colour, measure one then repeat, lay out by a rule, nothing floats, matte matted pictures, sunset light outdoors, frame the arrangement, look at the image, dark text on light walls), SURFACES AND TRIM, and BUILD RECIPES with measured numbers (yard gallery, park walk, walkthrough, room gallery), then the full op reference. Read it before your first build in a session.
Paramètres, retour & exemple (2)
ParamètressceneId· string · requis
Scene id from list_scenes.operations· array · requis
Ordered edit operations, applied atomically. REFERENCE: METHOD (every build, indoors or out: a room, a shop, a park, a product, a diagram. The recipes after it are worked examples with proven numbers, not the only things to build): 1) The person's own content first: fetch their page, take every real picture (photographs and artwork; never a logo, favicon, icon, or a generic share card used on several items) and upload_asset {url} them all in one parallel round before create_scene. Each image answer carries its width, height and aspect: cut every picture plane to that aspect. No address given? Ask for it once. 2) Library before placing anything: list_assets with kind and a short q for every surface and prop. A full set (baseColor + normal + ormh, matched by setId and mapRole) bound with worldScale on every ground, path, wall and trim; models by name. No flat colour on anything larger than a sign face. 3) Measure one, then repeat: place one of each model and one complete unit (frame + mat + picture + posts; sign + board + caption), read get_scene bounds and measure openings, screenshot the unit close up, then add the rest in one batch as duplicate ops off a tempId so they instance. 4) Lay out from a rule, not by eye: a half circle from a radius and a step angle (spread -75 to +75 degrees, never 180), a path as a sine centreline sampled every 1.5 m, trees by spacing with rejection near the path, every sign and picture turned to face the line of approach. Keep the walkway clear. 5) Nothing floats: posts under frames, a plinth under an object, a board behind a picture, a post or a bracket under a sign; real geometry, so the sun throws real shadows. 6) Pictures matted and matte: the image at its own aspect inside a mat (or a dark frame box 0.2 m larger, the picture 0.035 m proud of it), centre at 1.5 to 1.6 m, with materialMaps.roughness 1 (a number) beside its baseColor so a low sun cannot glare off it. Never stretch a frame model (no non-uniform scale): fill its opening with a mat and put the picture inside the mat. TAPS (item 13): frame, mat and picture go in one PRINT group with data.tap {action: "inspect"} and data.inspectLabel = the picture's title (the lightbox shows the framed print at its own aspect, titled); the stand around it (posts plus the print, or a sign board) is a STAND group with data.tap {action: "moveTo"}. The innermost tapped group wins, so a tap on the picture inspects and a tap on a post or board travels. The picture is a plane with materialMaps, not a webImage (a webImage keeps its own click). Pages and signs keep their link taps. 7) Light the place, not the object. OUTDOORS: settings lighting {timeOfDay: {source: "fixed", preset: "sunset"}, env: {intensity: 1.1}} (a preset stays sunset all year; never pin minutes), viewport {toneMapping: "aces"}, a pale warm fog matched to the sky (environment fogNear 30, fogFar 140), no lamps; another time only when the user asks or the scene calls for it (a night scene, a noon product shot). INDOORS: a closed room lit by its own key light, 2 to 4 times the fill; probe_lighting to check it rakes the texture. One accent colour, on the primary action only. 8) Frame the arrangement, larger and closer: the arrival eye 7 to 9 m from the middle of the arrangement, at 1.6 to 1.8 m, fov 50, lookAt the middle a little below the picture centres; at most five pictures in the arrival shot (more go further round, for the visitor to turn to); with an even count the middle of the arrangement is the GAP between the two middle pictures, so aim there. fitWidth only to the real width of the arrangement, never to squeeze a wide arc onto a phone. The way out is a small sign (scale 0.45 to 0.7) on its own post, low and to the side, at least 1 m from every stand, post and frame, aimed at the camera, and NOT the primaryActionId unless the scene exists to convert. For a set of equal things set settings.design.primaryActionId to the middle one, or call probe_framing with subject "set". 9) Look at the image: get_scene_screenshot, one view at the default 640 px; read every caption in it; fix glare, overlap, cut edges and covered subjects; one close-up of the most text-heavy thing; two fix rounds, then report. Use probe_framing's numbers (cut on 9:16, no exit within 12 m, eye too high) and reject a suggested pose aimed at one member of a set or at the ground. 10) Text that reads: webText draws WHITE (#ffffff) unless data.color is set and is anchored at its LEFT edge; on a light surface give it a dark data.color, size it by role (h1 0.5 m letters, h2 0.36, h3 0.26, body 0.17, caption 0.12), never by node scale (the margin pass sets maxWidth in the node's own units and does not count its scale) and not by a fontSize of your own (it did not take effect in testing); or use centred text3d. SURFACES AND TRIM: no bare flat colour on a floor, wall or ceiling. Every large surface wears a library set (materialMaps baseColor + normal + ormh with worldScale, the size of ONE TILE of the set, not of one board) or, with no set that fits, a materialPreset, with a visible roughness and colour step between floor and wall. Sets that fit, by list_assets q: "white oak wide plank" (floor boards, 5 boards a tile: worldScale 1.0; "plank" alone lists 60 distressed sets first), "skim coat plaster pale gray" (walls, worldScale about 1), "dense green grass" (lawn, worldScale 2.5), "pea gravel" (paths), "flagstone" (paving; tile ground with BOXES or planes, since worldScale on a cylinder streaks its cap). Finish a room the way a builder would: a white ceiling (a thin box, depth 0.05, matte white), glossy white crown moulding (roughness 0.15, metalness 0, about 0.08 m tall and 0.05 m proud) along every wall at the ceiling, a baseboard (a 0.1 m by 0.015 m box) along every wall at the floor, door and window casings, a frame around every picture. A plinth has a top edge, a shelf a lip, a sign a post or a bracket. BUILD RECIPES (worked examples; their numbers are measured): YARD GALLERY (an open-air gallery of the user's pictures; the first build for "a gallery of the pictures on my site"): a 80 x 80 m ground box 0.1 m deep with the grass set at worldScale 2.5; the arrival eye at the CENTRE of the arc, (0, 1.7, 0), and one stand group per picture on the arc around it, radius 8 m, so every picture is 8 m from the eye and faces it. Five pictures (an odd count puts one dead centre): angles t = -30, -15, 0, 15, 30 degrees; with an even count the angles straddle 0 (for six: -37.5, -22.5, -7.5, 7.5, 22.5, 37.5) and the camera aims at the gap. Each group at (8 sin t, 0, -8 cos t) with rotation [0, -t, 0] (t in radians) so its local +Z faces the eye. Each stand group has data.tap {action: "moveTo"}; inside it, a print group (data.tap {action: "inspect"}, data.inspectLabel = the picture's title) holds the frame, the mat and the picture, and the two posts sit beside it in the stand. In local coordinates: the frame "frame-contemporary-1" (list_assets q "frame contemporary", 2.6 MB, faces +X, portrait 0.735 x 1.0 m) at [0, 1.55, 0], rotation [1.5708, 0, -1.5708] (landscape, facing +Z), uniform scale 1.7 (1.7 x 1.25 m, opening 1.59 x 1.15 m); a mat box 1.62 x 1.17 x 0.02 m (#f4f1ea, roughness 0.9) just inside it; the picture plane at its own aspect inside the mat, 1.5 m wide (or 1.05 m tall when that is the tighter), materialMaps {baseColor, roughness: 1}, 0.02 m in front of the mat; two dark posts (cylinder r 0.04) from the ground into the frame's lower edge. Build the first stand, screenshot it close up, then duplicate it. Entry camera at (0, 1.7, 0), data.fov 50, lookAt (0, 1.4, -8) (the middle picture, or the middle gap), no fitWidth; a showPanel:false webpage whose arrivalCameraId is that camera; settings.design primaryActionId = the middle frame. The sign back (webLink href = their site) at scale 0.5 on its own post, about 4 m from the eye at 35 degrees to the right, its top under 1.1 m so it sits below the frames in the shot, at least 1 m from every stand, aimed at the camera. Sunset, env about 1.1, fog, ACES (METHOD 7). PARK WALK (a path past the pictures): gravel discs (cylinder r 1.5, h 0.04) every 1.5 m along x = 5 sin(2 pi z / 44), each with a random Y turn and y from 0.02 to 0.032 against z-fighting, all duplicates of one; library trees (oak, pine, birch; scale 7 to 12, y = scale / 2) every 4.5 m per side at 6.5 to 13 m out, none within 5.5 m of the path; picture signs (a sign group with data.tap {action: "moveTo"}: two posts, a text3d caption, and a print group with data.tap {action: "inspect"} and its inspectLabel holding the 2.7 x 1.9 m board and the picture plane at its aspect 0.045 m in front) 2.9 m off the path, alternating sides, 11 m apart, each turned to face a point 7 m before it; a trailhead page with "Walk the path" (a camera riding a nurbs curve along the path at 1.65 m, 70 s, loop once, rideBreak "move") and "Skip to the end"; an end page with the sign back; entry eye 1.6 m. WALKTHROUGH (a site with sections): one showPanel:false webpage per section, 45 m apart; each with a pale wall box 2.4 m behind its origin, framed pictures at their aspect (each frame box and picture plane in a print group with data.tap {action: "inspect"} and its inspectLabel), dark h1 and body webText, a stone plaza box; a back sign and a next sign (webLink scale 0.7 on posts, within 12 m of the arrival eye, aimed at it); its own data.primaryActionId (the next sign) and arrivalCameraId (eye 2.0 to 2.3 m, 12 to 16 m back, fitWidth = the wall plus both signs). ROOM GALLERY (only when the user asks for a room, a hall or an exhibition room): walls, floor and ceiling as thin boxes; walls the off-white plaster set at worldScale about 1, floor the oak boards, the white ceiling, the glossy crown and the baseboard of SURFACES AND TRIM; pictures 1.6 to 1.8 m wide, centre at 1.5 to 1.6 m, on the wall the entry camera faces, the arrival framed on them: the arrival eye 7 to 9 m from the picture wall, 1.6 to 1.7 m up, fov 50, so the room is about 10 m deep; captions as centred text3d about 0.12 m tall (data.fontSize 0.12), dark, under each picture, readable from the arrival; each frame, mat and picture in a print group with data.tap {action: "inspect"} and the caption as its inspectLabel, and a picture on a stand or easel sits in a stand group with data.tap {action: "moveTo"} as in YARD GALLERY; the sign is the way out, smaller than a picture, centred on the wall's axis or a doorway, at least 1 m from every frame; never a logo on a wall; the page showPanel false with its anchor just behind the back wall; one key spot raking the pictures. FACTS THE BUILDERS FOUND BY PROBING: library GLBs arrive normalised to 1 m on their longest side and centred, so a model at uniform scale s stands on the ground at y = s x (its height) / 2 (get_scene reports the bounds); the low-poly picture frames face +X and are portrait 0.82 x 1.0 m with a 0.724 x 0.904 opening (roll a frame [1.5708, 0, -1.5708] for landscape facing +Z, never scale it unevenly); worldScale on a cylinder streaks its cap, so tile ground with boxes or planes; webImage takes data.width and data.height; the "no backdrop" and spacing warnings repeat on every batch and lintMute does not silence scene-wide ones: read them once, then go on. OP REFERENCE: SPACING: every foreground element on a panel (text, a link chip, a picture) is inset from it by the same margin, and the gaps between those elements are that same margin again - this door sets the widths and centres for you (reported as marginFixes) and warns when the vertical gaps disagree. Coordinates: Y up, units ≈ meters, ground at y≈0 — place objects so they rest sensibly. Geometry size lives in `data`, under the keys get_scene reports as `size`: box {width,height,depth}, plane {width,height}, sphere {radius}, cylinder {radius,height}, torus {radius,tube}; the default box is 1.5×1.5×1.5. An update writes them in patch.data (never patch.size). GROUND: {"op":"add","nodeType":"geometry","primitive":"plane","position":[0,0,0],"rotation":[-1.5708,0,0],"data":{"width":40,"height":40}}: a plane is XY-oriented (unrotated it is a wall), and a geometry node with no position is minted 1.25 m up, above everything at y~0. MATERIALS: to color an object pass `color` (#rrggbb) on add/assignMaterial; to apply a GENERATED material pass `materialMaps` (the map urls from get_generation) on add/assignMaterial; for a real surface with no image at all pass `materialPreset` (brushed-metal, frosted-ice, rough-stone, ... see the field) — all three mint-or-reuse a material and assign it, no pre-existing library entry needed. Only a geometry node wears a material: on text3d, a light, a cable, particles, a curve, a shadowPool or a backdrop `color` sets its own data.color, and on a group, camera, image, video, page or force field every material field is refused. Prefer a preset or a set from list_assets over a flat color for walls, floors, trim and metal, so the first pass reads as a place, not a grey box. IMPORTED MODELS: a glb from list_assets (kind "glb"; a row marked shared:true is the public library, copy it in first with upload_asset {assetId} and place the url that returns), from upload_asset {url} (a .glb link up to 36 MB) or from get_generation goes on a geometry node as data: {primitive:"imported", assetUrl:"<url>"}, NOT as the top-level `primitive` (that enum is the five built-ins). Once placed, get_scene reports the model's bounds and size. A GLB's own animation plays: the first clip loops on the published page (data.animationClip picks another clip by name or 0-based index, from the names in data.animationNames; data.animationPlay:false holds it still; a model swap keeps animationClip and the first clip plays when the new file lacks it). Animated or rigged models render individually, not instanced. The built-in low-poly picture frames face +X: to hang one on a wall that faces +Z rotate it [0, 1.5708, 0]. INSTANCING (971): identical PRIMITIVES are drawn as one batch too, keyed on the primitive, its data dimensions and segments, its material (color, materialMaps or materialPreset) and its room: 281 boxes that share one size and one material cost one draw call, and the weight meter credits it. Vary placement with position, rotation and the node SCALE (not data.width/height/depth) to stay in the batch; a different data size or material starts another. An animated, tapped or surface-emitter host node draws on its own. WEB BLOCKS (responsive site building-blocks): add webText (data.role h1|h2|h3|body|caption + data.text + data.fontWeight 400|500|600|700 for a real weighted face (a role already picks one); glyph outline via data.outline true|false + data.outlineColor + data.outlineWidth; it draws WHITE unless data.color is set, is anchored at its LEFT edge, sizes by role (a fontSize of your own did not take effect in testing), and the margin pass rewrites data.maxWidth in the node's own units without counting node scale, so scale a text node and it overflows its panel), webImage (data.src + data.alt; a src on another website is EMPTY for every visitor, so bring it in with upload_asset {url} first and use the /assets url it returns), webLink (data.label + data.href or data.linkedPageId), webVideo (data.src + data.poster); any web block also accepts data.anchor = world|billboard|hud (hud needs viewport.responsive3d true; apply_ops turns it on and says so). PAGES & NEIGHBORHOODS: add a `webpage` node per page (set data.pageTitle, data.slug); place pages tens of meters apart and parent each area's content under its page to build a multi-area site. Link areas with a webLink (data.linkedPageId = target page, or data.linkedCameraId = a saved viewpoint); a tempId minted ANYWHERE in the same batch works as linkedPageId (a sign may come before the page it links to), so a "sign in the park linking to the mall" can be built in one call. ROOMS: data.zonePageId (a page id or same-batch tempId) on a room's GROUP binds it to that page, INHERITED by its whole subtree (duplicate and scatter copy it verbatim, so re-point a cloned room); the room switches off when the visitor walks away, and each room gets its own 4 shadow-casting lights (a fifth in one room casts nothing; the result warns). data.zoneRadius (meters) keeps a landmark on within that distance of its page. SEO arrays on a page: data.faqItems [{"question","answer"}] and data.testimonials [{"quote","author"?,"role"?}], these EXACT keys. Set data.arrivalCameraId on a page (a camera node id, or a tempId from the same batch) to choose the viewpoint visitors ARRIVE at for it — otherwise the runtime auto-frames the page from a generic distance. It belongs on the PAGE, not on the signs: a sign that jumps to a camera skips the page change, so the URL and title would still name the previous room. MULTI-LEG ARRIVALS (969): a flight is a straight line between two poses, which cuts through a wall to reach a room. Set data.viaCameraIds on a CAMERA node (an ordered array of camera node ids, or same-batch tempIds, up to 8) and every flight to that camera (a page arrival through arrivalCameraId, a sign or tap with linkedCameraId, a #view deep link) passes through those viewpoints first on one smooth curve: place a via camera in the doorway, aimed into the room, and the visitor is threaded through the door. The flight takes longer in proportion to the path, the mid-flight bow is off on a legged flight, a via camera's own legs are not followed, and a via id that names no camera is skipped (get_scene warns). Wire a doorway in one batch: add the door camera with tempId "door", then the arrival camera with data.viaCameraIds ["door"]. PACING (1028): data.travelScale 0.25-4 on a camera node multiplies the viewport.cameraTravelScale of the scene for every flight that ENDS at that viewpoint (a page arrival, a sign, a #view link): 2 is a slow reveal into a hero room, 0.5 a quick hop. TAP ACTIONS: object nodes (geometry, text3d, group, cable) take data.tap = {"action":"inspect"} (fullscreen orbit lightbox on tap — products/exhibits/hero models), {"action":"moveTo"} (camera flies to frame it — tap-to-travel on landmarks), or {"action":"link", href|linkedPageId|linkedCameraId} (navigate like a webLink). inspect/moveTo take an optional "distance" (meters) overriding the auto camera distance. An inspect lightbox is headed by data.inspectLabel (else the node name) with data.inspectCaption under it. A tap on a GROUP catches taps on every mesh under it, and the innermost tapped node wins: a stand group with moveTo around a print group with inspect (frame, mat, picture plane) inspects the picture and travels from a post. Runs for visitors in the published scene. A tap with no action, a link with no target, any other key, or inspect/moveTo on another node type is REFUSED (each would do nothing); get_scene reads a working tap back as tapAction. ANIMATION: any node (geometry, text3d, group, cable, the web blocks and lights, and a camera, which makes it a RIDE, below) takes data.animation to move on a loop in the published scene: {"duration":4,"loop":"loop","easing":"easeInOut","tracks":{"position":[{"t":0,"v":[0,0,0]},{"t":0.5,"v":[0,0.6,0]},{"t":1,"v":[0,0,0]}]}} bobs the node half a meter. t is a FRACTION from 0 to 1 of the duration, NOT seconds (a key 2 s into a 4 s loop is t 0.5); values are OFFSETS from the authored transform (position meters, rotation euler radians, scale a multiplier as [x,y,z], [1,1,1] = authored size). tracks = position|rotation|scale; loop = loop|pingpong|once; easing = linear|easeIn|easeOut|easeInOut; duration 0.05-600 s; optional delay seconds; 2 to 16 keys per track, each {t, v, easing?}. Anything else (a "rotate" track, {time, value} keys, t in seconds) is REFUSED by name; it used to delete the whole animation on load. Animated nodes cost scene weight and cannot be GPU-instanced: animate a few focal objects, not everything. MOTION PATH (973): data.animation.path puts the node ON a curve instead of (or as well as) the tracks: {"duration":12,"loop":"loop","path":{"curveId":"<a nurbs node id, or its same-batch tempId>","facing":"tangent","forward":"z","up":[0,1,0]}}. facing = tangent (nose along the curve) | target (toward a world point, pass "target":[x,y,z]) | fixed (keep the authored rotation); forward = z|-z|x|-x is which local axis of the model leads (a glb whose nose points -Z wants "-z"); up is the world up the roll is kept against; offset 0..0.95 is where along the curve the ride starts (space several riders around one loop with different offsets); reverse:true rides it backwards; facingEase (seconds, default 1, 0 snaps) is how long the rider takes to TURN from the way it was placed into the facing of the path when the ride begins (and again if the heading jumps, such as the loop seam of an open curve), eased in and out. `easing` shapes the ride itself: linear is the default on a loop (constant speed, no braking at the seam) and easeInOut on once/pingpong (pull away, brake at the end). While bound, the authored position and rotation are NOT where the node is (it sits on the curve; scale still applies, tracks stack on top as offsets); a curveId that names no curve node leaves it at its authored place. The curve is a nurbs node: {"op":"add","nodeType":"nurbs","tempId":"track","data":{"controlPoints":[[0,0,0],[8,0,-4],[16,0,0],[8,0,4]],"closed":true}} then {"op":"add","nodeType":"geometry","primitive":"box","data":{"animation":{"duration":10,"path":{"curveId":"track"}}}}. get_scene reads a rider back as motionPath:<curveId>. A curve something rides is a HELPER on the published site (1032): registered for the ride, not drawn, so a swing arc does not show as a green spline across the door; set data.renderCurve:true on the curve to draw it anyway. The editor always shows it. CAMERA RIDE (1026): a CAMERA node with data.animation.path is a ride: every flight that lands on it (a page arrival through arrivalCameraId, a sign or tap with linkedCameraId, a #view link) ends at the curve's start pose and the visitor's camera then follows the curve, looking along it (facing tangent), at a world point (facing target + target) or the way it arrived (facing fixed); animation.duration, loop (once = ride to the end and hand control back there; loop and pingpong ride until the visitor takes over; on an OPEN curve loop cuts back to the start each lap, so use once or pingpong there or set closed:true on the curve), easing, path.offset and path.reverse mean what they mean for any rider (a pingpong ride looks where it is going on the way back too). data.rideBreak is the author's choice of what ends the ride early: "any" (default: any pointer down, key, wheel or touch), "move" (only a drag, a wheel or a movement key, so a tap on a sign still navigates and a stray click does not stop the ride) or "none" (nothing; a loop rides until the visitor navigates elsewhere). A new flight always ends a ride; a reduced-motion visitor and a screenshot get the start pose and no ride; the curve is a helper (not drawn) like any ridden curve. {"op":"add","nodeType":"nurbs","tempId":"rail","data":{"controlPoints":[[0,1.6,8],[0,1.6,2],[3,1.6,-2]]}},{"op":"add","nodeType":"camera","tempId":"arrive","data":{"animation":{"duration":8,"loop":"once","path":{"curveId":"rail"}},"rideBreak":"move"}} then arrivalCameraId "arrive" on the page. FAST PATH — make_page: for a page that is a heading + paragraph + some links, ONE `make_page` op builds the whole thing: pass name, data.pageTitle+data.slug, hero (h1 text), body (paragraph), and links [{label, ONE of to: a page id/tempId | linkedCameraId: a viewpoint | href}], plus a tempId (which becomes the PAGE id so other signs can target it). Create link-target pages earlier in the batch so their tempIds resolve. It replaces ~6–12 primitive ops. SET-DRESSING: use the `scatter` op to make `count` jittered copies of a node across an {area:{x,z}} (random rotation + slight scale + optional per-copy `tint` for imported models) — efficient for many props, debris, foliage, a trashy parking lot. The result names what it CREATED (`created`: id, type, name) so you can edit those nodes in your next call without re-reading the scene. LARGE SCENES: build INCREMENTALLY across multiple apply_ops calls (~40–50 objects per batch) instead of one huge batch, which stays well within limits. Each call is atomic and checkpointed: the owner can roll back in the editor (File > Version history). There is no undo over MCP; to reverse a call, apply the inverse ops. Call get_scene between batches to stay aligned. Do not try to emit hundreds of operations in a single call. The result may carry `warnings`: advisory scene lint (floating content, orphan web blocks, unreadable text, crowded pages, a lamp whose range reaches the ceiling above it, a plane facing a shadow lamp with content behind it, ambient IBL in a sun-less studio scene, a page card inside a room, a camera ride looping an open curve, a floor above the content it should hold up, shadow-casting lights past the 4 a room gets, scene WEIGHT over the perf red line) and design fails (text that does not read against what is behind it, with the nearest shade that does; a room with no composed arrival shot; a primary action outside its arrival frame; the action's accent hue worn everywhere on its page; dead-end pages; two h1s, or body text with none). These are the fails only; the full critique, ranked for the brief with ready fixes, is design_review. A per-node warning you have read and disagree with goes quiet with data.lintMute:true on that node (every rule about one node honours it; scene-wide ones do not). When more than six fire, the last entry counts the rest. The ops APPLIED; act on warnings in your next batch unless they contradict what the user asked for. A weight warning names the heaviest categories: trim them (lower-poly models, fewer shadow lights/particles) or publish will warn and far heavier scenes are blocked.
Exemple d'appel{"name": "apply_ops", "arguments": {"sceneId": "texte", "operations": []}}Exemple de retour{"content": [{"type": "text", "text": "…"}]} - compose_surface≈ 1076 tokens
Make a flat surface that looks PRINTED ON a real material: a quote on a stretched canvas, a poster, a shop sign, a label, a plaque, a book cover. Start from a `base`: a texture set from the library (`setId` from list_assets; tiled at `tileSize` meters, or `mode` "stretch" for a whole-sheet scan), explicit `maps` {baseColor, normal, ormh} urls, or a flat `color`; `tint` re-colours the base and keeps its detail. Then `layers`, painted in order: text {text (use \n or | for line breaks), font typewriter|sans|horror, weight, size (letter height in meters), color, align, x/y (the block centre, 0..1 from left/top), maxWidth (share of the width; the size shrinks to fit), tooth (0..1, how much ink skips the low spots of the weave), dry (patchy ribbon), jitter (typewriter wobble)}; image {src (an /assets url), x, y, width (share of the surface width), opacity, blend normal|multiply}; stains {amount, color, scale, seed}; spatter {x, y, size, drips, color (blood by default), seed}; grime {edge}; fill {color, opacity}. Ink and spatter sink into the base relief, emboss its normal and read glossier than the base, so light rakes across it like the real thing. `output` "panel" (default) saves a thin box MODEL of width x height x depth meters, its face looking down +X like the library picture frames, with a phone-sized copy made automatically, and a model waits for its room so a many-room site stays light on phones; place it with the `place` op the result gives. `output` "material" saves a baseColor/normal/ormh set and returns `materialMaps` for apply_ops (it stretches once across a face, repeat 1). To fill a picture frame, measure the frame first (measure gives its opening) and make the panel about 0.2 m larger than the opening both ways, placed just behind the frame's front. Returns a small preview image of the surface.
Paramètres, retour & exemple (10)
Paramètresbase· object · optionnel
The material the surface is made of.depth· number · optionnel
Panel thickness in meters (default 0.03).label· string · optionnelwidth· number · requis
Surface width in meters.height· number · requis
Surface height in meters.layers· array · optionnel
Painted on in order (max 24).output· string · optionnel · panel | materialkeywords· array · optionnelresolution· number · optionnel
Pixels on the long side, 256 to 2048 (default 2048).normalStrength· number · optionnel
Relief strength, 0 to 4 (default 1).
Exemple d'appel{"name": "compose_surface", "arguments": {"width": 1, "height": 1}}Exemple de retour{"content": [{"type": "text", "text": "…"}]} - create_scene≈ 270 tokens
Use this when the user wants a 3D website, a walkable portfolio, a product showcase, a gallery, an exhibit, an event page or any interactive space they can share as a link. Creates the scene in their 3dCMS account and returns its id; then build it with apply_ops. With copyFrom it is a full COPY of one of their scenes (Save As), the way to try a big change on a new version while the original and its published site stay untouched. It opens in the 3dCMS editor; a copy is unpublished until publish_scene.
Paramètres, retour & exemple (2)
Paramètresname· string · requis
A name for the new scene.copyFrom· string · optionnel
A scene id from list_scenes to copy every node, material and setting from. Omit for an empty scene.
Exemple d'appel{"name": "create_scene", "arguments": {"name": "texte"}}Exemple de retour{"content": [{"type": "text", "text": "…"}]} - design_review≈ 437 tokens
A designer's critique of a scene (or one page with pageId) against its BRIEF: what it is for (settings.design, or, when none is declared, what it reads as and why), its palette (dominant, secondary, accent, harmony, temperature, key, and whether that serves the intent and the mood), text contrast, heading hierarchy, every arrival and entry shot judged by probe_framing, wayfinding, the light's key to fill at the subject, and motion. `top` is the five things that matter most FOR THIS INTENT (a page meant to convert ranks the action and its accent first; one meant to inform, hierarchy and contrast; a showcase, the hero's framing and light), each with the finding, why it matters, and `fixOps`: a ready apply_ops batch where one exists. Read-only and instant, no render. Call it when a build is done, before you report, and whenever the user asks how their scene could be better. Tell the user the top findings in plain words, with the why. Apply fixOps to a scene you are building when they serve the brief; for the user's own work, offer them and apply on a yes. A brief read rather than declared is a guess: confirm it with the user before writing it.
Paramètres, retour & exemple (2)
ParamètrespageId· string · optionnel
Review one page (a webpage node id): its brief, its content, its arrival shot. Omit for the whole scene.sceneId· string · requis
Scene id from list_scenes.
Exemple d'appel{"name": "design_review", "arguments": {"sceneId": "texte"}}Exemple de retour{"content": [{"type": "text", "text": "…"}]} - get_scene≈ 894 tokens
Read a compact, high-signal summary of one scene: its nodes (id, type, name, parent, position, rotation [euler radians], scale, primitive, real `size` under the keys `data` takes (width/height/depth, radius, height, tube: write it back as patch.data as-is), assigned material; an imported model also carries its bounds {min,max}, size [w,h,d] and assetFile, the tail of its list_assets url, so a frame can be sized to a picture without a screenshot; a camera says what it SEES, from the pose the published viewer builds: lookingAt (the point it pivots on), pitchDeg, heightM, fov and fitWidth when set, looksAtNothing when nothing is ahead of it, and frames: up to six things in its picture on a square screen, biggest first, each at x and y from -1 to 1 with its share of the frame height, the floor left out) plus the material library — including each solid material's color/roughness/metalness and `usedBy` (how many nodes wear it, the first three ids) or `unused:true`, and `settings`: the scene-level look the `settings` op writes (lighting: mode, sun, timeOfDay, env IBL intensity; viewport: post effects, tone mapping, LUT, draw distance, camera flight; environment: fog; audio), every field that exists, plus `settings.sky`, one sentence on what actually lights the scene. Read it FIRST when a surface looks lit for no reason: env.intensity is ambient light with no source and no falloff, and a scene with every lamp deleted stays lit by it. Sizes are in scene units (≈ meters), BEFORE each node's scale; transforms that are zero/default are omitted. ALWAYS returns `counts` (nodes by type) and `matched`, so on a big scene you orient first and then ask for the part you need: narrow with `type` / `name` / `nameContains` / `parentId`, page with `limit` + `offset` (the reply carries `nextOffset` and a `truncated` note when there is more). A scene of a few hundred nodes WILL be cut off if you ask for all of it at once.
Paramètres, retour & exemple (9)
Paramètresname· string · optionnel
Only nodes whose name is exactly this.type· string · optionnel
Only nodes of this type (geometry, webText, webLink, webpage, light, cable, particle, group, camera, ...). Pair with the `counts` a first call returns to see what is worth asking for.limit· number · optionnel
Max nodes to return, 1-300 (default 250).offset· number · optionnel
Skip this many matching nodes - page with the `nextOffset` the previous reply gave you.sceneId· string · requis
Scene id from list_scenes (e.g. "src-1a2b3c4d").parentId· string · optionnel
Only the direct children of this node.settings· number · optionnel
The scene-level settings block (lighting, viewport, environment, audio, sky) rides on an unfiltered first-page call by default. Pass 1 to get it on a filtered or paged call, 0 to omit it.materials· number · optionnel
Pass 0 to omit the material library when paging a long node list you already have.nameContains· string · optionnel
Only nodes whose name contains this (case-sensitive). `scatter` names copies "<source> 1", "<source> 2", so this is how you find a scattered set.
Exemple d'appel{"name": "get_scene", "arguments": {"sceneId": "texte"}}Exemple de retour{"content": [{"type": "text", "text": "…"}]} - get_scene_screenshot≈ 933 tokens
Render the scene server-side (real WebGL, headless) and return screenshot image(s) — your EYES on the scene. Use it after apply_ops batches and after probe_framing, and judge each image as a photographer and a web designer would: one clear subject, on a third (for a page's own camera, the whole card at a readable angle); the horizon off the middle; the eye at a standing height; text legible and on even margins; a way out in view; the colours serving the brief (one accent, on the primary action); nothing floating, clipped or overlapping. Beside each image comes `composition`, read from its own pixels: tonalRange (p5 to p95 of lightness; under 0.35 is flat), clipping (share blown to white, crushed to black), key (low, mid, high), a 3x3 thirds grid of lightness and detail with the busiest and brightest cells, the hues on screen by share, and findings in sentences. Fix with apply_ops. At most 2 screenshot→fix rounds per request, then report. views (max 4, default = the visitor's entry view): pass "page:<pageIdOrSlug>" to frame one page/neighborhood, or {position:[x,y,z], target:[x,y,z], fov?} for an exact camera. Rendering is real but slow: ~10 s for a simple scene, 45 s per view by default (timeoutSeconds up to 180 for a big textured scene). The default is ONE view at 640 px; larger shots and several views are what timed out, so ask for one view at a time. A call answers within about 85 s either way: the image, or "still rendering, retry in N s"; then call again with the SAME arguments after N s and the image comes from the cache at no extra cost. A timeout comes back as an error naming it, never as an empty image; repeat shots of an unchanged scene at the same size are cached, instant and free; only a fresh render counts against the daily budget, and each reply says shotsLeft. If it returns a busy/unavailable error, keep building and retry once later — do not loop on it.
Paramètres, retour & exemple (5)
Paramètresviews· array · optionnel
Camera views to capture. Omit for the visitor's entry view.maxDim· number · optionnel
Longest side of the image in pixels, 64-1920 (default 640; height is 0.625x). 640 reads captions and renders inside the time limit; larger often does not.sceneId· string · requis
Scene id from list_scenes.atSeconds· number · optionnel
Seconds into the scene's animation the shot is taken at (0-600, default 0 = frame one). Every track and motion-path rider is frozen at that time, so a door with a 4 s swing is verified mid-swing at 2 and a rider on a 12 s loop at u=0.5 at 6. Cached per time.timeoutSeconds· number · optionnel
Per-view render budget in seconds, clamped 10-180 (default 45). Raise it for a big or texture-heavy scene instead of retrying a timeout at the same budget.
Exemple d'appel{"name": "get_scene_screenshot", "arguments": {"sceneId": "texte"}}Exemple de retour{"content": [{"type": "text", "text": "…"}]} - list_assets≈ 722 tokens
Search the images, models and sounds in the account AND the shared public library (frames, props, texture sets; `scope` mine|shared|all, default all). A row with shared:true is copied in first with upload_asset {assetId}: place the url that returns, never the shared one. This is how you TEXTURE something with what the user already owns: search for the look you want, take the `url` of the result, and bind it on an apply_ops add or assignMaterial as `materialMaps: { baseColor: "<url>" }`, plus `normal` and the set's packed `ormh` (or `orm`), or separate `roughness` / `metalness` maps. PBR sets are stored as SEPARATE images that share a setId; the base color member is often unsuffixed (mapRole null) while its siblings end in the map name ("... Normal", "... Ormh"). Search the set name, then pick one url per slot by mapRole; a base colour alone already reads as a texture. ALWAYS search rather than listing: an account can hold thousands of images. `q` is a set of terms that must ALL appear in the label or keywords, so "weathered wood" narrows instead of returning everything wooden. Returns id, kind, label, url, sizeBytes, keywords, mapRole and setId. mapRole names the slot an image is (baseColor | normal | roughness | metalness | height | emissive | ao | orm | ormh, or null when the label does not say); setId is shared by every image of one PBR set, so bind a whole set by matching setId and placing each url by its mapRole. orm/ormh are channel-packed (R=AO, G=roughness, B=metalness, A=height): bind one on materialMaps.ormh (or .orm), never as roughness; the channels are split for you. An `emissive` member goes on materialMaps.emissive. `kind` is "image" for textures and "glb" for models (a glb url goes on a geometry node as data: {primitive:"imported", assetUrl}, never as the top-level primitive), "audio" for sounds (data.audioClip.src).
Paramètres, retour & exemple (5)
Paramètresq· string · optionnel
Search terms, all of which must appear in the label or keywords. Omit to list the newest.kind· string · optionnel
"image" for textures, "glb" for 3D models, "audio" for sounds. Omit for all.limit· number · optionnel
Max results, 1-100 (default 40).scope· string · optionnel · mine | shared | all
"mine" = this account only, "shared" = the public library only, "all" (default) = both, yours first.offset· number · optionnel
Skip this many results - page with the `nextOffset` the previous reply gave you.
Exemple d'appel{"name": "list_assets", "arguments": {"q": "texte", "kind": "texte", "limit": 1, "scope": "mine", "offset": 1}}Exemple de retour{"content": [{"type": "text", "text": "…"}]} - list_scenes≈ 293 tokens
Use this first when the user mentions their 3dCMS scenes, a site they built with 3dCMS, or wants to edit, publish or check something they made. Lists the 3D scenes saved in their 3dCMS account (editable "sources"), newest first, 40 at a time. Returns each scene's id, name, page count, last-updated time and (when published) its site slug. Pass `q` to search by name or slug instead of paging through a big account; page with the `nextOffset` the previous reply gave you. Use a scene id with get_scene and apply_ops.
Paramètres, retour & exemple (3)
Paramètresq· string · optionnel
Search text matched against the scene name and its published slug. Omit to list.limit· number · optionnel
Max results, 1-100 (default 40).offset· number · optionnel
Skip this many results - page with the `nextOffset` the previous reply gave you.
Exemple d'appel{"name": "list_scenes", "arguments": {"q": "texte", "limit": 1, "offset": 1}}Exemple de retour{"content": [{"type": "text", "text": "…"}]} - measure≈ 433 tokens
Measure nodes in a saved scene (analytic, instant, no render). For each node in nodeIds: its world centre, its size along its own axes after every scale above it, its world bounding box, and `clearance`: the nearest visible thing in each world direction (+x, -x, +y, -y, +z, -z) that overlaps it across that axis, with the gap in meters (how far a frame hangs off its wall, how much room a camera has before it meets a side wall). An IMPORTED MODEL also gets `opening`: the hole through it (a picture frame, a doorway, a window, an arch), measured from the model's own triangles: its size in meters along the node's x, y, z, the axis it goes through, and `backed` when a board or glass covers the centre. Size a panel a little larger than the opening so its edge tucks behind the lip; get_scene only reports a model's OUTSIDE. Two or more nodes also give `pairs`: centre distance, the gap between their boxes (0 when they overlap) and that gap per axis. A `point` [x,y,z] gives its clearance in all six directions.
Paramètres, retour & exemple (3)
Paramètrespoint· array · optionnel
A world point [x,y,z] to measure the clearance around.nodeIds· array · optionnel
Up to 24 node ids to measure (and to pair up).sceneId· string · requis
Scene id from list_scenes.
Exemple d'appel{"name": "measure", "arguments": {"sceneId": "texte"}}Exemple de retour{"content": [{"type": "text", "text": "…"}]} - probe_framing≈ 856 tokens
Read a saved camera (cameraId), or an exact pose, as a visitor sees it at the screen shapes they actually have (16:9 desktop and 9:16 phone by default), against the rules a photographer and a web designer use. A PAGE shot (a page's own camera, its arrivalCameraId or a camera inside the page, with the card in view) should hold the whole card on every screen, most of the width, within 60 degrees of square so its text still reads: centred is right for a page. A SCENE shot (a room, an object, a place, and the entry view even with a page in it: a 3D view need not be head-on) puts its subject on a third, the horizon on a third, the eye at a standing person's 1.5 to 1.7 m. The subject is the declared primary action (settings.design, or the page's data.primaryActionId), else the page's h1, else a SET of 3+ equal things in frame (framed as one arrangement), else the biggest thing; subject "set" forces the set. A suggested scene pose keeps the horizon in frame. Returns, per screen shape: where the subject lands (x and y from -1 to 1, its thirds cell, how far from a power point, its share of the frame, whether all of it is in frame or which edge cuts it, whether text is legible), the page card (whole, width share, degrees off square), text the frame cuts, a near object cut in the foreground, the horizon row, the eye height above the floor (a phone backs a fitWidth camera up along its tilt, so read it on every shape), anything in the lens or around it, and exits (signs and tap targets within 12 m). Then `findings` in plain sentences, worst first, and `suggest`: one pose that fixes the composition on every shape, with why, and `suggest.op`, a ready apply_ops update for it (null when it already stands at the best pose). Call it on every entry and arrival camera you place, before get_scene_screenshot. On a scene you are building, apply the suggestion yourself when it serves the brief; on the user's own existing work, tell them what it found and offer the fix.
Paramètres, retour & exemple (7)
Paramètresfov· number · optionnel
With position: vertical fov in degrees (default 42).target· array · optionnel
With position: the point the eye looks at.aspects· array · optionnel
Screen shapes to read, width over height, 1 to 4 of them from 0.3 to 3.5 (default [1.778, 0.5625]: a desktop and a phone held upright).sceneId· string · requis
Scene id from list_scenes.subject· string · optionnel · set | auto
"set" frames the arrangement of equal things (a row or arc of pictures, signs) as the subject instead of one of them. Default auto.cameraId· string · optionnel
A camera node id. Its fitWidth, its page and its role (entry, arrival, via, sign target) are all read.position· array · optionnel
Instead of cameraId: an eye position [x,y,z], world meters.
Exemple d'appel{"name": "probe_framing", "arguments": {"sceneId": "texte"}}Exemple de retour{"content": [{"type": "text", "text": "…"}]} - probe_lighting≈ 398 tokens
For one world point, the contribution of EVERY light in the scene, computed from the saved scene (no render, instant): each light node in reach with its value (three's falloff and spot cone, from the node's WORLD position and aim), the studio sun or the live sky, and `ambient` = lighting.env.intensity NAMED as a term, sorted by contribution, plus a `why` on each light that does not reach (out of range, outside the cone, behind the panel). Pass `nodeId` for the surface's albedo: a pale albedo shows the ambient term 2-3x as strongly as a dark one. Use it BEFORE deleting lights to find a phantom glow: a surface no lamp reaches that still reads lit is lit by env.intensity (or the sky in time mode), and the answer is the settings op, not another lamp. Occlusion is not computed (a wall between does not reduce the number).
Paramètres, retour & exemple (3)
ParamètresnodeId· string · optionnel
The node whose surface this point is on, for its albedo and room binding.sceneId· string · requis
Scene id from list_scenes.position· array · requis
World point [x,y,z] in meters, e.g. the middle of the ceiling that looks lit.
Exemple d'appel{"name": "probe_lighting", "arguments": {"sceneId": "texte", "position": []}}Exemple de retour{"content": [{"type": "text", "text": "…"}]} - publish_scene≈ 591 tokens
Use this when the user wants their scene live as a public link to share, or to update one already live. Publish a saved scene to a PUBLIC, shareable URL so anyone can view it in 3D in a browser — no login required. PUBLISHING IS PARTLY IRREVERSIBLE: the URL is submitted to search engines (IndexNow) the moment it goes live, so it may appear in results even after a takedown. ALWAYS confirm with the user first, then call with confirm:true — without it this tool publishes nothing and returns what WOULD happen. Returns the public site URL plus a per-page URL list. Re-publishing the SAME scene updates its existing public site (the URL stays stable).
Paramètres, retour & exemple (6)
Paramètreslisted· boolean · optionnel
false publishes UNLISTED: reachable by its link, but kept off Explore and your creator profile, marked noindex and not submitted to search engines. Omit for a normal listed publish.confirm· boolean · optionnel
Must be exactly true to publish. Omit / false to get a needsConfirm summary for the user.sceneId· string · requis
Scene id from list_scenes.siteSlug· string · optionnel
Publish onto one of YOUR existing sites by its slug (the part after /sites/ in its URL) instead of this scene's own. When that site shows another scene, the first call answers willReplace: name the site to the user and call again on a yes with confirmReplace set to willReplace.replaceToken. Later publishes of this scene go to that site.shortLink· boolean · optionnel
true also returns shortUrl, a short 3dcms.info/s/<code> link to the site (one stable code per site), for sharing and QR codes. Without confirm, a scene whose site is already live gets its shortUrl at once, no republish.confirmReplace· boolean|string · optionnel
Only after a reply with needsConfirm and willReplace, and the user's yes naming that site: pass willReplace.replaceToken exactly when it has one (siteSlug publishes), otherwise true.
Exemple d'appel{"name": "publish_scene", "arguments": {"sceneId": "texte"}}Exemple de retour{"content": [{"type": "text", "text": "…"}]} - upload_asset≈ 627 tokens
Put a file into the account's asset library and get back its /assets url to use in apply_ops (a glb on a geometry node as data {primitive:"imported", assetUrl}, an image in materialMaps or a webImage src, an mp3 in an audioClip: data.audioClip = {src, volume 0-1, loop, mode, muted} on any node; get_scene reports it as `audio`). A `url` may be a picture (JPEG, PNG, WebP, GIF, AVIF, up to 12 MB), a binary glTF 2.0 model (.glb, up to 36 MB) or a sound (MP3, OGG, WAV, M4A, up to 12 MB); the type is read from the bytes. `assetId` instead copies a SHARED library asset (a list_assets row marked shared:true) into this account and returns the url to place; placing the copy keeps the page whole if the sharer removes theirs, and the same asset copied twice returns the first copy. Give ONE source: `url` (a public http(s) link, fetched by the server; use this for anything larger), `dataBase64` with `filename` (the file itself, up to about 3 MB on this hosted connector; bigger files go by `url` or the editor's upload), or (`path` is only available when the MCP runs on your own computer). An image answers its width, height and aspect in pixels: cut a picture plane to that aspect, never a guess. A model gets its phone-sized copy made automatically, the same as an editor upload. Label it and give keywords so list_assets finds it again.
Paramètres, retour & exemple (7)
Paramètresurl· string · optionnel
A public http(s) URL to import: a picture, a .glb model or a sound.path· string · optionnel
A local file path (only when this MCP server runs on your own computer).label· string · optionnel
A human label for the library.assetId· string · optionnel
Copy this shared library asset (a list_assets id with shared:true) into your library instead.filename· string · optionnel
File name WITH extension (e.g. "sign.glb", "poster.png"); required with dataBase64, optional with path.keywords· array · optionnel
Search keywords for list_assets.dataBase64· string · optionnel
The file, base64-encoded. Needs filename.
Exemple d'appel{"name": "upload_asset", "arguments": {"url": "texte", "path": "texte", "label": "texte", "assetId": "texte", "filename": "texte", "keywords": []}}Exemple de retour{"content": [{"type": "text", "text": "…"}]}
C'est votre serveur ?
Revendiquez-le sur l'espace créateur (preuve GitHub, domaine ou npm) pour afficher le badge « propriétaire vérifié » et lancer un pentest comportemental à la demande afin d'obtenir le badge « Vérifié ».