Developers

Build on what Breno keeps.

Your knowledge stays with you, and so does the way in: the same access rules as the app, one token for the API and for MCP, and an export you can read without us.

  • REST and MCP
  • Go and TypeScript
  • Scoped, revocable tokens
export BRENO=https://<your-breno-host>/api/v1   # your instance
export TOKEN=sirmx_mcp_…                        # from Connect AI

curl -s -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"question":"What did we decide about the Q3 launch?"}' \
  "$BRENO/search/ask"

Quick start

Three steps from nothing to a first answer. A token belongs to you in one workspace and sees exactly what you can see.

  1. Create a token. In Breno open Connect AI, name the token, choose its scopes and expiry, and copy it. It starts with sirmx_mcp_ and is shown once.
  2. Send it as a bearer token. The same token works on the REST API and on the MCP endpoint. Revoke it and it stops at once.
  3. Search, then ask. Search returns passages and calls no model. Ask returns an answer with citations.
Search, then ask
export BRENO=https://<your-breno-host>/api/v1
export TOKEN=sirmx_mcp_…

# Search without generating an answer (scope: read)
curl -s -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"query":"data retention policy"}' "$BRENO/search/query"

# Ask, with citations (scope: ask)
curl -s -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"question":"What did we decide about the Q3 launch?"}' "$BRENO/search/ask"

Authentication

Every request carries a personal token as a bearer token. A token has one or more scopes, chosen when it is created, and a call outside them returns 403 INSUFFICIENT_SCOPE.

Every request
Authorization: Bearer sirmx_mcp_…
ScopeAllows
readListing and reading items, passage search, listing connectors and connected sources.
askAnswers with citations, including the streamed form. These spend coins.
exportJSON and ZIP exports, and asynchronous export jobs and their download.
writeUpload, link capture, and editing notes the token’s owner created.

Everything else (deleting, sharing, members, settings, token management) refuses a token with 403 SESSION_REQUIRED, so a leaked token cannot administer your workspace.

Ask

POST /search/ask answers from your own material, with numbered citations. When the evidence is not there, insufficient_evidence is true and the answer says so. Asking spends coins; a workspace with none returns 402.

Ask, then read the sources
curl -s -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"question":"What is our refund policy?"}' "$BRENO/search/ask" \
  | jq '.data | {answer, confidence, sources: [.evidence[] | {title, url: .source.url}]}'
Answer fieldMeaning
answerThe text, with numbered markers.
evidenceThe cited passages, each with its item and provenance.
confidenceHow strongly the evidence supports the answer.
insufficient_evidenceTrue when the knowledge did not support an answer.
suggestionsFollow-up questions.

GET /search/ask/stream returns the same answer as server-sent events: chunk events as it is written, then one done event.

Capture and edit

These need the write scope; each is recorded in the audit log with the token’s id. Send an Idempotency-Key on upload and capture, so a retry after a timeout cannot create two items.

curl -s -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"url":"https://example.com/article","visibility":"workspace"}' \
  "$BRENO/documents/capture"

Capture returns 202 with a document_id, a job_id and duplicate: when it is true the link was already captured. With a token you can edit only notes your account created.

Export

Your knowledge can always leave. Small sets come back at once; everything, or more than 500 items, runs as a background job you download when it finishes. The archive is Markdown, JSONL, the original files and checksums, and you can read it without Breno.

Export as a ZIP
# up to 500 items, synchronously (scope: export)
curl -s -X POST -H "Authorization: Bearer $TOKEN" -o breno-export.zip "$BRENO/knowledge/export/zip"

The format is documented member by member in Export format.

MCP server

Any MCP client can search, read, ask, export and capture under the same access rule as the app. The server is Streamable HTTP at /mcp on your Breno host; give your client the URL and the token.

A remote MCP client's server entry
{
  "url": "https://<your-breno-host>/mcp",
  "headers": { "Authorization": "Bearer sirmx_mcp_…" }
}

A client that can only start a local program uses the CLI bridge instead:

A stdio client's server entry
{
  "mcpServers": {
    "breno": {
      "command": "brainers",
      "args": ["serve", "mcp"],
      "env": { "BRENO_MCP_TOKEN": "sirmx_mcp_…" }
    }
  }
}

The nine tools

ToolScopeWhat it does
searchreadRanked results, one per item, each with its best passage. No coins.
fetchreadOne item in full, with provenance.
list_documentsreadItems newest first, filtered and paged.
read_documentreadAn item’s summary and extracted content.
list_sourcesreadConnected sources with sync state.
ask_knowledgeaskAn answer with confidence and citations. Spends coins.
export_knowledgeexportWhat this token can read, in the portable format.
capture_notewriteSaves a note, and reports duplicates.
capture_urlwriteSaves a link, and Breno reads it in the background.

For a plain lookup use search then fetch: neither spends coins.

SDKs and CLI

Go and TypeScript clients cover the public API, with paging helpers and typed errors. The CLI’s serve mcp bridges stdio clients to your workspace. They live in the Breno repository and are not published to a package registry, so check the repository for how to add them to your project.

import { BrenoClient, RateLimitError } from '@brainers/sdk-ts';

const breno = new BrenoClient({
  baseUrl: 'https://<your-breno-host>',
  token: process.env.BRENO_TOKEN!,
});

for await (const doc of breno.iterateDocuments({ owner: 'me' })) console.log(doc.title);

await breno.captureNote('Standup 8 Oct', '- shipped the REST API');

Without an SDK the API is plain HTTP and JSON, so any language works.

Errors and limits

Responses use one envelope: { "success": true, "data": … } or { "success": false, "error": { "code", "message" } }.

StatusCodeWhat to do
401INVALID_TOKENUnknown, expired or revoked. Create a new token.
402noneOut of coins (ask). Top up, or use search, which is free.
403INSUFFICIENT_SCOPEdetails.required_scope names the scope the token lacks.
403SESSION_REQUIREDNot part of the public API.
404NOT_FOUNDNo such item, or one you cannot read; the two look the same on purpose.
422SOURCE_UNSUPPORTEDA link Breno cannot read. Nothing was saved.
429RATE_LIMIT_EXCEEDEDWait for Retry-After seconds.

Limits are 120 requests a minute per token and 300 per IP address for token traffic. Page instead of polling, back off on 429 and 5xx with a little jitter, and prefer search to ask for lookups.

A rate-limited response
HTTP/1.1 429 Too Many Requests
Retry-After: 12

Reference

The full contract is the OpenAPI document, and a test fails if the router, the token allowlist and the spec disagree. Stuck on something? Use the Ask Breno button at the bottom right, or write to us.