ModelRunner

<a href="https://modelrunner.ai">ModelRunner</a> is a hosted remote MCP (Model Context Protocol) server that lets AI assistants like Claude and Cursor run…

Community: Submitted by a user or imported; check the owner before granting accessOnlineNo sign-inGlobalFreeRead-only

What it can do

  • List Models: Lists publicly available models. Filter by category or input/output modality. Returns compact summaries — use `get_model` for full details.
  • Recommended Models: Returns the admin-curated shortlist of models for a category. The fastest way for an AI assistant to pick a good model.
  • Get Model: Returns a compact, readable description of a model: inputs, outputs, pricing, examples. For raw JSON Schema use `get_model_raw_schema`.

What data it sees

Do you need an account

No: the server works without sign-in

ModelRunner is a hosted remote MCP (Model Context Protocol) server that lets AI assistants like Claude and Cursor run 100+ AI models — text-to-image, image-to-image, text-to-video, image-to-video, video-to-video, music generation, speech-to-text, and image-to-3D, including Kling, HiDream, Hunyuan Image, Stable Audio, and Rodin. One connection exposes every model as a callable tool: search the catalog, inspect a model's input schema, run inference with run_model, and get results back as hosted URLs directly in the conversation.

Unlike single-vendor MCP servers, ModelRunner aggregates models from multiple providers behind one endpoint and one billing account — pay-per-use credits, no subscription. Authorization is OAuth 2.1: your assistant opens a browser window once; no API key is ever pasted into a config file. Beyond inference, the server can upload local files for use as model inputs and author reusable "wrappers" — simplified, purpose-built interfaces over base models.

Endpoint: https://mcp.modelrunner.run/mcp (Streamable HTTP; registry name ai.modelrunner/mcp) Setup and full tool reference: ModelRunner MCP setup guide · GitHub

Server tool list (23)

Raw names from tools/list. Only developers need these.

