mcp-for-maya

io.github.Xxx91nv0.5.0Updated Sep 30, 2026

AI agents' spatial awareness inside Autodesk Maya: audit, rollback safety, visual loop (Beta)

VerifiedSTDIODesktop onlyAI & ML

Installation

In SourceWeft

  1. Open mcp-for-maya in the dashboard and add it to a workspace.
  2. Enable the server for the chats that should use its tools.

Desktop only via STDIO. STDIO servers start a local process, so they need the SourceWeft desktop host.

Other MCP clients

Follow the launch instructions in the repository.

README

English | 简体中文

[mcp-for-maya — Give AI agents eyes inside Autodesk Maya]

mcp-for-maya

MCP server giving AI agents spatial awareness of Autodesk Maya scenes

[CI] [PyPI] [License: MIT] [Python]

What Is This

mcp-for-maya is a Model Context Protocol (MCP) server that lets LLM agents (Codex, Claude, etc.) directly drive Autodesk Maya for 3D modeling, scene planning, and engineering-grade delivery.

Forked from chadrik/maya-mcp-server, it adds a scene-intelligence layer on top of the upstream connection stack: spatial awareness, deterministic auditing, transactional safety, and a visual loop.

Key capability: the agent stops "writing blind" — it can perceive spatial state, materials, and object relationships, then verify changes against engineering rules.

[!WARNING] This server executes arbitrary Python inside Maya — that is a designed capability, not a bug. The built-in validation / rate-limit / audit pipeline is a safety net for accidents and injected instructions, not a boundary against a malicious client; the connected agent is trusted. See docs/threat-model.md.

[Live Demo — captured by the product itself]

Every asset below is a real capture produced by this project's own tool chain — no mockups: scenes were built procedurally through execute_code / write_module (plus one live asset_import), frames rendered through scene_render_preview, the audit pair via scene_review + scene_viewport_snapshot, and the orbit sequence captured frame-by-frame with playblast (Maya 2024 GUI session).

PromptResult
write_module → t20_movement.build() — "parametric involute gear train caliber: true involute teeth, Geneva-striped plates, blue-steel screws, ruby jewels, spiral hairspring"[parametric watch movement: involute gears, Geneva striping, balance + hairspring]
write_module → t20_bonsai.build() — "low-poly L-system bonsai: recursive branching, faceted foliage pads, pot + moss + stones"[low-poly L-system bonsai: recursive branching, foliage pads, pot + moss + stones]
asset_import("vintage_pocket_watch") + asset_import("metal_tool_chest") → t20_workbench.build() — "horologist's workbench: imported assets with textures wired, procedural involute spares"[horologist workbench: imported pocket watch + tool chest, procedural gear spares]
write_module → t20_street.build() — "low-poly corner block: 11 parametric buildings, gable roofs, awnings, street furniture, parked vans"[low-poly street block: 11 parametric buildings, awnings, street furniture]
write_module → t20_teapot.build() — "Utah teapot recreation: revolve-profile body, Bezier tapered spout, ear handle, checkered floor"[Utah teapot recreation: lathe body, bezier tapered spout, checkered floor]
scene_review() on a bench littered with junk → scene_plan(auto_fix=True) + cleanup → scene_review() again — score 53.7 → 64.2[scene_review before: default-named junk piled on the metrology bench][scene_review after: violations removed, bench restored]

[movement orbit — 20 real playblast frames, 120° sweep]

Reproduce every frame with the scripts in .github/assets-src/.

vs blender-mcp

An honest three-tier comparison with ahujasid/mcp-for-blender (measured 2026-09):

TierContents
Unique to this projectICEV enforced workflow (in server instructions), CoS notation output, checkpoint/rollback transactional safety, scene_plan holistic planning (zone mapping + layout suggestions), multi-session management, 11 deterministic audit checks, playblast render preview with metadata
Unique to blender-mcpAsset ecosystem breadth (Sketchfab/Hyper3D/Hunyuan3D), first-class object CRUD tools, AI-generated-model integrations, community scale
SharedMCP tool surface, Poly Haven asset source, viewport screenshot feedback, arbitrary Python execution, local socket connection

