Skip to main content
Glama
ultralytics-mcp
by amanharshx

Ultralytics Platform MCP

npm version CI License: MIT

MCP server for Ultralytics Platform workflows: projects, datasets, models, training, prediction, exports, and dataset uploads.

IMPORTANT

Independent community project. Not affiliated with or endorsed by Ultralytics.

Install · Tools · Safety · Troubleshooting

Try Asking

  • "Show me my Ultralytics projects and which datasets are ready to train on."

  • "Create a private project called traffic-cams and upload ./clips/junction.mp4 as a dataset."

  • "Fine-tune yolo11n on traffic-cams for 50 epochs."

  • "How is that training going? Show me the last 10 epochs of metrics."

  • "Run the trained model on https://example.com/frame.jpg, then download the weights to ./weights."

  • "Move my scratch project to trash." (restorable for 30 days)

https://github.com/user-attachments/assets/449d051b-d162-4539-93c5-94be478303f0

Related MCP server: Coreshub MCP Server

Installation

You need:

  • Node.js >=20

  • An Ultralytics Platform API key

  • ffmpeg and ffprobe on PATH, to upload a dataset from a local video file

  • Claude Code, Codex, or another MCP client that can launch stdio servers

Get an API key

Sign in at Ultralytics Platform, open Settings -> API Keys, and create or copy a key. The official API key docs cover creation, usage, and revocation.

Environment variables

Variable

Required

Description

ULTRALYTICS_API_KEY

✅

Ultralytics API key. Expected format: ul_ followed by 40 hex characters

ULTRALYTICS_API_BASE

❌

Advanced: override API base URL. Default: https://platform.ultralytics.com/api

Treat ULTRALYTICS_API_KEY as a bearer token. Pass it through your MCP client's environment configuration only. Never paste real keys into prompts, scripts, or committed config files. Project-scoped .mcp.json files are ignored by this repo to reduce accidental key commits; if a key is exposed, revoke it in Ultralytics Platform and create a replacement.

Standard config

Works in MCP clients that accept JSON stdio server definitions.

{
  "mcpServers": {
    "ultralytics": {
      "command": "npx",
      "args": ["-y", "ultralytics-mcp@latest"],
      "env": {
        "ULTRALYTICS_API_KEY": "ul_your_api_key_here"
      }
    }
  }
}

These examples track the latest published npm release. Restart your MCP client or session after upgrading, so the new server process picks up the latest package.

Add the standard config above through Antigravity settings, or by editing your configuration file directly.

claude mcp add ultralytics --env ULTRALYTICS_API_KEY=ul_your_api_key_here -- npx -y ultralytics-mcp@latest

Or add a project-scoped server in repo-root .mcp.json:

{
  "mcpServers": {
    "ultralytics": {
      "command": "npx",
      "args": ["-y", "ultralytics-mcp@latest"],
      "env": {
        "ULTRALYTICS_API_KEY": "ul_your_api_key_here"
      }
    }
  }
}

Follow the MCP install guide with the standard config above.

codex mcp add ultralytics --env ULTRALYTICS_API_KEY=ul_your_api_key_here -- npx -y ultralytics-mcp@latest

Or add it directly to ~/.codex/config.toml:

[mcp_servers.ultralytics]
command = "npx"
args = ["-y", "ultralytics-mcp@latest"]

[mcp_servers.ultralytics.env]
ULTRALYTICS_API_KEY = "ul_your_api_key_here"

Important The install button writes a placeholder key. After installing, open your Cursor MCP config and replace ul_your_api_key_here with your Ultralytics API key, then restart Cursor.

To install manually, go to Cursor Settings -> MCP -> Add new MCP Server (or edit ~/.cursor/mcp.json) and use the standard config above.

Follow the MCP install guide with the standard config above.

Important The install button writes a placeholder key. After installing, open your VS Code MCP config and replace ul_your_api_key_here with your Ultralytics API key, then restart VS Code.

To install manually, follow the MCP install guide, or use the VS Code CLI:

code --add-mcp '{"name":"ultralytics","command":"npx","args":["-y","ultralytics-mcp@latest"],"env":{"ULTRALYTICS_API_KEY":"ul_your_api_key_here"}}'

Verify

Run claude mcp list or codex mcp list. You should see ultralytics among the configured MCP servers.

Tools

See TOOLS.md for the full parameter reference, safety notes, local-path behavior, and examples for the tricky tools.

Safety

  • Projects and datasets are created private by default, even though the platform itself defaults to public

  • export_create requires confirm_cost: true

  • training_start requires confirm_cost: true, plus confirm_history_loss: true when restarting training on an existing model that already has a recorded run. That path replaces its status, epoch count, and training result history irrecoverably

  • Starting a training job or an export is billable immediately, so the estimated cost and remaining balance are reported after the job starts, not before

  • training_start in checkpoint mode (a base checkpoint like yolo11n.pt, not an existing model ref) creates the project model before the platform checks the checkpoint's task against the dataset's

  • If that check fails, the model it already created is not deleted automatically. The error names the model; review it and delete it with models_delete if it is unwanted

  • Cancelling a running training job preserves the latest checkpoint and keeps the model

  • export_cancel proceeds only when it observes an export as queued, starting, or running, and refuses every other status, including unrecognized ones. Because the status check and the cancel request are not atomic, an export that finishes between them may have its artifact irreversibly deleted

  • Deleting a project or dataset is a soft delete to trash, restorable for 30 days. Deleting a project reports the cascade count; deleting a dataset moves its images and annotations with it and leaves models trained on it unaffected

  • Ambiguous project or dataset refs fail instead of guessing

  • Undeclared tool arguments fail instead of being silently ignored

  • Signed upload and download URLs do not forward Authorization

  • Local upload tools, model_predict with file_path, and deployment_predict read files from the MCP client host; approve calls only for paths you expect to share with Ultralytics

  • model_download writes to the requested local path; review output_path and overwrite before approving

  • Adding a named YOLO ZIP (with data.yaml class names) to an existing dataset imports its labels and merges classes

  • Re-ingest does not re-label images already in the dataset (use the annotation editor); re-uploading the same image under a different split can create a duplicate

Troubleshooting

Invalid API key

ULTRALYTICS_API_KEY must start with ul_ and contain exactly 40 hex characters after the prefix.

Server not loading

Run claude mcp list or codex mcp list, then verify that npx and Node.js are installed and that ULTRALYTICS_API_KEY reached the client — passed with --env when adding the server, or set in ~/.codex/config.toml. In Claude Code, claude mcp get ultralytics shows the resolved config.

To smoke-test the server on its own:

ULTRALYTICS_API_KEY=ul_your_api_key_here npx -y ultralytics-mcp@latest

If the command exits immediately with a config error, fix the environment first.

Platform API errors

For authentication, rate-limit, or endpoint behavior, compare against the official Ultralytics Platform REST API docs. When asking for help, include the tool name, request summary, response status, redacted response body, and a minimal reproduction. Do not include real API keys, signed URLs, private dataset contents, or private model artifacts.

Contributing

See CONTRIBUTING.md for setup, the check suite, and the live smoke test.

Available Tools

44 tools
auto_annotate_startA

Start an auto-annotation run on a dataset by slug, owner/slug, or a ul://owner/datasets/slug URI, labelling it with a model given by owner/project/model, ul://owner/project/model, or slug with a project (state-changing, billable, may cost credits). Requires confirm_cost=true: there is no cost preview, no published rate, and a 402 signals insufficient credits; gauge magnitude with datasets_get (the unlabeled image count by default, the total count when include_annotated is true). Sends only modelId plus any of confidence, iou, class_mapping, and include_annotated the caller sets explicitly, omitting the rest so the server's own defaults (confidence 0.25, iou 0.7, include_annotated false, illustrative only) apply undisturbed. There is no imgsz parameter. class_mapping bridges a model/dataset class-taxonomy mismatch (for example a 1-class model against an 80-class dataset, which otherwise fails outright); it passes through with no length check. Labels are additive, never overwritten, so no overwrite confirmation is needed. Every start snapshots a dataset version before labelling, listed via datasets_get and undoable exactly with dataset_version_restore. Billing settles at run time, not at dismissal, so auto_annotate_stop does not refund a charge already incurred. Use auto_annotate_status to poll and auto_annotate_stop to cancel.

Inputs: model (required), dataset (required), iou, project, +4 more.

auto_annotate_statusA
Read-only

Get an auto-annotation run's status for a dataset by slug, owner/slug, or a ul://owner/datasets/slug URI. Surfaces activeJob and lastRun unmodified: both null means the dataset has never run one; activeJob carries progress for a run in flight; lastRun carries failed/stopped booleans plus results, or an error when the run failed.

Inputs: dataset (required).

auto_annotate_stopA
Destructive

Stop a dataset's active auto-annotation run by slug, owner/slug, or a ul://owner/datasets/slug URI. Reads status first and refuses without calling the endpoint when no run is active, including when the last run has already finished, since there is nothing to stop. When a run is active it sends the request and surfaces the server's own action verbatim rather than inferring it, for example cancelled for a run stopped mid-flight. Ships ungated, consistent with training_cancel and export_cancel: an off-switch is never gated. A finished run left in place does not block the next start, so this never strands anything.

Inputs: dataset (required).

dataset_class_statsA
Read-only

Get per-class annotation counts for a dataset by slug, owner/slug, or a ul://owner/datasets/slug URI. By default omits the bulky histogram and heatmap groups (image size, file size, format, points-per-annotation, bbox distributions, and location/dimension heatmaps), naming them in the summary; pass include_histograms: true to get the full payload unmodified.

Inputs: dataset (required), include_histograms.

dataset_exportA
Read-only

Get a time-limited export download link for a dataset by slug, owner/slug, or a ul://owner/datasets/slug URI, for the latest export or one frozen version.

Inputs: dataset (required), version.

dataset_images_listB
Read-only

List images in a dataset by slug, owner/slug, or a ul://owner/datasets/slug URI with optional filtering.

Inputs: dataset (required), limit, split, offset, +4 more.

dataset_ingestA

Start a remote URL ingest job for a dataset by slug, owner/slug, or a ul://owner/datasets/slug URI. Defaults conflictPolicy to skip (the platform default is undocumented). Reports the queued job id with the dataset's current ingest status; use datasets_get to follow up.

Inputs: dataset (required), sourceUrl (required), targetSplit, conflictPolicy.

datasets_createA

Create a dataset in your Ultralytics workspace. Defaults to private visibility (the platform defaults to public when visibility is omitted).

Inputs: name (required), task (required), dataset (required), owner, +3 more.

datasets_deleteA
Destructive

Delete a dataset by slug, owner/slug, or a ul://owner/datasets/slug URI. Deleting a dataset moves its images and annotations to trash with it; models trained on it are not deleted. Trashed items remain restorable for a bounded window.

Inputs: dataset (required).

datasets_getA
Read-only

Get details for one dataset by slug, owner/slug, or a ul://owner/datasets/slug URI.

Inputs: dataset (required).

datasets_listC
Read-only

List datasets in your Ultralytics workspace.

Inputs: owner, username.

dataset_upload_fileA

Upload a local dataset archive through the signed-upload flow for a dataset by slug, owner/slug, or a ul://owner/datasets/slug URI. Defaults conflictPolicy to skip (the platform default is undocumented). Reports the queued job id with the dataset's current ingest status; use datasets_get to follow up.

Inputs: dataset (required), file_path (required), targetSplit, conflictPolicy.

dataset_upload_folderA

Upload a local image folder as a zip through the signed-upload flow for a dataset by slug, owner/slug, or a ul://owner/datasets/slug URI. Defaults conflictPolicy to skip (the platform default is undocumented). Reports the queued job id with the dataset's current ingest status; use datasets_get to follow up.

Inputs: dataset (required), folder_path (required), targetSplit, conflictPolicy.

dataset_upload_videoA

Upload a local video as extracted frames through the signed-upload flow for a dataset by slug, owner/slug, or a ul://owner/datasets/slug URI. Defaults conflictPolicy to skip (the platform default is undocumented). Reports the queued job id with the dataset's current ingest status; use datasets_get to follow up.

Inputs: dataset (required), video_path (required), fps, max_frames, +2 more.

dataset_version_createA

Create a frozen dataset version snapshot by slug, owner/slug, or a ul://owner/datasets/slug URI. If the dataset is unchanged since the previous snapshot the existing version is returned instead of a new one, and a passed description then replaces the existing version's note; omit description to leave that note untouched.

Inputs: dataset (required), description.

dataset_version_restoreA
Destructive

Restore a dataset to a previously saved version by slug, owner/slug, or a ul://owner/datasets/slug URI, and an integer version number. Versions are listed via datasets_get (the versions array, already returned unprojected). This REPLACES the dataset's current images, labels, and splits with that snapshot outright: anything done since that version, including un-versioned manual annotation work, is discarded. Ships ungated anyway, since it is the undo tool — an auto-annotate run snapshots a version before labelling, so restoring that version undoes the run exactly, and a mistaken restore is itself recoverable by restoring a later version. Restore also reassigns image IDs: a pre-restore image ID still resolves afterward but returns an empty label array rather than a 404, so callers must re-list images (for example with dataset_images_list) after a restore instead of reusing held IDs.

Inputs: dataset (required), version (required).

deployment_getB
Read-only

Get details for one deployment by owner/deployment or a bare slug (owner defaults to the account owner). serviceUrl and deployedAt are null until the deployment reaches status ready.

Inputs: deployment (required).

deployment_healthA
Read-only

Probe one deployment's health by owner/deployment or a bare slug (owner defaults to the account owner). status is the upstream HTTP status the health probe observed at the deployment's own service URL, not the status of this tool call.

Inputs: deployment (required).

deployment_logsA
Read-only

Read log entries for one deployment by owner/deployment or a bare slug (owner defaults to the account owner). severity is passed through to the server unvalidated (illustrative values: DEBUG, INFO, NOTICE, WARNING, ERROR, CRITICAL, ALERT, EMERGENCY); an invalid value returns the server's own rejection message. limit defaults to 50, max 200. nextPageToken pages through older entries.

Inputs: deployment (required), limit, severity, pageToken.

deployment_metricsA
Read-only

Read metrics for one deployment by owner/deployment or a bare slug (owner defaults to the account owner). The response is one of two shapes selected by sparkline: the default shape carries timeRange (a {start, end} object)/summary/timeSeries, sparkline=true carries requests24h (an array of per-hour points, not a total)/totalRequests/errorRate/avgLatencyMs. The two are never merged; which shape came back is returned as-is. range (e.g. 1h, 24h, 7d; default 24h) is passed through to the server unvalidated.

Inputs: deployment (required), range, sparkline.

deployment_predictA
Read-only

Run inference through a deployment's own serving endpoint on a local image or video file, by owner/deployment or a bare slug (owner defaults to the account owner). Returns images/metadata verbatim, including undocumented metadata fields. No per-request cost is documented for this endpoint; costs follow the deployment's own resource configuration. A cold start on a scaled-to-zero deployment may respond slowly or with a 503 — check deployment_health rather than retrying blindly.

Inputs: imagePath (required), deployment (required), iou, conf, +1 more.

deployments_listB
Read-only

List model deployments in your Ultralytics workspace.

Inputs: limit, owner.

deployment_stopA
Destructive

Stop a deployment by owner/deployment or a bare slug (owner defaults to the account owner). Sends only {action: stop}; the endpoint's start/resize/replace actions are unreachable from this tool. Stopping preserves the deployment's URL and configuration and still counts toward deployment quota; it is a money-off switch and ships ungated, consistent with training_cancel and export_cancel. Stopping an already-stopped deployment is rejected by the server (400) rather than treated as a success. Reversing this (start) is not available in this tool set.

Inputs: deployment (required).

explore_datasetsA
Read-only

Search public datasets on Ultralytics Explore. Matching is currently loose: results need not contain the search term, so even an unrelated query returns datasets.

Inputs: q (required), sort, task, offset.

explore_projectsB
Read-only

Search public projects on Ultralytics Explore.

Inputs: q (required), sort, offset.

export_cancelA
Destructive

Cancel an active export job for a model by owner/project/model, ul://owner/project/model, or slug with a project, plus the export id. Checks the export's status first and sends the cancellation only while it is still active, refusing on any terminal status; the same API verb deletes a finished export's artifact irreversibly instead of cancelling it. The status check cannot be atomic: an export that finishes between the check and the request will have its artifact deleted rather than cancelled, and that deletion cannot be undone.

Inputs: model (required), export_id (required), project.

export_createA

