Brain MCP server

Mount the workspace brain as tools in Claude Code, Cursor, or your own agent.

Your Alfera workspace brain, mounted as tools in the agent you already use — Claude Code, Cursor, or your own harness. Point it at one URL and it can do the two things the brain offers: get facts, or get an answer from the worker.

https://api.alfera.ai/v1/mcp
  • Facts for your own prompt: get_memory_context returns the rendered block the worker gets each turn, inside a token budget. search_memory returns the individual facts as data.
  • An answer from the worker: ask_worker, then wait_for_answer if the wait runs out.
  • Streamable HTTP, stateless: no session to open, resume, or close. Every request carries its own key, so restarting your client or load-balancing across instances changes nothing.
  • The server speaks MCP 2025-06-18 and accepts 2025-03-26 and 2024-11-05.
  • Same brain, same keys, and the same disclosure rules as the Brain API.

Connect

Create a key in the app under Settings → API Keys, pick its scopes and audience, and export the secret:

export ALFERA_API_KEY=ak_live_...

Claude Code

claude mcp add --transport http alfera-brain https://api.alfera.ai/v1/mcp \
  --header "Authorization: Bearer $ALFERA_API_KEY"

Cursor — add the server to ~/.cursor/mcp.json (global) or .cursor/mcp.json (one project):

{
  "mcpServers": {
    "alfera-brain": { "url": "https://api.alfera.ai/v1/mcp", "headers": { "Authorization": "Bearer ak_live_..." } }
  }
}

Anything else that speaks Streamable HTTP: POST JSON-RPC to https://api.alfera.ai/v1/mcp with Authorization: Bearer <key> on every request. X-Api-Key: <key> is accepted as well. The endpoint is POST-only, so GET and DELETE answer 405 method_not_allowed.

Verify with whoami

whoami needs no scope, so it answers for any live key and reports what the connection can do.

curl https://api.alfera.ai/v1/mcp \
  -H "Authorization: Bearer $ALFERA_API_KEY" -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"whoami","arguments":{}}}'
{
  "key_name": "support-bot",
  "key_prefix": "ak_live_x7f4",
  "scopes": ["memory.read", "answers.write"],
  "key_audience": "external",
  "rate_limit": { "requests_per_window": 120, "window_seconds": 60 }
}

tools/list only advertises what this key's scopes allow. A memory.read-only key never sees ask_worker, so a tool missing from your agent's list means the key lacks its scope.

Tools

ToolWhat it doesRequired scope
whoamiReports this connection's key name, prefix, scopes, audience, and rate limit. Call it first.none
search_memorySearches the workspace brain and returns matching facts, most relevant first. Name the end_user to also reach that person's own facts.memory.read
get_memory_contextBuilds the rendered memory context packet for a query — the same block the worker gets each turn — inside a token budget, for pasting into your own prompt.memory.read
teach_memoryTeaches the workspace brain new facts. Each runs through the normal capture pipeline; repeats of something already known are skipped.memory.write
ask_workerAsks the workspace worker a question and waits up to timeout_seconds. Returns {wait_timed_out, answer_id} if time runs out.answers.write
wait_for_answerKeeps waiting for an answer started earlier, by answer_id.answers.write
ToolArguments
whoaminone
search_memoryquery (1–2000), limit (1–100, default 20), end_user {id, name?}
get_memory_contextquery (1–2000), token_budget (100–20000, default 1500), end_user {id, name?}
teach_memoryfacts: 1–20 of {text} (up to 4000 characters each)
ask_workerinput (1–8000), conversation_id, end_user, agent_slug, timeout_seconds (0–120, default 60), idempotency_key (1–200)
wait_for_answeranswer_id, timeout_seconds (0–120, default 60)
  • Each tool takes exactly the arguments its REST counterpart takes as a body and returns exactly what that route returns. search_memory is POST /v1/memory/search, get_memory_context is POST /v1/memory/context, teach_memory is POST /v1/memory/facts. ask_worker is the queued POST /v1/answers plus the wait; wait_for_answer is GET /v1/answers/:answer_id plus the wait. Field-level detail is in the Brain API reference.
  • Disclosure rules are the REST ones, unchanged: an external key receives only profile_fact, preference, decision, and observation, and never facts about your team, agent_inferred facts, or facts about an end user the call did not name. Full list: what external keys can never see.

Waiting for an answer

ask_worker queues the question and waits up to timeout_seconds. Answers take seconds to minutes, so long ones outlast the wait. When that happens you get a result, not an error:

{ "wait_timed_out": true, "answer_id": "event_01k9p3zq8w4m1te6h2ndkbx9pf" }
  • Call wait_for_answer with that answer_id{"answer_id": "event_01k9p3zq8w4m1te6h2ndkbx9pf", "timeout_seconds": 120} — to keep waiting. Each call is a fresh bounded wait, and the answer keeps running the whole time. Repeat as often as needed; do not raise your client's transport timeout instead.
  • Always send idempotency_key. Re-calling ask_worker after a timeout without the same key is a new question and a second run: double the cost, two answers, and the conversation lock making them queue behind each other. The same key with the same arguments returns the same answer_id and starts nothing; the same key with a different question is refused as idempotency_key_reused.
  • timeout_seconds: 0 skips the wait and returns the answer_id straight away.

A finished answer comes back whole. Both answer tools always include sources.

{
  "answer_id": "event_01k9p3zq8w4m1te6h2ndkbx9pf",
  "status": "completed",
  "output_text": "She can move it without losing the deposit, as long as the change lands more than 30 days before the current date.",
  "conversation_id": "support-ticket-9931",
  "usage": { "input_tokens": 2841, "output_tokens": 96 },
  "sources": [
    { "fact_id": "fact_01k9p3v8m7f2ha6z0qc4rjxn5w", "fact_text": "Deposits are non-refundable inside 30 days of the event date.", "kind": "decision", "subject": "refund policy" }
  ]
}

Errors

  • Credential problems are plain HTTP. A bad, revoked, or expired key fails the request itself with 401, before any tool runs: {"error":{"code":"api_key_revoked","message":"This API key was revoked"}}. Going over 120 requests in a 60-second window fails the same way with 429 rate_limited. The limit is per key, so give each client its own.
  • Everything a tool decides comes back as a readable tool result, with isError: true and a JSON body your agent can act on: {"error":"scope_missing","message":"This API key is missing the 'memory.write' scope","http_status":403}.
  • An unknown method or an unknown tool name comes back as a JSON-RPC error (-32601 and -32602), because the request never reached a tool.
errorMeaning and fix
scope_missingThis key lacks the scope the tool needs. Scopes are fixed at creation, so create a key that has it in Settings → API Keys.
out_of_creditsThe workspace balance hit zero. Add credits or upgrade the plan; nothing runs until you do.
conversation_busyThat conversation_id is still answering the previous message. Wait, or use a different one.
validation_errorThe arguments did not match the tool's schema. The message names the offending fields.
not_foundNo answer with that answer_id in this workspace.
internal_errorOur side. Retry; if it persists, send us the timestamp.

Your next hire is an AI worker.

Get early access to Alfera and put cloud agents to work across your company today.