> ## Documentation Index
> Fetch the complete documentation index at: https://retrievalcontextprotocol.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Embedding

> Turn content into vectors — dense (embed), learned-sparse (embed/sparse), or multi-vector late-interaction (embed/multi).

RCP exposes three embedding methods, one per vector family. A server advertises
each independently, so a client can request exactly the representation it wants
for a client-side ANN index or a custom pipeline.

<CardGroup cols={3}>
  <Card title="embed" icon="arrows-to-dot">
    One dense vector per input. `embed` capability.
  </Card>

  <Card title="embed/sparse" icon="list-ol">
    A learned-sparse term→weight vector (SPLADE). `sparseEmbed` capability.
  </Card>

  <Card title="embed/multi" icon="table-cells">
    A matrix of per-token/per-patch vectors (ColBERT/ColPali). `multiVector`.
  </Card>
</CardGroup>

## `embed` — dense

Gated by **`embed`**. One vector per input, in order.

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0", "id": 1, "method": "embed",
    "params": { "inputs": ["attention is all you need", "the eiffel tower"], "kind": "document" }
  }
  ```

  ```json Response theme={null}
  { "jsonrpc": "2.0", "id": 1, "result": { "vectors": [[0.01, -0.04, "…"], [0.07, 0.02, "…"]] } }
  ```
</CodeGroup>

<ParamField path="inputs" type="(string | Content)[]" required>
  Bare strings or [Content blocks](/concepts/message-format#content-blocks-modality).
  A text-only server accepts only strings; a multimodal server that advertises
  `embed.modalities` also accepts `image`/`audio` blocks.
</ParamField>

<ParamField path="kind" type="&#x22;query&#x22; | &#x22;document&#x22;">
  Lets asymmetric encoders (e5/BGE query vs passage prefixes) select the right
  pooling.
</ParamField>

<ResponseField name="vectors" type="float[][]">
  One vector per input, in the same order.
</ResponseField>

<Note>
  For backward compatibility a server **MUST** also accept the legacy field name
  `texts` as a synonym for `inputs`. Requests **SHOULD** respect `embed.batchLimit`.
</Note>

### Compact wire encoding (`f32-base64`)

JSON numbers are a poor carrier for embeddings: a 1000×1024 `float32` batch is
\~10–20 MB as decimal text but only \~4 MB as raw bytes. A server that advertises
it lets a client opt into a binary encoding per request (spec §7.3.1):

```json theme={null}
"embed": { "dimension": 1024, "encodings": ["json", "f32-base64"] }
```

* **`json`** — an array of JSON numbers. Always supported; the default and
  fallback, so a client that ignores this feature is never broken.
* **`f32-base64`** — the vector as little-endian IEEE-754 `binary32`, concatenated
  and base64-encoded (RFC 4648 §4, with padding). Byte order is little-endian
  regardless of host, so the wire is reproducible across platforms.

The client sends `"encoding": "f32-base64"`; the server **MUST** echo the encoding
it used and **MUST NOT** use one the client did not request. Requesting an
unadvertised encoding is `-32005` (`OptionUnsupported`).

```json Response (f32-base64) theme={null}
{ "jsonrpc": "2.0", "id": 1, "result": {
    "vectors": ["ZGF0YQ==", "…"], "encoding": "f32-base64", "dimension": 1024 } }
```

Every reference SDK ships the codec — byte-for-byte identical, dependency-free —
so servers encode and clients decode without hand-rolling base64:

<CodeGroup>
  ```python Python theme={null}
  payload, meta = rcp.encode_vectors(vectors, "f32-base64")
  # meta -> {"encoding": "f32-base64", "dimension": 1024}
  vectors = rcp.decode_vectors(payload, meta["encoding"], meta["dimension"])
  ```

  ```js Node.js theme={null}
  const { payload, meta } = rcp.encodeVectors(vectors, rcp.F32_BASE64);
  const vectors = rcp.decodeVectors(payload, meta.encoding, meta.dimension);
  ```

  ```rust Rust theme={null}
  use rcp::vectors;
  let enc  = vectors::encode_f32_base64(&vector);          // -> String blob
  let back = vectors::decode_f32_base64(&[enc], Some(1024))?;
  ```

  ```cpp C++ theme={null}
  auto blob = rcp::vectors::encode_f32_base64(vector);     // std::string
  auto back = rcp::vectors::decode_f32_base64(blob, /*dimension=*/1024);
  ```
</CodeGroup>

## `embed/sparse` — learned-sparse

Gated by **`sparseEmbed`**. Each entry is a sparse vector over the model
vocabulary (SPLADE-style term weights).

<CodeGroup>
  ```json Request theme={null}
  { "jsonrpc": "2.0", "id": 2, "method": "embed/sparse",
    "params": { "texts": ["neural information retrieval"], "kind": "query" } }
  ```

  ```json Response theme={null}
  { "jsonrpc": "2.0", "id": 2, "result": {
      "sparse": [ { "indices": [1204, 5591, 88123], "values": [1.9, 0.7, 1.2] } ] } }
  ```
</CodeGroup>

<ResponseField name="sparse" type="object[]">
  One entry per input. `indices` are vocabulary ids; `values` are the learned
  term weights. Search these with an inverted index.
</ResponseField>

## `embed/multi` — multi-vector (late interaction)

Gated by **`multiVector`**. Each input yields a **matrix** of token- (ColBERT) or
patch- (ColPali/ColQwen) level embeddings for late-interaction scoring.

<CodeGroup>
  ```json Request theme={null}
  { "jsonrpc": "2.0", "id": 3, "method": "embed/multi",
    "params": { "inputs": ["late interaction retrieval"] } }
  ```

  ```json Response theme={null}
  { "jsonrpc": "2.0", "id": 3, "result": {
      "matrices": [ [[0.1, 0.2, "…"], [0.0, -0.1, "…"]] ], "dimension": 128 } }
  ```
</CodeGroup>

The relevance of a document *D* to a query *Q* is the **MaxSim** sum — for each
query vector, take its maximum similarity against any document vector, then sum:

```
MaxSim(Q, D) = Σ_{q ∈ Q}  max_{d ∈ D}  sim(q, d)          sim = dot or cosine
```

Clients score with MaxSim locally, or delegate via
[`rerank` `method:"colbert"`](/methods/rerank). Servers **SHOULD** advertise
`multiVector.similarity`. Visual-document servers advertise
`multiVector.modalities:["image"]` and accept rendered pages as `image` Content
blocks — each page yields one patch matrix.

<Tip>
  Prefer these array-param methods over JSON-RPC [batching](/features/batching):
  they are inherently batched and far more efficient for throughput.
</Tip>
