Maya plugin for the DCC Model Context Protocol (MCP) ecosystem — embeds a Streamable HTTP MCP server directly inside Maya
Project description
dcc-mcp-maya
Maya plugin for the DCC Model Context Protocol (MCP) ecosystem.
Embeds a standards-compliant MCP Streamable HTTP server (2025-03-26 spec) directly inside Maya — no external gateway or separate IPC process required.
Architecture
┌─────────────────────────────────────────────────────────┐
│ Maya (embedded Python) │
│ │
│ import dcc_mcp_maya │
│ handle = dcc_mcp_maya.start_server(port=8765) │
│ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ McpHttpServer (dcc-mcp-core / Rust/axum) │ │
│ │ POST /mcp ──► ToolRegistry │ │
│ │ GET /mcp ──► SSE stream │ │
│ └─────────────────────────────────────────────────┘ │
└─────────────────────────────┬───────────────────────────┘
│ http://127.0.0.1:8765/mcp
┌─────────────────────────────▼───────────────────────────┐
│ MCP Host (Claude Desktop / OpenClaw / Cursor / …) │
└─────────────────────────────────────────────────────────┘
Installation
Into Maya's Python
mayapy -m pip install dcc-mcp-maya
As a Maya Plugin
- Load the plugin via Window > Settings/Preferences > Plug-in Manager and find
dcc_mcp_maya. - Or add to your
userSetup.py:import maya.cmds as cmds cmds.loadPlugin("dcc_mcp_maya_plugin")
Quick Start
Option A — From Python Script Panel
import dcc_mcp_maya
handle = dcc_mcp_maya.start_server(port=8765)
print(handle.mcp_url()) # http://127.0.0.1:8765/mcp
Point your MCP host at the URL above.
Option B — Load Plugin
Copy maya/plugin/dcc_mcp_maya_plugin.py to a directory on MAYA_PLUG_IN_PATH.
The server starts automatically when the plugin loads.
Configuration
| Environment variable | Default | Description |
|---|---|---|
DCC_MCP_MAYA_PORT |
8765 |
TCP port for the MCP server |
DCC_MCP_MAYA_SERVER_NAME |
maya-mcp |
Name shown in MCP initialize |
DCC_MCP_MAYA_SKILL_PATHS |
(none) | Extra skill directories (semicolon-separated on Windows, colon on Unix) |
DCC_MCP_SKILL_PATHS |
(none) | Global fallback skill directories for all DCC adapters |
DCC_MCP_MAYA_MINIMAL |
1 |
0 = load all skills at startup (legacy); 1 = minimal core surface |
DCC_MCP_MAYA_DEFAULT_TOOLS |
(none) | Comma-separated skill names to load at startup (overrides minimal default) |
Progressive Loading (Minimal Mode)
By default, dcc-mcp-maya boots with a minimal tool surface — only core
skills (maya-scripting, maya-scene) are loaded, and within those only the
essential tools are active:
| Tool | Role | Source skill |
|---|---|---|
execute_python |
Write + execute | maya-scripting (core group) |
execute_mel |
Write + execute | maya-scripting (core group) |
get_scene_info |
Read | maya-scene (core group) |
get_selection |
Read | maya-scene (core group) |
get_session_info |
Read | maya-scene (core group) |
search_tools |
Discover | core |
list_skills |
Browse | core |
load_skill |
Progressive activation | core |
All other skills appear as __skill__<name> stubs. The agent calls
load_skill("maya-primitives") to expand the surface on demand, and
activate_group("extended") to expose additional tool groups within a
loaded skill.
Opt out (restore legacy full-load):
# Environment variable
export DCC_MCP_MAYA_MINIMAL=0
# Or programmatically
server = MayaMcpServer(port=8765)
server.register_builtin_actions(minimal=False)
handle = server.start()
Custom default tools via environment variable:
# Load only specific skills at startup
export DCC_MCP_MAYA_DEFAULT_TOOLS="maya-scripting,maya-scene,maya-primitives"
Bundled Skills (Zero Configuration)
dcc-mcp-maya automatically loads the bundled general-purpose skills shipped
inside the dcc-mcp-core wheel — no path configuration required.
| Skill | Tools | Notes |
|---|---|---|
dcc-diagnostics |
screenshot, audit_log, action_metrics, process_status |
Observability & debugging |
workflow |
run_chain |
Multi-step action chaining |
git-automation |
repo_stats, changelog_gen |
Git analysis |
ffmpeg-media |
convert, probe, thumbnail |
Requires ffmpeg on PATH |
imagemagick-tools |
resize, composite |
Requires ImageMagick on PATH |
To opt-out of bundled skills:
# Disable all bundled core skills
handle = dcc_mcp_maya.start_server(include_bundled=False)
# Or fine-grained control
server = MayaMcpServer()
server.register_builtin_actions(include_bundled=False)
Skill search-path priority (highest → lowest):
extra_skill_pathsargument- Built-in Maya skills (shipped in this package)
DCC_MCP_MAYA_SKILL_PATHSenvironment variableDCC_MCP_SKILL_PATHSenvironment variable- Bundled
dcc-mcp-coreskills ← loaded by default - Platform default skills directory
Diagnostic IPC Actions
When register_builtin_actions() is called, three IPC callback actions are
automatically registered so the dcc-diagnostics skill can retrieve live
runtime data from the running Maya process:
| Action | Returns |
|---|---|
get_audit_log |
SandboxContext audit entries |
get_tool_metrics |
ToolRecorder performance counters |
dispatch_tool |
Relay for workflow__run_chain |
The DCC_MCP_IPC_ADDRESS environment variable is set automatically so skill
subprocesses can connect back without any manual configuration.
Available MCP Tools
dcc-mcp-maya ships 64 built-in skill packages and 370+ Maya MCP tools.
In the default minimal mode, only the core tools above are active at startup;
the rest are progressively loaded via load_skill.
The sections below are representative categories, not an exhaustive inventory.
Scene
| Tool | Description |
|---|---|
get_session_info |
Maya version, scene path, FPS, object count |
new_scene |
Create a new scene |
save_scene |
Save scene to disk |
open_scene |
Open a scene file |
list_objects |
List DAG objects (optional type filter) |
get_selection |
Get current selection |
set_selection |
Set active selection |
Geometry
| Tool | Description |
|---|---|
create_sphere |
Create polygon sphere |
create_cube |
Create polygon cube |
create_cylinder |
Create polygon cylinder |
create_plane |
Create polygon plane |
delete_objects |
Delete objects from the scene |
set_transform |
Set translate/rotate/scale |
get_transform |
Query translate/rotate/scale |
rename_object |
Rename an object |
Material
| Tool | Description |
|---|---|
create_material |
Create Lambert/Blinn/Phong/Arnold material |
assign_material |
Assign material to objects |
set_material_attribute |
Set material color, roughness, etc. |
list_materials |
List all scene materials |
Animation
| Tool | Description |
|---|---|
set_keyframe |
Set keyframe on object attributes |
get_keyframes |
Get keyframe times for object/attribute |
set_timeline |
Set playback timeline range |
get_current_time |
Get current frame number |
set_current_time |
Set current frame number |
Render
| Tool | Description |
|---|---|
set_render_settings |
Set resolution, frame range, renderer |
capture_viewport |
Capture viewport as base64-encoded PNG |
import_file |
Import FBX/OBJ/Alembic/Maya file |
export_selection |
Export selection to FBX/OBJ/Alembic |
Scripting
| Tool | Description |
|---|---|
execute_mel |
Execute a MEL script |
execute_python |
Execute Python inside Maya |
Authoring Skills (execution + affinity)
Every tool in a tools.yaml must declare two fields so the MCP host
knows how to dispatch it safely. Omitting either breaks async dispatch
(core #318) or crashes Maya when a main-thread-only Maya API is routed to
a Tokio worker (core #332):
tools:
- name: playblast
description: Capture a viewport screenshot as a base64-encoded PNG
execution: async # sync | async — default sync
affinity: main # main | any — default main for Maya tools
timeout_hint_secs: 600 # required when execution: async
- name: get_render_settings
execution: sync
affinity: main # cmds.getAttr must run on the UI thread
- name: list_export_presets
execution: sync
affinity: any # pure filesystem read — worker-thread safe
annotations:
read_only_hint: true
idempotent_hint: true
Classification rules (see issue #84):
| Field | When to use | Notes |
|---|---|---|
execution: async |
Typical wall-clock > 2s (render, bake, cache, large import/export, simulation) | Must also set timeout_hint_secs. Surfaces as MCP deferredHint=true. |
execution: sync |
Bounded-time queries and single-attribute setters | Default. |
affinity: main |
Anything that imports maya.*, calls OpenMaya, or uses dcc_mcp_maya.api.validate_* |
Safe default for Maya tools. |
affinity: any |
Pure filesystem / pure Python tools that never touch Maya | Verified by grepping the script for import maya. |
timeout_hint_secs: N |
Required alongside execution: async |
Positive integer; becomes _meta.dcc.timeout_hint_secs on tools/list. |
Annotation workflow for bundled skills:
# Apply the per-skill / per-tool classification table to every tools.yaml
python tools/annotate_skill_affinity.py
# CI lints the result — missing fields or async-without-timeout fail fast
python tools/lint_skill_affinity.py
The lint runs in the Lint Skills CI job, so a PR that adds a new tool
without these fields will be rejected. Third-party skill authors can run
the same lint against their own skills root:
python tools/lint_skill_affinity.py --skills-root /path/to/your/skills
Prometheus Metrics (issue #87)
Enable the /metrics endpoint for real-time observability (requires a
wheel built with the prometheus feature):
# Programmatic:
server = MayaMcpServer(port=8765, metrics_enabled=True)
# Or via env var (useful in Maya's userSetup.py):
# DCC_MCP_MAYA_METRICS=1
Exposed metrics include MayaUiPump overrun cycles, queue depth, and
per-tool job-duration histograms. Scrape at:
http://127.0.0.1:<port>/metrics
Job Persistence & Recovery (issue #89)
Enable SQLite job persistence so clients can poll interrupted jobs after a Maya restart:
server = MayaMcpServer(
port=8765,
job_storage_path="/path/to/maya-jobs.db", # default: platform data dir
job_recovery="requeue", # "drop" (default) | "requeue" idempotent jobs
)
Environment variable equivalents:
| Variable | Effect |
|---|---|
DCC_MCP_MAYA_JOB_STORAGE=<path> |
SQLite job DB path |
DCC_MCP_MAYA_JOB_RECOVERY=requeue |
Re-queue idempotent interrupted jobs |
The jobs.get_status built-in MCP tool is automatically available
whenever job_storage_path is configured.
Claude Desktop Integration
Add to claude_desktop_config.json:
{
"mcpServers": {
"maya": {
"url": "http://127.0.0.1:8765/mcp"
}
}
}
Requirements
- Maya 2020+ (Python 3.7+)
dcc-mcp-core≥ 0.12.29
Cooperative Cancellation in Skill Scripts
Long-running skill scripts (renders, bakes, mocap ingest, …) should poll
check_maya_cancelled() at safe checkpoints so the dispatcher can preempt
them when the MCP client sends notifications/cancelled or when
MayaMcpServer.stop() drains pending jobs:
from dcc_mcp_maya import check_maya_cancelled, maya_success
def render_frames(frames):
for frame in frames:
check_maya_cancelled() # raises CancelledError when cancelled
cmds.currentTime(frame)
cmds.render()
return maya_success("rendered", frames=len(frames))
check_maya_cancelled() checks two cancellation sources:
- MCP request token (
dcc_mcp_core.cancellation.check_cancelled) — set by the HTTP handler whennotifications/cancelledarrives for the owningtools/call. - Per-job dispatcher flag — set by
MayaUiDispatcher.cancel(...)orMayaUiDispatcher.shutdown(...). Covers jobs launched outside an MCP request (queued batch render, scriptJob, …) where the contextvar token is not installed.
Outside any of those contexts the call is a cheap no-op, so dropping it into a loop is safe even when the script runs from an interactive REPL or a unit test.
MayaUiPump.stats exposes overrun_cycles (idle ticks where a single
non-cooperative job exceeded budget_ms × 2) and longest_job_ms (worst
single-job wall-clock observed) so operators can tell when a skill needs
to be chunked behind check_maya_cancelled() instead of monopolising the
UI thread.
MayaMcpServer.stop() calls dispatcher.shutdown("Interrupted") on any
dispatcher attached via server.attach_dispatcher(...), so threads blocked
inside submit_callable unblock within the normal event.wait() poll
instead of hanging when Maya restarts mid-job (issue #89).
Authoring Skills: Execution & Affinity
Every tool declared in a tools.yaml file must tell the MCP gateway how it
should be dispatched. This is what lets the gateway return an async job_id
instead of blocking, and what prevents main-thread-affine tools from running
on a worker thread and crashing Maya.
Each entry in tools.yaml supports three dispatch fields:
tools:
- name: render_frames
execution: async # long-running — spawn as a Job
affinity: main # cmds.render touches scene state
timeout_hint_secs: 600 # required when execution: async
- name: get_scene_info
execution: sync
affinity: main # cmds.ls is main-thread-only
- name: list_render_presets
execution: sync
affinity: any # pure filesystem read — worker-thread safe
Rules of thumb:
| Property | Guidance |
|---|---|
execution: async |
Use for anything that typically runs > 2s (render, bake, simulation, large I/O). Must declare timeout_hint_secs. |
execution: sync |
Use for fast queries, attribute edits, and small creations. |
affinity: main |
Default. Anything that calls maya.cmds or OpenMaya. |
affinity: any |
Pure Python / filesystem only — never touches Maya state. |
Two helpers keep the annotations consistent across the 64 bundled skills:
# Annotate every bundled tools.yaml from the SKILL_DEFAULTS table.
python tools/annotate_skill_affinity.py
# CI enforcement — fails if any tool is missing affinity/execution
# or if an async tool is missing timeout_hint_secs.
python tools/lint_skill_affinity.py
Third-party skill authors should run tools/lint_skill_affinity.py against
their own skill packages before publishing. See issue
#84 for the full
categorisation matrix.
Deployment Guides
- Multi-instance deployment (中文)
— run multiple Maya sessions on a single workstation behind one MCP gateway.
A drop-in
userSetup.pyis provided underexamples/multi-instance/.
Development
Clone and Install
git clone https://github.com/loonghao/dcc-mcp-maya
cd dcc-mcp-maya
pip install -e ".[dev]"
pytest tests/
Maya Development Setup
Unix/macOS
# Link source code to Maya modules directory
just maya-link
# Install dcc-mcp-core into Maya Python
just maya-install-core maya-py=/path/to/mayapy
# Or if mayapy is on PATH:
just maya-install-core
# Check link status
just maya-status
# Full setup
just maya-dev
Windows (PowerShell)
# Link source code to Maya modules directory
just maya-link-win
# Install dcc-mcp-core into Maya Python
just maya-install-core-win maya-version=2025
# Check link status
just maya-status-win
# Clean up (remove symlinks)
just maya-unlink-win
Note: Windows symlinks require either:
- Windows Developer Mode enabled (Windows 10/11)
- Or running PowerShell as Administrator
If symlinks fail, the scripts will automatically fall back to copying files (changes will require re-running just maya-link-win).
Verify Installation
just verify-deps
Run Tests
just test-quick
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dcc_mcp_maya-0.2.14.tar.gz.
File metadata
- Download URL: dcc_mcp_maya-0.2.14.tar.gz
- Upload date:
- Size: 621.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bb450542877bedd279993ad5dcc723803de4e90ac2f1aa40396610d2e7e95499
|
|
| MD5 |
cc67b3d3c570b7a416eb32135121d1f9
|
|
| BLAKE2b-256 |
c532b87e35ce3c2e036ec5f4d04652e901c99fad48039ae547281bbd7f710e2f
|
Provenance
The following attestation bundles were made for dcc_mcp_maya-0.2.14.tar.gz:
Publisher:
release.yml on loonghao/dcc-mcp-maya
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dcc_mcp_maya-0.2.14.tar.gz -
Subject digest:
bb450542877bedd279993ad5dcc723803de4e90ac2f1aa40396610d2e7e95499 - Sigstore transparency entry: 1358416689
- Sigstore integration time:
-
Permalink:
loonghao/dcc-mcp-maya@0b97a21ff9bd7e7bd87827018728cf829bf12010 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/loonghao
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@0b97a21ff9bd7e7bd87827018728cf829bf12010 -
Trigger Event:
push
-
Statement type:
File details
Details for the file dcc_mcp_maya-0.2.14-py3-none-any.whl.
File metadata
- Download URL: dcc_mcp_maya-0.2.14-py3-none-any.whl
- Upload date:
- Size: 616.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
624032c54b37f3483e23361166773a2d1970fcb95ec59df9ba26244b27f6544c
|
|
| MD5 |
2fb09c4efd11952ce85fa85b0c570ece
|
|
| BLAKE2b-256 |
6d8c7387a1a5e53135a8811e3adbe0d3996c0b81e3b9da00d63fec24749e8040
|
Provenance
The following attestation bundles were made for dcc_mcp_maya-0.2.14-py3-none-any.whl:
Publisher:
release.yml on loonghao/dcc-mcp-maya
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dcc_mcp_maya-0.2.14-py3-none-any.whl -
Subject digest:
624032c54b37f3483e23361166773a2d1970fcb95ec59df9ba26244b27f6544c - Sigstore transparency entry: 1358416694
- Sigstore integration time:
-
Permalink:
loonghao/dcc-mcp-maya@0b97a21ff9bd7e7bd87827018728cf829bf12010 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/loonghao
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@0b97a21ff9bd7e7bd87827018728cf829bf12010 -
Trigger Event:
push
-
Statement type: