Sasha MCP reference

writeAppFile

Create or replace one source file of a Sasha App you manage

Create a file (omit expectedVersion; refused if it exists) or replace one in full (pass the version from readAppFile; refused if the file changed). The change is LIVE immediately. There is no draft and no undo. Allowed: text files with extensions .md .html .css .js .sql .yaml .yml .json .txt .svg, up to 1 MiB, inside the package. A migration that is already applied on this instance must not be edited. Add a new migrations/NNN-*.sql instead. If this call returns an error, the change may still have landed. Call readAppFile before retrying. The result carries status: when status.ok is false the app is NOT usable until the listed diagnostics are fixed. Each names the package file, the line when known, the error code and a reason token. Fix the file and check again; the app is live as soon as it validates.

Arguments

ArgumentTypeRequiredDescription
appstringrequiredThe app id (lowercase kebab-case), as shown by open_app__<id> or listAppFiles.
pathstringrequiredPackage-relative path such as APP.md, index.html, styles.css, app.js, schema.sql, migrations/002-add-code.sql or actions/<id>.action.yaml.
contentstringrequiredNo description
reasonstringrequiredOne line saying why, recorded in the audit log.
expectedVersionstringoptionalThe version returned by readAppFile or listAppFiles for the bytes you last saw.

Scopes

apps:invoke, apps:write

Annotations

  • Read only: no
  • Destructive: no

When to use

Use writeAppFile to create a file, or to replace all of a file. To change one passage, use editAppFile: it is safer.

The tool needs the same access as listAppFiles: the scopes apps:invoke and apps:write, an admin or staff user, and manage access on the app. There is no confirmation step for the source tools. The change is made when the call succeeds.

  • To create a file, omit expectedVersion. The call is refused if a file already exists at path.
  • To replace a file, call readAppFile first and pass its version as expectedVersion. The call is refused if the file changed after your read.
  • content is the complete new text of the file. Allowed file types are .md, .html, .css, .js, .sql, .yaml, .yml, .json, .txt and .svg. A file is at most 1 MiB. A package holds at most 64 files and 1 MiB in total.
  • reason is one line, 1 to 100 characters, that says why. It goes in the audit log with the file versions, not the content.
  • The change is live at once. There is no draft, no preview and no undo.
  • Do not edit a migration that this instance has already applied. Add a new migrations/NNN-*.sql file, and change schema.sql so that replaying every migration gives the same schema.

The result has version (the new version of the file), created (true for a new file) and status. A write that passes the path, size and version checks always lands, even when it breaks the app. Then status.ok is false and status.diagnostics says what to fix. The app cannot be used until you fix each diagnostic. When status.ok is true, the app is live at status.revision.

If the call returns an error, the change can still have landed. Call readAppFile before you retry.

Example

A new migration that adds a column:

{
  "app": "timesheet",
  "path": "migrations/002-add-billable.sql",
  "content": "ALTER TABLE entries ADD COLUMN billable INTEGER NOT NULL DEFAULT 1;\n",
  "reason": "Record whether time on an entry is billable"
}

The structured result (structuredContent). The app does not validate yet, because replaying the migrations now gives a column that schema.sql does not have:

{
  "app": "timesheet",
  "path": "migrations/002-add-billable.sql",
  "version": "cd0aa9856147b6c5b4ff2b7dfee5da20aa38253099ef1b4a64aced233c9afe29",
  "created": true,
  "status": {
    "ok": false,
    "revision": null,
    "diagnostics": [
      { "file": "schema.sql", "code": "APP_MIGRATION_FAILED", "reason": "replay_mismatch" }
    ]
  }
}

The text part of the result says Created migrations/002-add-billable.sql (version …)., then lists each problem as <file>:<line> <code> <reason> and says to fix the named file and call checkApp. The next step here is editAppFile on schema.sql.

Refusals and what to do

The error result's text is the message. structuredContent.error holds code, message, retryable and diagnosticId.

  • APP_SOURCE_CONFLICT: the message says that the file changed after it was read, or that the file to create already exists. Call readAppFile (or listAppFiles) again, check the current text, and retry with the new version.
  • APP_SOURCE_FILE_INVALID: the file type is not allowed. The message lists the allowed extensions.
  • APP_PATH_INVALID (app_path_invalid): the path is not a valid package path, for example it has more than four segments, a segment that starts with ., or ...
  • APP_RESOURCE_LIMIT (app_resource_limit): the file is larger than 1 MiB, or the change would take the package past 64 files or 1 MiB in total. Make the file smaller, or delete a file you do not need.
  • APP_INPUT_INVALID (app_input_invalid): the arguments do not match the schema. Examples: an empty reason, a reason longer than 100 characters or with a control character, an expectedVersion that is not 64 hex characters, or an extra argument.
  • APP_ACCESS_DENIED (app_access_denied): this person does not have manage access on the app, or is not an admin or staff user. An app id that does not exist gets the same answer.
  • If the connection does not hold both apps:invoke and apps:write, the tool is not in your tool list, and a call to it returns MCP error -32602: Tool writeAppFile not found. Read the permissions section of getDocs. The person must reconnect, or mint a new token, with apps:write. Only admin and staff can hold it.

Related

  • readAppFile gives the version to pass as expectedVersion.
  • editAppFile changes one passage.
  • deleteAppFile removes a file.
  • listAppFiles and checkApp show the package status.
made with bernard

Cookie settings