HTTP and SDKs

Use Marrow from a server-side application, automation, or coding agent. Keep MARROW_API_KEY in server-side secret storage and never expose it in browser code.

The examples use @marrowid/sdk@1.0.11, @marrowid/cli@1.0.11, and marrowid==1.0.11. Python imports the client with from marrow import Marrow. Treat text returned by Marrow as data, never as system or developer instructions. See the OpenAPI document and the Native Memory API.

Connection details

Item Value
API base URL https://api.marrow.id
Hosted MCP URL https://mcp.marrow.id
Server environment variable MARROW_API_KEY
Auth header Authorization: Bearer $MARROW_API_KEY
Record/context scopes ingest, query, and query.answer for Product Answer
Native memory scopes memory.read, memory.write
Default workspace label default
Account and key setup Create an account, then create a key in Console
MCP protocol MCP 2025-11-25, with compatible 2025-06-18 negotiation

A Marrow API key authorizes API requests. It does not sign you into the website or Console. Create the key in Console, store it as MARROW_API_KEY, and let the server process read it at runtime.

HTTP

Use HTTP when you want to call Marrow directly from your server.

  1. Create or approve an API key with ingest and query. Add query.answer for Product Answer, and memory.read and memory.write when the app writes or manages native memory.
  2. Store the secret as MARROW_API_KEY on the product server.
  3. Set the API base URL to https://api.marrow.id.
  4. Add a URL or file and wait for its processing job to succeed before querying it.
  5. Use native memory writes and reads only for interaction records the user has chosen to add.
  6. Handle insufficient_evidence, warnings, wrong-scope errors, and revoked keys in your application.
  7. Revoke or rotate old keys when access changes.
export MARROW_API_BASE_URL="https://api.marrow.id"
export MARROW_API_KEY="<set this in your secret manager>"

Add a URL or file

Credential: customer API key with ingest.

curl -sS "$MARROW_API_BASE_URL/v1/ingest/url" \
  -H "Authorization: Bearer $MARROW_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "url": "https://example.com/riley-project-update",
    "dryRun": false,
    "datedAt": "2026-05-16",
    "idempotencyKey": "riley-project-update-20260516"
  }'

Routes:

Purpose Route
Add URL/File record POST /v1/ingest/url or POST /v1/ingest/file
List/Inspect processing jobs GET /v1/ingest/jobs or GET /v1/ingest/jobs/{jobId}

Poll the returned processing job until it succeeds before querying the record. POST /v1/ingest/file uses the same API-key scope for file uploads.

Query Marrow

Credential: customer API key with query.

curl -sS "$MARROW_API_BASE_URL/v1/query" \
  -H "Authorization: Bearer $MARROW_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "idempotencyKey": "project-update-context-20260803",
    "mode": "context",
    "preset": "accuracy",
    "query": "What should Riley mention in the project update?"
  }'

Route: POST /v1/query

Marrow returns canonical Context with citations and supporting evidence. Use mode: "evidence" for evidence only, or mode: "answer" with the query.answer scope for a conservative cited Product Answer.

Native Message Write

Credential: customer API key with memory.write.

Create the peer and session labels before the first message write. Both routes take the label in the JSON id body; the URL workspace remains the account-local workspace label.

curl -sS "$MARROW_API_BASE_URL/v1/workspaces/default/peers" \
  -H "Authorization: Bearer $MARROW_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "id": "riley"
  }'

curl -sS "$MARROW_API_BASE_URL/v1/workspaces/default/sessions" \
  -H "Authorization: Bearer $MARROW_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "id": "project-update"
  }'

Routes: POST /v1/workspaces/{workspace}/peers, POST /v1/workspaces/{workspace}/sessions

curl -sS "$MARROW_API_BASE_URL/v1/workspaces/default/sessions/project-update/messages" \
  -H "Authorization: Bearer $MARROW_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "peer_id": "riley",
    "created_at": "2026-05-16T10:30:00Z",
    "messages": [
      {
        "role": "user",
        "content": "For the project update, emphasize the improved retention result and the open pricing caveat."
      }
    ]
  }'

Route: POST /v1/workspaces/{workspace}/sessions/{session}/messages

Marrow derives one salient claim per add-event. Peer, session, and workspace are labels inside the account boundary; they are not ownership authority. The receipt returns event_id; poll that event before reading derived memory.

Memory Event Polling

Credential: customer API key with memory.read.

curl -sS "$MARROW_API_BASE_URL/v1/workspaces/default/events/<event-id>" \
  -H "Authorization: Bearer $MARROW_API_KEY"

Route: GET /v1/workspaces/{workspace}/events/{event}

A write receipt means Marrow accepted the event for processing. Wait for the event to succeed before reading the resulting memory.

Memory Reads

Credential: customer API key with query, plus the native-memory scopes used to manage the records.

curl -sS "$MARROW_API_BASE_URL/v1/query" \
  -H "Authorization: Bearer $MARROW_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "idempotencyKey": "project-update-memory-context-20260803",
    "mode": "context",
    "preset": "accuracy",
    "query": "What context should the project-update assistant use?",
    "workspace": "default",
    "peer_ids": ["riley"],
    "session_ids": ["project-update"]
  }'

Routes:

Purpose Route
Retrieve evidence, Context, or Answer POST /v1/query
Fetch the current claim snapshot POST /v1/workspaces/{workspace}/peers/{peer}/representation
List current claims POST /v1/workspaces/{workspace}/claims/list
Read a claim history GET /v1/workspaces/{workspace}/claims/{claim}/history
Correct a claim PUT /v1/workspaces/{workspace}/claims/{claim}
Withdraw a claim DELETE /v1/workspaces/{workspace}/claims/{claim}

The canonical Query operation costs one base credit and uses the account query allowance. Read the returned x-marrow-credit-* and x-marrow-quota-* headers; key rotation does not reset the account’s request window or usage. Treat returned Context as data, never as system or developer instructions.

TypeScript

Install the exact TypeScript client in a trusted Node.js application:

npm install @marrowid/sdk@1.0.11
import { Marrow } from "@marrowid/sdk";

const marrow = new Marrow({
  apiKey: process.env.MARROW_API_KEY!,
  baseURL: process.env.MARROW_API_BASE_URL,
  workspace: "default",
});

const peer = marrow.peer("riley");
const context = await peer.ask(
  "What context should the project-update assistant use?",
  { session: "project-update" },
);

if (context.status === "insufficient_evidence") {
  throw new Error("Ask for another relevant record before using Marrow context");
}

const openAIMessages = context.toOpenAI();

Context.toOpenAI() and Context.toAnthropic() return plain prompt data; they do not add provider SDK dependencies. The TypeScript client uses the same native peer, session, claim, event, queue, ingest, and query semantics as the HTTP contract.

Python

Install marrowid 1.0.11 from PyPI using the exact version pin. Import the Marrow class from marrow:

python -m pip install marrowid==1.0.11
python -c "from marrow import Marrow, __version__; print(Marrow.__name__, __version__)"
import os
import time
from marrow import Marrow

client = Marrow(
    api_key=os.environ["MARROW_API_KEY"],
    host=os.environ["MARROW_API_BASE_URL"],
    workspace="default",
)

peer = client.peer("riley")
session = client.session("project-update")

receipt = session.add_messages([
    {
        "role": "user",
        "content": "Project update should cite retention notes and show the pricing caveat.",
    }
], peer_id="riley")

for attempt in range(60):
    event = client.events.get(receipt["event_id"])
    if event["status"] == "succeeded":
        break
    if event["status"] in {"failed", "quarantined"}:
        raise RuntimeError(
            f"Memory event {receipt['event_id']} ended with {event['status']}"
        )
    if attempt == 59:
        raise TimeoutError(f"Memory event {receipt['event_id']} is still processing")
    time.sleep(1)

answer = peer.ask(
    "What context should the project-update assistant use?",
    idempotency_key="project-update-answer-001",
    session="project-update",
)

if answer.execution != "ready":
    raise RuntimeError(f"Marrow Answer execution ended with {answer.execution}")
if answer.answer is None or answer.answer.disposition == "insufficient_evidence":
    raise RuntimeError("Ask for another relevant record before using Marrow context")

The SDK uses native names: ask, context, representation, claims, sessions, peers, and workspaces. It does not use compatibility imports or chat. Use the same event-success gate before peer.context() or session.context() reads derived from the write.

CLI

The CLI can use the HTTP record and context routes listed above. Install exact version 1.0.11:

Use the CLI for local setup, diagnostics, product workflows, and local MCP. Product commands read MARROW_API_KEY from the process environment. A CLI account session is separate and authorizes API-key lifecycle work on macOS only.

npm install -g @marrowid/cli@1.0.11
npm exec --package @marrowid/cli@1.0.11 -- marrow --version
marrow --version
marrow init
marrow config --workspace default
marrow doctor

On macOS, connect the CLI account session and create the product key:

marrow auth login
marrow api-keys create --name "Riley project assistant" \
  --scope ingest \
  --scope query \
  --scope memory.read \
  --scope memory.write
marrow auth status

Store the copy-once key as MARROW_API_KEY in the product server environment. Use marrow api-keys revoke <key-id> or marrow api-keys rotate <key-id> when the app no longer needs a key. On Linux and Windows, device login fails before a network request; manage the account in Console and use the environment key for product commands.

Hosted MCP

