56 results available
Sign in
Skills directory

cuopt-server-api-python

nvidia

·

Last changed
Hardened

This skill has been hardened by Chainguard

Last changed

This version passed the hardening gate. Hardening updated the skill content and independently checked the resulting changes. Classified findings before hardening: 19. Classified findings closed: 0. Classified findings remaining: 19. Unclassified scanner findings remaining: 0. Review findings closed: 7. Review findings remaining: 8.


Open before hardening

18

Medium

1

Low
Open after hardening

18

Medium

1

Low

Expand
File
Group
Subtype
Severity
Status
assets/milp_basic/client.py

Sensitive Data & Secret Exposure

Data exfiltration

Medium
Open
assets/pdp_basic/client.py

Malicious Code & Command Execution

—

Medium
Open
SKILL.md

Tool & MCP Manipulation

MCP over-permissioning

Medium
Open
BENCHMARK.md

Sensitive Data & Secret Exposure

Data exfiltration

Medium
Open
assets/vrp_simple/client.py

Malicious Code & Command Execution

—

Medium
Open
assets/lp_basic/client.py

Malicious Code & Command Execution

—

Medium
Open
assets/vrp_basic/client.py

Malicious Code & Command Execution

—

Medium
Open
assets/vrp_basic/client.py

Sensitive Data & Secret Exposure

Data exfiltration

Medium
Open

19 findings


SKILL.md

cuOpt Server — Deploy and client (Python/curl)

This skill covers starting the server and client examples (curl, Python). Server has no separate C API (clients can be any language).

Purpose

Use this skill when the user is deploying the cuOpt REST server or writing a client against it — choosing a deployment target, mapping a problem onto the HTTP endpoints, translating between Python-API and REST field names, or debugging a rejected payload.

Prerequisites

  • An NVIDIA GPU with a working CUDA driver (the server requires one; --gpus all for Docker).
  • cuopt-server installed, or Docker with the NVIDIA Container Toolkit. See the install skill.
  • Python clients need requests. No API key or auth token is required by the server itself.

Minimal required access: network access to the cuOpt server the user has confirmed, and Docker with GPU access only when deploying in a container. Nothing else is needed.

Problem types supported

Problem typeSupported

Routing

✓

LP

✓

MILP

✓

QP

✗

Required questions

Ask these if not already clear:

  1. Problem type — Routing or LP/MILP? (QP not available via REST.)
  2. Deployment — Local, Docker, Kubernetes, or cloud?
  3. Client — Which language or tool will call the API (e.g. Python, curl, another service)?

Start server

# Development on a trusted host only
python -m cuopt_server.cuopt_service --ip 0.0.0.0 --port 8000

# Docker — pick the tag matching your CUDA major version
docker run --gpus all -d -p 8000:8000 -e CUOPT_SERVER_PORT=8000 \
  nvidia/cuopt:<release>-cu<cuda-major>

The development command listens on every network interface, and the server has no authentication or TLS. Run it only on a trusted network or behind an authenticating TLS gateway or reverse proxy. For local-only use, bind the server to the loopback interface instead.

A published Docker port is reachable on every host interface, and Docker port publishing can bypass host firewalls. For local use, publish the port on the loopback interface only; otherwise expose it only through an authenticated TLS gateway or a network policy.

For a quick development try, latest-cu12 or latest-cu13 can be used to match your driver's CUDA major version (latest-cu13-ubi10 for a UBI10 base).

For production, pin rather than float: latest-* tags are mutable and can silently move to a different image. Use a full release tag (nvidia/cuopt:<release>-cu<cuda-major>) or an immutable digest (nvidia/cuopt@sha256:<digest>). Check the nvidia/cuopt registry for available tags.

Verify

Confirm the server is up by requesting GET /cuopt/health on the local port (e.g. http://localhost:8000/cuopt/health) — a healthy server returns HTTP 200.

Instructions

  1. POST to /cuopt/request → get reqId
  2. Poll /cuopt/solution/{reqId} with a fixed maximum number of attempts sized to solver_config.time_limit plus a margin, sleep between polls, set a timeout on each request, and stop with an error once the budget is used up (as the runnable assets do)
  3. Parse response

Treat reqId as untrusted input: validate it (e.g. re.fullmatch(r"[A-Za-z0-9_-]{1,64}", req_id)) before interpolating it into the polling URL, and set an explicit timeout on every request.

Call raise_for_status() on the submit response before reading reqId, as the runnable assets do, and report the status code on failure.

Examples

import requests, time
SERVER = "http://localhost:8000"
HEADERS = {"Content-Type": "application/json", "CLIENT-VERSION": "custom"}
payload = {
    "cost_matrix_data": {"data": {"0": [[0,10,15],[10,0,12],[15,12,0]]}},
    "travel_time_matrix_data": {"data": {"0": [[0,10,15],[10,0,12],[15,12,0]]}},
    "task_data": {"task_locations": [1, 2], "demand": [[10, 20]], "task_time_windows": [[0,100],[0,100]], "service_times": [5, 5]},
    "fleet_data": {"vehicle_locations": [[0, 0]], "capacities": [[50]], "vehicle_time_windows": [[0, 200]]},
    "solver_config": {"time_limit": 5}
}
r = requests.post(f"{SERVER}/cuopt/request", json=payload, headers=HEADERS, timeout=30)
# Check the status code of the submit response before reading reqId.
req_id = r.json()["reqId"]
# Validate req_id against the pattern in Instructions before polling.
# Poll: GET /cuopt/solution/{req_id}
# Poll a bounded number of times with a timeout on each request.

The runnable assets below show the complete pattern, including reqId validation, status checks, timeouts, and a bounded poll loop.

Terminology: REST vs Python API

Python APIREST

order_locations

task_locations

set_order_time_windows()

task_time_windows

service_times

service_times

Use travel_time_matrix_data (not transit_time_matrix_data). Capacities: [[50, 50]] not [[50], [50]].

Troubleshooting

ErrorCauseSolution

422 Unprocessable Content

Field name not in the schema

Check names against the OpenAPI spec at /cuopt.yaml. Most common: transit_time_matrix_data → travel_time_matrix_data

422 on fleet_data

Capacities nested per vehicle instead of per dimension

Use [[50, 50]] (one inner list per capacity dimension), not [[50], [50]]

Connection refused

Server not up, or bound to a different interface/port

curl http://localhost:8000/cuopt/health; verify the bind address and port the server was started with. Local clients can use a loopback bind; remote clients should reach the server through a gateway

Docker container exits immediately

No GPU visible to the container

Run with --gpus all and confirm the NVIDIA Container Toolkit is installed

Polling never returns a solution

Solve exceeds the client's poll budget

Raise solver_config.time_limit and the poll loop count together

For any failed request, capture the reqId, the HTTP status code, and the error message. Redact problem data such as locations, demands, and costs before logging or sharing a response body.

Limitations

  • QP is not exposed over REST. Use the Python or C API for quadratic objectives.
  • The server ships no authentication or TLS. Anything that can reach the port can submit jobs. Put it behind a gateway and treat --server/base URLs as trusted-network endpoints only. Use only a server URL the user has explicitly confirmed, send problem data only to that server, and treat server responses as untrusted input.
  • Plain HTTP is acceptable only for a local server. Reach any other server through a TLS-terminating proxy, with certificate verification left enabled.
  • Solutions are retrieved by polling; there is no push/webhook delivery.
  • One request is solved at a time per server process; concurrency requires multiple replicas. For shared deployments, enforce authentication and rate limiting at the gateway, cap solver_config.time_limit, and scale replicas.

Runnable assets

Run from each asset directory (server must be running; scripts exit 0 if server unreachable). All use Python requests and accept --server (default http://localhost:8000):

  • assets/vrp_simple/ — Basic VRP (no time windows)
  • assets/vrp_basic/ — VRP with time windows
  • assets/pdp_basic/ — Pickup and delivery
  • assets/lp_basic/ — LP via REST (CSR format)
  • assets/milp_basic/ — MILP via REST

A "Server not running, skipping" message with exit 0 means the example did not run. Report it to the user as a skipped run, and report a solve only when the script prints a solution.

See assets/README.md for overview.

Escalate

For contribution or build-from-source, see the developer skill.

Install

Install with chainctl
chainctl skill install public/nvidia/cuopt-server-api-python:latest
Get started with chainctl
View source

Harden your own skills

Bring Chainguard's hardening pipeline to your first-party skills — custom rulesets, automated remediation, full audit trail.

Provenance

Upstream sourcehttps://github.com/nvidia/skills
Upstream commit38b6f0dc04e97ad42788b96c258cb3f6e7bb040c
OCI reference

skills.cgr.dev/public/github.com/nvidia/skills/cuopt-server-api-python:latest

License

Apache-2.0

Files

BENCHMARK.md

HARDENING.md

SKILL.md

assets/README.md

assets/lp_basic/README.md

assets/lp_basic/client.py

assets/milp_basic/README.md

assets/milp_basic/client.py

assets/pdp_basic/README.md

assets/pdp_basic/client.py

assets/vrp_basic/README.md

assets/vrp_basic/client.py

assets/vrp_simple/README.md

assets/vrp_simple/client.py

evals/evals.json

skill-card.md

skill.oms.sig


The trusted source for open source

Talk to an expert
PrivacyTerms

Product

Chainguard ContainersChainguard LibrariesChainguard VMsChainguard OS PackagesChainguard ActionsChainguard Agent SkillsIntegrationsPricing
© 2026 Chainguard, Inc. All Rights Reserved.
Chainguard® and the Chainguard logo are registered trademarks of Chainguard, Inc. in the United States and/or other countries.
The other respective trademarks mentioned on this page are owned by the respective companies and use of them does not imply any affiliation or endorsement.