fpt-mcp
MCP server for Autodesk Flow Production Tracking (ShotGrid) enabling AI assistants to query, create, update, and delete entities via the ShotGrid API with built-in RAG anti-hallucination and safety layers.
README
fpt-mcp
Connect Claude to Autodesk Flow Production Tracking (ShotGrid) for production management using the Model Context Protocol (MCP)
[!WARNING] Experimental project โ use at your own risk. This is an independent, unofficial experiment created with Claude Code. It is not affiliated with, endorsed by, or officially supported by Autodesk in any way. The ShotGrid / Flow Production Tracking name and trademarks belong to Autodesk, Inc.
Allowing AI-generated operations against a live ShotGrid instance carries real risks: unintended data modifications, accidental entity deletion, incorrect publishes, or metadata corruption. Always test against a dedicated sandbox project first. Never run this against production data without understanding the operations being performed. The author(s) accept no responsibility for data loss, corruption, or any other damage resulting from its use.
๐ Code knowledge graph
Interactive, auto-published map of this codebase โ modules, functions, call/import edges and community clusters โ rebuilt by graphify and deployed to GitHub Pages on every push to src/:
abrahamadsk.github.io/fpt-mcp ยท part of the MCP ecosystem graph hub.
MCP server for Autodesk Flow Production Tracking (formerly ShotGrid).
Gives any MCP-compatible AI assistant (Claude Desktop, Claude Code, or any MCP client) full access to the ShotGrid API, Toolkit path resolution, and a RAG-powered knowledge engine that prevents common API hallucinations.
Claude Desktop / Claude Code / any MCP client
โโโ fpt-mcp
โโโ stdio โ Claude Desktop / Claude Code
โโโ HTTP โ scripts, inter-service calls
โโโ Qt console โ native chat app via fpt-mcp:// protocol handler
Features
Unrestricted ShotGrid API Access
fpt-mcp exposes the full shotgun_api3 Python SDK without locking down entity types or fields. Any entity โ Asset, Shot, Sequence, Version, Task, PublishedFile, or custom entities โ can be queried, created, updated, deleted, or batched through a single consistent set of tools. This matters because production pipelines vary widely: the server never assumes which entity types or field names a studio uses.
Toolkit Path Resolution
When a project has an Advanced Setup in ShotGrid, the server queries the PipelineConfiguration entity, reads roots.yml and templates.yml directly from the installed Toolkit config, and resolves publish paths using the project's real template definitions. No paths are hardcoded โ the resolution uses whatever tk-config is installed, whether default, custom, or forked. Projects without a PipelineConfiguration still get full publish support through explicit path fallback.
RAG Anti-Hallucination Engine
LLMs hallucinate ShotGrid API details constantly โ invalid filter operators, wrong entity reference formats, non-existent Toolkit template tokens. fpt-mcp counters this with a hybrid retrieval system: at query time, search_sg_docs performs semantic search (ChromaDB + BAAI/bge-large-en-v1.5) and lexical search (BM25) against three verified API reference documents, fuses the rankings with RRF, and injects the most relevant chunks into Claude's context. The result is correct filter syntax and valid entity formats on the first attempt instead of the third.
Safety Layer
The safety.py module scans every tool call before execution against twelve regex patterns that cover the most destructive operations: bulk delete without specific IDs, unfiltered queries with no limit, path traversal in publish paths, PublishedFile deletion, invalid filter operators, large batch operations, and schema modifications. Blocked operations return a warning with a safe alternative โ they never reach the ShotGrid API.
The two tools that actually write files โ tk_publish (copies a source file to a publish path) and sg_download (writes a downloaded attachment) โ additionally enforce write-path containment via paths.py. Each write destination is anchored on a legitimate project root before any bytes are written, computed on the real path (os.path.realpath + Path.is_relative_to), so it catches dot-dot traversal, absolute escapes with no .. (e.g. /etc/passwd), and symlink escapes that the detection-only safety.py regex cannot. Allowed roots = the discovered TkConfig.project_root (when a PipelineConfiguration resolves) plus the FPT_MCP_ALLOWED_WRITE_ROOTS allowlist. The default policy is warn-and-allow (a destination outside the roots is logged and permitted, so existing workflows are unaffected); set FPT_MCP_STRICT_PATHS=1 to turn it into a hard refusal that writes nothing. See FPT_MCP_ALLOWED_WRITE_ROOTS / FPT_MCP_STRICT_PATHS below.
Structured ShotGrid error responses
When a ShotGrid call fails on authentication, connectivity, or a protocol error, the tool no longer surfaces an opaque Error executing tool ... string. Instead sg_errors.py translates the shotgun_api3 fault family (AuthenticationFault, Fault, MissingTwoFactorAuthenticationFault, ProtocolError, ResponseError, ShotgunFileDownloadError) plus the underlying socket/urllib/SSL/timeout errors โ and the credential EnvironmentError raised at startup by _validate_config โ into a consistent JSON object the model can branch on:
{
"error": "<scrubbed, truncated server message>",
"error_type": "authentication_failed",
"hint": "ShotGrid rejected the credentials. Check SHOTGRID_SCRIPT_NAME / SHOTGRID_SCRIPT_KEY in .env (SG Admin -> Scripts) ...",
"retryable": false
}
error_type is a stable machine-readable class (authentication_failed, two_factor_required, sso_credentials_rejected, shotgrid_api_fault, protocol_error, malformed_response, download_failed, ssl_error, timeout, connection_error, config_error), hint is concrete remediation guidance, and retryable is an advisory label (the server does not auto-retry โ a 5xx/timeout is worth retrying, a bad key is not). The translation is applied by the @sg_errors_to_json decorator at the *_impl / *_do_* tool-boundary layer, reusing the standard top-level error key so the result is counted as a failed turn (p_fallo) and skips suggestion annotation like every other error path. The echoed server message is scrubbed of credential-shaped tokens and truncated to 300 characters. Unrecognised exceptions (genuine bugs) are re-raised with their traceback rather than swallowed.
Qt Console and Protocol Handler
fpt-mcp ships a native PySide6 chat window that routes messages through the Claude Code CLI and renders responses with full Markdown support. The console registers the fpt-mcp:// custom URL scheme on macOS, which means a ShotGrid Action Menu Item can open a chat window with full entity context (entity type, ID, project) pre-populated in a single click โ no browser tab, no copy-paste of IDs.
Requirements
- Python >= 3.10
- macOS (for protocol handler; Qt console also works on Linux/Windows without protocol handler)
shotgun_api3(ShotGrid Python API)mcp[cli](MCP Python SDK with FastMCP)pydantic>= 2.0PySide6>= 6.6 (Qt for Python)python-dotenvhttpxpyyaml(Toolkit config parsing)chromadb>= 0.5.0 (RAG vector database)sentence-transformers>= 2.2.0 (RAG embeddings โ BAAI/bge-large-en-v1.5)rank-bm25>= 0.2.2 (RAG lexical search)- Claude Code CLI (
npm install -g @anthropic-ai/claude-code)
Optional โ local / free inference with Ollama:
- Ollama >= 0.17.6
- macOS:
brew install ollama && brew services start ollama - Linux: https://ollama.com/download/linux (systemd)
- Verify:
ollama --version
- macOS:
- Create the
qwen3.5-mcpmodel (required for Ollama backends):ollama pull qwen3.5:9b cat > /tmp/Modelfile.qwen35mcp <<'EOF' FROM qwen3.5:9b PARAMETER num_ctx 16384 PARAMETER temperature 0.7 PARAMETER top_p 0.8 PARAMETER top_k 20 EOF ollama create qwen3.5-mcp -f /tmp/Modelfile.qwen35mcp - See MODEL_STRATEGY.md for the full rationale (num_ctx bump,
think: falserequirement, KEEP_ALIVE tuning, KV-cache dtype)
Install
cd fpt-mcp
python3 -m venv .venv
source .venv/bin/activate
pip install -e .
Or use the automated installer (creates venv, installs deps, builds RAG index, registers in Claude Code, pre-approves tools):
chmod +x install.sh
./install.sh
After installing, run the doctor to verify everything is wired correctly:
./install.sh --doctor
A legacy setup_venv.sh script also exists (creates venv + launchd service + Qt console .app bundle on macOS) but install.sh is the recommended entry point.
Configure (MANDATORY โ do not skip)
[!IMPORTANT] Running
setup_venv.shorinstall.shon its own is not enough. The installer creates.envfrom the template but leaves the fields holding placeholder values. Until you edit.envwith your real ShotGrid credentials, every MCP call fails with an SSLCERTIFICATE_VERIFY_FAILEDerror.
Copy .env.example โ .env (or let the installer do it) and replace
every field with your real values:
SHOTGRID_URL=https://your-actual-site.shotgrid.autodesk.com
SHOTGRID_SCRIPT_NAME=your-actual-script-name
SHOTGRID_SCRIPT_KEY=your-actual-application-key
SHOTGRID_PROJECT_ID=123
Where each field comes from:
SHOTGRID_URLโ the exact URL you use to log into your ShotGrid site via browser, in the formhttps://<your-site>.shotgrid.autodesk.com.SHOTGRID_SCRIPT_NAMEโ the name of an API script registered in ShotGrid Admin โ Scripts. If you don't have one with the permissions you need, create it there first.SHOTGRID_SCRIPT_KEYโ the application key shown next to the script name in the same admin page.SHOTGRID_PROJECT_IDโ integer ID of the project you work in most often. Used as a default filter forsg_find,sg_create,sg_upload, and as the key for ToolkitPipelineConfigurationlookup. Set to0to disable the default filter (every call must then specify project explicitly).
After editing .env, restart any running fpt-mcp process (Qt console, MCP server) so it picks up the new values.
Optional: server-behaviour env vars
These are optional and control server-side behaviour, not ShotGrid identity:
FPT_MCP_ALLOWED_WRITE_ROOTSโos.pathsep-separated list of absolute directory roots thattk_publishandsg_downloadare permitted to write under. The effective allowlist is this list UNION the discoveredTkConfig.project_root(when a PipelineConfiguration resolves). Leave unset to rely solely on the discovered project root (or, with no config, no root โ see the policy below).FPT_MCP_STRICT_PATHSโ set to1to enforce write-path containment: a destination outside the allowed roots is refused with an{"error": ...}and nothing is written. Default (unset / any other value) is warn-and-allow: the out-of-root destination is logged and the write proceeds, so no existing workflow breaks. Turn this on once you have declared your write roots viaFPT_MCP_ALLOWED_WRITE_ROOTS.
The installer scripts now detect placeholder values left in .env and emit a visible warning at the end of the install. The MCP server itself will also refuse to start with a clear error message pointing to .env if placeholders remain. Both safeguards exist specifically to prevent confusing SSL errors on the first real call.
Verify credentials
After editing .env, run the doctor to validate connectivity end-to-end:
./install.sh --doctor
The doctor performs five independent checks โ claude.json registration, .env placeholder detection, venv importability, live ShotGrid API connectivity, and Qt dependency availability. Any FAIL line includes a concrete remediation sentence.
Common pitfalls:
- Placeholder values left in
.envโ the most frequent cause ofCERTIFICATE_VERIFY_FAILEDerrors on first use. The doctor detects these automatically. SHOTGRID_PROJECT_ID=0โ disables default project scoping. Everysg_find,sg_create, andsg_uploadcall must then specify a project filter explicitly. This is valid for multi-project workflows but unexpected for single-project setups.- Script key vs. user credentials โ the
.envkey is an API script key from Admin โ Scripts, not your personal login password. - Stale
.envafter site migration โ if your ShotGrid site URL changes (e.g. during an Autodesk ID migration), updateSHOTGRID_URLand re-run--doctor.
Usage
Once configured, fpt-mcp is available through Claude Code, Claude Desktop, or the Qt console. Connect to your ShotGrid instance and start a conversation:
You: "Find all Character assets in the Sunrise project that are currently in Pending Review"
Claude โ search_sg_docs (filter syntax for Asset) โ sg_find (entity=Asset, filters=[project, sg_asset_type, sg_status_list]) โ Returns asset list with name, status, and assigned tasks
You: "Create a new Shot called sh0150 in sequence SQ010 for project Sunrise, cut in 1001 cut out 1024"
Claude โ search_sg_docs (Shot entity format) โ sg_create (entity=Shot, fields={code, sg_sequence, project, sg_cut_in, sg_cut_out}) โ Shot created and linked to sequence
You: "Publish /jobs/sunrise/assets/char_hero/maya/publish/char_hero_v003.ma to the Rigging task on asset Hero"
Claude โ search_sg_docs (publish pattern) โ tk_resolve_path (PipelineConfiguration lookup) โ tk_publish (copy file, find/create PublishedFileType, link Task, register PublishedFile) โ Publish registered in ShotGrid
You: "How do I filter Versions by review status using the ShotGrid Python API?"
Claude โ search_sg_docs (status filter operators, Version entity) โ Returns verified filter syntax, valid operator names, and a working code example from the RAG knowledge base
<!-- concept:mcp_tool_count start -->
Tools (15 MCP tool registrations โ dispatcher pattern)
<!-- concept:mcp_tool_count end -->
General-purpose tools with no entity restrictions โ works with any ShotGrid entity type and field. Bulk and reporting operations are consolidated behind two dispatcher tools to reduce tool-count overhead for the LLM.
<!-- concept:mcp_tool_table start -->
ShotGrid API โ Direct Tools (6 tools)
| Tool | Description |
|---|---|
sg_find |
Search any entity type with any filters and fields |
sg_create |
Create any entity with any fields (project auto-linked) |
sg_update |
Update any field on any entity |
sg_schema |
Inspect available fields for any entity type |
sg_upload |
Upload file to any entity field (thumbnail, movie, attachment) |
sg_download |
Download attachment from any entity field |
ShotGrid API โ Bulk Dispatcher (fpt_bulk โ 1 tool, 3 actions)
<!-- concept:fpt_bulk_actions start -->
| Action | Description |
|---|---|
fpt_bulk(action="delete") |
Soft-delete (retire) any entity. Can be restored from trash |
fpt_bulk(action="revive") |
Restore a previously retired entity |
fpt_bulk(action="batch") |
Transactional bulk operations โ all succeed or all fail |
| <!-- concept:fpt_bulk_actions end --> |
ShotGrid API โ Reporting Dispatcher (fpt_reporting โ 1 tool, 4 actions)
<!-- concept:fpt_reporting_actions start -->
| Action | Description |
|---|---|
fpt_reporting(action="text_search") |
Full-text search across multiple entity types simultaneously |
fpt_reporting(action="summarize") |
Server-side aggregation: count, sum, avg, min, max with grouping |
fpt_reporting(action="note_thread") |
Read the full reply thread of a Note with all nested replies |
fpt_reporting(action="activity") |
Read the activity stream (updates, status changes, notes) for an entity |
| <!-- concept:fpt_reporting_actions end --> |
Toolkit (2 tools)
| Tool | Description |
|---|---|
tk_resolve_path |
Resolve publish path from the project's real PipelineConfiguration |
tk_publish |
Publish file: resolve path, copy file, find/create PublishedFileType, link Task, register in ShotGrid |
Launcher (1 tool)
| Tool | Description |
|---|---|
fpt_launch_app |
Launch a DCC (Maya, Flame) scoped to a ShotGrid entity. OS-first discovery with the FPT-selected Software version authoritative over "newest installed". Maya routes through Toolkit tank when available (open -a fallback); Flame launches directly into the matching local project via startApplication --start-project (route auto/direct/toolkit). Returns a launch plan with pid, argv, launch_method, warnings. See Launcher prerequisites before first use. |
RAG โ API Knowledge Engine (4 tools)
| Tool | Description |
|---|---|
search_sg_docs |
Hybrid search across ShotGrid API documentation (ChromaDB + BM25 + HyDE + RRF). Returns relevant API patterns, correct filter syntax, and entity format examples. Called automatically before complex queries |
learn_pattern |
Persist validated API patterns into the knowledge base. Model trust gates: Opus/Fable write directly, other models stage candidates for human review |
session_stats |
Token usage statistics: calls, tokens in/out, RAG savings, cache hits, efficiency ratio, p_fallo |
reset_session_stats |
Zero the session counters immediately (manual companion to the 30-min idle auto-reset) |
| <!-- concept:mcp_tool_table end --> |
Approach
Full ShotGrid API access via shotgun_api3 with no entity restrictions.
Toolkit path resolution
Projects with Advanced Setup (PipelineConfiguration exists):
The server queries the PipelineConfiguration entity from ShotGrid, reads the local roots.yml and templates.yml, and resolves publish paths using the project's real Toolkit config. This works with local configs, dev descriptors, and distributed configs. No hardcoded templates โ paths come from the actual tk-config.
Projects without Advanced Setup:
If no PipelineConfiguration is found, tk_publish asks for an explicit publish path. The file is copied to the given location and registered as a PublishedFile in ShotGrid. If the project has a Local File Storage configured (ShotGrid โ File Management โ Local File Storage), the path will be resolvable from the ShotGrid web UI. Without Local Storage, the path is still stored in the PublishedFile path field and accessible to any script or loader that reads it.
The tk_config.py module reads whatever Toolkit config is installed โ default, custom, or forked.
Launcher prerequisites
fpt_launch_app uses an OS-first resolver (software_resolver.py) to find the DCC binary on the local machine, then upgrades the launch to route through Toolkit's tank CLI when the project has an Advanced Setup PipelineConfiguration. On fresh machines, two one-time setup steps are required before the tool can launch a DCC in context:
1. Tank CLI authentication (per user, per site)
Toolkit's tank CLI has its own browser-based authentication, separate from the script key used by the ShotGrid Python API. The cached session expires periodically. On first use (or after expiry), you must run once interactively:
/path/to/PipelineConfiguration/tank <EntityType> <entity_id>
The CLI will open a browser for Autodesk SSO, approve, and the session token is cached under ~/Library/Caches/Shotgun/<site>/. After that, all subsequent tank invocations โ including the ones fpt_launch_app spawns โ work non-interactively.
If you see an error like EOF when reading a line or Authentication ... expired when calling fpt_launch_app, your tank session needs a refresh via the manual step above.
2. bundle_cache_fallback_roots in pipeline_configuration.yml
Classic Advanced Setup configs created by setup_project expect bundles (engines, apps, frameworks) to live under <config>/install/engines/, <config>/install/apps/, etc. When the config was set up without running the bundle-cache step, or when it shares bundles with other projects via the global ShotGrid cache, the local install/ directory will only contain core/ and tank will fail with Cannot start engine! tk-shell v<X> does not exist on disk.
Fix by adding a fallback path to <config>/config/core/pipeline_configuration.yml:
pc_id: <project-pc-id>
pc_name: Primary
project_id: <project-id>
project_name: <project-name>
published_file_entity_type: PublishedFile
use_shotgun_path_cache: true
bundle_cache_fallback_roots:
- /Users/<you>/Library/Caches/Shotgun/bundle_cache
This is an additive change: classic localized bundles under <config>/install/ still win when present; the fallback kicks in only for bundles that are not in the local install dir but exist in the global ShotGrid cache from a previous FPT Desktop sync.
3. Tank command naming convention
tk-multi-launchapp registers its launcher command under two common names depending on the pipeline:
launch_<app>โ the default when the pipeline exposes a single DCC version.<app>_<version>โ the convention when the pipeline registers one launcher per installed version (maya_2027,nuke_16.0v4, etc.).
fpt_launch_app prefers the version-specific form when the OS scan parses a version from the install path, and falls back to launch_<app> otherwise. Pipelines with yet another convention will need a wrapper that maps to the right tank command.
Flame context launch
Flame does not need the tank prerequisites above: by default (route="auto" or "direct") fpt_launch_app composes the direct CLI launch
/opt/Autodesk/flame_<ver>/bin/startApplication \
--start-project=<name> [--start-workspace=<ws> | --create-workspace] --closed-libs
with three guard rails, in order:
- Version: the FPT-selected
Software.version_namesentry wins over the newest local install (held-back versions are intentional); a warning names both when the selected version is not installed. - Project mapping: the SG project name is slugified with tk-flame's exact convention (
re.sub(r"\W+", "_", name)) and validated against the projects that actually exist locally (Stone+Wiresw_listProjects, fallback/opt/Autodesk/projectscan). An unknown project is refused โ Flame errors on non-existent--start-projectnames โ withroute="toolkit"suggested, since the tk-flame route pre-creates missing projects via Wiretap. - Single instance: if a Flame-family GUI is already running the launch is refused (Flame holds exclusive per-project locks);
force=trueoverrides explicitly.
route="toolkit" opts into the tank route (pipeline hooks + project auto-creation) and then the tank prerequisites above apply.
RAG โ Anti-hallucination Engine
fpt-mcp includes a hybrid Retrieval-Augmented Generation (RAG) system that provides Claude with verified ShotGrid API knowledge at query time, eliminating common hallucinations like invalid filter operators, incorrect entity reference formats, and wrong Toolkit template tokens.
Architecture
User query โ search_sg_docs tool
โ
โโโโโโโโโดโโโโโโโโ
โ HyDE Expander โ โ Adaptive: detects shotgun_api3 / Toolkit / REST
โโโโโโโโโฌโโโโโโโโ
โ
โโโโโโโโโโโโโผโโโโโโโโโโโโ
โ โ โ
ChromaDB BM25 Index In-session
(semantic) (lexical) Cache
โ โ
โโโโโโโฌโโโโโโ
โ
RRF Fusion (k=60)
โ
Top-N chunks + relevance score
Technology stack
| Component | Technology | Purpose |
|---|---|---|
| Vector DB | ChromaDB (persistent) | Semantic search with cosine similarity |
| Embeddings | BAAI/bge-large-en-v1.5 | Document and query encoding (~570 MB model) |
| Lexical search | BM25Okapi (rank_bm25) | Exact API method name matching |
| Query expansion | HyDE (adaptive) | Generates domain-specific hypothetical code before embedding |
| Rank fusion | RRF (k=60) | Combines semantic + BM25 rankings without score calibration |
| Safety | 12+ regex patterns | Detects dangerous operations before execution |
| Token tracking | Session stats | Measures tokens used vs saved by RAG, calculates efficiency |
| Self-learning | learn_pattern + model gates | Grows the knowledge base from validated patterns |
| Cache | In-session dict | Avoids redundant ChromaDB queries within a session |
Knowledge corpus
The RAG indexes three ShotGrid API reference documents covering distinct domains:
| Document | Content | Size |
|---|---|---|
docs/SG_API.md |
shotgun_api3 Python SDK โ methods, filter operators by field type, entity format rules, anti-patterns | ~7 KB |
docs/TK_API.md |
Toolkit (sgtk) โ PipelineConfiguration discovery, template tokens (case-sensitive), descriptor types, path resolution | ~7 KB |
docs/REST_API.md |
REST API โ comparison table vs Python SDK, filter syntax differences | ~2.5 KB |
HyDE adaptive expansion
Unlike generic HyDE, fpt-mcp detects which API domain the query targets and generates a domain-specific hypothetical document:
- Toolkit queries (template, publish path, roots.yml) โ generates
import sgtkcode skeleton - REST API queries (oauth, bearer, endpoint) โ generates
import requestsHTTP skeleton - Default (most queries) โ generates
from shotgun_api3 import Shotgunskeleton
This produces embeddings closer to the relevant corpus section, improving retrieval precision.
Dangerous pattern detection
The safety.py module scans tool parameters before execution and blocks or warns about dangerous operations:
- Bulk delete without specific IDs
- Unfiltered search with no limit (returns entire database)
- Entity reference format errors (int instead of
{type, id}dict) - Path traversal in publish paths (
../) - Schema modifications (field create/delete)
- PublishedFile deletion (breaks Toolkit references)
- Invalid filter operators (hallucinated by LLMs)
- Large batch operations (>100 entities)
- Incorrect template tokens
Building the RAG index
After installing dependencies, build the ChromaDB index from the documentation corpus:
# From the project directory, with venv activated:
source .venv/bin/activate
python -m fpt_mcp.rag.build_index
This creates the persistent ChromaDB database and BM25 corpus.json. The first run downloads the BAAI/bge-large-en-v1.5 embedding model (~570 MB). The index only needs rebuilding when the documentation files in docs/ change.
Self-Learning
When search_sg_docs returns a low-relevance score (below 60%) but the operation succeeds, Claude can call learn_pattern to persist the working pattern into the knowledge base for future sessions. Model trust gates control who can write directly: only the two top cloud tiers โ Opus and Fable โ append the pattern to the docs (status appended_pending_index; it becomes retrievable on the next build_index). Every other model, including Sonnet and local Ollama models, is read-only and stages candidates in rag/candidates.json for human review before promotion. The allow-list lives in write_allowed_models in config.json (default ["claude-opus", "claude-fable"]).
Token Tracking
Every tool call tracks tokens consumed in and out. The session_stats tool reports the full session breakdown: total calls, tokens used, tokens saved by RAG (versus loading raw documentation), cache hits, patterns learned, and an efficiency ratio. This makes the RAG savings measurable and visible rather than implicit.
Transports
stdio (Claude Desktop / Claude Code)
Default mode. The server communicates via standard input/output as a subprocess.
python -m fpt_mcp.server
HTTP (inter-service, scripts)
Runs on a network port so Maya, Flame, and scripts can connect via TCP.
python -m fpt_mcp.server --http # port 8090 (default)
python -m fpt_mcp.server --http --port 9000 # custom port
Qt Console (native chat app)
Native PySide6 chat window that routes messages through Claude Code CLI. Replaces the browser-based AMI console with a proper desktop app.
Features:
- Markdown rendering (bold, italic, code, headings, lists)
- Dark theme matching ShotGrid aesthetic
- Protocol handler (
fpt-mcp://) for direct launch from ShotGrid AMIs - ShotGrid entity context passed automatically via URL params
- Light Payload support (fetches full context from EventLogEntry API)
- No HTTP server dependency โ launches as a standalone app
Launch
# Direct
fpt-console
# With entity context
fpt-console --entity-type Shot --entity-id 456 --project-id 123
# Via protocol handler (from ShotGrid AMI or terminal)
open "fpt-mcp://chat?entity_type=Asset&selected_ids=123&project_id=456"
ShotGrid AMI setup
Admin โ Action Menu Items โ Add:
- Title: FPT Console
- Entity types: Asset, Shot, Sequence, Version, Task (or any)
- URL:
fpt-mcp://chat
ShotGrid automatically appends entity context parameters (entity_type, selected_ids, project_id, project_name, user_login) to custom protocol URLs. Do not add {placeholder} tokens โ they are only substituted for http:// and https:// URLs.
If Light Payload is enabled in the AMI configuration, ShotGrid sends only an event_log_entry_id instead of the full entity context. The Qt console detects this automatically and fetches the real entity context from the ShotGrid API via EventLogEntry.meta.ami_payload. This requires valid ShotGrid API credentials in .env.
After changing an AMI URL in ShotGrid, you may need to hard-refresh the browser (Cmd+Shift+R) to clear the cached AMI configuration.
When launched from an AMI, the entity context is displayed in the header badge and included in every message sent to Claude.
Client configurations
Claude Desktop
Add to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"fpt-mcp": {
"command": "/path/to/fpt-mcp/.venv/bin/python",
"args": ["-m", "fpt_mcp.server"],
"cwd": "/path/to/fpt-mcp",
"env": {
"SHOTGRID_URL": "https://yoursite.shotgrid.autodesk.com",
"SHOTGRID_SCRIPT_NAME": "your_script_name",
"SHOTGRID_SCRIPT_KEY": "your_key",
"SHOTGRID_PROJECT_ID": "123"
}
}
}
}
The cwd field is required so the server can find the .env file and resolve relative paths correctly.
Claude Code
Claude Code uses two separate files for MCP configuration:
1. MCP server definitions โ ~/.claude.json (note: file in home dir, not inside ~/.claude/):
# Add the server via CLI (recommended):
claude mcp add fpt-mcp -s user -e SHOTGRID_URL=https://yoursite.shotgrid.autodesk.com -e SHOTGRID_SCRIPT_NAME=your_script_name -e SHOTGRID_SCRIPT_KEY=your_key -- /path/to/fpt-mcp/.venv/bin/python -m fpt_mcp.server
# Or edit ~/.claude.json manually:
{
"mcpServers": {
"fpt-mcp": {
"command": "/path/to/fpt-mcp/.venv/bin/python",
"args": ["-m", "fpt_mcp.server"],
"env": {
"SHOTGRID_URL": "https://yoursite.shotgrid.autodesk.com",
"SHOTGRID_SCRIPT_NAME": "your_script_name",
"SHOTGRID_SCRIPT_KEY": "your_key"
}
}
}
}
2. Tool permissions โ ~/.claude/settings.json:
{
"permissions": {
"allow": [
"mcp__fpt-mcp__sg_find",
"mcp__fpt-mcp__sg_create",
"mcp__fpt-mcp__sg_update",
"mcp__fpt-mcp__sg_schema",
"mcp__fpt-mcp__sg_upload",
"mcp__fpt-mcp__sg_download",
"mcp__fpt-mcp__fpt_bulk",
"mcp__fpt-mcp__fpt_reporting",
"mcp__fpt-mcp__fpt_launch_app",
"mcp__fpt-mcp__tk_resolve_path",
"mcp__fpt-mcp__tk_publish",
"mcp__fpt-mcp__search_sg_docs",
"mcp__fpt-mcp__learn_pattern",
"mcp__fpt-mcp__session_stats",
"mcp__fpt-mcp__reset_session_stats"
]
}
}
Important:
mcpServersmust be in~/.claude.json, NOT in~/.claude/settings.json. Thesettings.jsonfile is only for permissions and other settings. If you putmcpServersin the wrong file,claude mcp listwill not show the server.
The permissions.allow list auto-approves all fpt-mcp tools so Claude Code (and the Qt console, which uses Claude Code CLI internally) can call them without manual confirmation each time.
Cross-MCP orchestration (optional)
fpt-mcp works standalone, but when combined with other MCP servers in the same Claude session, Claude can orchestrate multi-tool workflows automatically. For example, with a DCC MCP server configured alongside fpt-mcp, Claude can query ShotGrid for asset data, download references, and register publishes โ all in a single conversation.
Autostart with launchd (macOS)
The setup_venv.sh script (legacy) handles launchd and Qt console setup:
- Creates the venv and installs dependencies
- Generates and installs the MCP server launchd plist (HTTP mode on port 8090)
- Builds the Qt console .app bundle with protocol handler registration
- Registers the protocol handler with macOS Launch Services
For most users, install.sh is the recommended entry point (handles venv, deps, RAG index, Claude Code registration, and tool permissions). Use setup_venv.sh only if you need launchd auto-start or the Qt console .app bundle.
./setup_venv.sh
Manage the MCP server:
launchctl stop com.fpt-mcp.serverโ stoplaunchctl start com.fpt-mcp.serverโ startlaunchctl unload ~/Library/LaunchAgents/com.fpt-mcp.server.plistโ uninstall
Logs: /tmp/fpt-mcp.log and /tmp/fpt-mcp.err
Qt console logs: /tmp/fpt-console.log
Architecture
ShotGrid AMI click
โ fpt-mcp://chat (macOS appends entity params automatically)
โ macOS opens FPT-MCP Console.app (protocol handler via Apple Events)
โ QFileOpenEvent delivers the URL to the Qt app
โ If Light Payload: fetch real context from EventLogEntry API
โ Qt chat window with entity context badge
โ User types natural language
โ Claude Code CLI (claude -p "message" --output-format text)
โ Claude calls fpt-mcp tools via MCP (stdio)
โ ShotGrid API response
โ Markdown rendered in Qt chat window
Project Structure
fpt-mcp/
โโโ pyproject.toml # Package metadata and dependencies
โโโ install.sh # One-step installation script (venv, .env, RAG index, launchd, MCP registration)
โโโ setup_venv.sh # Venv setup; generates and loads the launchd plist at install time
โโโ .env.example # Environment variables template
โโโ .concepts.yml # Concept registry (cross-cutting invariants, strict mode)
โโโ .pre-commit-config.yaml # Pre-commit hooks (verify_concepts, verify_templates)
โโโ CHANGELOG.md # Keep a Changelog + SemVer
โโโ CLAUDE.md # Project context for Claude sessions
โโโ MODEL_STRATEGY.md # LLM backend strategy (cloud + local models)
โโโ LICENSE / NOTICE.md # License and third-party notices
โโโ docs/
โ โโโ DEPLOY.md # Reinstall recipes and deploy workflow
โ โโโ BUCKET_F_PLAN.md # server.py refactor plan (Bucket F)
โ โโโ O3_NEXT_SUGGESTED_ACTIONS.md # Chaining-hints design (next_suggested_actions)
โโโ scripts/
โ โโโ cut-release.sh # Canonical release script (the only supported release path)
โ โโโ verify_concepts.py # Concept-registry drift checker (pre-commit)
โ โโโ verify_templates.py # Toolkit templates vs TK_API.md checker (pre-commit)
โ โโโ check_adversarial_count.py # F3b precondition gate (adversarial test count)
โ โโโ invariant_types.py # Shared invariant engine types
โโโ src/
โ โโโ fpt_mcp/
โ โโโ __init__.py
โ โโโ server.py # MCP server entry point (FastMCP) โ tool registrations
โ โโโ shotgrid.py # Bodies of the direct SG tools + fpt_bulk dispatcher handlers
โ โโโ reporting.py # fpt_reporting dispatcher handlers
โ โโโ toolkit_tools.py # Bodies of tk_resolve_path and tk_publish
โ โโโ launcher.py # Body of the fpt_launch_app tool
โ โโโ rag_tools.py # Bodies of search_sg_docs and learn_pattern
โ โโโ client.py # ShotGrid API client wrapper
โ โโโ filters.py # ShotGrid filter validation and safety constants
โ โโโ models.py # Pydantic input models for every MCP tool (extra="forbid")
โ โโโ safety.py # Safety module โ blocks dangerous write patterns
โ โโโ software_resolver.py # DCC discovery for fpt_launch_app (OS-first cascade)
โ โโโ suggestions.py # Per-tool chaining hints (next_suggested_actions)
โ โโโ tk_config.py # Toolkit config loader (PipelineConfiguration discovery)
โ โโโ _session_stats.py # Session reset + F0 telemetry
โ โโโ ami/
โ โ โโโ handler.py # AMI URL protocol handler (fpt-mcp://)
โ โ โโโ console.html # AMI console HTML template
โ โโโ qt/
โ โ โโโ app.py # Qt application entry point
โ โ โโโ chat_window.py # Chat window widget
โ โ โโโ claude_worker.py # Claude subprocess worker (visible-progress streaming, canonical)
โ โ โโโ build_app_bundle.py # macOS .app bundle builder (registers the fpt-mcp:// URL scheme)
โ โโโ rag/
โ โ โโโ build_index.py # RAG index builder (run to rebuild)
โ โ โโโ config.py # RAG configuration (chunk size, model)
โ โ โโโ corpus.json # Parsed documentation corpus
โ โ โโโ search.py # Hybrid search (ChromaDB semantic + BM25 + HyDE + RRF)
โ โ โโโ index/ # auto-generated (ChromaDB vector store)
โ โโโ docs/
โ โ โโโ REST_API.md # ShotGrid REST API documentation corpus
โ โ โโโ SG_API.md # ShotGrid Python API documentation corpus
โ โ โโโ TK_API.md # Toolkit API documentation corpus
โ โโโ skills/
โ โโโ asset-creation/
โ โโโ SKILL.md # Claude skill for asset creation workflows
โโโ tests/ # Mock suites + golden transcripts + real-index guards
โโโ conftest.py
โโโ fixtures/ # Mock Toolkit templates and fixtures
โโโ golden/ # Golden transcripts (determinism guards)
No machine-specific files in the repo. The launchd plist is not a tracked file:
setup_venv.shwrites~/Library/LaunchAgents/com.fpt-mcp.server.plistat install time, deriving every path from wherever the repo was cloned ($FPT_DIRauto-detected,$HOMEexpanded by the shell). launchd requires absolute paths, so the installed plist is machine-local by design โ it never enters version control. Thefpt-mcp://AMI URL handler is registered by the Qt.appbundle (qt/build_app_bundle.py), not via launchd.
Troubleshooting
Connection refused on ShotGrid API
- Verify
SHOTGRID_URLandSHOTGRID_SCRIPT_KEYin.env - Check that the Script Application is active in ShotGrid Admin โ Scripts
- Test connectivity:
curl -s https://YOUR_SITE.shotgrid.autodesk.com/api/v1
RAG index not found
- Run
python -m fpt_mcp.rag.build_indexto rebuild - Check that
docs/directory contains the ShotGrid API documentation corpus
Toolkit path resolution fails
- Verify that a PipelineConfiguration entity exists for the project in ShotGrid
- Check
roots.ymlandtemplates.ymlpaths in the PipelineConfiguration'sdescriptorfield - For distributed configs, only
devdescriptor type is currently supported
Ecosystem
fpt-mcp is part of a four-component VFX pipeline. Each component has a defined role:
| Repo | Role |
|---|---|
| flame-mcp | Controls Autodesk Flame for compositing, conform, and finishing |
| maya-mcp | Controls Autodesk Maya for 3D modeling, animation, and rendering |
| fpt-mcp | Connects to Autodesk Flow Production Tracking (ShotGrid) for production tracking, asset management, and publishes |
| vision3d | GPU inference server for AI-powered 3D generation โ the remote backend for maya-mcp's image-to-3D and text-to-3D tools |
fpt-mcp is the production backbone of the pipeline. It provides asset metadata, task assignments, path resolution, and publish registration for the other tools. maya-mcp and flame-mcp both consume fpt-mcp data โ Maya for asset context and publish targets, Flame for shot and sequence lookup. vision3d has no direct connection to fpt-mcp.
License
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.