list_modelsLists publicly available models. Filter by category or input/output modality. Returns compact summaries — use `get_model` for full details.
recommended_modelsReturns the admin-curated shortlist of models for a category. The fastest way for an AI assistant to pick a good model.
get_modelReturns a compact, readable description of a model: inputs, outputs, pricing, examples. For raw JSON Schema use `get_model_raw_schema`.
get_model_raw_schemaReturns the raw OpenAPI-style JSON Schema for a model. Prefer `get_model` for most use cases.
list_wrappersLists publicly available wrappers (curated combinations of base models with prompt templates). Returns compact summaries — use `get_wrapper` for full details.
list_my_wrappersLists the wrappers YOU own — scoped to your authenticated identity, including private and draft wrappers (which `list_wrappers` does not show). Returns each wrapper's `id`, `endpoint`, `visibility`, and `status`; pass that `id` to `patch_wrapper` or `delete_wrapper`. Requires authentication.
recommended_wrappersReturns the admin-curated shortlist of wrappers for a category.
get_wrapperReturns a compact, readable description of a wrapper: inputs, outputs, base models, and effective pricing (with markup). This readable view truncates long enum lists ("…N more") and omits the prompt template and field mappings. To edit a wrapper, fetch ONLY the part(s) you need with the focused tools — `get_wrapper_raw_schema` (full input schema + untruncated enums), `get_wrapper_prompt_template` (the Handlebars template + templateContext), `get_wrapper_field_mappings` (per-base-model mappings + defaultBaseModel). These are deliberately split so you pull just one slice into context; for a large wrapper, fan each part out to its own sub-agent rather than loading the whole definition at once.
get_wrapper_raw_schemaReturns ONLY the raw OpenAPI-style input `schema` for a wrapper, with the FULL, untruncated enum value lists that `get_wrapper` abbreviates ("…N more"). This is the authoritative source for allowed field values — do not reconstruct enums from a client app. Pair with `get_wrapper_prompt_template` and `get_wrapper_field_mappings` (separate calls) only when you actually need those parts.
get_wrapper_prompt_templateReturns ONLY the wrapper's Handlebars `promptTemplate` and its `templateContext` ({ maps, constants }) — nothing else. Use this when you intend to read or edit the template. Note it can be large (up to ~50k chars), which is exactly why it is a separate tool: fetch it in its own context/sub-agent rather than alongside the schema and mappings.
get_wrapper_field_mappingsReturns ONLY the wrapper's base-model wiring: the `defaultBaseModel` endpoint and each base model's `fieldMappings` (collectFields/staticValues/presets/renames/omit). Shaped to match `patch_wrapper`/`create_wrapper` input (`baseModels: [{ baseModel, fieldMappings }]`, defaultBaseModel as an "ownerName/alias" endpoint) so you can edit and submit it back. Fetch separately from the schema/template so each part stays in its own context.
wrapper_authoring_guideReturns the full ModelRunner wrapper authoring guide: how to design the user-facing input schema, write the Handlebars prompt template + templateContext, choose base models, and derive per-base-model fieldMappings — with all constraints and worked examples. Read this BEFORE calling create_wrapper or patch_wrapper.
preview_wrapperDry-run a wrapper prompt template + field mappings against a sample input WITHOUT creating anything. Returns the transformed base-model input so you can validate template rendering, collectFields, presets, renames, and omit while authoring. Note: preview does not guarantee every produced key is accepted by the base model — create/update validation is stricter.
create_wrapperCreate a new wrapper you own (a curated base model + prompt template + user-facing input schema). It is created under YOUR account — `ownerName` is derived from your authenticated identity; do not pass it. Defaults to visibility=private, status=draft. BEFORE calling: (1) read `wrapper_authoring_guide`; (2) inspect each base model's app Input schema via `get_model` / `get_model_raw_schema` so your fieldMappings target valid keys; (3) dry-run with `preview_wrapper`. Constraints: `schema` is OpenAPI-style `{ components: { schemas: { Input: {...} } } }` and MUST NOT contain a `base_model` field. `promptTemplate` is Handlebars (helpers: lookup, eq, and, or, exists; no partials or raw blocks). Base models are referenced by their `ownerName/alias` endpoint (the same identifier you call a model with), not a UUID; `defaultBaseModel` must be one of `baseModels[].baseModel`. fieldMappings target each base model's APP schema and apply in order: collectFields → staticValues → presets → renames → omit. `alias` must be unique across your models and wrappers. Author a short "How to use" / orchestration passage INTO `description` — `get_wrapper` shows it to callers before they run. Especially when the wrapper is meant to produce a consistent SET across multiple runs, tell the caller to plan the set up front, generate the first item, then reuse that first output as the reference/anchor for the rest (not chain each run to its predecessor).
patch_wrapperUpdate one of your existing wrappers by id. Provide only the fields you want to change; you can only modify wrappers you own. `ownerName` cannot be changed. Before editing, read the wrapper's current source with the focused tools — `get_wrapper_raw_schema`, `get_wrapper_prompt_template`, `get_wrapper_field_mappings` — fetching only the part you intend to change (`get_wrapper` truncates enums and omits the template/mappings). For a large or multi-part edit, fan each part out to its own sub-agent so no single context holds the whole definition. The same authoring constraints as `create_wrapper` apply to any changed field (schema shape, Handlebars helpers, fieldMappings target the base model app schema, base models referenced by `ownerName/alias` endpoint, defaultBaseModel ∈ baseModels). Re-run `preview_wrapper` after changing the template or mappings.
delete_wrapperDelete one of your wrappers by id or "ownerName/alias" endpoint. You can only delete wrappers you own.
searchRelevance-ranked free-text search across the public catalog (models AND wrappers), designed for you to evaluate the results: - `score`: full-text rank, comparable across models and wrappers. - `matchedOn`: which fields matched (name/alias/tags/shortDescription/description/category/owner); 'fulltext' = only the stemmed query matched, no verbatim substring. - `pricing.averageCost`: average USD per run from curated examples. - `examplePrompts`: real prompts from example runs — proof of what the entry actually handles. - `collections`: published themed sets it belongs to. - `rootModel`: entries sharing it are variants (speed/price tiers) of one family — compare their pricing before picking. Recall-first (default 25 results) — YOU are the precision layer; filter and re-rank against the user's use case. Describe the use case in `q` with descriptive words ("remove background product photo"), not stopword sentences. Follow up with `get_model` / `get_wrapper` to see input schemas before running.
run_modelStarts an asynchronous inference request against the specified model or wrapper endpoint. Returns immediately with a requestId — poll with `get_request` or use `wait_for_request`.
get_requestReturns the current status, outputs (if completed), pricing snapshot, and error (if failed) for a request.
wait_for_requestPolls `get_request` server-side until the request reaches a terminal state or the timeout elapses. Returns the final status payload.
create_upload_urlPREFERRED way to turn a LOCAL file into a ModelRunner file-input URL. Returns two short-lived PUT URLs plus the final canonical `file_url`, so you stream the bytes straight to storage from your own environment — the bytes never pass through this MCP or your token output. Use this for any local file (especially images/audio/video over ~100 KB): (1) call this tool, (2) PUT the file with the returned headers using your shell, starting with `upload_url` (direct to storage) — e.g. `curl -X PUT -T <localPath> -H "Content-Type: <type>" "<upload_url>"`; if that PUT is blocked by a host/egress allowlist (HTTP 403 `host_not_allowed` / "not allowed host"), retry the SAME PUT to `relay_upload_url` (served on the ModelRunner API domain, which an allowlist is more likely to permit), (3) pass `file_url` as the model/wrapper input. ALWAYS prefer this over `upload_file` for local files — `upload_file` sends the bytes through the model as base64, which burns a large amount of tokens/compute and is unreliable above a few hundred KB. URLs are short-lived (PUT promptly). Requires a shell or other way to make an HTTP PUT; only if you have none, AND BOTH URLs are blocked by your network, fall back to `upload_file` (base64 — token-expensive, last resort).
upload_fileUploads a file to ModelRunner storage and returns the canonical `file_url` for a `run_model` / wrapper file input. ⚠️ LAST RESORT for local files — almost always use `create_upload_url` instead. To upload LOCAL-file bytes this tool takes `base64`, which means the file is written into the MODEL'S TOKENS: that is slow and burns a large amount of tokens/compute, and it gets worse the bigger the file (and far worse in chunked mode — every chunk's base64 is emitted into the conversation). `create_upload_url` streams the bytes out-of-band via a shell PUT (direct-to-storage OR its relay URL on the ModelRunner domain) so NO base64 ever touches the model. Only fall back to base64 here when `create_upload_url` is genuinely impossible — i.e. you have no shell to PUT with AND it is a fully egress-locked sandbox where the MCP channel is the only way out. Re-hosting a remote `url` (no base64) is always fine. BASE64 MODES (last resort only). (1) SINGLE-SHOT: pass the whole file as `base64`; ALWAYS pass `expectedDecodedBytes` = the file's size in bytes so a silently-truncated base64 becomes a loud error instead of a corrupt upload. (2) CHUNKED (only when the file is too large to fit one base64 string in that locked sandbox — expensive, avoid otherwise): split into small base64 chunks (~32-48 KB each), one tool call per chunk; omit `uploadId` on the FIRST chunk (the response returns one), pass it back on every later chunk with an incrementing `partIndex`, set `isLastPart:true` on the final chunk. Each chunk carries its own `expectedDecodedBytes` and is validated on arrival — a truncated chunk errors alone and you resend just it (same `partIndex`). The response contains `file_url` once the last chunk assembles. Then pass `file_url` as the model/wrapper input.
list_my_requestsReturns the authenticated user's past requests, newest first. Filters by status, model endpoint, and date range.