Skip to content

3dCMS

by 3dcms.info · remote · no sign-in to list tools · v1.1.0 · published by info.3dcms

Build a real 3D website by chatting: pages, models and text in space, published to a live URL.

Deletes · 2Changes · 6

13 tools: 2 can delete or cancel things, 6 change things and 5 only read.

Scanned Oct 21, 2026

No check matched anything in the tool definitions. No finding is not a safety guarantee. How the checks work.

claude mcp add --transport http 3dcms https://3dcms.info/mcp

Tools

Open a tool for its reasons and full description. Descriptions are the publisher's own words, shown as they are.

13 tools

Deletes or cancels 2Claude Code: deny
  • apply_opsUse this to build or change a 3D scene: add rooms, text, pictures, links, models, lights, pages.No findings

    Why it is in this group

    • The name "apply_ops" says "apply": a word for a change.
    • The server marks it destructive (destructiveHint: true).
    Description, as the server wrote it
    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.

    Annotations the server declares

    • title: Edit a 3dCMS scene
    • readOnlyHint: false
    • destructiveHint: true
    • idempotentHint: false
    • openWorldHint: false
  • publish_sceneUse this when the user wants their scene live as a public link to share, or to update one already live.No findings

    Why it is in this group

    • The name "publish_scene" says "publish": a word for a change that another call does not undo.
    • The description says "IRREVERSIBLE".
    • The server marks it destructive (destructiveHint: true).
    Description, as the server wrote it
    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).

    Annotations the server declares

    • title: Publish a 3dCMS scene
    • readOnlyHint: false
    • destructiveHint: true
    • idempotentHint: true
    • openWorldHint: true
Changes things 6Claude Code: ask
  • compose_surfaceMake 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.No findings

    Why it is in this group

    • Nothing in its name or description says what it does, so it is counted as a write.
    Description, as the server wrote it
    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.

    Annotations the server declares

    • title: Build a printed surface
    • readOnlyHint: false
    • destructiveHint: false
    • idempotentHint: false
    • openWorldHint: false
  • create_sceneUse 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.No findings

    Why it is in this group

    • The name "create_scene" says "create": a word for a change.
    Description, as the server wrote it
    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.

    Annotations the server declares

    • title: Create a 3dCMS scene
    • readOnlyHint: false
    • destructiveHint: false
    • idempotentHint: false
    • openWorldHint: false
  • design_reviewA 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 (do…No findings

    Why it is in this group

    • Nothing in its name or description says what it does, so it is counted as a write.
    • The server marks it read-only (readOnlyHint: true), but an annotation never lowers a class.
    Description, as the server wrote it
    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.

    Annotations the server declares

    • title: Design review of a scene
    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: false
  • measureMeasure nodes in a saved scene (analytic, instant, no render).No findings

    Why it is in this group

    • Nothing in its name or description says what it does, so it is counted as a write.
    • The server marks it read-only (readOnlyHint: true), but an annotation never lowers a class.
    Description, as the server wrote it
    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.

    Annotations the server declares

    • title: Measure things in a scene
    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: false
  • probe_lightingFor 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 …No findings

    Why it is in this group

    • Nothing in its name or description says what it does, so it is counted as a write.
    • The server marks it read-only (readOnlyHint: true), but an annotation never lowers a class.
    Description, as the server wrote it
    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).

    Annotations the server declares

    • title: What is lighting this point?
    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: false
  • upload_assetPut 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 materia…No findings

    Why it is in this group

    • The name "upload_asset" says "upload": a word for a change.
    Description, as the server wrote it
    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.

    Annotations the server declares

    • title: Add a file to the asset library
    • readOnlyHint: false
    • destructiveHint: false
    • idempotentHint: false
    • openWorldHint: true
Only reads 5Claude Code: allow
  • get_sceneRead 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 (…No findings

    Why it is in this group

    • The name "get_scene" says "get": a word for reading.
    Description, as the server wrote it
    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.

    Annotations the server declares

    • title: Get a 3dCMS scene
    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: false
  • get_scene_screenshotRender the scene server-side (real WebGL, headless) and return screenshot image(s) — your EYES on the scene.No findings

    Why it is in this group

    • The name "get_scene_screenshot" says "get": a word for reading.
    Description, as the server wrote it
    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.

    Annotations the server declares

    • title: Screenshot a 3dCMS scene
    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: false
  • list_assetsSearch the images, models and sounds in the account AND the shared public library (frames, props, texture sets; `scope` mine|shared|all, default all).No findings

    Why it is in this group

    • The name "list_assets" says "list": a word for reading.
    Description, as the server wrote it
    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).

    Annotations the server declares

    • title: Search the 3dCMS asset library
    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: false
  • list_scenesUse 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.No findings

    Why it is in this group

    • The name "list_scenes" says "list": a word for reading.
    Description, as the server wrote it
    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.

    Annotations the server declares

    • title: List 3dCMS scenes
    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: false
  • probe_framingRead 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 photogr…No findings

    Why it is in this group

    • The description's first verb is "read": a word for reading.
    Description, as the server wrote it
    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.

    Annotations the server declares

    • title: Is this camera a good photograph?
    • readOnlyHint: true
    • destructiveHint: false
    • idempotentHint: true
    • openWorldHint: false

This is not a safety rating, and no finding is not a safety guarantee. The groups and findings come from fixed checks of the tool definitions the server returned on the date shown, not from its code or what it does when called. How the checks work.

Install

Pinned to version 1.1.0. Values in angle brackets are yours to fill in.

claude mcp add --transport http 3dcms https://3dcms.info/mcp

Run in a terminal.

Claude Code permissions

Allow the reads, ask before a change, deny the deletes. Paste into .claude/settings.json.

.claude/settings.json
{
  "permissions": {
    "allow": [
      "mcp__3dcms__list_scenes",
      "mcp__3dcms__probe_framing",
      "mcp__3dcms__get_scene",
      "mcp__3dcms__list_assets",
      "mcp__3dcms__get_scene_screenshot"
    ],
    "ask": [
      "mcp__3dcms__probe_lighting",
      "mcp__3dcms__design_review",
      "mcp__3dcms__upload_asset",
      "mcp__3dcms__compose_surface",
      "mcp__3dcms__measure",
      "mcp__3dcms__create_scene"
    ],
    "deny": [
      "mcp__3dcms__apply_ops",
      "mcp__3dcms__publish_scene"
    ]
  }
}

Tools that only read are allowed, tools that change things ask first, tools that delete or cancel are denied. It assumes the server is installed as 3dcms. Review it before you use it.