Create a model export job by owner/project/model, ul://owner/project/model, or slug with a project (state-changing, may cost credits). The format is validated immediately by the server; task and architecture compatibility is only known when the job runs, so a queued export can still fail. Use export_status and exports_list for the real outcome. Requires confirm_cost=true.

Inputs: model (required), format (required), imgsz, dynamic, +4 more.

exports_listB
Read-only

List export jobs for a model by owner/project/model, ul://owner/project/model, or slug with a project.

Inputs: model (required), limit, project.

export_statusA
Read-only

Get one export job's status for a model by owner/project/model, ul://owner/project/model, or slug with a project, plus the export id.

Inputs: model (required), export_id (required), project.

gpu_availabilityA
Read-only

Get current cloud-GPU stock status by GPU type.

Inputs: no named parameters.

model_downloadB

Download a trained model's weight file to an explicit local path by owner/project/model, ul://owner/project/model, or slug with a project.

Inputs: model (required), output_path (required), project, filename, +1 more.

model_metricsA
Read-only

Report a model's best training epoch and its reported metrics, labelled so neither can be mistaken for the other (works for private and public projects). bestEpoch, bestFitness, and bestEpochMetrics are stated only when exactly one trainResults record has the reported bestEpoch and that record's fitness exactly equals the reported bestFitness; otherwise all three are null and bestEpochNote keeps the platform's raw values and says why (older Ultralytics versions reported the last epoch as bestEpoch). reportedMetrics is the model's top-level metrics field verbatim; the API does not say which evaluation produced it (on finished Platform-trained runs observed live it matches the post-training evaluation of the best checkpoint, not the last training epoch), so it makes no epoch claim. resultRecordCount counts trainResults records, not epochs. include_train_args adds the full trainArgs object (111 keys observed live), omitted by default. include_history adds the last N records in API order and always states the window it covers, with record counts, the min/max reported epoch, and duplicate and missing epoch numbers in that range.

Inputs: model (required), project, history_last_n, include_history, +1 more.

model_plotsA
Read-only

Report a model's evaluation plots (per-class pr_curve, f1_curve, precision_curve, recall_curve, confusion_matrix), which model_metrics and training_monitor do not surface. By default lists each plot's type and the shape of its fields (array lengths only, never the values) since one pr_curve alone can carry thousands of numbers on a multi-class model; pass type to get that one plot's data back exactly as the platform returned it, unmodified. Field shapes vary by type: pr_curve/f1_curve/precision_curve/recall_curve carry x/y (and pr_curve additionally ap); confusion_matrix carries a matrix field instead, not x/y/ap. Plot presence does not track training history: a model can have plots with no trainResults, or (rarely) plots: [] on an otherwise completed model.

Inputs: model (required), type, project.

model_predictA
Read-only

Run inference with a trained model on an image URL or base64 image (source), or on a local image or video file (file_path). Give exactly one.

Inputs: model (required), iou, conf, imgsz, +3 more.

models_deleteA
Destructive

Soft-delete a model by owner/project/model, ul://owner/project/model, or slug with a project. Deleted models go to trash and remain restorable; weights, training history, and exports are removed only on permanent deletion.

Inputs: model (required), project.

models_getA
Read-only

Get details for one model by owner/project/model, ul://owner/project/model, or slug with a project. Model quality (best epoch and fitness) is not included; use model_metrics, which validates the platform's best-epoch fields.

Inputs: model (required), project.

models_listA
Read-only

List models in a project by slug, owner/slug, or project ul:// URI. Model quality is not included; use model_metrics, which validates the platform's best-epoch fields.

Inputs: project (required), limit.

projects_createA

Create a project in your Ultralytics workspace. Defaults to private visibility (the platform defaults to public when visibility is omitted).

Inputs: name (required), project (required), owner, visibility, +1 more.

projects_deleteA
Destructive

Soft-delete a project by slug, owner/slug, or project ul:// URI. Deleted projects land in trash and remain restorable for a bounded window.

Inputs: project (required).

projects_getA
Read-only

Get details for one project by slug, owner/slug, or project ul:// URI.

Inputs: project (required).

projects_listC
Read-only

List computer-vision projects in your Ultralytics workspace.

Inputs: limit, owner, username.