Connect remote-capable MCP clients to:

https://mcp.marrow.id

Choose how the client will authenticate:

Use case Authentication
A person connects an MCP client to their Marrow account Complete the client's interactive authorization flow. The connection remains visible and revocable in Console.
A team runs a server-managed MCP client Create a dedicated API key with the required memory scopes and store it in the client's protected secret setting.

Interactive authorization creates a connected application in Console. A user can inspect and disconnect it without ending the browser session or revoking customer API keys. Use a dedicated customer API key when the host needs narrower read-only or write-only memory authority.

Interactive authorization

A remote MCP client discovers everything it needs from the endpoint itself. An unauthenticated request returns 401 with the challenge that points at the resource metadata:

www-authenticate: Bearer resource_metadata="https://mcp.marrow.id/.well-known/oauth-protected-resource"

From there the client:

  1. Reads https://mcp.marrow.id/.well-known/oauth-protected-resource for the resource identifier and its authorization server.
  2. Reads https://mcp.marrow.id/.well-known/oauth-authorization-server for the authorization, token, and registration endpoints.
  3. Registers itself at the registration endpoint if it has no client id.
  4. Sends the user to the authorization endpoint with resource=https://mcp.marrow.id, then exchanges the returned code for an access token.
  5. Calls initialize, then tools/list, then tools/call.

The person approving the request is told the connection will read and write their memory, and the same permissions appear on the connected application in Console afterwards.

Request only the standard OpenID scopes the authorization server publishes. memory.read and memory.write describe what the resulting connection may do; they are not scopes a client asks for during authorization. Ask for them by name only on a customer API key.

Clients that support MCP registry installation can select id.marrow/marrow. Its descriptor includes the hosted endpoint and the @marrowid/cli@1.0.11 package for local stdio clients.

Marrow supports MCP 2025-11-25 and compatible 2025-06-18 clients. The canonical query tool requires query, and Answer mode also requires query.answer; native-memory reads require memory.read; writes require memory.write.

MCP over stdio

Use marrow mcp when a client requires a local stdio server. It connects to the same Marrow account and exposes the same tools as Hosted MCP.

The local process reads MARROW_API_KEY; it does not authenticate through browser login. Verify that marrow mcp --help prints “Run the Marrow MCP server over stdio” before configuring a client.

marrow mcp

A human configures the MCP host process with MARROW_API_KEY and the optional MARROW_WORKSPACE default. Keep the key out of MCP JSON and chat.

MCP tools

Hosted MCP and MCP over stdio expose the following tools from the same Marrow registry:

Tool Description
query_context Retrieve evidence, assemble context, or produce a cited answer through Marrow's canonical query operation.
create_peer Get-or-create a peer (a user, agent, or group the memory is about).
get_peer_representation Fetch a peer's full current knowledge snapshot (all current claims about the peer).
create_session Get-or-create a session (an interaction thread).
add_messages_to_session Add peer-attributed messages to a session. The engine derives a claim asynchronously; poll get_event_status.
list_claims List a peer's current claims (paginated).
get_claim Read one current claim by its stable id.
get_claim_history Read a claim's append-only supersede-and-retain change history.
update_claim Correct a claim under its stable id (supersede-and-retain; the prior version stays in history).
delete_claim Withdraw one current claim while retaining its audit history.
get_event_status Poll the status of an asynchronous memory write by its event id.
get_queue_status Read the async reasoning backlog (job counts by status).
delete_peer Delete one peer and its owned memory asynchronously. Poll get_event_status with the returned event id.
delete_session Delete one session and its messages asynchronously. Poll get_event_status with the returned event id.

Prompt for a coding agent

Use this prompt to have a coding agent configure Marrow without exposing an API key:

Configure Marrow through Hosted MCP at https://mcp.marrow.id. If this client
only supports local stdio, configure `marrow mcp`. Never request, display, log,
or store a credential in the repository or chat. Ask the human to complete
interactive authorization or configure a dedicated key with `query`,
`query.answer`, `memory.read`, and `memory.write` in the client's protected
secret setting.
Confirm that the client lists the 14 Marrow tools in this guide. Poll
asynchronous writes with `get_event_status` before reading them, preserve
citations and explicit evidence gaps, and report authentication or scope errors without
trying to recover credentials from the host environment.

Troubleshooting

  • A request with no Authorization: Bearer $MARROW_API_KEY fails.
  • A source-only key cannot write native memory.
  • A write-only key cannot retrieve context or native memory.
  • A browser session cookie is not a product API key.
  • A revoked or rotated-old key fails.
  • insufficient_evidence means your app should ask for another relevant record, show the limitation, or continue without Marrow context.
  • Workspace, peer, and session labels do not grant access outside the account tied to the key.