# Docs for AI agents

Source: https://docs.settlemint.com/docs/api-reference/docs-for-agents
Choose between the llms.txt index, the full corpus, a markdown page, the OpenAPI documents, the MCP endpoint and search, and handle each one's failures.

The documentation site serves every page to software over public, read-only addresses. None of them needs a sign-in.

An agent can read the page index, one page as markdown, all pages in one file, the pages that match a query, or the OpenAPI documents. It can also call a Model Context Protocol server, MCP for short, that serves the documentation pages through tools.

This page covers reading the documentation. To let an agent operate DALP, see [CLI for AI agents](https://docs.settlemint.com/docs/api-reference/cli/ai-agents), whose `dalp --mcp` server runs `dalp` commands against the Platform API, or [Hosted MCP server](https://docs.settlemint.com/docs/api-reference/cli/hosted-mcp), which runs inside a DALP deployment.

The addresses on this page are relative to the documentation host, `https://docs.settlemint.com`. A DALP deployment also serves its own copy of the pages under `/docs` on its hostname. To call your own deployment, keep the path and replace the host. That copy builds these absolute links from the host in its `PUBLIC_URL` environment variable:

- the `llms.txt` and `llms-full.txt` indexes
- the `Source:` line of each markdown page
- the canonical `Link` header of each markdown response
- the canonical and Open Graph tags of each page
- the URLs that MCP `search` and `list_pages` return

The DALP Helm chart sets `PUBLIC_URL` from the hostname that serves the documentation, unless the operator overrides it. [Documentation host](https://docs.settlemint.com/docs/deployment/install/values-secrets#documentation-host) explains how the chart picks it.

Call these addresses from a script or a server-side client. The MCP and search endpoints answer 403 when a request has `Sec-Fetch-Site: cross-site` or an `Origin` header for another origin. They send no cross-origin resource sharing headers, so a page on another origin cannot call them. The 403 body is the plain text `Forbidden`, not JSON-RPC.

## Choose an endpoint [#choose-an-endpoint]

| Your agent has | Call | Returns | Rate limit |
| --- | --- | --- | --- |
| No page in mind | `GET` [`/docs/llms.txt`](https://docs.settlemint.com/docs/llms.txt) or [`/llms.txt`](https://docs.settlemint.com/llms.txt) | A plain text index of every page. It ends with an "Agent endpoints" section that lists the other addresses. | None |
| A large context and wants everything | `GET` [`/docs/llms-full.txt`](https://docs.settlemint.com/docs/llms-full.txt) or [`/llms-full.txt`](https://docs.settlemint.com/llms-full.txt) | Every page as markdown in one plain text file. It is several megabytes. | None |
| The path of one page | `GET /docs/<path>.md`, or `GET /docs/<path>` with `Accept: text/markdown`, for example [`/docs/api-reference/webhooks/consuming.md`](https://docs.settlemint.com/docs/api-reference/webhooks/consuming.md) | The page as markdown | None |
| The API contract | `GET` [`/docs/api-reference/openapi-v2.json`](https://docs.settlemint.com/docs/api-reference/openapi-v2.json) or [`/docs/api-reference/openapi-v1.json`](https://docs.settlemint.com/docs/api-reference/openapi-v1.json) | The OpenAPI document as JSON | None |
| An MCP client | `POST /docs/api/mcp`. A `GET` answers 405. | The tools `list_pages`, `get_page` and `search` | 60 requests per minute |
| Words, not a path | `GET /docs/api/search?query=<terms>`, for example [`/docs/api/search?query=webhook`](https://docs.settlemint.com/docs/api/search?query=webhook) | Matching pages and text fragments as JSON | 300 requests per minute |

A crawl can read the index, then fetch each page with `.md`. The links in the table open the public host.

The OpenAPI documents in the table are the contract built with this documentation. To generate a client for a running deployment, fetch that deployment's own `/api/v2/spec.json`, as [the API reference overview](https://docs.settlemint.com/docs/api-reference) describes.

## Page markdown [#page-markdown]

A page answers as markdown in two ways. Append `.md` to the page path, or send `Accept: text/markdown` to the page URL. The root page `/docs` is the exception: its `.md` address is `/docs/index.md`. Both forms return the same markdown with the same headers.

```bash
DOCS=https://docs.settlemint.com

curl -sSD - "$DOCS/docs/api-reference/webhooks/consuming.md"
curl -sSD - -H 'Accept: text/markdown' "$DOCS/docs/api-reference/webhooks/consuming"
```

Both calls return `200` and a markdown body that starts with a `# Title` line and a `Source:` line with the canonical URL. The headers that matter to a client are:

```http
Content-Type: text/markdown; charset=utf-8
Link: <https://docs.settlemint.com/docs/api-reference/webhooks/consuming>; rel="canonical"
Vary: Accept
Cache-Control: public, max-age=300, s-maxage=900, stale-while-revalidate=3600
```

For the `Accept` form, the types `text/markdown`, `text/x-markdown` and `text/plain` count as markdown. A q-value is the weight from 0 to 1 that a client gives a type, and 1 is the default. Markdown wins when the highest q-value among the markdown types is greater than 0 and at least the highest q-value among `text/html`, `text/*` and `*/*`. A request with no `Accept` header, or with `*/*` alone, returns the HTML page.

An HTML response for a page that has a markdown form includes `Link: </docs/<path>.md>; rel="alternate"; type="text/markdown"`, which points an agent to that form. An unknown page has no markdown form, so its HTML response has no such header.

The two forms differ only when a page has no markdown form:

| Page state | `.md` suffix | `Accept: text/markdown` alone |
| --- | --- | --- |
| Page at its present path | 200 markdown | 200 markdown |
| Moved, so the old path redirects | 301 to the new `.md` path | 406 JSON |
| Unknown | 404 markdown | 406 JSON |
| API explorer, such as `/docs/api-reference/v2` | 200 markdown | 200 markdown |

The 404 body for an unknown page reads:

```markdown
# Page not found

No markdown page exists at /docs/no/such/page. The index at /docs/llms.txt lists every page.
```

The 406 body is `{"error":"Only HTML requests are supported here"}`. To get the HTML answer instead, add the HTML type to the header: `Accept: text/markdown, text/html;q=0.9`. A moved page then answers 301 to its new HTML path, and an unknown path answers 404 HTML.

## MCP endpoint [#mcp-endpoint]

`POST /docs/api/mcp` is a Model Context Protocol server over streamable HTTP, which lets the server answer a request with an event stream. Requests and replies use JSON-RPC, a JSON message format for remote procedure calls. The public site serves the endpoint at `https://docs.settlemint.com/docs/api/mcp`. Each request stands alone: there is no session.

This section describes requests in the protocol revisions up to 2025-11-25, which have no `_meta` envelope. The `MCP-Protocol-Version` header is optional for them. A request that names an older revision the server does not support gets 400, and the error message lists the supported older revisions. Revision 2026-07-28 uses a different request format, with its own headers and a `_meta` envelope in `params`. This page does not describe it. A request in that format that breaks its rules gets 400 with a JSON-RPC error code.

A request needs three things:

- `Content-Type: application/json`. Another type gets 415.
- An `Accept` header that lists both `application/json` and `text/event-stream`. `*/*` does not count, and a request without both gets 406.
- The `POST` method. `GET` and `DELETE` answer 405.

`tools/call` works without an earlier `initialize` call. This request uses the `DOCS` variable from [Page markdown](https://docs.settlemint.com/docs/api-reference/docs-for-agents#page-markdown) and asks for a page that does not exist:

```bash
curl -sS -X POST "$DOCS/docs/api/mcp" \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call",
"params":{"name":"get_page","arguments":{"url":"/docs/no/such/page"}}}'
```

The reply is an event stream with one message, and the response sends `Cache-Control: no-cache, no-transform`:

```text
event: message
data: {"result":{"content":[{"type":"text","text":"page not found: /docs/no/such/page"}],"isError":true},"jsonrpc":"2.0","id":1}
```

The server offers three tools. Send `tools/list` for the exact input schemas.

| Tool | Arguments | Notes |
| --- | --- | --- |
| `list_pages` | None | The page index, with a `.md` URL for each page. |
| `get_page` | `url` | The page as markdown, starting with a `# Title` line and a `Source:` line. `url` is a `/docs/...` path, or a full URL on the origin in `PUBLIC_URL`, with or without `.md`. A `/docs/...` path works whichever host `PUBLIC_URL` names. |
| `search` | `query`, optional `locale` | Up to 60 matching records as JSON text. See [Search endpoint](https://docs.settlemint.com/docs/api-reference/docs-for-agents#search-endpoint). |

`get_page` reports a problem in the result, not in the HTTP status, which stays 200 with `isError` set to `true`. A missing page gives the text `page not found: <input>`. The same result comes back for a URL on another host, a moved page and an API explorer page, because `get_page` reads only documentation pages at their present path, and an API explorer page is not one of them. Read an API explorer page with `.md`.

A missing or mistyped argument gives `Input validation error: ...` with the same `isError`.

A request for a tool that does not exist returns a JSON-RPC `error` object with code `-32602` in place of `result`. A body that is not valid JSON gets 400.

## Search endpoint [#search-endpoint]

`GET /docs/api/search?query=<terms>` matches page titles, descriptions, headings and body text, and returns a JSON array.

A page whose title holds every searched word comes before a page that only mentions them. Title words match whole and ignore case and accents, without stemming. The last word may be half typed, from two letters. Only the first 201 records the engine finds are reordered.

Each matched page gives one record for the page and up to eight records for text fragments on it. Every record has `id`, `type`, `content` and `url`. A page record has `type` set to `page`, the page title in `content` and a `breadcrumbs` list. A fragment record has `type` set to `heading` or `text` and a `url` that usually ends in an anchor. A `heading` record has the heading text in `content`. A `text` record has the text fragment in `content`. A `text` record that comes from a table row holds the header row and that row as a markdown table in `content`, and has a `table` key that names the table. This request uses the `DOCS` variable from Page markdown, holds the search to one section and raises the cap:

```bash
curl -sSD - "$DOCS/docs/api/search?query=retries&tag=api-reference&limit=100"
```

The reply sends `X-Docs-Search-Limit: 100` and an `X-Docs-Search-Truncated` header, and its body is an array of records. This is one page record from such a reply:

```json
{
  "id": "/docs/api-reference/webhooks/consuming",
  "type": "page",
  "content": "Consuming events",
  "breadcrumbs": ["Documentation", "API reference", "Webhooks"],
  "url": "/docs/api-reference/webhooks/consuming"
}
```

| Parameter | Effect |
| --- | --- |
| `query` | The terms to match. A missing or empty `query` returns 200 and `[]`. |
| `tag` | Holds the search to one section: `overview`, `getting-started`, `platform`, `console`, `concepts`, `deployment`, `api-reference`, `changelog` or `business`. `overview` holds the root page `/docs`, and `business` holds the privacy policy. `tag` takes one value. A list such as `&tag=a,b`, or an unknown value, returns `[]`. |
| `limit` | The maximum number of records, not pages. The default is 60. A value that is not a whole number of 1 or more falls back to 60, and a value over 200 becomes 200. |

Every 200 response reports the cap it applied in `X-Docs-Search-Limit`. `X-Docs-Search-Truncated: true` means more records exist: raise `limit` up to 200, then narrow the query or add `tag`. `false` does not prove the array holds every match, because a page contributes at most eight fragments. The endpoint has no offset, page or cursor parameter. Send only `query`, `tag` and `limit`: a search with a `query` and `mode=vector` answers 500, because the index holds no embeddings.

Three groups of error pages are not in the search index: the error index at `/docs/api-reference/errors`, and the two error references at `/docs/api-reference/errors/error-code-reference` and `/docs/api-reference/errors/platform-api-error-reference` with every code-range page under them. Find them through `llms.txt`, or open the error index and follow the link for the code's range.

The MCP `search` tool takes `query` and `locale`, and ignores `locale`. It has no `tag` and no `limit`: it returns at most 60 records, with a page whose title holds every searched word ahead of a page that only mentions them. Nothing in the reply says whether more records exist, so use the HTTP endpoint when you need to know whether the result was cut, or need more than 60 records.

MCP `search` records have full page URLs on the `PUBLIC_URL` host, such as `https://docs.settlemint.com/docs/api-reference/webhooks/consuming`, while `list_pages` returns `.md` URLs. `get_page` accepts both.

## Limits and freshness [#limits-and-freshness]

The MCP endpoint allows 60 requests per minute for each client, and search allows 300. Both budgets count HTTP requests, not tool calls. The `initialize` and `tools/list` calls each use one request, and so does a `GET` that gets 405. A client over its budget gets status 429, the plain text body `Too many requests` and a `Retry-After` header in seconds. The 429 body is not JSON-RPC. The `Retry-After` value depends on the cause:

| `Retry-After` | Cause |
| --- | --- |
| Seconds until the client's window resets | The client used its own budget. |
| 60 | The server already tracks 10,000 clients and cannot add another. |
| 1 | The Redis store that all instances share is configured but unreachable. Every caller gets 429, whatever its own rate. |

The server counts a client by the address that a configured trusted proxy forwards. A deployment with no trusted proxy configured counts every caller as one client, and all callers share one budget. A request whose forwarded address is missing or invalid also counts against that shared budget. The default install sets `DOCS_CHAT_TRUSTED_PROXY`, the setting that names the trusted proxy for these budgets and for the docs chat, to `none`, as [Ask AI provider key](https://docs.settlemint.com/docs/deployment/install/values-secrets#ask-ai-provider-key) in the install values reference describes. A 429 can then come from other callers' traffic: wait for `Retry-After` before you send again. On a deployment behind Cloudflare that sets `DOCS_CHAT_TRUSTED_PROXY` to `envoy`, the server counts each caller by the address Cloudflare adds to `X-Forwarded-For` when the operator has configured Envoy Gateway as [Count readers separately behind Cloudflare](https://docs.settlemint.com/docs/deployment/install/values-secrets#count-readers-separately-behind-cloudflare) describes. Otherwise callers that arrive through the same Cloudflare address share a budget. A deployment that has no Redis store keeps a separate budget on each server instance.

Three kinds of `200` response send `Cache-Control: public, max-age=300, s-maxage=900, stale-while-revalidate=3600`: markdown pages in either form, the `llms.txt` and `llms-full.txt` files at both the `/docs/...` path and the root path, and the two OpenAPI JSON files. Error responses, redirects and search replies send none, and MCP event-stream replies send `Cache-Control: no-cache, no-transform`. A browser or agent can reuse a response for 5 minutes. A shared cache holds it fresh for 15 minutes and can serve it for up to 60 more minutes while it fetches a new copy, so an answer can be 75 minutes behind the server.

The server builds `llms-full.txt` on the first request after it starts and reuses that text until it restarts, so the first request takes longer than the ones after it.

## When a request fails [#when-a-request-fails]

Every endpoint on this page only reads, so any request is safe to send again. Retry a `429` after its delay, and retry a `5xx` or a timeout with your own backoff. Fix the request and resend for `400`, `403`, `405`, `406` and `415`. Do not retry a `404` or an `isError` result with the same input. A search with a `query` and `mode=vector` answers `500` every time, so remove `mode` instead of retrying.

| Symptom | Cause and fix |
| --- | --- |
| `.md` answers 404 with "Page not found" | No page exists at that path. Look the path up in `llms.txt`. |
| `Accept: text/markdown` answers 406 with `{"error":"Only HTML requests are supported here"}` | The page has no markdown form: it is moved or unknown. Add `text/html;q=0.9` to the header to see which: 301 is moved and 404 HTML is unknown. |
| `.md` answers 301 | The page moved. Follow `Location`. |
| MCP answers 415 | The `Content-Type` is not `application/json`. |
| MCP answers 406 | `Accept` lacks `application/json` or `text/event-stream`, or is `*/*`. |
| MCP answers 405 | The request used `GET` or `DELETE`. Use `POST`. |
| MCP answers 400 | The body is not valid JSON, is JSON that is not a JSON-RPC message, the `MCP-Protocol-Version` header names an unsupported revision, or a 2026-07-28 request breaks that revision's rules. |
| MCP or search answers 403 | The request came from another site: it has an `Origin` header for another origin or `Sec-Fetch-Site: cross-site`. Call from a server-side client. |
| MCP result has `isError: true` and `page not found` | The page is missing, moved, on another host or an API explorer page. Check the path in `llms.txt`, and read a moved page or an API explorer page with `.md`. |
| MCP result has `isError: true` and `Input validation error` | An argument is missing or has the wrong type. Match the tool definition from `tools/list`. |
| MCP answers a JSON-RPC error `-32602` | The tool name is wrong or missing or `arguments` is not an object. Send `tools/list`. |
| Search answers 500 | The request has a `query` and `mode=vector`, and the index holds no embeddings. Remove `mode`. |
| Search returns `[]` for `tag=a,b`, an unknown tag or an empty `query` | `tag` takes one value from the list in [Search endpoint](https://docs.settlemint.com/docs/api-reference/docs-for-agents#search-endpoint). `query` is required. |
| The error index, an error reference or a code-range page is missing from search | Those pages are not indexed. Use `llms.txt`, or open `/docs/api-reference/errors` and follow the link for the code's range. |
| MCP or search answers 429 | Wait for `Retry-After`. See [Limits and freshness](https://docs.settlemint.com/docs/api-reference/docs-for-agents#limits-and-freshness). |
| A new page is missing from a cached response | A shared cache can be 75 minutes behind. See [Limits and freshness](https://docs.settlemint.com/docs/api-reference/docs-for-agents#limits-and-freshness). |

## Related [#related]

- [CLI for AI agents](https://docs.settlemint.com/docs/api-reference/cli/ai-agents): run the `dalp` client from an agent.
- [API explorer](https://docs.settlemint.com/docs/api-reference/v2): browse the v2 OpenAPI contract.
- [API reference overview](https://docs.settlemint.com/docs/api-reference): authenticate and integrate the Platform API.
