unsloth/studio/MCP.md
Etherl 4a1037e9a9
Some checks are pending
CodeQL / Languages to analyse (push) Waiting to run
CodeQL / Analyze () (push) Blocked by required conditions
CodeQL / Prune superseded CodeQL overlay bases (push) Blocked by required conditions
Core / Resolve the unsloth_zoo revision (push) Waiting to run
Core / Core (HF=default + TRL=default) (push) Blocked by required conditions
Core / Core (HF=4.57.6 + TRL<1) (push) Blocked by required conditions
Core / Core (HF=latest + TRL=latest) (push) Blocked by required conditions
Core / Core zoo (HF=default + TRL=default) (push) Blocked by required conditions
Core / Core zoo (HF=4.57.6 + TRL<1) (push) Blocked by required conditions
Core / Core zoo (HF=latest + TRL=latest) (push) Blocked by required conditions
Core / llama.cpp build + smoke (push) Waiting to run
Cross-platform parity / parity (ubuntu-latest) (push) Waiting to run
Cross-platform parity / parity (windows-latest) (push) Waiting to run
Interrupted install recovery / select legs (push) Waiting to run
Interrupted install recovery / kill@ (push) Blocked by required conditions
Interrupted install recovery / windows kill@ (push) Blocked by required conditions
Kaggle T4 Unsloth GPU CI / gate (push) Waiting to run
Kaggle T4 Unsloth GPU CI / Unsloth GPU smoke (push) Blocked by required conditions
Lint CI / Source lint (Python + shell + YAML + JSON + safety nets) (push) Waiting to run
Local Agent Guides CI / connection (claude, stable) (push) Waiting to run
Local Agent Guides CI / connection (codex, stable) (push) Waiting to run
Local Agent Guides CI / connection (dsh, stable) (push) Waiting to run
Local Agent Guides CI / connection (hermes, stable) (push) Waiting to run
Local Agent Guides CI / connection (openclaw, stable) (push) Waiting to run
Local Agent Guides CI / connection (opencode, stable) (push) Waiting to run
Local Agent Guides CI / connection (opencode, v2) (push) Waiting to run
Local Agent Guides CI / connection (pi, stable) (push) Waiting to run
Local Agent Guides CI / connection (vibe, stable) (push) Waiting to run
Local Agent Guides CI / file-edit (claude) (push) Waiting to run
Local Agent Guides CI / file-edit (codex) (push) Waiting to run
Local Agent Guides CI / file-edit (dsh) (push) Waiting to run
Local Agent Guides CI / file-edit (hermes) (push) Waiting to run
Local Agent Guides CI / file-edit (openclaw) (push) Waiting to run
Local Agent Guides CI / file-edit (opencode) (push) Waiting to run
Local Agent Guides CI / file-edit (pi) (push) Waiting to run
Local Agent Guides CI / file-edit (vibe) (push) Waiting to run
Local Agent Guides CI / resume (claude) (push) Waiting to run
Local Agent Guides CI / resume (codex) (push) Waiting to run
Local Agent Guides CI / resume (opencode) (push) Waiting to run
Local Agent Guides CI / resume (pi) (push) Waiting to run
Local Agent Guides CI / prompt-cache (gemma-3-270m) (push) Waiting to run
Security audit / advisory audit (pip + npm + cargo) (push) Waiting to run
Security audit / pip scan-packages :: audio-torch280 (push) Waiting to run
Security audit / pip scan-packages :: audio-torch290 (push) Waiting to run
Security audit / pip scan-packages :: extras (push) Waiting to run
Security audit / pip scan-packages :: studio (push) Waiting to run
Security audit / pip scan-packages :: hf-stack (push) Waiting to run
Security audit / npm scan-packages (Unsloth frontend tarballs) (push) Waiting to run
Security audit / npm provenance + new install-script diff (push) Waiting to run
Unsloth API CI / Unsloth API & Auth Tests (push) Waiting to run
Backend CI / (Python 3.11, floor) (push) Waiting to run
Backend CI / (Python 3.13, a-k) (push) Waiting to run
Backend CI / (Python 3.13, l-r) (push) Waiting to run
Backend CI / (Python 3.13, rest) (push) Waiting to run
Backend CI / Repo tests (CPU, rest) (push) Waiting to run
Backend CI / Repo tests (CPU, studio) (push) Waiting to run
Backend CI / Repo tests (CPU, studio-install) (push) Waiting to run
Backend CI / Shell installer tests (push) Waiting to run
Frontend CI / Frontend build + bundle sanity (push) Waiting to run
Frontend CI / Frontend unit tests (Windows) (push) Waiting to run
Unsloth GGUF CI / GGUF inference smoke (API, tools, vision) (push) Waiting to run
Mac Unsloth UI + API + Update + Inference CI / Chat UI, API, Update and GGUF inference (push) Waiting to run
Unsloth Tauri CI / Tauri Linux debug build (no codesign) (push) Waiting to run
Unsloth Tauri CI / Rust unit tests (windows) (push) Waiting to run
Unsloth Tauri CI / Rust unit tests (macos) (push) Waiting to run
Unsloth UI CI / Chat UI Tests (extra) (push) Waiting to run
Unsloth UI CI / Chat UI Tests (chat) (push) Waiting to run
Unsloth UI CI / Loaded-models indicator (cross-browser) (push) Waiting to run
Unsloth Update CI / Unsloth Updating Tests (push) Waiting to run
Unsloth Update CI / Unsloth Updating Tests (macOS) (push) Waiting to run
Unsloth Update CI / Unsloth Updating Tests (Windows) (push) Waiting to run
Studio VAE seam guard / seam-guard (push) Waiting to run
Windows Unsloth API CI / Unsloth API & Auth Tests (push) Waiting to run
Windows Unsloth GGUF CI / GGUF inference smoke (API, tools, vision) (push) Waiting to run
Windows Unsloth GGUF CI / Unsloth install + inference without Visual Studio (push) Waiting to run
Windows Unsloth GGUF CI / real-VS detection (VS 2022) (push) Waiting to run
Windows Unsloth GGUF CI / real-VS detection + VC++ round-trip (VS 2026) (push) Waiting to run
Windows Unsloth GGUF CI / setup.ps1 units, no-VS resolve, VC++ round-trip (windows-latest) (push) Waiting to run
Windows Unsloth UI CI / Chat UI Tests (push) Waiting to run
Windows Unsloth Update CI / Unsloth Updating Tests (push) Waiting to run
studiobench CI / Selftests, lint and the single-file build (push) Waiting to run
studiobench CI / Real-path session, every action ran (push) Waiting to run
Wheel CI / Wheel build + content sanity + import smoke (push) Waiting to run
Windows Application Control CI / installer survives a denied unsloth.exe (push) Waiting to run
Windows No Compiler CI / the installer spawns no C# compiler (push) Waiting to run
Workflow trigger lint / workflow-trigger lint (pull_request_target / cache-poisoning) (push) Waiting to run
Workflow trigger lint / security suites (torch-dependent) (push) Waiting to run
Studio: image and video generation follow each model's defaults and prompting tips, and /v1/videos takes Unsloth Studio controls (#14078)
## Summary