training_cancelA
Destructive

Cancel a running training job by owner/project/model, ul://owner/project/model, or slug with a project. Cancelling releases the compute instance; elapsed GPU time is still charged and the most recently uploaded checkpoint is preserved rather than discarded. This stops the job and does not delete the model.

Inputs: model (required), project.

training_monitorA
Read-only

Report a model's training status and progress (works for private and public projects). reportedCurrentEpoch, reportedProgressPercentage, and etaMs are the training job's own counters, passed through verbatim; after a run ends reportedCurrentEpoch can count a post-training evaluation as an epoch, so it may be one higher than the epochs actually trained, with reportedProgressPercentage inflated to match, and etaMs can stay nonzero. With no training job, progress is reported unavailable rather than inferred. resultRecordCount counts trainResults records, which are not epochs: a history can include a post-training evaluation record, duplicate or missing epoch numbers, and records out of epoch order. lastReportedMetrics is the last record in API order with its reported epoch, not necessarily the latest epoch. Model quality (best epoch, the model's reported metrics) belongs to model_metrics. timing.elapsedMs is wall-clock since model creation, evaluated at request time: it tracks elapsed run time while training is active, but for a finished model it reflects the model's age, not training duration. Billed training time is computeCost.durationMs.

Inputs: model (required), project, history_last_n, include_history.

training_startA
Destructive

Start a cloud training job from an existing model or a base checkpoint (state-changing, may cost credits). Checkpoint mode is chosen by the model ref's shape and owner, not a list of model families: a name ending in .pt, or a model owned by another account (ul://owner/project/model or owner/project/model), is used as the base checkpoint, and the server decides whether it exists. Any other ref is one of your own models to retrain. Trains on exactly one dataset and requires epochs. The dataset is validated immediately, so an unusable dataset is rejected before any compute starts. In checkpoint mode a project model is created first, because starting requires a model id, so any rejection when training starts leaves that model behind, unrequested: a missing or not-ready dataset, an invalid gpu_type, a checkpoint/dataset task mismatch, or a 503 GPU_UNAVAILABLE when no GPU of the requested type is in stock, which is not a caller error (choose another gpu_type). The error names the model so it can be reviewed and deleted (models_delete) if unwanted. Starting is billable immediately: the platform has no cost preview before that, so the projected cost and remaining balance are only reported after the job starts. Training an existing model that already has a recorded run (any status past pending/untrained) replaces that model's status, epoch count, and training result history the instant the new job starts, and that history cannot be recovered afterward; the previously uploaded weights survive. That path requires confirm_history_loss=true in addition to confirm_cost=true. Checkpoint mode never destroys an existing model's history since it always creates a new one, so it never needs confirm_history_loss, including for another account's model — its own risk is the possible leftover model described above. An untrained or never-trained model needs no extra confirmation either. Use training_cancel to stop a job that is already running. Requires confirm_cost=true.

Inputs: model (required), epochs (required), dataset (required), project (required), +7 more.

Tool Schema Changelog

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

Loading tool schema changelog…

    TDQS

    B3.4/5.0

    Scored across 44 tools

    Disambiguation4/5

    The tools mostly target clearly distinct resources and actions, and the descriptions explicitly separate close pairs such as training_monitor vs model_metrics vs model_plots and model_predict vs deployment_predict. Similar-looking lifecycle tools remain understandable, though the large surface makes some selection care necessary.

    Naming Consistency3/5

    Names use snake_case and mostly follow a resource_action pattern, but singular/plural prefixes are mixed: models_list/models_get/models_delete alongside model_metrics/model_predict/model_download, deployments_list alongside deployment_get, and exports_list alongside export_create/export_status. The convention is readable but not fully predictable.

    Tool Count2/5

    The server exposes 44 tools, which is far above a well-scoped set and creates a heavy selection burden even for a broad ML-platform domain. Many are justified individually, but the overall surface is too large for efficient agent use.

    Completeness3/5

    Coverage is broad across projects, datasets, models, training, exports, deployments, and auto-annotation, but lifecycle gaps are notable: there are no update operations for projects/datasets/models and deployment_stop has no corresponding deployment start/create in this tool set. The core workflows are supported, but several operations end in a dead end.

    Maintenance

    ActivityActive
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers