Skip to content
Back to skills

Asset Import

ASecurity

Hosted ChatCut plugin sessions only (the `chatcut` MCP server). Import local or downloaded media, or relink missing media to an existing ChatCut asset. Use the editor loopback bridge when the editor and files are on the same machine; use the upload helper otherwise. Desktop sessions use their own built-in import tools.

  • 1,028 stars
  • 0 votes
  • 0 copies
  • 5 views
  • Added November 6, 2026
ai-agentsgoshellbashnodebackend

Works with

  • cli
  • mcp

Security analysis

A100/100

Pro scans all 3 files and shows the line behind each finding

Scanned November 6, 2026

npx -y skills add ChatCut-Inc/agent-plugin --skill asset-import --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Asset Import?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Asset Import
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/chatcut-inc-asset-import-1e2396a8/badge)](https://www.skillsdirectory.com/skills/chatcut-inc-asset-import-1e2396a8)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: asset-import
description: Hosted ChatCut plugin sessions only (the `chatcut` MCP server). Import local or downloaded media, or relink missing media to an existing ChatCut asset. Use the editor loopback bridge when the editor and files are on the same machine; use the upload helper otherwise. Desktop sessions use their own built-in import tools.
---

# Asset Import

Check `browse_assets` first when a file may already be imported.

Grok Bot normally runs on a cloud computer. First confirm that the host exposes
readable bytes for the requested attachment; a chat attachment card alone does
not establish a filesystem path. If bytes are unavailable, use the host's
supported file handoff with the user's permission, without scanning unrelated
files or bypassing a denied transfer. When the media stays on the user's phone
or never reaches the cloud computer, call `import_media` with
`{"action":"create_session"}` and give the user its `userUploadFallback.url`:
it opens a browser upload page for this project, including on a phone.

A ChatCut tab on the user's laptop cannot reach the cloud computer's loopback
server. Use the upload-helper route unless the editor browser and source files
are confirmed to share the same computer and network namespace. Follow the
host's local-execution and file-transfer permissions.

## Same-machine editor import (preferred)

1. Open the target project using `browserHandoff.url` or `editorUrl`. Keep exactly one editor tab for this project open, on the same machine/network namespace as your shell. A remote sandbox's localhost is not the user's localhost.
2. Start the bundled server using the host's bundled Node runtime when available, otherwise Node 18+ from `PATH`, and the origin of the actual editor URL:

```bash
"<bundled-or-global-node>" <this-skill-dir>/scripts/serve-local-media.mjs --origin <editor-origin> /path/to/source.mp4
```

Keep this process alive using the host's background-process support while calling MCP. It prints one JSON line and automatically exits after 900 seconds. It serves only the listed files over loopback URLs without an access token. URLs use the public `chatcut-local-media-v1` path prefix to remain compatible with existing editors. Legacy token-prefixed URLs remain supported; the JSON `token` field contains that public prefix, not a credential.

3. Import multiple files in **one** `import_media` call: `{"action":"from_editor","files":[...]}`. Copy each file's `assetId`, `url`, `filename`, and `sizeBytes` from the printed `imports` array into `files`, omitting its per-file `action`. Each URL may come from a different running helper. Send 1–16 files per call; for larger sets, submit successive batches of 16. Up to eight files are processed concurrently; the editor streams each one straight into its local store, so a card with transfer progress appears as soon as the download starts. There is no loopback-specific file-size cap. The original top-level single-file arguments still work.
4. Inspect every entry in `results`: successful entries have `ok:true` and `status:"locally_imported"`; failed entries have an `error`. Results preserve input order and include `assetId` and `filename`, with top-level `succeeded`/`failed` counts. Retry only failed files with the same asset IDs. Success means the editor has persisted local bytes and registered the asset locally. Stop the helpers only after all files succeed. Keep the editor open for server sync, background upload and transcription.
5. Use the returned asset IDs for timeline work. Wait on `track_progress target:"transcription"` before transcript/caption work. Browser-renderable timelines defer original-file uploads; cloud-only or unsupported timelines upload automatically. Check `browse_assets` before waiting on `target:"upload"`; a deferred upload is not in progress. Use the editor's Upload action when cloud bytes are needed, preserving the same asset ID. If server sync is still catching up, retry the asset lookup.

On timeout, check `browse_assets` and retry with the **same assetId**; the import may still be running, and a retry resumes an interrupted download from where it stopped rather than starting over. Keep the same ID even if restarting the helper changes its URL. Do not blindly start a second import. Allow the editor's browser local-network permission if prompted. If the editor cannot reach the helper or the bridge is unavailable, use the fallback. A host-policy denial is not permission to try another transfer route.

For visual analysis, inspect readable original files locally rather than waiting for cloud upload. Import original source assets; do not flatten an edit into a local pre-render.

## Relink an existing asset

For missing local media, preserve the existing asset and its timeline references:

1. Get the existing `assetId` from `browse_assets` and locate its corresponding original source file.
2. Serve that file with the same loopback helper above.
3. Call `import_media` with the helper's `url`, `filename`, and `sizeBytes`, but set `action: "relink_from_editor"` and replace the generated `assetId` with the **existing assetId**.
   For multiple files, use the same `files` array form, with an existing asset ID in every entry.
4. Wait for `status: "locally_relinked"` before stopping the helper. Upload/transcription may still be pending; keep the editor open.

Relink always reads the supplied file, even if the editor has cached bytes. The media type must match. Use the corresponding original, not a different replacement clip: relink preserves existing edits and transcripts. If the target is missing from the editor, let project sync finish and retry. A failed relink must not fall back to creating a new asset.

## Upload-helper fallback

For a remote sandbox, unavailable editor, or blocked browser connection:

This route requires Node.js 18+, `ffmpeg`, and `ffprobe` on the computer running
the helper. No media-tool binaries are bundled in this plugin. If these tools
are unavailable, report the dependency and give the user the
`userUploadFallback.url` returned by `create_session` (step 2) to upload in
their browser; do not claim that Node alone is enough or install software silently.

1. Download a public URL to a local file when needed.
2. Call `import_media` with `{"action":"create_session"}`.
3. Run this skill's `scripts/upload-media.mjs` once with the returned token and endpoint and at most four local files. Split larger sets into batches of four and create one session per batch.

```bash
"<bundled-or-global-node>" <this-skill-dir>/scripts/upload-media.mjs --token <token> --endpoint <endpoint> /path/to/source-1.mp4 /path/to/source-2.wav
```

Resolve the helper relative to this skill; do not search the workspace. Run it in the foreground and read its final JSON from stdout. Do not detach it or invent status files. Do not replace it with handwritten `ffprobe`, `ffmpeg`, `curl`, metadata, transcode, or presigned-upload commands. MCP OAuth stays inside the MCP client; only the short-lived import token goes to the helper. Media bytes upload directly to storage and must not pass through the ChatCut backend.

Use each returned `imports[].result.assetId` for timeline work. Wait for
`track_progress` target `transcription` before transcript or caption work. Wait
for target `upload` only before byte-dependent work such as cloud export,
`request_asset_download`, or remote frame inspection.

If the helper returns an error with `retry`, create a fresh import session when requested and rerun exactly the returned arguments. If host policy denies transfer of the user's file, stop instead of trying a local-editing or alternate-upload workaround; tell the user the upload was denied and ask them to upload through the session's `userUploadFallback.url` or the ChatCut editor upload UI, or to grant the required permission.

## Download an existing source

Follow the delivery contract returned by `request_asset_download`. A URL marked
as a user-authenticated download belongs in the user's signed-in browser; Grok's
cloud shell does not share that browser session. An unauthenticated HTTP 401 from
that URL is not evidence that the MCP connection expired. Do not extract browser
cookies or substitute a raw storage URL. For agent inspection, use readable
original bytes or the supported `inspect_asset` path. Only download directly when
the tool explicitly returns an agent-readable signed URL.

Files in this skill

  • SKILL.md8.2 KB
  • scripts/serve-local-media.mjs6 KB
  • scripts/upload-media.mjs66.9 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

View all in ai-agents →

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.