`/api/inference/images/generate` used fixed defaults of 9 steps and
guidance 0 when a caller left them out. Those values only suit turbo
models. Omitted `steps` and `guidance` now come from the loaded model:
the diffusers `generation_defaults` when the status reports them, else
the family table (sd.cpp and MLX). `/v1/videos` also accepts the Unsloth
Studio generation controls that `/video/generate` already had, and the
MCP `generate_image` and `generate_video` tools expose the new options.

## Changes

Images:

- The image route reads the defaults again on each retry attempt, so a
model replacement between attempts brings its own values, and it pins
the load it read them from. `/v1/images` now uses the same
`_image_generation_defaults` helper.
- A request that leaves out `steps` or `guidance` while another client's
image load is still running is pinned to "nothing loaded". The engine
then refuses the new model on its first try, and the retry reads that
model's defaults instead of running it with 9 steps and guidance 0.
- MCP `generate_image` refuses requests the engine cannot run before
uploading anything: `reference`, `edit` or `outpaint` without
`init_image`, `outpaint` without `mask_image`, and `upscale <= 1`. It
also takes `seeds` and `prompts` lists (up to 32) for a batch in one
call.
- `studio_status` image now reports `workflows`, `generation_defaults`,
`dimension_multiple`, `max_condition_images` and `prompt_hint`.

