Skip to main content

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.

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).

Prompt Result
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 benchscene_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):

Tier Contents
Unique to this project ICEV 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-mcp Asset ecosystem breadth (Sketchfab/Hyper3D/Hunyuan3D), first-class object CRUD tools, AI-generated-model integrations, community scale
Shared MCP 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
Capability Tools Notes
🧊 Spatial awareness scene_snapshot scene_inspect scene_measure One-call full-scene spatial model; precise distance/overlap/gap measurement
🎨 Aesthetic analysis scene_aesthetics 5 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 planning camera_create camera_orbit 8 industry-standard shot types + orbit animation
🛡️ Disaster recovery scene_checkpoint scene_rollback scene_checkpoint_list exportAll in-memory snapshots; rollback explicitly rebinds the original path
🧠 Scene planning scene_plan Organization health, zone balance, layout suggestions, conflict prevention, natural-language planning
📋 Engineering audit scene_review scene_validate scene_assert 11 deterministic checks (0-100 score) + custom constraint validation + state assertions
⚡ Code execution execute_code write_module Run arbitrary Python in Maya / inject reusable modules
👁️ Visual loop scene_viewport_snapshot scene_render_preview WYSIWYG viewport capture + single-frame playblast preview (GUI sessions only)
🔌 Session management list_sessions add_session maya_setup_guide Multi-session discovery/attach + connection diagnosis/install/fallback guidance
📦 Asset library asset_search asset_import Poly 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 export scene_export FBX/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 introspection scene_describe scene_nodes API-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

# Install from PyPI (recommended)
pip install mcp-for-maya

# or run straight away with uvx
uvx mcp-for-maya

# alternative: install from git with uv
uv tool install git+https://github.com/Xxx91n/mcp-for-maya.git

# or clone the source
git clone https://github.com/Xxx91n/mcp-for-maya.git
cd mcp-for-maya
pip install -e .

2. Connect Maya

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):

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:

Platform Path
Windows %MAYA_APP_DIR%\<version>\scripts\
Linux ~/maya/<version>/scripts/
macOS ~/Library/Preferences/Autodesk/maya/<version>/scripts/
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 instance commandPort Notes
Instance A :7001 python primary
Instance B :7002 python second instance
Instance A :7011 mel MEL 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

Problem Fix
list_sessions returns empty call maya_setup_guide(action="diagnose")
Port in use close other Maya instances or pick another port
userSetup.py not loading check it sits in the right scripts dir, restart Maya
Firewall blocks ensure localhost:7001 is reachable
Second Maya instance not listed each instance needs its own commandPort (same port = bind conflict); if scanning still misses it, call add_session(host, port)
Script Editor spams syntax errors legacy 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:

[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

scene_snapshot(detail="compact", format="cos")  # full scene in one call
scene_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

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

Cameras

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

Disaster recovery

scene_checkpoint(name="before_renovation")  # exportAll in-memory snapshot; no undo history
scene_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)

asset_search(query="camera", asset_type="models", limit=20)  # Poly Haven index
asset_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

scene_export(path="D:/out/scene.fbx")  # whole scene; format inferred from .fbx
scene_export(path="/tmp/kit", format="obj")  # missing extension is appended -> kit.obj
scene_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)

scene_viewport_snapshot(
    max_size=800, format="jpeg"
)  # HUD/selection included — what the artist sees
scene_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=y
shell (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/:

Skill Purpose
skills/icev-workflow ICEV discipline: every scene mutation goes through Inspect→Compute→Execute→Verify
skills/scene-review-playbook Audit 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):

Check Max pts What it looks at
spatial 10 object/camera/light presence
overlaps 10 bbox collisions (parent-child excluded)
conflicts 10 penetration between unrelated objects
zones 5 naming-rule zone coverage
naming 5 production naming convention
components 10 GRP_ grouping + nesting depth ≤ 4
orphans 5 empty groups / default names
aesthetics 15 5-dimension aesthetics (color/composition/scale/lighting/flow)
lighting 10 three-point setup, fill ratio, decay
organization 10 overall hierarchy health
constraints 5 custom 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 (all-green required).

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

Environment Requirement
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 against Maya 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

uv sync --frozen                  # locked dev env from uv.lock (alt: pip install -e . --group dev, pip>=25.1)
python -m pytest tests/ -q       # tests
ruff check src tests             # lint
mypy src                         # typecheck
python -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.

Metadata

Release files for mcp-for-maya 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mcp-for-maya 0.4.0
File Size Uploaded Provenance Actions
mcp_for_maya-0.4.0.tar.gz 649.0 kB With provenance Details for mcp_for_maya-0.4.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for mcp-for-maya 0.4.0
File Interpreter ABI Platform Actions
mcp_for_maya-0.4.0-py3-none-any.whl Python 3 none any Details for mcp_for_maya-0.4.0-py3-none-any.whl

Total release size: 810.3 kB

Release files / mcp_for_maya-0.4.0.tar.gz

Download URL mcp_for_maya-0.4.0.tar.gz
Size 649.0 kB
Tags Source
SHA-256 checksum
How to use checksums
b359c282abd360a292c7079daae84ef8530dcba1e18ea71de6ec934dd65e5379
BLAKE2b-256 checksum
How to use checksums
c1efc70d162780495d0fb6bd8e291a96a9d19c826c656f4b3f1c89bc3fae317e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.

Transparency log

Release files / mcp_for_maya-0.4.0-py3-none-any.whl

Download URL mcp_for_maya-0.4.0-py3-none-any.whl
Size 161.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6677355931c5e4656786f849da876e8e6ff03c3baa88a804b89902eb674b0d5c
BLAKE2b-256 checksum
How to use checksums
61108a254add987dec278a915d65449c18331a48f8ba8626ff2981df97ffea90
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.

Transparency log

Security for mcp-for-maya 0.4.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for mcp_for_maya-0.4.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.4.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page