Poly Haven model search + import shipped in 0.2.0 (issue #2 thin slice: FBX + texture wiring; HDRIs and texture packs remain roadmap). AI generation and first-class object CRUD are explicitly out of scope — the latter is already covered by execute_code.

On the shared asset-download path, this project's controls are enforced in code rather than conventional: downloads happen host-side only — https + host allowlist, per-file md5, size caps, filenames sanitized from the URL's last segment (polyhaven.py) — and Maya itself never touches the network. Enforcement detail: docs/threat-model.md.

[Capability Matrix]
CapabilityToolsNotes
🧊 Spatial awarenessscene_snapshot scene_inspect scene_measureOne-call full-scene spatial model; precise distance/overlap/gap measurement
🎨 Aesthetic analysisscene_aesthetics5 dimensions: color theory (60-30-10), spatial composition (golden ratio / rule of thirds), proportion & scale (ergonomics), lighting quality (three-point / fill ratio / temperature / decay), visual flow
🎬 Camera planningcamera_create camera_orbit8 industry-standard shot types + orbit animation
🛡️ Disaster recoveryscene_checkpoint scene_rollback scene_checkpoint_listexportAll in-memory snapshots; rollback explicitly rebinds the original path
🧠 Scene planningscene_planOrganization health, zone balance, layout suggestions, conflict prevention, natural-language planning
📋 Engineering auditscene_review scene_validate scene_assert11 deterministic checks (0-100 score) + custom constraint validation + state assertions
⚡ Code executionexecute_code write_moduleRun arbitrary Python in Maya / inject reusable modules
👁️ Visual loopscene_viewport_snapshot scene_render_previewWYSIWYG viewport capture + single-frame playblast preview (GUI sessions only)
🔌 Session managementlist_sessions add_session maya_setup_guideMulti-session discovery/attach + connection diagnosis/install/fallback guidance
📦 Asset libraryasset_search asset_importPoly Haven CC0 models — host-side HTTPS download (host allowlist, md5 verify, size caps, platformdirs cache), Maya-side FBX import with texture wiring, polycount/dims guards, GRP_asset_<id> dedup
📤 Scene exportscene_exportFBX/OBJ/USD export — whole scene or named objects; format inferred from extension (conflict is an error, never a guess), parent dirs auto-created, overwrite opt-in, selection restored
🔎 Scene-graph introspectionscene_describe scene_nodesAPI-level node self-description (exact type, per-attribute metadata: keyable/connectable/enum/ranges, connection wiring — size-bounded, *_truncated disclosure, limit up to 1000) + bounded enumeration incl. non-DAG nodes (materials/tool nodes) with has_more/next_cursor pagination

25 MCP tools in total.

[Quick Start]

1. Install

bash
# Install from PyPI (recommended)pip install mcp-for-maya
# or run straight away with uvxuvx mcp-for-maya
# alternative: install from git with uvuv tool install git+https://github.com/Xxx91n/mcp-for-maya.git
# or clone the sourcegit clone https://github.com/Xxx91n/mcp-for-maya.gitcd mcp-for-mayapip install -e .

[!NOTE] Three-layer naming: dist name mcp-for-maya (PyPI shelf name) → installs import package maya_mcp_server (kept from upstream); script name mcp-for-maya (old name maya-mcp-server remains as a compat alias). uvx mcp-for-maya resolves precisely because the command name matches the dist name.

2. Connect Maya

Option A: automatic (recommended)

With the MCP server running, the agent calls maya_setup_guide to walk the connection:

  1. Make sure Maya is running
  2. Give the agent any instruction (e.g. "look at my Maya scene")
  3. If unconnected, the agent runs diagnostics and can install userSetup.py (idempotent marker-block merge, timestamped backup before writing)
  4. After restarting Maya, the command port opens automatically
Option B: manual

In Maya's Script Editor (Python mode, not MEL):

python
import maya.cmds as cmds
cmds.commandPort(name=":7001", sourceType="python")
Option C: persistent auto-connect

Save this as userSetup.py in your Maya scripts directory:

PlatformPath
Windows%MAYA_APP_DIR%\<version>\scripts\
Linux~/maya/<version>/scripts/
macOS~/Library/Preferences/Autodesk/maya/<version>/scripts/
python
import maya.cmds as cmds
cmds.evalDeferred('cmds.commandPort(name=":7001", sourceType="python")', lowestPriority=True)
Multiple Maya instances

A commandPort is a single listening socket bound to one host:port — a second instance fails to bind the same port, so each Maya instance needs its own port. Typical topology:

Maya instancecommandPortNotes
Instance A:7001 pythonprimary
Instance B:7002 pythonsecond instance
Instance A:7011 melMEL port (auto-detected and exempted — no error spam)

Run cmds.commandPort(name=":<port>", sourceType="python") inside each instance (its Script Editor or its own userSetup.py). Auto-scan is the primary path — the server periodically enumerates listening Maya ports and bootstraps them; if a session is missed, add_session(host, port) is the manual fallback. If scanning probes a non-Maya TCP service on the box, bound the probe set with MAYA_MCP_INCLUDE_PORTS=7001,7002 (comma-separated, 7005-7010 ranges allowed) or exclude offenders via MAYA_MCP_EXCLUDE_PORTS=<port>.

Note: a commandPort does not persist across sessions — it dies with Maya; for persistence write it into userSetup.py (Option C).

Troubleshooting
ProblemFix
list_sessions returns emptycall maya_setup_guide(action="diagnose")
Port in useclose other Maya instances or pick another port
userSetup.py not loadingcheck it sits in the right scripts dir, restart Maya
Firewall blocksensure localhost:7001 is reachable
Second Maya instance not listedeach instance needs its own commandPort (same port = bind conflict); if scanning still misses it, call add_session(host, port)
Script Editor spams syntax errorslegacy symptom of probing a MEL port — current versions auto-exempt non-Python ports; if it persists, exclude the port via MAYA_MCP_EXCLUDE_PORTS

3. Configure the MCP client

Codex ~/.codex/config.toml:

toml
[mcp_servers.maya]command = "uvx"args = ["mcp-for-maya"]tool_timeout_sec = 120

For the git source use args = ["--from", "git+https://github.com/Xxx91n/mcp-for-maya.git", "mcp-for-maya"]; for a source checkout use command = "python", args = ["-m", "maya_mcp_server"], and point PYTHONPATH at <repo>/src under env.

4. Use it

Talk naturally:

"Look at what's in my Maya scene, then create a display shelf at the entrance"

The agent calls scene_snapshot() → understands the scene → models → scene_review() audits the result.

[ICEV Workflow]

Every scene modification follows the ICEV loop (also shipped as an agent process card, see skills/icev-workflow):

┌──────────┐     ┌──────────┐     ┌──────────┐     ┌──────────┐│ INSPECT  │ ──→ │ COMPUTE  │ ──→ │ EXECUTE  │ ──→ │ VERIFY   ││ snapshot │     │  plan    │     │  apply   │     │  audit   │└──────────┘     └──────────┘     └──────────┘     └──────────┘
  1. INSPECT: scene_snapshot() for full-scene spatial data
  2. COMPUTE: plan positions, sizes, clearances from that data
  3. EXECUTE: execute_code() applies Maya Python
  4. VERIFY: scene_assert() + scene_review() confirm the result; on GUI sessions the visual tools give pixel-level confirmation

Tools Reference

Spatial

python
scene_snapshot(detail="compact", format="cos")  # full scene in one callscene_inspect(target="wall_entrance", include_neighbors=True)scene_measure(obj_a="wall_north", obj_b="counter_A", mode="clearance")scene_assert(expectations='{"wall": {"exists": true, "position": [0,0,500]}}')

Audit

python
scene_review()  # 11 deterministic checks, 0-100 scorescene_validate(rules='[{"type": "min_clearance", "value": 180}]')

Cameras

python
camera_create(target="product_display", shot_type="medium", azimuth=30, elevation=15)# extreme_wide / wide / medium / close / extreme_close / bird_eye / low_angle / over_shouldercamera_orbit(center=[0, 100, 0], radius=500, frames=120)

Disaster recovery

python
scene_checkpoint(name="before_renovation")  # exportAll in-memory snapshot; no undo historyscene_checkpoint_list()scene_rollback(filename="cp_before_renovation.ma")# auto safety snapshot first, then rebinds the scene name to the original path# call scene_snapshot() after a rollback — snapshots carry no undo history# self-contained: references are flattened (no write-back); one scene file per session assumed

Assets (Poly Haven, host-side download)

python
asset_search(query="camera", asset_type="models", limit=20)  # Poly Haven indexasset_import(asset_id="Camera_01", resolution="1k")# HTTPS-only download into a platformdirs cache (per-file md5 verify + sha256 audit),# then Maya imports the local FBX under GRP_asset_<asset_id> (repeat calls dedup;# force=True re-imports). Textures auto-wire by filename suffix# (diff/rough/metal/nor_gl/ao/disp...) with sRGB/Raw color spaces and bump2d normals.# Single-part assets ship bare map names (Diffuse/Rough/Metal...) — those are# recognised too and wired onto the asset's single material.# Guards: 100k-face polycount cap (allow_high_polycount override), dims sanity report.

Scene export

python
scene_export(path="D:/out/scene.fbx")  # whole scene; format inferred from .fbxscene_export(path="/tmp/kit", format="obj")  # missing extension is appended -> kit.objscene_export(path="D:/out/kit.usd", objects=["GEO_box"])  # exportSelected; prior selection restored# format {fbx,obj,usd}: an extension/format conflict is an error, never a guess.# An existing file is rejected unless overwrite=True. prompt=False is forced# (no modal can hang the channel); the scene's modified flag is untouched.# Alembic is not supported — AbcExport is not a cmds.file surface.

Visual loop (GUI sessions only)

python
scene_viewport_snapshot(    max_size=800, format="jpeg")  # HUD/selection included — what the artist seesscene_render_preview(camera="CAM_hero", width=640, height=360)  # clean single-frame playblast# both return [image, JSON metadata]; headless sessions get a gui_session_required error# prefer format="png" for wireframe/line-art review; trust returned metadata for actual size

CoS Notation

Default output uses Chain-of-Symbol notation to compress scene data. The format's paper reports ~65% token savings vs JSON on its demo scenes (arXiv:2305.10276, −65.8%) — this project implements the notation; that figure is the paper's measurement, not a benchmark of this project.

SCENE[164obj, 5zones] UNIT=cm UP=yshell (23obj) @(-11.8,178.8,145.7)  GRP_floor[mesh]@(0,0,0) 1121.5x20x1530.5

Agent Skills

Two Experimental process cards ship in skills/:

SkillPurpose
skills/icev-workflowICEV discipline: every scene mutation goes through Inspect→Compute→Execute→Verify
skills/scene-review-playbookAudit playbook: what the 11 checks weigh and how to map findings to fixes

Evaluated on Claude Code only; untested on Codex/Gemini CLI/Cursor. Cross-model evaluation is tracked in issue #3.

[Audit & Trust]

scene_review() provides 11 universal checks (score normalized to 0-100):

CheckMax ptsWhat it looks at
spatial10object/camera/light presence
overlaps10bbox collisions (parent-child excluded)
conflicts10penetration between unrelated objects
zones5naming-rule zone coverage
naming5production naming convention
components10GRP_ grouping + nesting depth ≤ 4
orphans5empty groups / default names
aesthetics155-dimension aesthetics (color/composition/scale/lighting/flow)
lighting10three-point setup, fill ratio, decay
organization10overall hierarchy health
constraints5custom rule violations

Trust & Privacy

  • Zero telemetry: no phone-home — the project ships no telemetry or unsolicited outbound traffic; verify in source. The ONLY outbound calls are the two asset tools: HTTPS to api.polyhaven.com / dl.polyhaven.org|.com (host allowlist + md5 + size caps in polyhaven.py), and only when you call them.
  • Local, single-user: the command port binds localhost only; the connected MCP client is trusted.
  • Safety net: a unified pipeline (pipeline.py + security.py) validates arguments + token-bucket rate limits (~100/60s reads, ~20/60s writes, per session) + pattern scan (warn-only by default) + an independent JSONL audit log across all 25 tools. It catches accidents, not malicious clients — full model in docs/threat-model.md.
  • Transactional safety: scene_checkpoint/scene_rollback give in-memory snapshots and explicit rollback (no undo history; references flattened).
  • Vulnerability reporting: SECURITY.md.

Versioning

This project follows Semantic Versioning:

  • 0.x (through 0.3.x, Alpha): the tool surface could still change; minor bumps carried features, no compatibility freeze.
  • Beta (0.4.0): feature-complete tier — external testing begins here (classifier 4 - Beta).
  • 1.0.0: public API freeze — tool surface and output schemas stable per semver; breaking changes require 2.0.0. Promoted together with the 5 - Production/Stable classifier in one commit; gated by the #7 real-machine checklist (Pass-set green + explicit waived items with owner/expiry — three-state gate, D-163).

The public API is the MCP tool surface: tool names, their input/output shapes, the two-layer error contract (host isError failures vs {error:{code,message,suggestion}} domain results), and tool-annotation semantics (docs/threat-model.md §5). Additive changes (new tools, new optional response fields) ship as minor releases; breaking changes ship as a major bump. 1.0.0 is a freeze commitment on this surface — not a quality certification: the remaining real-machine verification surface is tracked explicitly in #7 rather than implied away.

Releases are milestone-driven — no fixed cadence promised. Roadmap lives in GitHub issues: #2 Poly Haven integration (model slice shipped in 0.2.0; scene_plan recommendation residual split to #31), #3 Skills program (v1.x), #4 security & permission model (v1.x), #5 scene export + introspection (scene_export shipped in 0.3.0: FBX/OBJ/USD; scene_describe/scene_nodes introspection shipped in the same 0.3.0), #6 more asset sources (exploratory), #7 real-machine checklist + v1.0 feedback (pinned).

Requirements

EnvironmentRequirement
Host (runs the MCP server)Python >= 3.10 (requires-python); Windows / Linux / macOS
Injected helper (runs inside Maya)Maya >= 2023 (bundled Python >= 3.9; relies on ast.unparse — older versions get an explicit refusal at injection)
Verified againstMaya 2024 GUI

The two visual-loop tools need a GUI session (headless/mayapy returns a structured capability error). On the first capture the server probes the VP2 readback direction per-session (a disposable scene probe, net-zero side effects); MAYA_MCP_VP2_BOTTOM_UP=0|1 forces it when a driver misreports.

Development

bash
uv sync --frozen                  # locked dev env from uv.lock (alt: pip install -e . --group dev, pip>=25.1)python -m pytest tests/ -q       # testsruff check src tests             # lintmypy src                         # typecheckpython -m maya_mcp_server -vv    # run with DEBUG logs (-v=INFO, -vv=DEBUG)

See CONTRIBUTING.md for the PR flow and CHANGELOG.md for the change log.

Credits

Forked from chadrik/maya-mcp-server — upstream MIT copyright retained (see LICENSE); this project adds the scene-intelligence layer on top of its connection stack.

How each upstream open issue maps to a disposition and release version in this fork: docs/upstream-issue-status.md.

Source: README.md at commit 8d4e273

Tools

0
Tool metadata has not been indexed yet.

Version history

1
  1. v0.5.0LatestSep 30, 2026