Prompt hints:

- Image and video families have an optional `prompt_hint`, returned in
the status of every engine (diffusers, sd.cpp, MLX, video). FLUX.1
Kontext, Qwen-Image-Edit, Qwen-Image 2.1 and Ideogram 4 have one. No
video family sets one yet.
- The Images and Video pages show the hint as the Prompt field's info
hint. It is hidden for external image providers.
- New bundled `image-prompting` skill, off by default. It tells the
model how to expand a short request into a detailed prompt, and to leave
steps and guidance unset so the model's defaults apply.

Videos:

- `/v1/videos` accepts `seed`, `negative_prompt`, `steps`, `guidance`,
`num_frames`, `fps`, `last_frame`, `reference_images` (up to 9) and
`reference_audios` (up to 3, as data URLs, uploads or Unsloth Studio
audio ids `{"input_id" | "clip_id" | "voice_id"}`). These work in both
JSON and multipart bodies.
- The new fields are validated before any model switch, including the
family checks, image decoding and audio id resolution. Sending both
`seconds` and `num_frames` returns 400. So do `last_frame` with
references, `input_reference` with `reference_images`, and reference
audio with no reference image.
- MiniMax-H3 always writes its clip at 24 fps, so `/v1/videos` refuses
another `fps` for it (400, `param: fps`) rather than computing the frame
count and the reported length from a rate the file never plays at. The
check runs before a switch, on the resident model, and on the pinned
snapshot that auto-switch and managed accounts use.
- `last_frame` and each `reference_images` entry take the same 32 MB
image `input_reference` takes. Before, their base64 cap stopped images
at about 24 MB. Each reference audio takes a full 24 MB clip as a data
URL. A stored reference audio is sized before it is read. Multipart
reference lists keep the order they were sent in, across the
`reference_images` and `reference_images[]` spellings, and are counted
before any file is encoded. Before an automatic switch, each reference
audio is decoded the way the engine would, so an unreadable clip is a
400 instead of a failure after the new model loads.
- One request body carries about 32 MB of inline images and audio in
all; the field descriptions say so and point larger or several audio
clips at Unsloth Studio audio ids.
- When no seed is sent, the route draws one before the retry loop,
stores it on the job and returns it in the job response. A plain
OpenAI-shaped request behaves as before, except that the response now
includes `seed`.
- MCP `generate_video` exposes the same controls, accepts `seconds` as a
number or a string, accepts fractional `seconds`, refuses images over
the 32 MB one `/v1/videos` request carries, audio over 24 MB, and field
combinations the route refuses (before it uploads any audio), and
returns the seed on the job and from `get_job`. `studio_status` video
now reports `prompt_hint`, `supports_last_frame`, `references` and
`size_presets`.

`studio/MCP.md` lists the new tool options.

## Testing

New tests: `test_image_generate_model_defaults.py`,
`test_openai_videos_controls.py`, `test_mcp_tools_video_controls.py`,
`test_mcp_status_media_slots.py`, `test_diffusion_prompt_hint.py` and
`studio/frontend/tests/images-prompt-hint.test.ts`. Updated in place:
`test_mcp_tools_images.py`, `test_mcp_tools_status.py`,
`test_mcp_tools_video.py`, `test_skills.py` and
`test_video_families.py`.

- The new and updated backend tests pass. They cover:
  - each MCP refusal, checked before any route call;
- the image fill on diffusers, sd.cpp and MLX shapes, including the
model-replaced retry;
- a plain OpenAI `/v1/videos` request, which still sends
`begin_generate` exactly its old arguments plus `seed`;
  - the seed surviving a restart, with old records loading `seed: null`;
  - audio ids resolving in the caller's account.
