Skip to main content
Glama

JANCTION Render

JasmyLab-JANCTION/janction-render MCP server

What is JANCTION Render?

JANCTION Render is a cloud GPU render farm for Blender that AI agents call as an MCP server or HTTP API. Send a .blend file, a bpy script or a 3D file (glTF / FBX / USD), preview in seconds, and get frames or an MP4 back from JANCTION's NVIDIA GPUs. Every preview also returns a verdict on what is wrong, such as too dark, blown out, no light or an object out of frame, and the bpy code to fix it, so the agent can correct the scene before the final render. No local Blender or GPU is needed. A 100 JPY welcome credit for a new key (one per network every 30 days; further keys on the same network share what is left) and 400 JPY more for saving a card that is not charged (once per card), then 0.1 JPY per GPU-second (previews free up to 2 GPU-minutes a day); operated by JasmyLab Inc.

AI agents can render Blender projects on JANCTION GPUs without running Blender locally. Works from Claude, ChatGPT, Claude Code, Codex, Cursor or any MCP client: an MCP server (remote and stdio), an HTTP API and a CLI.

JANCTION Render is a separate product from SmartRender (JasmyLab's distributed rendering for people at a desktop) and is not affiliated with Render.com or the Render Network. The numbers, as of 2026-10-08 (the primary source is https://render.janction.jp/facts.json): a 100 JPY welcome credit (1,000 GPU-seconds, 14 days, no card) for a new key, one per network every 30 days (further keys on the same network share what is left), plus 400 JPY more once a card is saved on a page that charges nothing (once per card); after that, previews are free up to 2 GPU-minutes a day and finals cost 0.1 JPY per GPU-second from prepaid credit (paid use started on 2026-10-08); finals up to 3,000 frames per instruction (run as parts of 240 under one job id); 1080p on free time, up to 4K on prepaid credit; inputs and results deleted 24 hours after last use (7 days, normally, for keys that have paid 500 JPY or more in total).

Official site: https://render.janction.jp · MCP endpoint: https://render.janction.jp/mcp · Fact sheet: https://render.janction.jp/facts

Try it from a terminal in a few seconds, free and with nothing to sign up for (needs uv; or pip install janction-render and drop the uvx):

uvx janction-render try                      # renders a sample scene and shows the free GPU time of your new key
uvx janction-render preview scene.blend      # your .blend, bpy script or 3D file
uvx janction-render render scene.blend --frames 1-48 --output mp4 --wait
uvx janction-render turntable model.glb      # a 360-degree turntable MP4 in one command (a path or an https link)
uvx janction-render shots model.glb --transparent   # four product shots (PNG)

What one command makes (real outputs)

Rendered on 2026-10-10 on the production GPU (NVIDIA RTX PRO 6000 Blackwell) from Khronos's WaterBottle sample (public domain, CC0); copy any line and it runs as is. Prices are at 0.1 JPY per GPU-second and are covered by the welcome credit of a new key.

Command

GPU time

Price

four product shots of a bottle

uvx janction-render shots https://github.com/KhronosGroup/glTF-Sample-Assets/blob/main/Models/WaterBottle/glTF-Binary/WaterBottle.glb

13.9 s

about 1.4 JPY

360-degree turntable of a bottle

uvx janction-render turntable https://github.com/KhronosGroup/glTF-Sample-Assets/blob/main/Models/WaterBottle/glTF-Binary/WaterBottle.glb

85.2 s

about 8.5 JPY

a spinning logo ring

uvx janction-render render https://render.janction.jp/samples/ex12_logo_ring_spin.py --frames 1-48 --size 1280x720 --engine eevee --output mp4 --wait

54.1 s

about 5.4 JPY

The shots are four 1920x1080 PNGs; the turntable and the animation are MP4s (shown here as GIFs). Your own .glb, .blend or bpy script goes in place of the link. More, with their scripts: https://render.janction.jp/examples

Keep 3D files in a repository? Add a button that lets anyone render them from their own AI or terminal (links to file pages on GitHub and Hugging Face work as they are; make one at https://render.janction.jp/go):

[![Render on JANCTION](https://render.janction.jp/badge.svg)](https://render.janction.jp/go?scene=https://github.com/you/repo/blob/main/model.glb)

Related MCP server: blender-render-mcp

Guides on the official site

Why use it?

  • No GPU, no Blender install. The scene can be a bpy script the agent writes, a .blend, or a 3D file; Blender runs on our GPUs.

  • Built for agents. Preview first (1-4 frames in a few GPU seconds), an estimate with time and cost before the final, structured errors with the fix, spending caps per key, safe retries with Idempotency-Key.

  • 3D files and turntables. glTF / GLB, FBX, USD, OBJ, STL, PLY, Alembic are imported into an empty scene with a camera and HDRI lighting; orbit=True makes a turntable. Fixed-price outcomes: POST /v1/outcomes/turntable and /product-shot.

  • Honest limits. a 100 JPY welcome credit for a new key with no card (14 days; one per network every 30 days) and 400 JPY more after saving a card that is not charged, then 0.1 JPY per GPU-second (previews free up to 2 GPU-minutes a day), finals up to 3,000 frames per instruction as parts of 240 (1080p on free time, up to 4K on prepaid credit), on JANCTION's own GPUs (NVIDIA RTX PRO 6000 Blackwell); when they are busy jobs wait in a queue and the ETA says so. Inputs and results are deleted 24 hours after last use (7 days, normally, for keys that have paid 500 JPY or more in total) and never used for training.

  • Not Render.com. Same word, different product.

Quick start

Claude.ai / ChatGPT (nothing to install). Settings → Connectors → add https://render.janction.jp/mcp → Connect (a free key is created on the consent page). Then paste:

Render a preview of https://render.janction.jp/samples/cube_scene.py

A 4-frame preview comes back in a few seconds. A file on your computer: drop it at https://render.janction.jp/upload to get a 12-hour link, then "Render this file: ".

Claude Code.

claude mcp add --transport http janction-render https://render.janction.jp/mcp

Then /mcp to authenticate and ask: "Build a small street scene in Blender with a camera fly-through and render a preview with janction-render."

HTTP (any language).

curl -s -X POST https://render.janction.jp/v1/keys                                   # -> {"api_key": "jr_..."}  no sign-up
curl -s -X POST https://render.janction.jp/v1/files -H "X-API-Key: $KEY" -F "file=@scene.blend"   # -> {"scene_id": "f_..."}
curl -s -X POST https://render.janction.jp/v1/jobs -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
  -d '{"scene_id":"f_...","kind":"preview","frames":[1]}'                             # -> job_id; then GET /v1/jobs/{job_id}

From your own agent or app

Python (pip install janction-render; the first call creates a free key and keeps it in ~/.janction-render.json):

from janction_render.client import Client

c = Client()                                   # or Client(api_key="jr_...")
scene = c.upload("scene.py")                   # a bpy script, a .blend, or a .glb / .fbx / .usd / .obj file
job = c.submit(scene["scene_id"], kind="final", frame_start=1, frame_end=48, output="mp4")
job = c.wait(job["job_id"], timeout=1800)
print(job["status"], c.download(job["job_id"], "out", only="mp4"))

Pay per use with prepaid credit; no subscription is needed (prices: https://render.janction.jp/pricing). Instead of polling, pass notify_url (https) to POST /v1/jobs and get one JSON POST when the job finishes (job.done / job.failed, with download links); an Idempotency-Key header makes retries safe. OpenAPI: https://render.janction.jp/openapi.json A complete app example (a user uploads a GLB, the app orders fixed-price product shots, a webhook stores the images): https://render.janction.jp/blender-render-api#embed

Agent frameworks connect to the remote MCP server at https://render.janction.jp/mcp with the key as a bearer token (curl -s -X POST https://render.janction.jp/v1/keys gives one, no sign-up).

OpenAI Agents SDK (keep the longer timeout: render_preview waits for the image, longer than the 5-second default):

import asyncio
from agents import Agent, Runner
from agents.mcp import MCPServerStreamableHttp

async def main():
    async with MCPServerStreamableHttp(name="janction-render", client_session_timeout_seconds=120,
                                       params={"url": "https://render.janction.jp/mcp",
                                               "headers": {"Authorization": "Bearer jr_..."}}) as render:
        agent = Agent(name="3D artist", instructions="Render Blender scenes with janction-render.", mcp_servers=[render])
        result = await Runner.run(agent, "Render a preview of https://render.janction.jp/samples/cube_scene.py")
        print(result.final_output)

asyncio.run(main())

LangChain (pip install langchain-mcp-adapters):

import asyncio
from langchain_mcp_adapters.client import MultiServerMCPClient

async def main():
    client = MultiServerMCPClient({"janction-render": {"url": "https://render.janction.jp/mcp", "transport": "streamable_http",
                                                       "headers": {"Authorization": "Bearer jr_..."}}})
    tools = await client.get_tools()           # render_preview, render_final, render_status, render_download, ...
    print([t.name for t in tools])

asyncio.run(main())

OpenAI Responses API (remote MCP; render_final keeps asking for approval because it spends credit):

from openai import OpenAI

client = OpenAI()
resp = client.responses.create(
    model="gpt-5",
    tools=[{"type": "mcp", "server_label": "janction_render", "server_url": "https://render.janction.jp/mcp",
            "authorization": "jr_...",
            "require_approval": {"never": {"tool_names": ["scene_info", "render_preview", "render_estimate",
                                                         "render_status", "render_download"]}}}],
    input="Render a preview of https://render.janction.jp/samples/cube_scene.py and give me the image link.",
)
print(resp.output_text)

Anthropic Messages API (MCP connector; fallbacks="default" reruns a declined request on a fallback model):

import anthropic

client = anthropic.Anthropic()
response = client.beta.messages.create(
    model="claude-opus-5-5",
    max_tokens=16000,
    betas=["mcp-client-2025-11-20", "server-side-fallback-2026-07-01"],
    fallbacks="default",
    mcp_servers=[{"type": "url", "url": "https://render.janction.jp/mcp", "name": "janction-render",
                  "authorization_token": "jr_..."}],
    tools=[{"type": "mcp_toolset", "mcp_server_name": "janction-render"}],
    messages=[{"role": "user", "content": "Render a preview of https://render.janction.jp/samples/cube_scene.py"}],
)
for block in response.content:
    if block.type == "text":
        print(block.text)

Google ADK:

import os
from google.adk.agents import Agent
from google.adk.tools.mcp_tool import MCPToolset, StreamableHTTPConnectionParams

agent = Agent(
    name="renderer",
    model="gemini-2.5-flash",
    instruction="Render Blender scenes with JANCTION Render: preview first, ask before a final render.",
    tools=[MCPToolset(connection_params=StreamableHTTPConnectionParams(
        url="https://render.janction.jp/mcp",
        headers={"Authorization": "Bearer " + os.environ["JANCTION_RENDER_API_KEY"]}))],
)

Pydantic AI:

from pydantic_ai import Agent
from pydantic_ai.mcp import MCPToolset

render = MCPToolset("https://render.janction.jp/mcp", headers={"Authorization": "Bearer jr_..."})
agent = Agent("anthropic:claude-opus-5-5", toolsets=[render])

Connect the AI apps on this computer in one command, and tell every coding agent in a project when and how to render:

uvx janction-render connect             # lists Claude Code, Codex, Gemini CLI, Cursor, Windsurf, VS Code and the step for each
uvx janction-render connect claude-code # applies one (or: connect all --yes)
uvx janction-render init                # writes a short section to AGENTS.md and adds the server to .mcp.json

init touches CLAUDE.md, GEMINI.md, .cursor/ and .vscode/ only when they already exist (or with --claude, --cursor, --vscode); it keeps everything else in those files and backs up JSON it changes.

The local MCP server (stdio) also offers prompts that show up as slash commands, for example /mcp__janction-render__turntable_video in Claude Code: try_janction_render, render_my_scene, turntable_video, product_shots, scene_from_description, blend_to_mp4.

MCP

Remote (Streamable HTTP, OAuth 2.1 with dynamic client registration; a raw key also works as Authorization: Bearer jr_...)

client

how

Claude.ai (web, desktop, mobile)

Settings → Connectors → Add custom connector → paste the URL → Connect

ChatGPT

Settings → Connectors → Advanced → Developer mode → Create → paste the URL (OAuth)

Claude Code

claude mcp add --transport http janction-render https://render.janction.jp/mcp, then /mcp to authenticate

Codex

codex mcp add janction-render --url https://render.janction.jp/mcp

Gemini CLI / Antigravity CLI

gemini extensions install https://github.com/JasmyLab-JANCTION/janction-render (this repository carries gemini-extension.json)

Grok (grok.com)

Connectors → New Connector → Custom → paste the URL

Perplexity (Pro / Max / Enterprise), Le Chat (workspace admin)

Add a custom remote MCP connector with the URL

Notion Agent (Business / Enterprise)

Settings → Connections → Discover → Add Custom MCP → paste the URL, then sign in (the button shows when a workspace admin allows custom MCP servers)

Cursor

.cursor/mcp.json (project) or ~/.cursor/mcp.json: {"mcpServers": {"janction-render": {"url": "https://render.janction.jp/mcp"}}}, then sign in when Cursor asks (OAuth). One click: install in Cursor

VS Code (Copilot agent mode)

.vscode/mcp.json: {"servers": {"janction-render": {"type": "http", "url": "https://render.janction.jp/mcp"}}} or code --add-mcp '{"name":"janction-render","type":"http","url":"https://render.janction.jp/mcp"}', then Start the server and sign in (OAuth)

Windsurf, Cline, Goose, other MCP clients

Streamable HTTP at the URL above (OAuth, or a Bearer API key header). Installer notes: llms-install.md. Cursor project rule (when to use it, preview-first flow): integrations/cursor

Claude Desktop and other stdio-only clients (npm)

{"mcpServers": {"janction-render": {"command": "npx", "args": ["-y", "janction-render"]}}}: the npm package janction-render bridges stdio to the URL above with OAuth (--key jr_... for a key you have, --local for the Python stdio server through uv). Claude Code: claude mcp add janction-render -- npx -y janction-render

Remote tools take scene_script (bpy code as text), scene_url (an https link to a .blend, .py or a 3D file, or a link from https://render.janction.jp/upload) or scene_id, plus asset_urls for textures or glTF .bin files. Results come back as an inline image plus download links that need no key and work for about 24 hours (render_download(only="mp4") for just the video).

Claude Code plugin (the remote connector plus a skill with the workflow):

/plugin marketplace add JasmyLab-JANCTION/janction-render
/plugin install janction-render@janction-render

Stdio (sends local files)

The package is on PyPI as janction-render (and the npm launcher janction-render runs it with npx -y janction-render --local when uv is installed).

# Claude Code (uvx runs it without a global install)
claude mcp add janction-render -e JANCTION_RENDER_SERVER=https://render.janction.jp -- uvx --from janction-render janction-render-mcp

# or with pip / pipx
pip install janction-render
claude mcp add janction-render -e JANCTION_RENDER_SERVER=https://render.janction.jp -- janction-render-mcp

Codex: add to ~/.codex/config.toml

[mcp_servers.janction-render]
command = "uvx"
args = ["--from", "janction-render", "janction-render-mcp"]
env = { JANCTION_RENDER_SERVER = "https://render.janction.jp" }

A temporary API key is issued automatically on first use and cached in ~/.janction-render.json; set JANCTION_RENDER_API_KEY to pin one (quota and, later, credit belong to the key). The same key can be used from the remote connector: paste it on the connect page.

Tools

tool

what

`scene_info(scene_script

scene_url

render_preview(..., frames="1-24", environment?, blender?)

up to 4 frames (720p budget) tiled with frame labels; returns the image inline

render_review(scene_path / scene_script / scene_url / scene_id, environment="studio")

checks a 3D model or a generated scene from 4 sides (0/90/180/270 degrees) under studio light: pass / warning / fail, a score, the checks it ran (files, visibility, framing, exposure, lighting) with fix code, and the 4 views in one image. Stdio server; same GPU time as one preview

render_estimate(scene_id, frame_start, frame_end, width, height, samples)

GPU seconds, queue wait, "about N minutes", fits the free GPU time left? No GPU time used

render_final(scene_id, frame_start, frame_end, width, height, samples, fps, output, environment?, blender?, engine?, transparent?, notify_url?)

frames (png / exr) or video (mp4 / webm / prores / gif / webp); transparent=True keeps an alpha background (png / exr / webm / gif / webp); notify_url gets one JSON POST when the job finishes; returns job_id + estimate

render_status(job_id)

progress and ETA (eta.human); render_download(job_id, only="mp4" / "frames" / "all") files or links; render_cancel(job_id)

billing()

the free GPU time left (the welcome credit, then the free preview minutes today), the credit, a top-up link, and the auto top-up and monthly plan status

render_share(job_id, title?, note?, include_script?, listed?)

a public page /r/<id> with the image or video, the conditions and (optionally) the script; survives the 24-hour expiry until render_unshare; with listed=True it appears in /gallery after a review

asset_search(query, kind)

CC0 models / textures / HDRIs on Poly Haven by words; results carry polyhaven:<id> and the entry file

render_info()

workers online or gated (GPU lent to another workload), queue, expected wait, supported inputs, environment presets, Blender versions

Options on render_preview / render_final: environment (studio, sunset, overcast, night, compare on previews; environment_strength, environment_visible=False for a flat grey backdrop with HDRI lighting), orbit / orbit_frames / orbit_elevation (turntable), blender ("5.2"), and assets (stdio: local files sent with the scene, found in the script through os.environ["JR_ASSETS_DIR"]; a .blend's external files are collected automatically with pip install janction-render[blend]) or asset_urls (remote).

CLI: janction-render inspect|preview|render|status|download|share|unshare|cancel|jobs|balance|topup|limits|outcomes|info.

API

POST /v1/keys                                   -> {api_key}         (header X-API-Key afterwards)
POST /v1/files  multipart "file" (.blend|.py|.glb|.fbx|.usd|.obj|...)   -> {scene_id}
POST /v1/files/{id}/assets  multipart "files"   textures, glTF .bin ...   GET /v1/files/lookup?sha256=  reuse an upload
POST /v1/estimate {kind, frames|frame_start/frame_end, width, height, samples, scene_id?} -> seconds, wall_seconds, human, quota, currency, expires_at
POST /v1/jobs   {scene_id, kind: info|preview|final, frames|frame_start/frame_end, width, height, samples, camera, fps, output (png|exr|mp4|webm|prores|gif|webp), transparent, notify_url (https), engine (cycles|eevee),
                 environment, environment_strength, environment_visible, blender, orbit, orbit_frames, orbit_elevation}   header Idempotency-Key makes retries safe
GET  /v1/jobs/{id}      status, progress, eta, artifacts[], cost, warnings, info, failure (code + fix)    DELETE /v1/jobs/{id}  cancel
GET  /v1/jobs/{id}/artifacts/{name}             PNG / MP4
GET  /v1/jobs/{id}/archive?only=png             every file of the job in one zip (frame sequences: one request instead of hundreds)
GET  /v1/outcomes       fixed-price outcomes;  POST /v1/outcomes/turntable {scene_id, size, frames}   POST /v1/outcomes/product-shot {scene_id, size, transparent?}
POST /v1/try    JSON {scene_script | scene_url, frames?, width?, height?, environment?} (no key) -> first 720p preview + an API key to continue, in one response (1 per network per 24h)
POST /v1/drops  multipart "file" (no key)       -> a 12-hour https link to pass as scene_url (the /upload page uses this)
POST /v1/jobs/{id}/share {title?, note?, include_script?, listed?} -> {share_id, url}   DELETE /v1/jobs/{id}/share   GET /v1/shares
GET  /r/{share_id}  public page (no key)   GET /gallery
GET  /v1/assets/search?q=&kind=models|textures|hdris   CC0 assets (Poly Haven) -> spec polyhaven:<id>
POST /v1/files/{id}/assets/urls {urls: ["https://...", "polyhaven:<id>"]}   fetch assets server-side
GET  /v1/me  (quota, balance, limits)   POST /v1/me/limits {job_yen?, day_yen?}   spending caps per key
POST /mcp                                       remote MCP (Streamable HTTP; Bearer api key or OAuth)
GET  /.well-known/oauth-protected-resource/mcp  OAuth discovery
POST /v1/billing/checkout {amount_yen} -> {checkout_url}   POST /v1/billing/sync   GET /v1/ledger
GET  /openapi.json  /llms.txt  /llms-full.txt  /ja/llms.txt  /facts.json  /version.json  /capabilities.json  /pricing.json  /status.json

A job that goes past the free GPU time without enough credit gets 402 payment_required with checkout_url (show it to the user), topup_yen and how much of the job the free time covers; a 400 beta_limit means the job is too big (split it). Every API error carries retryable, possible_fix and docs_url; a failed job carries failure with a code and the recommended action. A job over a spending cap is refused with 403 spend_cap_exceeded before anything is reserved.

Example

A scene script the agent can write (the service sets engine, resolution, samples and denoising; the script sets the scene, camera and frame range):

import bpy, math
for ob in list(bpy.data.objects):
    bpy.data.objects.remove(ob, do_unlink=True)
scene = bpy.context.scene
scene.frame_start, scene.frame_end = 1, 24
bpy.ops.mesh.primitive_monkey_add(location=(0, 0, 1))
cam = bpy.data.objects.new("Camera", bpy.data.cameras.new("Camera"))
scene.collection.objects.link(cam); scene.camera = cam
cam.location = (6, -6, 4); cam.rotation_euler = (math.radians(60), 0, math.radians(45))
sun = bpy.data.objects.new("Sun", bpy.data.lights.new("Sun", "SUN"))
scene.collection.objects.link(sun)

Cycles by default; engine="eevee" for cheaper animations (about half the per-frame cost after ~7 s of shader compilation per job). In Blender 5.0 materials always use nodes: set the Principled BSDF Base Color, not diffuse_color. Scripts run in an isolated container with no network. More: samples/cube_scene.py, samples/polyhaven_room.py. Measured timings: https://render.janction.jp/benchmarks

Pricing

A new key starts with a 100 JPY welcome credit (1,000 GPU-seconds, 14 days, no card) that covers previews and finals; one full credit per network every 30 days (later keys on the same network share what is left of it). Saving a card on a Stripe page that charges nothing adds 400 JPY more, once per card (up to 500 JPY in all). After it is used up or expires, previews are free up to 2 GPU-minutes a day and finals cost 0.1 JPY per GPU-second from prepaid credit, bought by card at a Stripe Checkout page (from 500 JPY; 2,000 JPY gives 2,200 JPY of credit, 5,000 gives 5,750, 10,000 gives 12,000; the first top-up in the welcome period counts 1.5x, bonus up to 500 JPY). Only the part the free time does not cover is charged. Finals go up to 3,000 frames per instruction (run as parts of 240 under one job id): 1080p on free time, up to 4K (3840x2160) on prepaid credit. POST /v1/estimate quotes what will be charged (cost.estimated_yen), the currency and an expiry before any GPU time is used: https://render.janction.jp/pricing

Troubleshooting

You see

What it means

What to do

402 payment_required

The job goes past the free credit left on the key

tell_user in the reply says what this render costs and what a top-up buys; pay at checkout_url (from 500 JPY) and send the same job again, or render fewer frames / a lower resolution

script_blocked

The bpy script uses something the sandbox refuses (network, processes, ctypes)

The GPU worker has no network: pass files from the web in asset_urls=[...] (MCP) or POST /v1/files/{scene_id}/assets/urls, then open them with jr_assets.path('<name>'). A script refused only for urllib / requests does not count toward revoking the key

script_path / scene_path

The scene points at a file on your own computer

Send the file as an asset and reference it by name (relative path)

McpError: Timed out while waiting for response (OpenAI Agents SDK)

The SDK waits 5 seconds for a tool by default

MCPServerStreamableHttp(..., client_session_timeout_seconds=120) (see "From your own agent or app")

The job sits in queued and eta.human says the GPU is lent out

The GPU is shared with another workload for a while

Tell the user the wait; call render_download(job_id, wait_seconds=45) later instead of polling

429 rate_limited

Too many requests in a short time

Wait for Retry-After seconds and send again

Too dark, blown out, or the object out of frame

The preview's verdict says which, with bpy code to fix it

Apply the fix and preview again (seconds) before the final; 3D files are framed at their real size automatically

401 from Claude, ChatGPT or Codex

The connector's sign-in expired

Reconnect the connector (/mcp in Claude Code), or pass the key as X-API-Key / Authorization: Bearer jr_...

Docs

Features in detail

  • Input: a .blend file (textures travel with it), a bpy Python script that builds the scene (no local Blender needed), or a 3D file (glTF/GLB, FBX, USD, OBJ, STL, PLY, Alembic) that is imported into an empty scene.

  • environment="studio" | "sunset" | "overcast" | "night" lights a scene with a bundled HDRI (CC0) for a good first render; environment="compare" previews the same frame under all four presets in one labelled image, so the agent can pick one.

  • A .gltf or .obj brings its .bin / .mtl / textures along automatically (from the same folder or the same URL folder).

  • orbit=True turns any scene or imported model into a turntable: an orbit camera circles it once (orbit_frames, default 24; a preview shows 0/90/180/270 degrees, a final render without frame_end gives the whole turn as an MP4). Flat floors and walls are ignored when framing; orbit_target (object name or x,y,z) and orbit_distance (multiplier) adjust the shot.

  • While the GPU is lent to another workload, tools answer right away with the queued job and a wait estimate (how long it has been out, how long it usually stays out, how much longer to expect; eta.gate) instead of waiting.

  • While a job renders, render_status counts finished frames inside the running chunk, so the ETA updates every few seconds.

  • In hosts that support MCP Apps (Claude web and desktop, among others), previews, progress and download links also appear as an interactive panel in the chat: the image, a progress bar, "Open MP4", and preset buttons after an environment="compare" preview. Both the remote connector and the stdio package ship the panel (janction_render/mcp_app.html); set JR_MCP_APPS=0 to turn it off.

  • CC0 assets by name: asset_search("wooden table") finds Poly Haven models, textures and HDRIs; pass polyhaven:<id> in asset_urls (remote) or assets (stdio) and the files land in JR_ASSETS_DIR/<id>/ on the GPU, ready to import (bpy.ops.import_scene.gltf(filepath=os.path.join(os.environ['JR_ASSETS_DIR'], 'wooden_table_02', 'wooden_table_02_1k.gltf'))). Scene scripts can import jr_assets for one-liners: jr_assets.import_model('wooden_table_02'), jr_assets.apply(floor, jr_assets.material('wood_floor_deck', scale=2)) (diff / normal / roughness / metal wired into a Principled BSDF), jr_assets.world_hdri('studio_small_09'). See samples/polyhaven_room.py.

  • A render you choose to share (render_share) gets a public page (/r/<id>, OGP for X and Discord) that stays until you unshare it.

  • Blender 5.0, Cycles on GPU (blender="5.2" selects Blender 5.2 when the worker has it; render_info lists what is available).

Blender add-on and DCC tools (for people, not agents)

  • Blender extension (addons/blender/, Blender 4.2+): a JANCTION Render panel under Properties → Render with Preview, Estimate and Final. A copy of the open file and the textures it references with relative paths are uploaded; results land next to the .blend. Install from the extension repository https://render.janction.jp/extensions/index.json (Preferences → Get Extensions → Repositories → + → Add Remote Repository), or install the zip from https://render.janction.jp/extensions/janction_render-0.1.2.zip (python scripts/build_blender_addon.py builds it from this repository). Guide: https://render.janction.jp/blender-addon

  • Maya, Houdini, Cinema 4D (integrations/): export to USD / FBX / Alembic, upload with textures, render with Cycles, open the result; Preview, Final (MP4) and Turntable. Standard-library Python only; jr_submit.py is the shared client. Guide: https://render.janction.jp/maya-houdini-cinema4d

Self-hosting

The server (FastAPI + SQLite, with the remote MCP endpoint) and the worker (Blender in disposable Docker containers, --network none --cap-drop ALL) live in the internal repository and are not part of this package yet. This repository holds the client side: stdio MCP server, CLI, HTTP client, samples, the Claude Code plugin, the Blender add-on and the DCC tools.

MCP registry

This server is listed in the official MCP registry as io.github.JasmyLab-JANCTION/janction-render (remote: https://render.janction.jp/mcp).

mcp-name: io.github.JasmyLab-JANCTION/janction-render

Security

Vulnerability reports: see SECURITY.md. Retention, isolation and the external tests are summarised on the security page.

License

MIT (see LICENSE) for the package, the MCP servers, the CLI and the DCC tools. The Blender extension under addons/blender/ is GPL-3.0-or-later, as Blender requires for add-ons. Operated by JasmyLab Inc.

Available Tools

13 tools
billingA
Read-onlyIdempotent
Inspect

Check what this key can still render for free and its credit (no GPU time): the free GPU time left and when it expires or resets (each new key gets 100 JPY of GPU time free with no card (14 days) and 400 JPY more once the user saves a card on a page that charges nothing (once per card); after that, previews are free up to 2 GPU-minutes a day and finals cost 0.1 JPY per GPU-second (prepaid)), the balance in yen, the price per GPU-second, any pending checkout link, and card_offer / autocharge_offer when they apply. Relay tell_user to the user in their language when it is present.

ParametersJSON Schema
NameRequiredDescriptionDefault
topup_yenNo0 = just report the quota / balance; > 0 (minimum 500) = create a Stripe checkout link for that amount in yen.

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover readOnly/idempotent/openWorld/non-destructive, so the bar is lower, and the description still adds real behavioral context: credit expiry (14 days), the once-per-card 400 JPY grant, prepaid charging rates (previews free to 2 GPU-min/day, finals 0.1 JPY per GPU-second), and a tell_user relay directive that appears nowhere in structured fields. There is a mild tension between readOnlyHint=true and the topup_yen path that creates a Stripe checkout link, but the description frames it as link generation with no charge, so it is not a clear contradiction.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness2/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The body is effectively one enormous sentence dense with nested parentheses enumerating the pricing ladder, expiry windows, and offer flags. It is front-loaded with the core purpose, but the run-on structure makes it hard to scan and several clauses (deposit mechanics, per-second rates) are crammed together rather than separated.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, return values need not be explained, and the description still covers the operational rules an agent needs: what is reported, the topup threshold, credit expiry/reset, and the tell_user relay. It is close to complete for a one-parameter tool; only the read-only-vs-checkout tension is left unaddressed.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the single parameter is fully documented in the schema, so the baseline is 3. The description contextualises the topup path (creating a checkout link) but adds no syntax or format meaning beyond what the schema already states.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb+resource ('Check what this key can still render for free and its credit'), then catalogues exactly what is reported: free GPU time, balance in yen, price per GPU-second, pending checkout link, and card/autocharge offers. It is clearly a billing/quota tool rather than a renderer, so an agent can place it against the render_* siblings. It stops short of naming any sibling or exclusion explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied rather than stated: checking credits/balance is the obvious 'use' and the schema's topup_yen documents the one conditional action. There is no explicit when-to-use vs when-not, no prerequisites, and no reference to alternatives, so guidance is only adequate.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

render_cancelA
DestructiveIdempotent
Inspect

Stop a queued or running render job of this key (a j_... job, or a b_... job split into parts, which stops every part). Effects: queued frames are dropped; frames already rendered are charged and stay downloadable until the job expires; the rest of the GPU time held for the job is returned to the key at once. It cannot be undone or resumed: to render again, call render_final again (a new job). A job that is already done, failed or canceled is returned unchanged, and a job whose frames are all rendered and is being assembled into the video cannot be stopped (nothing more is charged). Only the key that started the job can stop it; any other job_id returns not_found. Ask the user before cancelling a render they asked for.

ParametersJSON Schema
NameRequiredDescriptionDefault
job_idYesThe job_id returned by render_preview or render_final (j_...; a long final split into parts is b_...). Only this key's jobs; in render_status, leave it empty to list them.

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the destructiveHint/idempotentHint annotations: it details that queued frames are dropped, already-rendered frames are charged and stay downloadable until expiry, held GPU time is returned, cancellation is irreversible, terminal jobs return unchanged, and assembling jobs cannot be stopped. It also states the auth boundary (only the owning key; otherwise not_found), which annotations do not cover.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the action and scope, then presents effects and edge cases in a logical sequence. It is on the longer side with some mild redundancy around irreversibility, but nearly every clause carries an edge case the agent needs.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-param destructive mutation with an output schema and annotations already present, the description fills every remaining gap: side effects, billing, reversibility, idempotent terminal-state behavior, and permission boundaries.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% for the single job_id parameter, so the baseline is 3, but the description adds the authorization constraint ('Only the key that started the job can stop it; any other job_id returns not_found'), which is behavioral meaning the schema does not carry.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Stop a queued or running render job of this key') and immediately distinguishes scope by naming the job id formats (j_..., b_...) and the part-job behavior. An agent can tell this apart from render_final/render_status without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear operating context: use it to stop a queued/running job, call render_final again to re-render, and 'Ask the user before cancelling a render they asked for.' It does not explicitly contrast against alternatives like render_status or render_final beyond the re-render note, so it stops short of full when/when-not routing.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

render_downloadA
Read-onlyIdempotent
Inspect

Download a job's files to out_dir (default ~/janction-render/<job_id>) and return the local paths. only picks the files: 'all' (default), 'mp4' (just the video; use it when the user wants the video, to skip hundreds of frames), 'frames', 'sheet' or 'output'. wait_seconds > 0 first waits that long for the job to finish.

ParametersJSON Schema
NameRequiredDescriptionDefault
onlyNo'all' (every frame plus output.mp4 / sheet.png) | 'mp4' | 'frames' | 'sheet' | 'output' (the MP4 or the sheet only).all
job_idYesThe job_id returned by render_preview or render_final (j_...; a long final split into parts is b_...). Only this key's jobs; in render_status, leave it empty to list them.
out_dirNoLocal folder to save the files in (default ~/janction-render/<job_id>).
wait_secondsNoWait up to this many seconds for the job to finish before downloading (0 = do not wait).

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint and destructiveHint=false, so the safety profile is covered. The description adds context the annotations cannot: artifacts are written to a local directory (~/janction-render/<job_id> by default), local paths are returned, and a positive wait_seconds blocks until the job finishes. It does not describe behavior when the job is still unfinished with wait_seconds=0, or download size/limits.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Roughly three compact sentences, front-loaded with the action and destination before the option list; every sentence carries information. Minor awkwardness in the 'only picks the files' phrasing and the inline enumeration, but no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be spelled out, and the schema plus annotations cover parameters and safety. What remains thin is the unfinished-job case (behavior when wait_seconds=0 and the job is not done) — otherwise the definition is sufficient to call the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so all four parameters are already documented — the baseline is 3. The description mostly restates the enum values and the out_dir/wait_seconds defaults, adding only the rationale for 'mp4' ('to skip hundreds of frames'), which is a modest value-add beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Download a job's files') plus the destination ('out_dir, default ~/janction-render/<job_id>') and the return ('local paths'). It is unambiguous among siblings such as render_preview, render_final and render_status, which produce or inspect jobs rather than retrieve their artifacts.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives concrete selection guidance for the 'only' mode, including the condition for the most important case ('mp4' — use when the user wants the video, to skip hundreds of frames), and explains the wait_seconds timing tradeoff. It does not, however, state when to prefer this tool over render_status/render_preview for checking job state, so there is no explicit exclusion.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

render_estimateA
Read-onlyIdempotent
Inspect

Estimate a render before starting it (no GPU time): GPU seconds, queue wait, the wall-clock time as text (estimate.human, e.g. 'about 3 minutes') and whether it fits the free GPU time left (the welcome credit, or 2 preview GPU-minutes a day after it) and the size limits. Call it before render_final when the time or quota is uncertain, the job is longer than about 24 frames or above 720p, or the user asks how long it takes; tell the user the result. With scene_id the estimate uses measured render times and returns calibration.final_path_measured. If false, treat it as preliminary: run a short contiguous final-path test and estimate again before the full animation. It also says when to split a job.

ParametersJSON Schema
NameRequiredDescriptionDefault
kindNo'final' (frame_start..frame_end at width x height, samples) or 'preview' (frames like '1-24').final
widthNoOutput width in pixels (previews are capped at 1280x720 keeping the aspect ratio; a final frame can have at most 1920x1080 pixels on free time, 3840x2160 on prepaid credit).
framesNoPreview frames: '' = frame 1; '12' = one frame; '1,8,16,24' or '1-24' = up to 4 frames tiled in one labeled image (to judge camera motion and animation; same GPU time as one 720p frame).
heightNoOutput height in pixels (previews are capped at 1280x720 keeping the aspect ratio; a final frame can have at most 1920x1080 pixels on free time, 3840x2160 on prepaid credit).
presetNoPurpose preset: 'product' (4 studio shots at 0/90/180/270 deg on a plain backdrop; the final gives 4 PNGs at 1440x1440), 'turntable' (one full turn as an MP4, studio light, plain backdrop), 'animation' (the scene's own camera, lights and frame range; the scene is read first when the range is unknown), or '' (none). It fills what you do not pass; environment, orbit_frames, width/height and the frames still win when given.
camerasNoSeveral camera object names (up to 8) rendered from the same frame in one job: the preview tiles them in one labeled sheet, the final returns one PNG/EXR per camera (camera_files maps names to files). For product shots from fixed angles. Not combinable with orbit, environment='compare' or camera.
samplesNoCycles samples per pixel (preview: up to 32, default 16; final: default 128).
scene_idNoscene_id returned by an earlier call (reuses the uploaded scene without sending it again).
frame_endNoLast frame to render (inclusive); equal to frame_start for a single image. With orbit=True and no frame_end, one full turn is rendered.
frame_startNoFirst frame to render (inclusive).

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint true and destructiveHint false. The description adds rich behavioral context: no GPU time consumed, measured vs preliminary estimates, calibration.final_path_measured semantics, splitting advice, and the consequence of a false preliminary flag. This far exceeds what annotations provide.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is information-dense and front-loaded with the key outputs. It is a single long paragraph but every sentence carries useful signal. Slightly verbose but appropriate for the complexity of the tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given 10 parameters, no required params, full schema coverage, and an output schema present, the description covers the essential behavioral context: what the estimate returns, when to call it, how to interpret preliminary results, and when to split jobs. Nothing critical is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so all 10 parameters are already documented in the schema. The description adds marginal semantic value by explaining what the estimate does with scene_id and what calibration output means, but it doesn't add parameter syntax beyond what the schema already provides. Baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (Estimate) and resource (a render) and immediately specifies the output signals: GPU seconds, queue wait, human-readable wall-clock text, and quota fit. Clearly distinguishable from render_final, render_preview, and the other siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit when-to-use guidance: 'Call it before render_final when the time or quota is uncertain, the job is longer than about 24 frames or above 720p, or the user asks how long it takes.' It also names the alternative (render_final) and gives concrete thresholds and exclusion conditions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

render_finalAInspect

Render the final frames or video of a Blender scene on cloud GPUs, after the user approved a preview: 'render the final', 'make the video', 'export the turntable MP4'. Call render_estimate first when the time or the free GPU time left (the welcome credit, or 2 preview GPU-minutes a day after it) is uncertain, the job is longer than about 24 frames or above 720p, or the user asks how long it takes, and tell the user. For animations, keep the approved engine/look, test 10 contiguous final-path frames, then estimate again. Long jobs are rendered in chunks and joined into one video. Returns job_id and estimate.human at once; then render_status until done, and render_download(job_id, only='mp4') for the video. Use the same environment and blender as the approved preview. Limits: up to 3,000 frames per call (over 240 runs as parts under one job id); 1920x1080 on free time, 3840x2160 with prepaid credit; each new key gets 100 JPY of GPU time free with no card (14 days) and 400 JPY more once the user saves a card on a page that charges nothing (once per card); after that, previews are free up to 2 GPU-minutes a day and finals cost 0.1 JPY per GPU-second (prepaid); ask before a render the free time does not cover; files are deleted 24 h after last use (7 days once topped up). preset='product' | 'turntable' | 'animation' fills the settings for that purpose. Options per parameter: output (png, exr, mp4, webm, prores, gif, webp), orbit, cameras, transparent, engine, notify_url, assets ('polyhaven:'). Pass scene_id from render_preview, or scene_path / scene_script / scene_url; files are saved locally.

ParametersJSON Schema
NameRequiredDescriptionDefault
fpsNoFrames per second of the video output (default 24).
orbitNoTrue: turntable; an orbit camera circles the scene once (the scene's own camera is not used). Flat floors and walls are ignored when framing. A preview without frames shows 0/90/180/270 degrees; a final without frame_end renders the whole turn as an MP4. Best for imported models and product videos.
widthNoOutput width in pixels (previews are capped at 1280x720 keeping the aspect ratio; a final frame can have at most 1920x1080 pixels on free time, 3840x2160 on prepaid credit).
assetsNoExtra files sent with the scene: local paths (textures, glTF .bin), https links, or 'polyhaven:<id>' CC0 assets from asset_search. A .blend finds them through relative paths (same folder); a script through os.environ['JR_ASSETS_DIR'] or the jr_assets helpers.
cameraNoName of the camera object to render from (default: the scene's active camera, or an automatic camera if there is none). Ignored with orbit=True; not combinable with cameras.
engineNo'' or 'cycles' (path tracing, default) | 'eevee' (real-time rasterizer: about half the per-frame cost on animations of a few dozen frames or more; each job pays about 7 s of shader compilation, so previews stay on Cycles).
heightNoOutput height in pixels (previews are capped at 1280x720 keeping the aspect ratio; a final frame can have at most 1920x1080 pixels on free time, 3840x2160 on prepaid credit).
outputNo'auto' (mp4 for a frame range, png for one frame) | 'png' | 'exr' (16-bit linear frames for compositing) | 'mp4' (H.264) | 'webm' (VP9) | 'prores' (Apple ProRes 422 HQ .mov, for editing) | 'gif' | 'webp' (animated, at most 960 px wide; good for chat and web).auto
presetNoPurpose preset: 'product' (4 studio shots at 0/90/180/270 deg on a plain backdrop; the final gives 4 PNGs at 1440x1440), 'turntable' (one full turn as an MP4, studio light, plain backdrop), 'animation' (the scene's own camera, lights and frame range; the scene is read first when the range is unknown), or '' (none). It fills what you do not pass; environment, orbit_frames, width/height and the frames still win when given.
blenderNoBlender version: '' (default: a .blend opens with the version it was saved in, other scenes with 5.0) or '5.0' / '5.2' (also '4.5', '4.2', '3.6'; a script that stops on Blender 5 because of an older API is rendered again on those automatically) to choose.
camerasNoSeveral camera object names (up to 8) rendered from the same frame in one job: the preview tiles them in one labeled sheet, the final returns one PNG/EXR per camera (camera_files maps names to files). For product shots from fixed angles. Not combinable with orbit, environment='compare' or camera.
max_yenNoCeiling for this job in JPY (-1 = none): the job is refused before anything is reserved when its reservation would exceed it. 0 means 'only if it fits the free time'.
samplesNoCycles samples per pixel (preview: up to 32, default 16; final: default 128).
scene_idNoscene_id returned by an earlier call (reuses the uploaded scene without sending it again).
frame_endNoLast frame to render (inclusive); equal to frame_start for a single image. With orbit=True and no frame_end, one full turn is rendered.
scene_urlNohttps link to a .blend, a .py script or a 3D file (.glb/.gltf/.fbx/.usd/.obj/.stl/.ply/.abc); the service fetches it (e.g. the sample https://render.janction.jp/samples/cube_scene.py, or a 12-hour /upload link). A .gltf or .obj also brings its .bin / .mtl / textures from the same folder.
notify_urlNoOptional https URL that receives one JSON POST when the final render finishes (job.done / job.failed, with download links), so nobody has to poll.
scene_pathNoLocal path to the scene: a .blend file, a bpy .py script, or a 3D file (.glb/.gltf/.fbx/.usd/.obj/.stl/.ply/.abc, imported into an empty scene). Uploaded once; reuse the returned scene_id afterwards.
environmentNoLighting preset: '' (the scene's own world), 'studio', 'sunset', 'overcast' or 'night' (bundled HDRIs; a good first render for scenes without lighting work), or 'compare' (preview only: all four in one labeled 2x2 image, to pick one).
frame_startNoFirst frame to render (inclusive).
transparentNoTrue renders on a transparent background (alpha) for product shots and overlays; png / exr / webm / gif / webp keep it, mp4 and prores cannot. The preview sheet shows it over dark grey.
orbit_framesNoNumber of frames for one full turn (default 24).
orbit_targetNoObject name or 'x,y,z' to centre the orbit on (default: the scene's main objects).
scene_scriptNoThe scene as bpy Python code (text). No file and no local Blender needed; the service runs it in Blender 5.0 (5.2 with blender='5.2'). Blender 5.0 API notes: materials are node-based, so set a colour on the Principled BSDF (mat.node_tree.nodes['Principled BSDF'].inputs['Base Color'].default_value = (r, g, b, 1)); mat.diffuse_color only affects the viewport; do not set Material.use_nodes. Animate with obj.keyframe_insert() (action.fcurves no longer exists; set bpy.context.preferences.edit.keyframe_new_interpolation_type = 'LINEAR' first for constant speed). Build the scene, camera and frame range only; leave resolution, samples and denoising to the service. Helpers: `import jr_assets`, then jr_assets.frame_camera(margin=1.1) points the camera at every object and fits them in the frame; jr_assets.import_model('<id>'), jr_assets.material('<id>') and jr_assets.world_hdri('<id>') use Poly Haven assets passed in assets.
orbit_distanceNoMultiplier for the orbit camera distance (default 1.0).
idempotency_keyNoAny string up to 128 characters that identifies this order: sending the same key again returns the first job instead of rendering twice (a different body with the same key is refused).
orbit_elevationNoOrbit camera elevation in degrees (default 18).
environment_visibleNoFalse hides the HDRI from the camera (flat grey backdrop, HDRI lighting only).
environment_strengthNoMultiplier for the HDRI preset's brightness (default 1.0).

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations mark this as non-read-only, non-idempotent, open-world, and the description adds far more: per-call frame limits (3,000; 240 as parts under one job id), resolution caps on free vs prepaid, pricing (100 JPY free credit, 400 JPY after card save, 0.1 JPY/GPU-second), file deletion windows, chunk-and-join behavior, and an explicit 'ask before a render the free time does not cover.' This is unusually rich behavioral context.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose and the estimate-first rule are front-loaded, and nearly every clause carries operational weight (limits, pricing, workflow). However, it is a single dense block that mixes workflow, pricing, and parameter notes; splitting into short labeled segments would improve scanability.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 29-parameter, open-world, paid-render tool with an output schema, the description covers the full lifecycle: when to estimate, how to render, how to poll (render_status), how to download (render_download), cost limits, and deletion policy. Return values need not be explained since output_schema exists.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3; the description earns an extra point by adding cross-parameter semantics not obvious from the schema, e.g. preset='product'|'turntable'|'animation' filling settings, output format list, assets ('polyhaven:<id>'), and using scene_id from render_preview vs scene_path/script/url. It mostly reinforces schema content rather than adding novel syntax detail.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb+resource+context: 'Render the final frames or video of a Blender scene on cloud GPUs, after the user approved a preview.' This clearly distinguishes it from render_preview (which happens before approval) and from render_estimate. An agent can select it without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states when to call render_estimate first (uncertain time, >24 frames, >720p, user asks duration) and 'tell the user.' It also prescribes the animation workflow ('keep the approved engine/look, test 10 contiguous final-path frames, then estimate again') and routes to render_status / render_download afterwards. Alternatives and conditions are named.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

render_infoA
Read-onlyIdempotent
Inspect

Check the connection and the service before rendering (read-only, no GPU time, no charge): the server URL, whether GPU workers are online, the queue length and expected wait, and this key's usage. Use it before the first render or when renders seem stuck, and to decide whether to route a render here: workers_available > 0 means a preview comes back in seconds; gated means the GPU is lent out and gate says how long the wait usually is. It uses the API key in JANCTION_RENDER_API_KEY or ~/.janction-render.json (a free key is made on first use). Every call is rate-limited per key; a 429 response carries retry_after_s, wait that long. diagnose.tell_user says in plain words whether the connection, the key, the free credit and the GPUs are fine and what the last failed render said; relay it when the user asks why something does not work.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations (which already cover read-only/idempotent/non-destructive), it discloses cost and resource behavior ('no GPU time, no charge'), the auth source (JANCTION_RENDER_API_KEY or ~/.janction-render.json, auto-provisioned), and rate limiting with the concrete recovery action ('a 429 response carries retry_after_s, wait that long'). It also explains how to interpret the gated state and diagnose.tell_user.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the action and the cost reassurance, and nearly every clause carries information an agent needs. However, it is delivered as one dense ~120-word paragraph mixing purpose, routing logic, auth, rate limits and diagnosis, which would scan better broken into discrete statements.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists so return values need not be documented exhaustively, yet the description goes further and tells the agent how to read the important fields (workers_available, gated, gate) and how to relay diagnose.tell_user to the user. Nothing an agent needs to call this correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so per the rubric the baseline is 4. There is no parameter surface for the description to clarify, and it correctly spends its words on return-value interpretation instead.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and scope: 'Check the connection and the service before rendering', then enumerates exactly what is reported (server URL, GPU worker health, queue length, expected wait, key usage). It is clearly a service-level diagnostic rather than a job-level one, but it never names the adjacent sibling render_status, so an agent must infer the boundary with that tool.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit triggering conditions ('before the first render', 'when renders seem stuck') plus a decision rule ('to decide whether to route a render here'). It also names the alternative path implicitly by explaining that workers_available > 0 vs gated determines whether a preview is worthwhile. This is textbook when-to-use guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

render_previewAInspect

Show what a Blender scene looks like: a fast, low-cost preview render on a cloud GPU, back as an image in seconds. Typical requests: 'render this .blend', 'show me the scene', 'preview the turntable', 'I have no GPU', 'Blender is too slow on my laptop', 'Blenderでレンダリングして', 'GPUがない', 'ターンテーブル', '商品の360度動画'. Also use it after writing a bpy script, to see what it builds. Each preview returns a critic verdict (ok / check / fix) with fix code: apply the fixes and preview again before any final render. It also returns final_estimate (the same scene as a 1080p final) and quota_left_today; tell the user both before asking to go on. A script that raises comes back as a failure with the line (nothing is rendered). When not to use: editing a scene open in the user's Blender belongs to a local Blender MCP, and a single still on a machine with its own NVIDIA GPU usually renders faster locally. This service is for CPU-only machines, animations, and scripts with no Blender installed. Limits: up to 1280x720; 1-4 frames tiled in one labeled image for the GPU time of one 720p frame. preset='product' | 'turntable' | 'animation' sets camera, light, backdrop and frames for that purpose. Other options are explained on each parameter: environment presets and 'compare', orbit (turntable), cameras (several named cameras), engine, transparent, assets with 'polyhaven:' CC0 assets. Give the scene as scene_path (a local .blend, .py or 3D file), scene_script, scene_url or scene_id; the image is saved locally and shown.

ParametersJSON Schema
NameRequiredDescriptionDefault
orbitNoTrue: turntable; an orbit camera circles the scene once (the scene's own camera is not used). Flat floors and walls are ignored when framing. A preview without frames shows 0/90/180/270 degrees; a final without frame_end renders the whole turn as an MP4. Best for imported models and product videos.
widthNoOutput width in pixels (previews are capped at 1280x720 keeping the aspect ratio; a final frame can have at most 1920x1080 pixels on free time, 3840x2160 on prepaid credit).
assetsNoExtra files sent with the scene: local paths (textures, glTF .bin), https links, or 'polyhaven:<id>' CC0 assets from asset_search. A .blend finds them through relative paths (same folder); a script through os.environ['JR_ASSETS_DIR'] or the jr_assets helpers.
cameraNoName of the camera object to render from (default: the scene's active camera, or an automatic camera if there is none). Ignored with orbit=True; not combinable with cameras.
engineNo'' or 'cycles' (path tracing, default) | 'eevee' (real-time rasterizer: about half the per-frame cost on animations of a few dozen frames or more; each job pays about 7 s of shader compilation, so previews stay on Cycles).
framesNoPreview frames: '' = frame 1; '12' = one frame; '1,8,16,24' or '1-24' = up to 4 frames tiled in one labeled image (to judge camera motion and animation; same GPU time as one 720p frame).
heightNoOutput height in pixels (previews are capped at 1280x720 keeping the aspect ratio; a final frame can have at most 1920x1080 pixels on free time, 3840x2160 on prepaid credit).
presetNoPurpose preset: 'product' (4 studio shots at 0/90/180/270 deg on a plain backdrop; the final gives 4 PNGs at 1440x1440), 'turntable' (one full turn as an MP4, studio light, plain backdrop), 'animation' (the scene's own camera, lights and frame range; the scene is read first when the range is unknown), or '' (none). It fills what you do not pass; environment, orbit_frames, width/height and the frames still win when given.
blenderNoBlender version: '' (default: a .blend opens with the version it was saved in, other scenes with 5.0) or '5.0' / '5.2' (also '4.5', '4.2', '3.6'; a script that stops on Blender 5 because of an older API is rendered again on those automatically) to choose.
camerasNoSeveral camera object names (up to 8) rendered from the same frame in one job: the preview tiles them in one labeled sheet, the final returns one PNG/EXR per camera (camera_files maps names to files). For product shots from fixed angles. Not combinable with orbit, environment='compare' or camera.
out_dirNoLocal folder to save the files in (default ~/janction-render/<job_id>).
samplesNoCycles samples per pixel (preview: up to 32, default 16; final: default 128).
scene_idNoscene_id returned by an earlier call (reuses the uploaded scene without sending it again).
scene_urlNohttps link to a .blend, a .py script or a 3D file (.glb/.gltf/.fbx/.usd/.obj/.stl/.ply/.abc); the service fetches it (e.g. the sample https://render.janction.jp/samples/cube_scene.py, or a 12-hour /upload link). A .gltf or .obj also brings its .bin / .mtl / textures from the same folder.
scene_pathNoLocal path to the scene: a .blend file, a bpy .py script, or a 3D file (.glb/.gltf/.fbx/.usd/.obj/.stl/.ply/.abc, imported into an empty scene). Uploaded once; reuse the returned scene_id afterwards.
environmentNoLighting preset: '' (the scene's own world), 'studio', 'sunset', 'overcast' or 'night' (bundled HDRIs; a good first render for scenes without lighting work), or 'compare' (preview only: all four in one labeled 2x2 image, to pick one).
transparentNoTrue renders on a transparent background (alpha) for product shots and overlays; png / exr / webm / gif / webp keep it, mp4 and prores cannot. The preview sheet shows it over dark grey.
orbit_framesNoNumber of frames for one full turn (default 24).
orbit_targetNoObject name or 'x,y,z' to centre the orbit on (default: the scene's main objects).
scene_scriptNoThe scene as bpy Python code (text). No file and no local Blender needed; the service runs it in Blender 5.0 (5.2 with blender='5.2'). Blender 5.0 API notes: materials are node-based, so set a colour on the Principled BSDF (mat.node_tree.nodes['Principled BSDF'].inputs['Base Color'].default_value = (r, g, b, 1)); mat.diffuse_color only affects the viewport; do not set Material.use_nodes. Animate with obj.keyframe_insert() (action.fcurves no longer exists; set bpy.context.preferences.edit.keyframe_new_interpolation_type = 'LINEAR' first for constant speed). Build the scene, camera and frame range only; leave resolution, samples and denoising to the service. Helpers: `import jr_assets`, then jr_assets.frame_camera(margin=1.1) points the camera at every object and fits them in the frame; jr_assets.import_model('<id>'), jr_assets.material('<id>') and jr_assets.world_hdri('<id>') use Poly Haven assets passed in assets.
orbit_distanceNoMultiplier for the orbit camera distance (default 1.0).
orbit_elevationNoOrbit camera elevation in degrees (default 18).
environment_visibleNoFalse hides the HDRI from the camera (flat grey backdrop, HDRI lighting only).
environment_strengthNoMultiplier for the HDRI preset's brightness (default 1.0).

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations give the safety profile (readOnly=false, openWorld=true, idempotent=false, non-destructive) but the description discloses behavior the annotations cannot: a critic verdict ok/check/fix with fix code, final_estimate and quota_left_today surfaced before asking to proceed, and a script that raises returning a failure with the offending line and nothing rendered. It also states resolution caps and the tiling economy (1-4 frames for the cost of one 720p frame).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the core purpose, then when-to-use, then when-not-to-use and limits, which is good ordering. It is on the long side and the multilingual trigger phrases add bulk, but nearly every sentence carries routing or behavioral information an agent needs, so little is wasted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 24-parameter zero-required tool with no output schema, the description still explains the salient returns (critic verdict, final_estimate, quota_left_today, failure-with-line), the limits, the input-source options and the follow-up workflow. Nothing an agent needs to call it correctly appears missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3; the description modestly exceeds it by mapping preset values to concrete behavior ('product' | 'turntable' | 'animation' set camera, light, backdrop and frames) and by summarizing the four scene-source channels (scene_path, scene_script, scene_url, scene_id). It otherwise defers to the per-parameter docs ('Other options are explained on each parameter'), which is appropriate but not additive.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource+medium: 'Show what a Blender scene looks like: a fast, low-cost preview render on a cloud GPU, back as an image in seconds.' Scope, cost class and output form are all named, and the preview-vs-final distinction is drawn against the sibling render_final implicitly but clearly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit when-to-use ('after writing a bpy script', 'I have no GPU') and when-not-to-use ('editing a scene open in the user's Blender belongs to a local Blender MCP', a single still on an NVIDIA machine renders faster locally), plus the intended workflow (apply fixes and preview again before any final render). Alternatives are named with the condition that selects them.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

render_reviewAInspect

Check a 3D model or a generated Blender scene by looking at it from 4 sides: a turntable preview (0, 90, 180 and 270 degrees) under neutral studio light on a cloud GPU, back with pass / warning / fail, a score, the checks it ran (texture files found, objects visible and not hidden behind a floor or wall, camera not inside an object, framing, exposure, light) with fix code for each problem, and the 4 views tiled in one image. Typical requests: 'check this model', 'does the scene look right', 'QA this GLB', 'モデルを確認して', '見た目をチェックして'. Use it after writing a bpy script, generating or converting a model (.glb/.gltf/.fbx/.usd/.obj/.stl/.ply/.abc) or changing materials, before showing the result to the user or rendering a final; apply the fixes and call it again. The checks cannot judge whether the shape matches the request: look at the views for that. It costs the same as one preview. To check a shot through the scene's own camera and lights, use render_preview (its critic runs the same checks). Give the scene as scene_path, scene_script, scene_url or scene_id.

ParametersJSON Schema
NameRequiredDescriptionDefault
assetsNoExtra files sent with the scene: local paths (textures, glTF .bin), https links, or 'polyhaven:<id>' CC0 assets from asset_search. A .blend finds them through relative paths (same folder); a script through os.environ['JR_ASSETS_DIR'] or the jr_assets helpers.
blenderNoBlender version: '' (default: a .blend opens with the version it was saved in, other scenes with 5.0) or '5.0' / '5.2' (also '4.5', '4.2', '3.6'; a script that stops on Blender 5 because of an older API is rendered again on those automatically) to choose.
out_dirNoLocal folder to save the files in (default ~/janction-render/<job_id>).
scene_idNoscene_id returned by an earlier call (reuses the uploaded scene without sending it again).
scene_urlNohttps link to a .blend, a .py script or a 3D file (.glb/.gltf/.fbx/.usd/.obj/.stl/.ply/.abc); the service fetches it (e.g. the sample https://render.janction.jp/samples/cube_scene.py, or a 12-hour /upload link). A .gltf or .obj also brings its .bin / .mtl / textures from the same folder.
scene_pathNoLocal path to the scene: a .blend file, a bpy .py script, or a 3D file (.glb/.gltf/.fbx/.usd/.obj/.stl/.ply/.abc, imported into an empty scene). Uploaded once; reuse the returned scene_id afterwards.
environmentNoLight for the review: 'studio' (default; the same neutral light every time), 'sunset', 'overcast', 'night', or '' for the scene's own lights.studio
orbit_targetNoObject name or 'x,y,z' to centre the orbit on (default: the scene's main objects).
scene_scriptNoThe scene as bpy Python code (text). No file and no local Blender needed; the service runs it in Blender 5.0 (5.2 with blender='5.2'). Blender 5.0 API notes: materials are node-based, so set a colour on the Principled BSDF (mat.node_tree.nodes['Principled BSDF'].inputs['Base Color'].default_value = (r, g, b, 1)); mat.diffuse_color only affects the viewport; do not set Material.use_nodes. Animate with obj.keyframe_insert() (action.fcurves no longer exists; set bpy.context.preferences.edit.keyframe_new_interpolation_type = 'LINEAR' first for constant speed). Build the scene, camera and frame range only; leave resolution, samples and denoising to the service. Helpers: `import jr_assets`, then jr_assets.frame_camera(margin=1.1) points the camera at every object and fits them in the frame; jr_assets.import_model('<id>'), jr_assets.material('<id>') and jr_assets.world_hdri('<id>') use Poly Haven assets passed in assets.
orbit_distanceNoMultiplier for the orbit camera distance (default 1.0).
orbit_elevationNoOrbit camera elevation in degrees (default 18).

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Adds substantial context beyond the annotations: it runs on a cloud GPU, costs the same as one preview, enumerates the concrete checks performed (texture files, hidden objects, camera inside geometry, framing, exposure, light), returns fix code per problem, and returns the 4 views tiled in one image. The annotations only carry the generic openWorld/non-idempotent profile, so the description is doing real work here.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action and output, then usage triggers, then the sibling routing rule. Every sentence carries information, but the block is long and the multi-language example strings ('モデルを確認して') add bulk without adding much decision value for an English-speaking agent.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For an 11-parameter, zero-required tool with no output schema, the description covers what matters: the return shape (pass/warning/fail, score, checks, fix code, tiled image), the input alternatives, cost, and the boundary of what the checks can judge. Nothing an agent needs to invoke it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds meaning the schema does not: it frames scene_path/scene_script/scene_url/scene_id as four alternative ways to supply the same scene ('Give the scene as ...'), which the flat schema never states. It also notes environment affects lighting choice. Minor gap: it does not explain orbit_distance/orbit_elevation semantics.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (check/review) and resource (a 3D model or generated Blender scene), and specifies the exact method: a 4-view turntable under neutral studio light returning pass/warning/fail, a score, and the checks run. It explicitly distinguishes itself from the sibling render_preview by naming the camera/lights case that selects the other tool.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit when-to-use triggers ('after writing a bpy script, generating or converting a model ... before showing the result to the user or rendering a final'), the loop to follow ('apply the fixes and call it again'), an explicit limitation ('the checks cannot judge whether the shape matches the request'), and the alternative for camera-based shots (render_preview). Nothing is left to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

render_shareAInspect

Publish a finished render as a public web page anyone with the link can open (for X, Discord or a client): the image or video, the render settings, an optional title and note, the user's request in their words (prompt), and the bpy script only if include_script=True. The page keeps its own copy of the result after the job's files expire, until render_unshare. listed=True only asks to appear in the public gallery; the operator reviews it first. Public: ask the user before sharing and return the url to them. Only the key that rendered the job can share it.

ParametersJSON Schema
NameRequiredDescriptionDefault
noteNoA sentence shown under the image on the share page (optional).
titleNoTitle shown on the public share page (optional).
job_idYesThe job_id returned by render_preview or render_final (j_...; a long final split into parts is b_...). Only this key's jobs; in render_status, leave it empty to list them.
listedNoTrue asks for the page to appear in the public gallery after the operator reviews it.
promptNoWhat the user asked you, in their words (shown as 'what the user asked the agent').
include_scriptNoTrue also publishes the bpy script on the share page.

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations declare mutation and open-world traits; the description goes well beyond them by disclosing page durability beyond job file expiry, the operator review gate for gallery listing, the consent requirement before publishing, and the ownership precondition on the key. These are exactly the non-obvious traits an agent needs before performing an irreversible public action.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action and the page contents before the operational caveats. It is long and clause-heavy in the opening sentence, but nearly every clause adds a fact (script gating, gallery review, durability, auth) rather than filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Although an output schema exists, the description still states that a URL is returned, and it covers durability, expiry, consent, ownership, and gallery review — everything an agent needs to call this correctly and safely. No material gap remains for a six-parameter public-publishing tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so a 3 is the floor, and the description beats it: it clarifies that include_script controls whether the bpy script appears, that prompt is rendered as 'what the user asked the agent', that title/note are shown on the page, and that listed only requests gallery placement subject to review. Marginal additions are modest since the schema already carries much of this.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Publish a finished render as a public web page') and enumerates exactly what the page contains, so the agent can distinguish it from render_unshare (removal) and the render_* job tools. An agent can select this tool without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit preconditions ('Only the key that rendered the job can share it'), the inverse tool for teardown ('until render_unshare'), the semantic difference of listed=True including operator review, and a direct behavioral instruction ('ask the user before sharing and return the url to them'). This is when-to-use, when-not-to, and alternatives all in one.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

render_statusA
Read-onlyIdempotent
Inspect

Check a render job: status (queued / running / done / failed / canceled), frames done, the ETA (eta.human, including queue wait), files ready, Blender warnings, and the error with the log tail if it failed. Use it to report progress to the user; call render_download once status is done. Without job_id it lists this key's recent jobs and the scene_ids still kept, to pick up earlier work in a new conversation.

ParametersJSON Schema
NameRequiredDescriptionDefault
job_idNoThe job_id returned by render_preview or render_final (j_...; a long final split into parts is b_...). Only this key's jobs; in render_status, leave it empty to list them.

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover the safety profile (readOnly, idempotent, non-destructive, openWorld), so the bar is lower. The description still adds genuine behavioral context: the enumerable status values, that eta.human includes queue wait, that Blender warnings and a log tail are surfaced on failure, and that omitting job_id switches to a listing mode.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two dense sentences, front-loaded with the returned fields and then the usage/fallback modes; nothing is padding. The long field enumeration is justified but makes the second half slightly heavy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return-value documentation is not required, yet the description still sketches the response shape, covers the failure path and the no-argument listing path. Nothing an agent needs to invoke it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% for the single job_id parameter, and the schema already documents its origin (j_.../b_...), key scoping, and the empty-string listing behavior. The description restates the empty case without adding new syntax or constraints, so baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Check a render job') and enumerates exactly what is reported: status enum values, frames done, ETA, files ready, warnings, error tail. It is clearly distinguishable from siblings like render_download or render_estimate, which it names as the follow-up step.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says when to use it ('to report progress to the user'), what to do next ('call render_download once status is done'), and defines the no-argument case ('lists this key's recent jobs and the scene_ids still kept') including the motivating scenario of resuming work in a new conversation.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

render_unshareA
DestructiveIdempotent
Inspect

Take down the public share page of a job made with render_share. Effects: the page URL stops working, its copy of the image or video, the shared script and the shown request are deleted, and the page leaves the public gallery. This cannot be undone: sharing again makes a new page with a new URL. The job's own files are not touched (they expire on their usual schedule). Only the key that shared the job can take the page down; a job without a share page returns not_found.

ParametersJSON Schema
NameRequiredDescriptionDefault
job_idYesThe job_id returned by render_preview or render_final (j_...; a long final split into parts is b_...). Only this key's jobs; in render_status, leave it empty to list them.

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With destructiveHint=true already in the annotations, the description still adds substantial value: it enumerates exactly what is destroyed (page URL, its copy of the image/video, shared script, shown request, gallery listing), states irreversibility and that re-sharing creates a new URL, clarifies job files are untouched, and documents the auth constraint (only the sharing key) plus the not_found case. The idempotentHint is consistent — repeat calls change nothing further.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The destructive effect is front-loaded in the first sentence, followed by consequence, irreversibility, scope of side effects, and error case in compact declarative sentences. No filler or repetition; every sentence carries operational information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists so return values need no explanation, and the annotations cover the safety profile. What remains for an agent to call this correctly — what gets deleted, that it can't be undone, whose key is required, and what happens with no share page — is all present.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the job_id field description is already detailed (j_.../b_... prefixes, which key's jobs, render_status behavior), so the schema does the heavy lifting. The description adds only the constraint that the caller must hold the key that created the share, which is auth context rather than parameter syntax. Baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb+resource ('Take down the public share page of a job') and names the sibling that creates that page (render_share), letting an agent separate it from render_share, render_download, or render_status without reading any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It establishes the precondition clearly ('a job made with render_share') and the failure mode ('a job without a share page returns not_found'), and the job_id schema text explains which identifier to supply from render_preview/render_final. It stops short of an explicit when-to-use/when-not-to pair or a pointer to the sharing sibling for the reverse action.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

scene_infoA
Idempotent
Inspect

Read a Blender scene without rendering (a few seconds, no GPU time): cameras and the active one, frame range and fps, resolution, objects by type, lights, materials, whether it is animated, and missing linked files that would render pink. Use it for a .blend you did not write, or to check what a bpy script built. Returns scene_id; pass it to render_preview and render_final instead of sending the scene again.

ParametersJSON Schema
NameRequiredDescriptionDefault
assetsNoExtra files sent with the scene: local paths (textures, glTF .bin), https links, or 'polyhaven:<id>' CC0 assets from asset_search. A .blend finds them through relative paths (same folder); a script through os.environ['JR_ASSETS_DIR'] or the jr_assets helpers.
blenderNoBlender version: '' (default: a .blend opens with the version it was saved in, other scenes with 5.0) or '5.0' / '5.2' (also '4.5', '4.2', '3.6'; a script that stops on Blender 5 because of an older API is rendered again on those automatically) to choose.
scene_idNoscene_id returned by an earlier call (reuses the uploaded scene without sending it again).
scene_urlNohttps link to a .blend, a .py script or a 3D file (.glb/.gltf/.fbx/.usd/.obj/.stl/.ply/.abc); the service fetches it (e.g. the sample https://render.janction.jp/samples/cube_scene.py, or a 12-hour /upload link). A .gltf or .obj also brings its .bin / .mtl / textures from the same folder.
scene_pathNoLocal path to the scene: a .blend file, a bpy .py script, or a 3D file (.glb/.gltf/.fbx/.usd/.obj/.stl/.ply/.abc, imported into an empty scene). Uploaded once; reuse the returned scene_id afterwards.
scene_scriptNoThe scene as bpy Python code (text). No file and no local Blender needed; the service runs it in Blender 5.0 (5.2 with blender='5.2'). Blender 5.0 API notes: materials are node-based, so set a colour on the Principled BSDF (mat.node_tree.nodes['Principled BSDF'].inputs['Base Color'].default_value = (r, g, b, 1)); mat.diffuse_color only affects the viewport; do not set Material.use_nodes. Animate with obj.keyframe_insert() (action.fcurves no longer exists; set bpy.context.preferences.edit.keyframe_new_interpolation_type = 'LINEAR' first for constant speed). Build the scene, camera and frame range only; leave resolution, samples and denoising to the service. Helpers: `import jr_assets`, then jr_assets.frame_camera(margin=1.1) points the camera at every object and fits them in the frame; jr_assets.import_model('<id>'), jr_assets.material('<id>') and jr_assets.world_hdri('<id>') use Poly Haven assets passed in assets.

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare idempotentHint=true and destructiveHint=false; the description adds genuinely useful cost/behavior context ('a few seconds, no GPU time') and clarifies that this is a non-rendering inspection step, which reconciles the readOnlyHint=false annotation with what the agent sees. It does not cover auth requirements, quotas, or failure modes, so 4 rather than 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, front-loaded with the verb and the no-render constraint, then the payload list, then the routing rule. Every clause carries information; nothing is padded or repeated.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need no explanation, and the description still sketches what is inspected. Combined with the scene_id hand-off instruction, an agent has everything needed to call it and chain it into rendering, though it says nothing about what happens when the scene fails to load or has unresolvable assets.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the per-parameter text is unusually detailed (Blender API notes, asset resolution rules, jr_assets helpers), so the schema does the heavy lifting and baseline is 3. The description only restates the scene_id reuse rule that the schema already documents, adding no new parameter-level meaning.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Read a Blender scene') and enumerates exactly what is returned: cameras, frame range, fps, resolution, objects, lights, materials, animation state, missing linked files. That enumeration distinguishes it cleanly from render_preview/render_final, which produce images rather than metadata.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit when-to-use conditions ('a .blend you did not write', 'check what a bpy script built') and an explicit alternative/sequencing rule: pass the returned scene_id to render_preview and render_final instead of re-uploading. Nothing about tool selection is left to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 4 tool updatesv0.4.120
    • Changedrender_final1 field changed
      • changedInput schema / properties / blender / description
        Previous value: -"Blender version: '' (default: a .blend opens with the version it was saved in, other scenes with 5.0) or '5.0' / '5.2' to choose."New value: +"Blender version: '' (default: a .blend opens with the version it was saved in, other scenes with 5.0) or '5.0' / '5.2' (also '4.5', '4.2', '3.6'; a script that stops on Blender 5 because of an older API is rendered again on those automatically) to choose."
    • Changedrender_preview1 field changed
      • changedInput schema / properties / blender / description
        Previous value: -"Blender version: '' (default: a .blend opens with the version it was saved in, other scenes with 5.0) or '5.0' / '5.2' to choose."New value: +"Blender version: '' (default: a .blend opens with the version it was saved in, other scenes with 5.0) or '5.0' / '5.2' (also '4.5', '4.2', '3.6'; a script that stops on Blender 5 because of an older API is rendered again on those automatically) to choose."
    • Changedrender_review1 field changed
      • changedInput schema / properties / blender / description
        Previous value: -"Blender version: '' (default: a .blend opens with the version it was saved in, other scenes with 5.0) or '5.0' / '5.2' to choose."New value: +"Blender version: '' (default: a .blend opens with the version it was saved in, other scenes with 5.0) or '5.0' / '5.2' (also '4.5', '4.2', '3.6'; a script that stops on Blender 5 because of an older API is rendered again on those automatically) to choose."
    • Changedscene_info1 field changed
      • changedInput schema / properties / blender / description
        Previous value: -"Blender version: '' (default: a .blend opens with the version it was saved in, other scenes with 5.0) or '5.0' / '5.2' to choose."New value: +"Blender version: '' (default: a .blend opens with the version it was saved in, other scenes with 5.0) or '5.0' / '5.2' (also '4.5', '4.2', '3.6'; a script that stops on Blender 5 because of an older API is rendered again on those automatically) to choose."
  2. 12 tool updatesv0.4.119
    • Changedasset_search2 fields changed
      • addedInput schema / properties / kind / description
        Added value: +"'models' (default) | 'textures' | 'hdris'."
      • addedInput schema / properties / query / description
        Added value: +"Words to search Poly Haven for (name, tags, category), e.g. 'wooden chair' or 'forest hdri'."
    • Changedbilling1 field changed
      • addedInput schema / properties / topup_yen / description
        Added value: +"0 = just report the quota / balance; > 0 (minimum 500) = create a Stripe checkout link for that amount in yen."
    • Changedrender_cancel1 field changed
      • addedInput schema / properties / job_id / description
        Added value: +"The job_id returned by render_preview or render_final (j_...; a long final split into parts is b_...). Only this key's jobs; in render_status, leave it empty to list them."
    • Changedrender_download4 fields changed
      • addedInput schema / properties / job_id / description
        Added value: +"The job_id returned by render_preview or render_final (j_...; a long final split into parts is b_...). Only this key's jobs; in render_status, leave it empty to list them."
      • addedInput schema / properties / only / description
        Added value: +"'all' (every frame plus output.mp4 / sheet.png) | 'mp4' | 'frames' | 'sheet' | 'output' (the MP4 or the sheet only)."
      • addedInput schema / properties / out_dir / description
        Added value: +"Local folder to save the files in (default ~/janction-render/<job_id>)."
      • addedInput schema / properties / wait_seconds / description
        Added value: +"Wait up to this many seconds for the job to finish before downloading (0 = do not wait)."
    • Changedrender_estimate10 fields changed
      • addedInput schema / properties / cameras
        Added value: +{
        +  "anyOf": [
        +    {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "description": "Several camera object names (up to 8) rendered from the same frame in one job: the preview tiles them in one labeled sheet, the final returns one PNG/EXR per camera (camera_files maps names to files). For product shots from fixed angles. Not combinable with orbit, environment='compare' or camera.",
        +  "title": "Cameras"
        +}
      • addedInput schema / properties / frame_end / description
        Added value: +"Last frame to render (inclusive); equal to frame_start for a single image. With orbit=True and no frame_end, one full turn is rendered."
      • addedInput schema / properties / frame_start / description
        Added value: +"First frame to render (inclusive)."
      • addedInput schema / properties / frames / description
        Added value: +"Preview frames: '' = frame 1; '12' = one frame; '1,8,16,24' or '1-24' = up to 4 frames tiled in one labeled image (to judge camera motion and animation; same GPU time as one 720p frame)."
      • addedInput schema / properties / height / description
        Added value: +"Output height in pixels (previews are capped at 1280x720 keeping the aspect ratio; a final frame can have at most 1920x1080 pixels on free time, 3840x2160 on prepaid credit)."
      • addedInput schema / properties / kind / description
        Added value: +"'final' (frame_start..frame_end at width x height, samples) or 'preview' (frames like '1-24')."
      • addedInput schema / properties / preset
        Added value: +{
        +  "default": "",
        +  "description": "Purpose preset: 'product' (4 studio shots at 0/90/180/270 deg on a plain backdrop; the final gives 4 PNGs at 1440x1440), 'turntable' (one full turn as an MP4, studio light, plain backdrop), 'animation' (the scene's own camera, lights and frame range; the scene is read first when the range is unknown), or '' (none). It fills what you do not pass; environment, orbit_frames, width/height and the frames still win when given.",
        +  "title": "Preset",
        +  "type": "string"
        +}
      • addedInput schema / properties / samples / description
        Added value: +"Cycles samples per pixel (preview: up to 32, default 16; final: default 128)."
      • addedInput schema / properties / scene_id / description
        Added value: +"scene_id returned by an earlier call (reuses the uploaded scene without sending it again)."
      • addedInput schema / properties / width / description
        Added value: +"Output width in pixels (previews are capped at 1280x720 keeping the aspect ratio; a final frame can have at most 1920x1080 pixels on free time, 3840x2160 on prepaid credit)."
    • Changedrender_final29 fields changed
      • addedInput schema / properties / assets / description
        Added value: +"Extra files sent with the scene: local paths (textures, glTF .bin), https links, or 'polyhaven:<id>' CC0 assets from asset_search. A .blend finds them through relative paths (same folder); a script through os.environ['JR_ASSETS_DIR'] or the jr_assets helpers."
      • addedInput schema / properties / blender / description
        Added value: +"Blender version: '' (default: a .blend opens with the version it was saved in, other scenes with 5.0) or '5.0' / '5.2' to choose."
      • addedInput schema / properties / camera / description
        Added value: +"Name of the camera object to render from (default: the scene's active camera, or an automatic camera if there is none). Ignored with orbit=True; not combinable with cameras."
      • addedInput schema / properties / cameras
        Added value: +{
        +  "anyOf": [
        +    {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "description": "Several camera object names (up to 8) rendered from the same frame in one job: the preview tiles them in one labeled sheet, the final returns one PNG/EXR per camera (camera_files maps names to files). For product shots from fixed angles. Not combinable with orbit, environment='compare' or camera.",
        +  "title": "Cameras"
        +}
      • addedInput schema / properties / engine / description
        Added value: +"'' or 'cycles' (path tracing, default) | 'eevee' (real-time rasterizer: about half the per-frame cost on animations of a few dozen frames or more; each job pays about 7 s of shader compilation, so previews stay on Cycles)."
      • addedInput schema / properties / environment / description
        Added value: +"Lighting preset: '' (the scene's own world), 'studio', 'sunset', 'overcast' or 'night' (bundled HDRIs; a good first render for scenes without lighting work), or 'compare' (preview only: all four in one labeled 2x2 image, to pick one)."
      • addedInput schema / properties / environment_strength / description
        Added value: +"Multiplier for the HDRI preset's brightness (default 1.0)."
      • addedInput schema / properties / environment_visible / description
        Added value: +"False hides the HDRI from the camera (flat grey backdrop, HDRI lighting only)."
      • addedInput schema / properties / fps / description
        Added value: +"Frames per second of the video output (default 24)."
      • addedInput schema / properties / frame_end / description
        Added value: +"Last frame to render (inclusive); equal to frame_start for a single image. With orbit=True and no frame_end, one full turn is rendered."
      • addedInput schema / properties / frame_start / description
        Added value: +"First frame to render (inclusive)."
      • addedInput schema / properties / height / description
        Added value: +"Output height in pixels (previews are capped at 1280x720 keeping the aspect ratio; a final frame can have at most 1920x1080 pixels on free time, 3840x2160 on prepaid credit)."
      • addedInput schema / properties / idempotency_key
        Added value: +{
        +  "default": "",
        +  "description": "Any string up to 128 characters that identifies this order: sending the same key again returns the first job instead of rendering twice (a different body with the same key is refused).",
        +  "title": "Idempotency Key",
        +  "type": "string"
        +}
      • addedInput schema / properties / max_yen
        Added value: +{
        +  "default": -1,
        +  "description": "Ceiling for this job in JPY (-1 = none): the job is refused before anything is reserved when its reservation would exceed it. 0 means 'only if it fits the free time'.",
        +  "title": "Max Yen",
        +  "type": "integer"
        +}
      • addedInput schema / properties / notify_url / description
        Added value: +"Optional https URL that receives one JSON POST when the final render finishes (job.done / job.failed, with download links), so nobody has to poll."
      • addedInput schema / properties / orbit / description
        Added value: +"True: turntable; an orbit camera circles the scene once (the scene's own camera is not used). Flat floors and walls are ignored when framing. A preview without frames shows 0/90/180/270 degrees; a final without frame_end renders the whole turn as an MP4. Best for imported models and product videos."
      • addedInput schema / properties / orbit_distance / description
        Added value: +"Multiplier for the orbit camera distance (default 1.0)."
      • addedInput schema / properties / orbit_elevation / description
        Added value: +"Orbit camera elevation in degrees (default 18)."
      • addedInput schema / properties / orbit_frames / description
        Added value: +"Number of frames for one full turn (default 24)."
      • addedInput schema / properties / orbit_target / description
        Added value: +"Object name or 'x,y,z' to centre the orbit on (default: the scene's main objects)."
      • addedInput schema / properties / output / description
        Added value: +"'auto' (mp4 for a frame range, png for one frame) | 'png' | 'exr' (16-bit linear frames for compositing) | 'mp4' (H.264) | 'webm' (VP9) | 'prores' (Apple ProRes 422 HQ .mov, for editing) | 'gif' | 'webp' (animated, at most 960 px wide; good for chat and web)."
      • addedInput schema / properties / preset
        Added value: +{
        +  "default": "",
        +  "description": "Purpose preset: 'product' (4 studio shots at 0/90/180/270 deg on a plain backdrop; the final gives 4 PNGs at 1440x1440), 'turntable' (one full turn as an MP4, studio light, plain backdrop), 'animation' (the scene's own camera, lights and frame range; the scene is read first when the range is unknown), or '' (none). It fills what you do not pass; environment, orbit_frames, width/height and the frames still win when given.",
        +  "title": "Preset",
        +  "type": "string"
        +}
      • addedInput schema / properties / samples / description
        Added value: +"Cycles samples per pixel (preview: up to 32, default 16; final: default 128)."
      • addedInput schema / properties / scene_id / description
        Added value: +"scene_id returned by an earlier call (reuses the uploaded scene without sending it again)."
      • addedInput schema / properties / scene_path / description
        Added value: +"Local path to the scene: a .blend file, a bpy .py script, or a 3D file (.glb/.gltf/.fbx/.usd/.obj/.stl/.ply/.abc, imported into an empty scene). Uploaded once; reuse the returned scene_id afterwards."
      • addedInput schema / properties / scene_script / description
        Added value: +"The scene as bpy Python code (text). No file and no local Blender needed; the service runs it in Blender 5.0 (5.2 with blender='5.2'). Blender 5.0 API notes: materials are node-based, so set a colour on the Principled BSDF (mat.node_tree.nodes['Principled BSDF'].inputs['Base Color'].default_value = (r, g, b, 1)); mat.diffuse_color only affects the viewport; do not set Material.use_nodes. Animate with obj.keyframe_insert() (action.fcurves no longer exists; set bpy.context.preferences.edit.keyframe_new_interpolation_type = 'LINEAR' first for constant speed). Build the scene, camera and frame range only; leave resolution, samples and denoising to the service. Helpers: `import jr_assets`, then jr_assets.frame_camera(margin=1.1) points the camera at every object and fits them in the frame; jr_assets.import_model('<id>'), jr_assets.material('<id>') and jr_assets.world_hdri('<id>') use Poly Haven assets passed in assets."
      • addedInput schema / properties / scene_url
        Added value: +{
        +  "default": "",
        +  "description": "https link to a .blend, a .py script or a 3D file (.glb/.gltf/.fbx/.usd/.obj/.stl/.ply/.abc); the service fetches it (e.g. the sample https://render.janction.jp/samples/cube_scene.py, or a 12-hour /upload link). A .gltf or .obj also brings its .bin / .mtl / textures from the same folder.",
        +  "title": "Scene Url",
        +  "type": "string"
        +}
      • addedInput schema / properties / transparent / description
        Added value: +"True renders on a transparent background (alpha) for product shots and overlays; png / exr / webm / gif / webp keep it, mp4 and prores cannot. The preview sheet shows it over dark grey."
      • addedInput schema / properties / width / description
        Added value: +"Output width in pixels (previews are capped at 1280x720 keeping the aspect ratio; a final frame can have at most 1920x1080 pixels on free time, 3840x2160 on prepaid credit)."
    • Changedrender_preview24 fields changed
      • addedInput schema / properties / assets / description
        Added value: +"Extra files sent with the scene: local paths (textures, glTF .bin), https links, or 'polyhaven:<id>' CC0 assets from asset_search. A .blend finds them through relative paths (same folder); a script through os.environ['JR_ASSETS_DIR'] or the jr_assets helpers."
      • addedInput schema / properties / blender / description
        Added value: +"Blender version: '' (default: a .blend opens with the version it was saved in, other scenes with 5.0) or '5.0' / '5.2' to choose."
      • addedInput schema / properties / camera / description
        Added value: +"Name of the camera object to render from (default: the scene's active camera, or an automatic camera if there is none). Ignored with orbit=True; not combinable with cameras."
      • addedInput schema / properties / cameras
        Added value: +{
        +  "anyOf": [
        +    {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "description": "Several camera object names (up to 8) rendered from the same frame in one job: the preview tiles them in one labeled sheet, the final returns one PNG/EXR per camera (camera_files maps names to files). For product shots from fixed angles. Not combinable with orbit, environment='compare' or camera.",
        +  "title": "Cameras"
        +}
      • addedInput schema / properties / engine / description
        Added value: +"'' or 'cycles' (path tracing, default) | 'eevee' (real-time rasterizer: about half the per-frame cost on animations of a few dozen frames or more; each job pays about 7 s of shader compilation, so previews stay on Cycles)."
      • addedInput schema / properties / environment / description
        Added value: +"Lighting preset: '' (the scene's own world), 'studio', 'sunset', 'overcast' or 'night' (bundled HDRIs; a good first render for scenes without lighting work), or 'compare' (preview only: all four in one labeled 2x2 image, to pick one)."
      • addedInput schema / properties / environment_strength / description
        Added value: +"Multiplier for the HDRI preset's brightness (default 1.0)."
      • addedInput schema / properties / environment_visible / description
        Added value: +"False hides the HDRI from the camera (flat grey backdrop, HDRI lighting only)."
      • addedInput schema / properties / frames / description
        Added value: +"Preview frames: '' = frame 1; '12' = one frame; '1,8,16,24' or '1-24' = up to 4 frames tiled in one labeled image (to judge camera motion and animation; same GPU time as one 720p frame)."
      • addedInput schema / properties / height / description
        Added value: +"Output height in pixels (previews are capped at 1280x720 keeping the aspect ratio; a final frame can have at most 1920x1080 pixels on free time, 3840x2160 on prepaid credit)."
      • addedInput schema / properties / orbit / description
        Added value: +"True: turntable; an orbit camera circles the scene once (the scene's own camera is not used). Flat floors and walls are ignored when framing. A preview without frames shows 0/90/180/270 degrees; a final without frame_end renders the whole turn as an MP4. Best for imported models and product videos."
      • addedInput schema / properties / orbit_distance / description
        Added value: +"Multiplier for the orbit camera distance (default 1.0)."
      • addedInput schema / properties / orbit_elevation / description
        Added value: +"Orbit camera elevation in degrees (default 18)."
      • addedInput schema / properties / orbit_frames / description
        Added value: +"Number of frames for one full turn (default 24)."
      • addedInput schema / properties / orbit_target / description
        Added value: +"Object name or 'x,y,z' to centre the orbit on (default: the scene's main objects)."
      • addedInput schema / properties / out_dir / description
        Added value: +"Local folder to save the files in (default ~/janction-render/<job_id>)."
      • addedInput schema / properties / preset
        Added value: +{
        +  "default": "",
        +  "description": "Purpose preset: 'product' (4 studio shots at 0/90/180/270 deg on a plain backdrop; the final gives 4 PNGs at 1440x1440), 'turntable' (one full turn as an MP4, studio light, plain backdrop), 'animation' (the scene's own camera, lights and frame range; the scene is read first when the range is unknown), or '' (none). It fills what you do not pass; environment, orbit_frames, width/height and the frames still win when given.",
        +  "title": "Preset",
        +  "type": "string"
        +}
      • addedInput schema / properties / samples / description
        Added value: +"Cycles samples per pixel (preview: up to 32, default 16; final: default 128)."
      • addedInput schema / properties / scene_id / description
        Added value: +"scene_id returned by an earlier call (reuses the uploaded scene without sending it again)."
      • addedInput schema / properties / scene_path / description
        Added value: +"Local path to the scene: a .blend file, a bpy .py script, or a 3D file (.glb/.gltf/.fbx/.usd/.obj/.stl/.ply/.abc, imported into an empty scene). Uploaded once; reuse the returned scene_id afterwards."
      • addedInput schema / properties / scene_script / description
        Added value: +"The scene as bpy Python code (text). No file and no local Blender needed; the service runs it in Blender 5.0 (5.2 with blender='5.2'). Blender 5.0 API notes: materials are node-based, so set a colour on the Principled BSDF (mat.node_tree.nodes['Principled BSDF'].inputs['Base Color'].default_value = (r, g, b, 1)); mat.diffuse_color only affects the viewport; do not set Material.use_nodes. Animate with obj.keyframe_insert() (action.fcurves no longer exists; set bpy.context.preferences.edit.keyframe_new_interpolation_type = 'LINEAR' first for constant speed). Build the scene, camera and frame range only; leave resolution, samples and denoising to the service. Helpers: `import jr_assets`, then jr_assets.frame_camera(margin=1.1) points the camera at every object and fits them in the frame; jr_assets.import_model('<id>'), jr_assets.material('<id>') and jr_assets.world_hdri('<id>') use Poly Haven assets passed in assets."
      • addedInput schema / properties / scene_url
        Added value: +{
        +  "default": "",
        +  "description": "https link to a .blend, a .py script or a 3D file (.glb/.gltf/.fbx/.usd/.obj/.stl/.ply/.abc); the service fetches it (e.g. the sample https://render.janction.jp/samples/cube_scene.py, or a 12-hour /upload link). A .gltf or .obj also brings its .bin / .mtl / textures from the same folder.",
        +  "title": "Scene Url",
        +  "type": "string"
        +}
      • addedInput schema / properties / transparent / description
        Added value: +"True renders on a transparent background (alpha) for product shots and overlays; png / exr / webm / gif / webp keep it, mp4 and prores cannot. The preview sheet shows it over dark grey."
      • addedInput schema / properties / width / description
        Added value: +"Output width in pixels (previews are capped at 1280x720 keeping the aspect ratio; a final frame can have at most 1920x1080 pixels on free time, 3840x2160 on prepaid credit)."
    • Addedrender_review
    • Changedrender_share6 fields changed
      • addedInput schema / properties / include_script / description
        Added value: +"True also publishes the bpy script on the share page."
      • addedInput schema / properties / job_id / description
        Added value: +"The job_id returned by render_preview or render_final (j_...; a long final split into parts is b_...). Only this key's jobs; in render_status, leave it empty to list them."
      • addedInput schema / properties / listed / description
        Added value: +"True asks for the page to appear in the public gallery after the operator reviews it."
      • addedInput schema / properties / note / description
        Added value: +"A sentence shown under the image on the share page (optional)."
      • addedInput schema / properties / prompt / description
        Added value: +"What the user asked you, in their words (shown as 'what the user asked the agent')."
      • addedInput schema / properties / title / description
        Added value: +"Title shown on the public share page (optional)."
    • Changedrender_status3 fields changed
      • addedInput schema / properties / job_id / default
        Added value: +""
      • addedInput schema / properties / job_id / description
        Added value: +"The job_id returned by render_preview or render_final (j_...; a long final split into parts is b_...). Only this key's jobs; in render_status, leave it empty to list them."
      • removedInput schema / required
        Removed value: -[
        -  "job_id"
        -]
    • Changedrender_unshare1 field changed
      • addedInput schema / properties / job_id / description
        Added value: +"The job_id returned by render_preview or render_final (j_...; a long final split into parts is b_...). Only this key's jobs; in render_status, leave it empty to list them."
    • Changedscene_info6 fields changed
      • addedInput schema / properties / assets / description
        Added value: +"Extra files sent with the scene: local paths (textures, glTF .bin), https links, or 'polyhaven:<id>' CC0 assets from asset_search. A .blend finds them through relative paths (same folder); a script through os.environ['JR_ASSETS_DIR'] or the jr_assets helpers."
      • addedInput schema / properties / blender / description
        Added value: +"Blender version: '' (default: a .blend opens with the version it was saved in, other scenes with 5.0) or '5.0' / '5.2' to choose."
      • addedInput schema / properties / scene_id / description
        Added value: +"scene_id returned by an earlier call (reuses the uploaded scene without sending it again)."
      • addedInput schema / properties / scene_path / description
        Added value: +"Local path to the scene: a .blend file, a bpy .py script, or a 3D file (.glb/.gltf/.fbx/.usd/.obj/.stl/.ply/.abc, imported into an empty scene). Uploaded once; reuse the returned scene_id afterwards."
      • addedInput schema / properties / scene_script / description
        Added value: +"The scene as bpy Python code (text). No file and no local Blender needed; the service runs it in Blender 5.0 (5.2 with blender='5.2'). Blender 5.0 API notes: materials are node-based, so set a colour on the Principled BSDF (mat.node_tree.nodes['Principled BSDF'].inputs['Base Color'].default_value = (r, g, b, 1)); mat.diffuse_color only affects the viewport; do not set Material.use_nodes. Animate with obj.keyframe_insert() (action.fcurves no longer exists; set bpy.context.preferences.edit.keyframe_new_interpolation_type = 'LINEAR' first for constant speed). Build the scene, camera and frame range only; leave resolution, samples and denoising to the service. Helpers: `import jr_assets`, then jr_assets.frame_camera(margin=1.1) points the camera at every object and fits them in the frame; jr_assets.import_model('<id>'), jr_assets.material('<id>') and jr_assets.world_hdri('<id>') use Poly Haven assets passed in assets."
      • addedInput schema / properties / scene_url
        Added value: +{
        +  "default": "",
        +  "description": "https link to a .blend, a .py script or a 3D file (.glb/.gltf/.fbx/.usd/.obj/.stl/.ply/.abc); the service fetches it (e.g. the sample https://render.janction.jp/samples/cube_scene.py, or a 12-hour /upload link). A .gltf or .obj also brings its .bin / .mtl / textures from the same folder.",
        +  "title": "Scene Url",
        +  "type": "string"
        +}
  3. 7 tool updatesv0.2.2
    • Addedasset_search
    • Changedrender_download1 field changed
      • addedInput schema / properties / only
        Added value: +{
        +  "default": "all",
        +  "title": "Only",
        +  "type": "string"
        +}
    • Changedrender_final13 fields changed
      • addedInput schema / properties / assets
        Added value: +{
        +  "anyOf": [
        +    {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "title": "Assets"
        +}
      • addedInput schema / properties / blender
        Added value: +{
        +  "default": "",
        +  "title": "Blender",
        +  "type": "string"
        +}
      • addedInput schema / properties / engine
        Added value: +{
        +  "default": "",
        +  "title": "Engine",
        +  "type": "string"
        +}
      • addedInput schema / properties / environment
        Added value: +{
        +  "default": "",
        +  "title": "Environment",
        +  "type": "string"
        +}
      • addedInput schema / properties / environment_strength
        Added value: +{
        +  "default": 1,
        +  "title": "Environment Strength",
        +  "type": "number"
        +}
      • addedInput schema / properties / environment_visible
        Added value: +{
        +  "default": true,
        +  "title": "Environment Visible",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / notify_url
        Added value: +{
        +  "default": "",
        +  "title": "Notify Url",
        +  "type": "string"
        +}
      • addedInput schema / properties / orbit
        Added value: +{
        +  "default": false,
        +  "title": "Orbit",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / orbit_distance
        Added value: +{
        +  "default": 1,
        +  "title": "Orbit Distance",
        +  "type": "number"
        +}
      • addedInput schema / properties / orbit_elevation
        Added value: +{
        +  "default": 18,
        +  "title": "Orbit Elevation",
        +  "type": "number"
        +}
      • addedInput schema / properties / orbit_frames
        Added value: +{
        +  "default": 24,
        +  "title": "Orbit Frames",
        +  "type": "integer"
        +}
      • addedInput schema / properties / orbit_target
        Added value: +{
        +  "default": "",
        +  "title": "Orbit Target",
        +  "type": "string"
        +}
      • addedInput schema / properties / transparent
        Added value: +{
        +  "default": false,
        +  "title": "Transparent",
        +  "type": "boolean"
        +}
    • Changedrender_preview12 fields changed
      • addedInput schema / properties / assets
        Added value: +{
        +  "anyOf": [
        +    {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "title": "Assets"
        +}
      • addedInput schema / properties / blender
        Added value: +{
        +  "default": "",
        +  "title": "Blender",
        +  "type": "string"
        +}
      • addedInput schema / properties / engine
        Added value: +{
        +  "default": "",
        +  "title": "Engine",
        +  "type": "string"
        +}
      • addedInput schema / properties / environment
        Added value: +{
        +  "default": "",
        +  "title": "Environment",
        +  "type": "string"
        +}
      • addedInput schema / properties / environment_strength
        Added value: +{
        +  "default": 1,
        +  "title": "Environment Strength",
        +  "type": "number"
        +}
      • addedInput schema / properties / environment_visible
        Added value: +{
        +  "default": true,
        +  "title": "Environment Visible",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / orbit
        Added value: +{
        +  "default": false,
        +  "title": "Orbit",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / orbit_distance
        Added value: +{
        +  "default": 1,
        +  "title": "Orbit Distance",
        +  "type": "number"
        +}
      • addedInput schema / properties / orbit_elevation
        Added value: +{
        +  "default": 18,
        +  "title": "Orbit Elevation",
        +  "type": "number"
        +}
      • addedInput schema / properties / orbit_frames
        Added value: +{
        +  "default": 24,
        +  "title": "Orbit Frames",
        +  "type": "integer"
        +}
      • addedInput schema / properties / orbit_target
        Added value: +{
        +  "default": "",
        +  "title": "Orbit Target",
        +  "type": "string"
        +}
      • addedInput schema / properties / transparent
        Added value: +{
        +  "default": false,
        +  "title": "Transparent",
        +  "type": "boolean"
        +}
    • Addedrender_share
    • Addedrender_unshare
    • Changedscene_info2 fields changed
      • addedInput schema / properties / assets
        Added value: +{
        +  "anyOf": [
        +    {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "title": "Assets"
        +}
      • addedInput schema / properties / blender
        Added value: +{
        +  "default": "",
        +  "title": "Blender",
        +  "type": "string"
        +}
  4. 9 tool updatesv0.2.1
    • First observedbilling
    • First observedrender_cancel
    • First observedrender_download
    • First observedrender_estimate
    • First observedrender_final
    • First observedrender_info
    • First observedrender_preview
    • First observedrender_status
    • First observedscene_info

TDQS

A4.2/5.0

Scored across 13 tools

Disambiguation4/5

Most tools map to clearly distinct stages of the cloud rendering workflow: estimate, preview, review, final render, status, download, cancel, share, info, billing, and asset search. The main ambiguity is between render_preview and render_review, which both return preview images and checks, and between render_status, render_info, and billing, which all report service or account state. Descriptions explicitly differentiate these, so an agent can tell them apart with care.

Naming Consistency4/5

Almost all tools use consistent snake_case, and most render operations share the predictable render_ prefix. The few deviations are scene_info, asset_search, and billing, which drop the verb prefix or use a different domain noun, but they remain readable and unsurprising. Overall the naming is coherent with minor inconsistencies.

Tool Count5/5

13 tools is well-scoped for a cloud Blender rendering service. The set covers the full workflow from scene inspection and estimation through preview, review, final render, download, cancel, sharing, and billing without obvious bloat. Each tool appears to earn its place.

Completeness5/5

The tool surface covers the rendering lifecycle comprehensively: scene_info, render_estimate, render_preview, render_review, render_final, render_status, render_download, render_cancel, render_share, render_unshare, render_info, billing, and asset_search. There are no obvious dead ends for the stated cloud rendering domain. Minor gaps like an explicit job-list tool are handled by render_status without job_id.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables remote control of Blender through MCP, allowing code execution, scene manipulation, rendering, and file transfer in a containerized environment.
    1
    -
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables MCP-compatible clients to control Blender for modeling, materials, animation, physics, rendering, scene inspection, documentation search, and asset/generation service integration. It exposes a stdio endpoint with many Blender operations for creating and editing 3D content.
    AGPL 3.0
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables AI assistants to drive a live Blender session over MCP by creating and transforming primitives, building and assigning materials, inspecting scenes and objects, capturing viewport screenshots, and executing arbitrary bpy Python. Commands are relayed over a local TCP bridge to a Blender add-on and executed on Blender's main thread, supporting multiple simultaneous AI clients.
    MIT