Skip to content

Actor source tools: read and edit Actor versions over MCP #1452

Description

@DaveHanns

Problem

An agent developing an Actor over MCP needs to read and change the Actor's source. The drafted push-actor (#1333) takes the full content of every file it touches, so a one-line fix resends the whole file, and a version stored as a zip needs the whole source resent every time. Coding agents work the other way: they read the current content and apply small, exact edits.

Review feedback on the drafts asked for three things:

  • tools that follow the version API rather than the CLI (get-actor-version and update-actor-version instead of pull and push),
  • writing kept separate from building,
  • no tool that waits for a build.

Proposal

Five tools in a new source category, which is not enabled by default:

Tool What it does
get-actor-version Reads a version: the file list with a size and a hash per file, a revision, and the content of the files asked for.
update-actor-version Writes, edits, or deletes files of a version in one call. Files the call does not mention stay as they are.
create-actor Creates a private Actor with its first version and files. It never touches an existing Actor.
create-actor-version Adds a version to an existing Actor, with files or as a copy of another version.
delete-actor-version Deletes a version. The platform refuses to delete the last one.

Building and running stay with build-actor, get-actor-build, and call-actor. The source tools can start a build (autoBuild, default false) but never wait for it.

The tools work on any Actor the token can write. The platform checks permissions, Actor names, the 3 MiB limit, path length, and version numbers, and its error goes to the agent unchanged.

What replaces push-actor

push-actor was used to Now
push files under a new name, creating the Actor create-actor
push files to an existing version update-actor-version
push files to a version the Actor does not have yet create-actor-version

Keeping creation separate removes the guessing push-actor had to do from a name: an Actor ID mistaken for a new name, or a typo that creates a new Actor.

get-actor-version

  • Without paths, it returns the file list only.
  • paths: [...] returns those files, in order, within 256 KiB. Files that do not fit, or do not exist, are named in omittedPaths or notFoundPaths.
  • One path with startLine and lineCount returns part of a large file.
  • Binary files come back as base64.
  • hash is the first 16 hex characters of the SHA-256 of a file's bytes. revision identifies the whole file set. Neither depends on how the version stores its files, so they stay the same once zip-stored versions are supported.

update-actor-version

One call applies a list of operations, all or nothing, and saves the version with one PUT:

  • write: create a file, or overwrite one (overwriting needs the file's current hash),
  • edit: search and replace inside a file; each oldText must match exactly once,
  • delete: remove a file (needs its hash).

With expectedRevision, the call fails if any file changed since the agent read the version. Renaming a file is a delete and a write.

The PUT carries only the files, never env vars or the build tag, so secrets stay untouched.

Conflicts

The platform has no per-file API and no concurrency check on the version PUT. So every write reads the version again first, and the hash, exact-match, and revision checks refuse a change when the file changed since the agent read it, whoever changed it: another agent, Apify Console, or apify push. The error names the operation, the file, and the reason, so the agent re-reads that file and tries again.

What these checks cannot catch is a save that lands between our read and our PUT. Closing that needs a conditional version PUT on the platform.

Versions not stored as files

A version built from a Git repository or a gist has no files on Apify. apify push stores sources over 3 MiB as a zip in the Actor's actor-<actorId>-source key-value store. The source tools refuse both kinds and name the URL, with any credentials in it hidden. The server never clones or downloads anything.

Reading and writing zip-stored sources comes in a later step, with adm-zip 0.6.1 or later. Apify already uses it: apify-core unpacks Actor template zips into source files with it, and apify pull reads source zips with it. That step downloads zips only from the session's own API host, caps the entry count and unpacked size, and refuses symlinks, encrypted entries, and unsafe names, since the server unpacks the zip in memory.

Delivery

  1. get-actor-version: feat: Add get-actor-version tool #1450.
  2. create-actor and update-actor-version: feat: Add create-actor and update-actor-version tools #1453, stacked on feat: Add get-actor-version tool #1450.
  3. create-actor-version and delete-actor-version: feat: Add create-actor-version and delete-actor-version tools #1454, stacked on feat: Add create-actor and update-actor-version tools #1453.
  4. Reading and writing sources stored as a zip, after a staging check that the build worker downloads the record URL the server builds.

In the first version there is no lock between concurrent MCP calls; the checks above are the only guard.

Relation to the API tools

The generic API tools (#1443) are plain proxies to the API. They cover what these tools leave out: env vars, build tags, Git sources, and replacing every file at once. For changing files, these tools are the better way: they send only the change, keep env vars untouched, and refuse a change that conflicts with a newer save.

What this replaces

This supersedes #1217 (push-actor), #1379 (zip storage), and #1427 (pull-actor). Their drafts (#1333, #1380, and #1433) will be closed once the new tools are in review.

Open questions

  • The hosted server's request body limit (reportedly 100 kB) caps how much source one call can send. Should it be raised to 4 MB?
  • Does the hosted server run several replicas? If so, a later lock between MCP calls has to live outside the process.

Acceptance

  • get-actor-version
  • create-actor and update-actor-version
  • create-actor-version and delete-actor-version
  • Zip-stored sources
  • Evals: create an Actor from scratch, fix one line, and a change across several files, each ending in a successful build and run

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions