Skillset stores the files that make up a Skill or Plugin — collectively called an Artifact — in S3-compatible object storage. MCP Servers are pure-metadata pointers and have no stored bytes; only Skills and Plugins write to storage. This page explains how to configure storage for production AWS S3 and for a local MinIO instance, and describes how Artifacts flow through the system.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/org-quicko/skillset/llms.txt
Use this file to discover all available pages before exploring further.
Why object storage
When a Writer publishes a Skill or Plugin, the API generates a presigned upload URL and returns it to the CLI or web client. The client uploads Artifact files directly to storage — bytes never pass through the API server. This keeps the API stateless and avoids memory pressure from large uploads. When a Reader installs a Skill or downloads a Plugin, the API reads the individual Artifact files from storage, assembles them into a zip in memory, and streams the zip to the client. Artifacts are stored as individual files, never pre-zipped — the zip is assembled on demand per request.Required configuration
Only one variable is mandatory:| Variable | Purpose |
|---|---|
STORAGE_BUCKET | Name of the S3 bucket Artifact files are stored in |
STORAGE_BUCKET is unset, because publishing presigns against a bucket at startup rather than at request time.
AWS S3 (production)
IAM policy
The Registry needs the following S3 actions on the bucket:Self-hosted MinIO (local development)
The.env.example ships pre-configured for a local MinIO instance. The two-endpoint split handles the Docker network/localhost boundary:
STORAGE_ENDPOINT— the address the API server uses to sign requests and read Artifacts. Resolves over the Docker network (http://minio:9000).STORAGE_PUBLIC_ENDPOINT— the endpoint embedded in presigned upload URLs that are returned to the browser. Must be resolvable by the browser, not by the API container (http://localhost:9000).
STORAGE_PUBLIC_ENDPOINT defaults to STORAGE_ENDPOINT when unset. Only set it when the API and the browser reach storage at different hostnames — such as when the API is inside a Docker network and the browser is on the host machine.How presigned uploads work
The publish flow never routes Artifact bytes through the API:The CLI or web client calls the Registry API with the list of files to publish. The API calls
presignUpload on the S3 adapter, signing a PUT URL with a 60-second expiry against the configured bucket, using STORAGE_PUBLIC_ENDPOINT (or STORAGE_ENDPOINT if unset) as the URL base.The signed
PUT URL is returned to the client, which uploads the file bytes directly to S3 or MinIO. The API server never sees the file bytes.How downloads and installs work
Whenskillset install or the web Download button is triggered:
- The API reads the list of Artifact files for the Skill or Plugin from storage using
list(prefix). - It fetches each file in turn with
get(key), streaming bytes from S3 into memory. - It assembles all files into a zip archive in memory.
- It streams the zip to the client in a single HTTP response.
Storage adapter reference
TheS3StorageAdapter in apps/api/src/storage/s3.ts is built on Bun’s native S3 client — no AWS SDK dependency. It surfaces the following operations used internally by the API:
| Method | S3 operation | Used for |
|---|---|---|
presignUpload | PUT presign | Generating upload URLs during publish |
presignDownload | GET presign | Generating download links for individual files |
put | PutObject | Writing individual Artifact files |
get | GetObject | Reading files for zip assembly and preview |
open | HeadObject + stream | Size-checked streaming for large file reads |
list | ListObjectsV2 | Enumerating all files in an Artifact prefix |
exists | HeadObject | Checking whether a file is present |
delete | DeleteObject | Removing files when a Resource is deleted |
list method handles S3’s paginated listing automatically — a prefix with many files is fetched in pages until isTruncated is false, so callers always receive the complete set.
S3 error handling
The adapter distinguishes “object not found” (NoSuchKey, NotFound) from other S3 errors. A bucket misconfiguration or expired credential is re-thrown rather than reported as a missing file, so a wrong bucket name does not silently serve 404s indefinitely.