- Review follow-ups (`bef45ec6b9` to `b1d07abd7c`) each come with tests
that fail on the earlier head: the H3 fps refusal (before a switch,
resident and pinned), multipart order and count, the audio size checks,
the 32 MB image and 24 MB audio caps, the MCP image budget, body cap and
pre-upload checks, fractional MCP seconds, the pre-switch audio decode
and the in-flight load retry. Affected suites at the final head (image
and video routes, `/v1/videos`, `/v1/images`, account pinning, MCP tools
and server, skills, families, prompt hints): 825 passed, 1 failed. That
one,
`test_video_download_plan_judges_a_quantized_reference_pick_per_partition`,
fails the same way on `main` here (no PyAV).
- Each fix was checked to be load-bearing. With the image fill disabled,
4 route tests fail. With the per-attempt reset removed, the
replacement-race test fails. With the video seed record line and None
filter removed, 5 tests fail.
- Affected backend suites (images, video, MCP, account media, skills,
sd.cpp, MLX, family freeze): 2,498 passed, 15 failed. 14 of the failures
fail the same way on `main` in this environment (no PyAV, and a
huggingface-hub version mismatch). The 15th,
`test_begin_load_answers_without_waiting_on_the_header_probe`, is a
timing test that passed 3 of 3 runs on its own.
- `UNSLOTH_FREEZE_UPDATE=1` regeneration of the diffusion family freeze
leaves the fixture unchanged. It records accessor outputs, not family
rows.
- Frontend: `npm run typecheck`, and 230 image and video node tests
pass.
- `ruff check` (0.16.10) is clean, and the repo formatter (ruff 0.6.9)
is a no-op on the changed files.

The UI before/after screenshots and the GPU harness runs (hero portrait
plus same-character shots with no HTTP 400s; two same-seed video takes)
follow in a comment.




<!-- ui-evidence:start -->
### UI before / after

With FLUX.1 Kontext loaded, the Images page Instruction field gains an
info icon whose tooltip reads 'Write the change you want as an
instruction, such as "make the sky orange", not a description of the
whole picture.' Before this PR the field has no icon. BEFORE is the
merge base, AFTER is this PR, two separate installs, each loading the
same tiny FLUX.1 Kontext pipeline through the real load route.

![Instruction field hint before and
after](https://raw.githubusercontent.com/danielhanchen/unsloth-staging-2/pr-media/pr/14078/pr14078_before_after_q-f850949abd71.png)
<!-- ui-evidence:end -->

---------

Co-authored-by: Daniel Han <23090290+danielhanchen@users.noreply.github.com>
2026-10-18 17:35:09 -07:00

15 KiB

MCP in Unsloth Studio

Connect Blender MCP

Blender MCP is disabled by default. Unsloth Studio downloads a pinned, checksum-verified runtime on first enable/test and caches it on the backend machine. No commands, Git or pip installs are needed. Subsequent starts use the cache without internet. The Blender add-on is installed separately. No MCP archive or source is shipped in Unsloth Studio's Python package or desktop build.

  1. Open Manage MCP servers → Blender, approve the execution warning and choose Enable Blender MCP. Use a tool-capable model with MCP enabled for the chat.
  2. Open Setup help → Download Blender add-on for Blender's official page.
  3. In Blender 5.1+, enable Preferences → System → Network → Allow Online Access. Drag the website's install button into Blender twice: first to add the Blender Lab repository, then to install MCP. Alternatively, search MCP in Get Extensions after adding the repository.
  4. Enable and start the add-on bridge, keep Blender open, then Test connection.

A green dot means Blender is connected; amber means only the MCP server is connected. Setup help stays in the same Blender entry. Advanced settings configure the bridge port (default 9876) and optional Blender executable. This port is not an HTTP URL.

The bridge uses loopback on the Unsloth Studio backend machine, not a remote browser. Unsloth Studio does not install or launch Blender during setup. Approved tools can run Python, write files and launch background Blender. Existing tool permissions apply; external model providers receive tool results. Keep the unauthenticated bridge local.

The downloaded runtime excludes the large API/manual reference corpus and its three offline documentation tools. The official source is https://projects.blender.org/lab/blender_mcp (GPL-3.0-or-later). The pinned revision and SHA-256 are in backend/integrations/blender/runtime.py. Downloads are staged and verified before activation; failures leave the server disabled and can be retried with Enable Blender MCP. Merely opening the dialog or launching Unsloth Studio does not download anything.

Large tool catalogs

A server can expose dozens of tools with long descriptions and deeply nested parameter schemas: Notion's catalog alone is about 65,000 tokens. Every tool is listed in full while the catalog takes at most a tenth of the loaded local model's context window. External providers always get the full listing.

Past that, Studio searches tools the way Claude Code and Codex do. The model gets mcp_tool_search, whose description names every tool with a one-line summary, instead of the schemas. A search ranks the catalog with the SQLite FTS5 BM25 index and rank fusion the knowledge base uses (tool names and descriptions searched separately) and loads the best matches, exact names always; the model then calls them with their full schemas. A tool the model calls by name loads the same way.

Up front, the listing also carries a tool a tool_choice forces, the tools mapped to take an attached image, and, within a third of the window, the tools the chat ran on earlier turns (so the prompt prefix the model server caches holds) and up to five tools ranked against the user's message. Tools a turn loads stay within half of the window, the oldest leaving first; a tool too large for that is refused with a message naming it.

Unsloth Decisions MCP

When the Decision API is on (Settings → API), the chat's MCP menu lists Unsloth Decisions. Enable it and a tool-capable chat model can call decide, which asks the local Laya model the same typed questions POST /v1/systemone answers (noul, choice and score), with the model chosen in Settings.

Other MCP clients reach the same tool at http://127.0.0.1:8888/mcp/decisions/ (use the actual Unsloth port). It takes the credentials /v1/systemone takes, so send an Unsloth API key as Authorization: Bearer sk-unsloth-....

Unsloth Studio's own MCP server

Unsloth Studio has its own MCP server at /mcp/. Coding agents such as Claude Code and Codex can use it to load models, chat, generate images, audio and video, transcribe, train and export. Every tool goes through Unsloth Studio's own routes as your API key, so it sees what that key may see and nothing more.

Turn it on

The server is off by default. While it is off, /mcp/ answers 404. Start Unsloth Studio with UNSLOTH_STUDIO_ENABLE_MCP=1 to turn it on.

The endpoint is http://127.0.0.1:8888/mcp/ on the default port. Always use the trailing slash. Use your own address and port when they differ, for example the LAN address or the Cloudflare tunnel URL.

Authentication

Every request needs an Unsloth Studio API key: Authorization: Bearer sk-unsloth-…. Create one in Settings → API. Unsloth Studio refuses everything else with 401:

  • no key, an empty key, or a placeholder key such as not-needed, even when keyless API access is on;
  • a signed-in session token;
  • a revoked or expired key;
  • the keys Unsloth Studio mints for its own recipe and Deep Research workflows.

A managed account's key works too. Its tools act for that account only.

Unsloth Studio does not offer OAuth. The OAuth discovery paths answer 404, so clients that probe them fall back to the key.

A browser page from another site gets 403 Origin not allowed for Unsloth Studio MCP. This also blocks browser-based MCP inspectors. Command-line agents send no Origin and are not affected.

Breaking changes

The static UNSLOTH_STUDIO_MCP_TOKEN is retired. A request that sends it gets 401 with this detail:

The MCP static token is no longer supported; use an Unsloth Studio API key (sk-unsloth-…)

If the variable is still set, Unsloth Studio logs one warning at startup. Unsloth Studio no longer refuses to start when the token is missing.

The tools changed:

Old tool New tool
list_local_models list_models
get_training_status studio_status
stop_training cancel with kind="training"
validate_recipe run_recipe with mode="validate"
get_recipe_job_status, get_recipe_job_dataset get_job with kind="recipe"
load_checkpoint and export_gguf export_model

studio_status and start_training keep their names, but now run as your key.

Set up an agent

One command

unsloth mcp add writes the agent's MCP entry for you. It supports claude-code, codex, cursor and generic:

unsloth mcp add claude-code
unsloth mcp add codex --url http://192.168.1.20:8888
unsloth mcp add cursor --dry-run
  • The entry names the UNSLOTH_API_KEY environment variable, never the key itself, and the command never prints a key. Pick another variable with --env-var.
  • It finds a running Unsloth Studio on this computer, or takes --url.
  • --dry-run prints the entry it would write and writes nothing. Running it again changes nothing.
  • A config file it creates is readable by you only (mode 0600).
  • codex also sets tool_timeout_sec = 300.
  • generic prints a JSON entry to paste into any other agent's config.

Then check the connection:

unsloth doctor --mcp

It checks that Unsloth Studio answers, that your key works, and that the MCP server is on. It also warns when an agent's tool timeout is under 240 s, because long tools such as load_model can wait that long.

By hand

Each one reads the key from the UNSLOTH_API_KEY environment variable, so set it before you start the agent. Replace http://127.0.0.1:8888 with your own address.

Claude Code (macOS or Linux):

claude mcp add --transport http --scope user unsloth-studio http://127.0.0.1:8888/mcp/ --header 'Authorization: Bearer ${UNSLOTH_API_KEY}'

Claude Code (Windows PowerShell):

claude mcp add --transport http --scope user unsloth-studio http://127.0.0.1:8888/mcp/ --header 'Authorization: Bearer ${UNSLOTH_API_KEY}'

OpenAI Codex:

codex mcp add unsloth-studio --url http://127.0.0.1:8888/mcp/ --bearer-token-env-var UNSLOTH_API_KEY
# Optional, for long jobs, in ~/.codex/config.toml under [mcp_servers.unsloth-studio]:
# tool_timeout_sec = 300

OpenCode, in ~/.config/opencode/opencode.json:

{
  "mcp": {
    "unsloth-studio": {
      "type": "remote",
      "url": "http://127.0.0.1:8888/mcp/",
      "oauth": false,
      "headers": {
        "Authorization": "Bearer {env:UNSLOTH_API_KEY}"
      }
    }
  }
}

Hermes Agent, in ~/.hermes/config.yaml, then run /reload-mcp in Hermes:

mcp_servers:
  unsloth_studio:
    url: "http://127.0.0.1:8888/mcp/"
    headers:
      Authorization: "Bearer ${UNSLOTH_API_KEY}"

OpenClaw, in ~/.openclaw/openclaw.json:

{
  "mcp": {
    "servers": {
      "unsloth-studio": {
        "url": "http://127.0.0.1:8888/mcp/",
        "transport": "streamable-http",
        "headers": {
          "Authorization": "Bearer ${UNSLOTH_API_KEY}"
        }
      }
    }
  }
}

Mistral Vibe, in ~/.vibe/config.toml:

[[mcp_servers]]
name = "unsloth_studio"
transport = "streamable-http"
url = "http://127.0.0.1:8888/mcp/"

[mcp_servers.auth]
type = "static"
api_key_env = "UNSLOTH_API_KEY"
api_key_header = "Authorization"
api_key_format = "Bearer {token}"

DeepSeek Harness, appended to ~/.dsh/cordis.patch.yml:

- insert:
    - id: mcp-unsloth-studio
      name: '@deepseek-ai/dsh-mcp-client'
      config:
        serverName: unsloth-studio
        transport: streamable-http
        url: "http://127.0.0.1:8888/mcp/"
        headers:
          Authorization: !!js '`Bearer ${process.env.UNSLOTH_API_KEY}`'

Tools

Tool What it does
studio_status What is loaded, loading and running: chat, image, video, speech-to-text and embedding models, training, export and GPUs.
list_models Models Unsloth Studio can serve, by kind or by Audio page workflow. With model, its training defaults. With source="catalog", the image, video and audio models it can download, with their size and whether they fit on the GPU now.
load_model Load a chat, image, video or speech-to-text model, downloading it first if needed. Reports progress.
unload_model Unload a model.
chat Ask the loaded model, with optional images. Returns a cancel_id.
embed Embed up to 2048 texts.
system_one Ask the Decision API typed questions. The Decision API must be on.
generate_image Text to image, image to image, inpaint, edit, reference, outpaint and upscale, one image or a batch of seeds or prompts. Left out, steps and guidance follow the loaded model.
generate_audio Clone, speak, edit, convert, music and separate, on the loaded model or a named model.
transcribe Speech to text, or translation to English.
generate_video Start a video, with a seed, frame count, last frame and image or audio references. One renders at a time. Poll it with get_job.
get_job The state of a video, recipe or export job.
run_recipe Validate, preview or run a Data Recipe.
datasets List, check, download and follow training datasets.
start_training Start LLM or image LoRA training. Follow it with studio_status.
list_training_runs Past runs and their checkpoints, by name.
export_model Export a checkpoint to GGUF, merged weights, a LoRA adapter or the base model.
cancel Stop training, a start request, image training, an export, a recipe, an image or video generation, a chat reply or a dataset download.

Long work returns at once. Start it, then poll get_job or studio_status, and stop it with cancel. Audio runs cannot be cancelled. Unsloth Studio runs one export at a time, so export_model is refused while another export runs, and cancelling an export job stops only that job's own step.

Media and files

Generated images, audio and videos are saved to Unsloth Studio's galleries, the same as in the UI. Tools return each item's id and URL. Small items also come back inline. Large images come back as a preview plus a link. A video comes back as a thumbnail plus a link, and the MP4 is never sent inline. Links point at Unsloth Studio's API, so fetch them with the same Authorization: Bearer key.

Media inputs can be an Unsloth Studio id, inline data, or a file path. A file path works only when the agent runs on the Unsloth Studio computer and connects over loopback. From any other computer, send the data or an Unsloth Studio id instead. An MCP request is limited to 4 MiB, so inline data has to fit in that. Send larger media as an Unsloth Studio id, or as a path from the Unsloth Studio computer. A remote agent can upload a large audio file, up to 200 MiB, to POST /v1/audio/inputs with its API key and pass the returned id as input_id. The route takes the file's raw bytes as the request body with a Content-Length, not a multipart form or JSON, and an optional name query parameter:

curl -X POST "http://127.0.0.1:8888/v1/audio/inputs?name=meeting.mp3" \
  -H "Authorization: Bearer $UNSLOTH_API_KEY" \
  --data-binary @meeting.mp3

transcribe sends files up to 25 MB directly. Larger files, and audio given by id, are uploaded to Unsloth Studio first, and their transcript is saved to Audio history. Translation needs a file under 25 MB. Transcribing from a URL or a YouTube link is not supported. timestamps needs a speech-to-text model that times segments, such as Qwen3-ASR (audio.cpp) or Parakeet-TDT; other models refuse it, and translation never has timestamps.

studio_status lists the loaded audio model's audio_options, such as its built-in voices. Pass them to generate_audio in options. A voice or other listed value is matched without regard to case, and a value the model does not list is refused.

Tool results never contain paths on the Unsloth Studio computer. Checkpoints are named <run folder> or <run folder>/checkpoint-N. Exports are named relative to Unsloth Studio's exports folder, and export_model takes only a relative save_directory.

Prompts

The server also offers two prompts, which Claude Code shows as slash commands: make_short_film and build_dataset_and_train. Each one reads what is loaded and which catalog models fit on the GPU right now, then lays out the tool calls for the job.

Known limits

  • An API key cannot unload a chat model that was loaded from a local folder. Unsloth Studio shows such a model to API keys under an opaque reference, and the unload route does not resolve it. Unload it in the Unsloth Studio UI.
  • Unsloth Studio runs one Data Recipe job at a time, and a recipe job id is not tied to an account. Anyone with a key who knows the id can read that job's status.
  • Image LoRA training takes a dataset that is already in Unsloth Studio. There is no upload tool.
  • Models can be unloaded between calls when an idle timeout is set. Tools then say to load the model again.