<!-- Generated by crates/swarmops-cli/src/reference/mcp_page.rs from the code: do not edit. Change the code, then run SWARMOPS_REGEN_REFERENCE=1 with the regen_reference test. -->

# blob_put

Stores content as a blob, outside any commit, and gives its id: a commit's change then names it as {"blob": id} content instead of carrying its bytes, the way to commit a large file. A {"file": path} content is read by this server: give an absolute path. A hint's swarmops blob put is this tool.

```yaml
title: "blob_put"
description: "Store a blob."
since: "0.1.0"
mutates: true
identity_required: true
cli_command: "swarmops blob put"
envelope_op: "blob_put"
request_type: "BlobPutReq"
annotations: {"destructiveHint":false,"idempotentHint":false,"openWorldHint":false,"readOnlyHint":false}
max_result_chars: null
```

## Input schema

`arguments` is a `BlobPutReq`: `swarmops schema BlobPutReq` prints the type. A field the type does not know is ignored.

| Field | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `content` | object | yes |  | The content: inline, base64 or a client file, at most 512 MiB (more is `E_TOO_LARGE` with `scope` `put`). A `blob` names content the store holds already, and is `E_INVALID_ARG` here. A `put`'s content, as an object with one key. |

### JSON Schema

As `tools/list` gives it: each `$ref` replaced by its definition, so that it stands alone.

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "description": "`blob_put` (CLI `blob put`): store content as a blob, outside any commit, so that a commit's\nchange list can name it by its id (`{\"blob\": id}`) instead of carrying its bytes. The blob is\ndurable once the call returns; until a commit names it, nothing references it.",
  "properties": {
    "content": {
      "description": "The content: inline, base64 or a client file, at most 512 MiB (more is `E_TOO_LARGE` with\n`scope` `put`). A `blob` names content the store holds already, and is `E_INVALID_ARG`\nhere. A `put`'s content, as an object with one key.",
      "oneOf": [
        {
          "additionalProperties": false,
          "description": "UTF-8 text, verbatim.",
          "properties": {
            "inline": {
              "type": "string"
            }
          },
          "required": [
            "inline"
          ],
          "type": "object"
        },
        {
          "additionalProperties": false,
          "description": "Bytes in standard, padded base64.",
          "properties": {
            "base64": {
              "type": "string"
            }
          },
          "required": [
            "base64"
          ],
          "type": "object"
        },
        {
          "additionalProperties": false,
          "description": "A blob the store holds already, by its id (64 hex digits), as `blob_put` returns it: the\ncommit neither sends nor reads its bytes. An id the store holds no blob under (none, or\na tree's or a changeset's) is `E_INVALID_ARG`, and nothing is written. `blob_put` takes\nthe other forms only.",
          "properties": {
            "blob": {
              "type": "string"
            }
          },
          "required": [
            "blob"
          ],
          "type": "object"
        },
        {
          "additionalProperties": false,
          "description": "A file on the client's machine. The client reads it and sends its bytes, so the store is\nnever asked to read a path.",
          "properties": {
            "file": {
              "type": "string"
            }
          },
          "required": [
            "file"
          ],
          "type": "object"
        }
      ]
    }
  },
  "required": [
    "content"
  ],
  "title": "BlobPutReq",
  "type": "object"
}
```

## Annotations

It adds to the store and changes nothing there. Run again, a `commit` adds again, another changeset signed at its own time, unless the call carries an `idempotency_key`, which makes the same call again a replay; a `blob_put` of the same content finds it stored, and says so in its result.

| Annotation | Value | Meaning |
| --- | --- | --- |
| `destructiveHint` | `false` | True: a tool that changes the store may overwrite or delete what is there, not only add to it. |
| `idempotentHint` | `false` | True: calling it again with the same arguments changes nothing more. |
| `openWorldHint` | `false` | True: it reaches beyond a closed set of things. Every tool here stays inside the store. |
| `readOnlyHint` | `false` | True: the tool does not change its environment, the store. |

Its entry in `tools/list` carries no `_meta`.

## CLI command

[`swarmops blob put`](../commands/blob-put.md) runs the same operation and prints the same envelope.

## Examples

### MCP

```json
{
  "id": 3,
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "arguments": {
      "content": {
        "inline": "# acme\n"
      }
    },
    "name": "blob_put"
  }
}
```

```json
{
  "id": 3,
  "jsonrpc": "2.0",
  "result": {
    "content": [
      {
        "text": "{\"ok\":true,\"op\":\"blob_put\",\"api\":1,\"result\":{\"blob\":\"[blob]\",\"size\":7,\"written\":true},\"meta\":{\"repo\":\"[tmp]/store\",\"elapsed_ms\":\"[elapsed_ms]\",\"resolved\":{},\"auth\":\"trust\"}}",
        "type": "text"
      }
    ],
    "isError": false,
    "structuredContent": {
      "api": 1,
      "meta": {
        "auth": "trust",
        "elapsed_ms": "[elapsed_ms]",
        "repo": "[tmp]/store",
        "resolved": {}
      },
      "ok": true,
      "op": "blob_put",
      "result": {
        "blob": "[blob]",
        "size": 7,
        "written": true
      }
    }
  }
}
```

The server ran as `swarmops mcp --repo [tmp]/store --as agent/worker-17`, after `initialize`. Recorded by the MCP tests. A name in square brackets, such as `[tmp]` or `[c1]`, stands for what differs from run to run: the test's temporary directory, an id, a time, the version.

## Details

It stores content as a blob, outside any commit, and gives its id; a commit's change then names
it as `{"blob": id}` instead of carrying its bytes, the way to commit a large file.
`written` is false when the store held the blob already, or a concurrent writer placed it first.
A `{"file": path}` content follows the rules of [`commit`](../mcp-tools/commit.md): an absolute path to a
regular file.
A hint that names `swarmops blob put` means this tool.

## Return information

A tool result: the envelope, whose `op` is `blob_put`, as `structuredContent` and again as the text of its one `content` block. `isError` is true exactly when the envelope's `ok` is false. On success the envelope's `result` is what [`swarmops blob put`](../commands/blob-put.md#return-information) returns.

## Errors

A failed call is a tool result with `isError: true`; the envelope's `error.code` is one of the [error codes](../errors.md).

- [`E_INVALID_ARG`](../errors.md#e_invalid_arg): arguments that do not fit `BlobPutReq`, a field named twice among them included, or that break one of the server's own rules.
- [`E_IDENTITY_REQUIRED`](../errors.md#e_identity_required): the server runs with no identity.
- [`E_NOT_A_REPO`](../errors.md#e_not_a_repo): the server's store is not there; the server serves on.
- [`E_INTERNAL`](../errors.md#e_internal): the operation panicked, a bug.

Then the errors of the operation, as [`swarmops blob put`](../commands/blob-put.md#errors) lists them.

## See also

- [`swarmops blob put`](../commands/blob-put.md)
- [MCP tools](README.md)
- [MCP integration](../../develop/mcp.md)
- [Error codes](../errors.md)
