Personal access keys
A personal access key (PAK) lets you use MemHub from your own code — an agent you're building, a script, an IDE assistant — without logging in through the browser each time. It authenticates as you, so everything it does happens in your workspace and under your name.
Keys look like mhk_…. You mint, list, and revoke them with the API calls below —
a point-and-click Settings → Developer → Access keys page is on the way.
When to use one
- You're building an agent that should search or write your team's memory in its own loop (via the MCP server or the REST API).
- You're wiring MemHub into a tool that can't do an interactive login — a CI job, a server, a coding assistant.
A key is a seat, not a bulk credential: it runs at roughly one person's throughput. If you need to serve many end-users at high volume, that's the Memory API (a separate product with its own keys), not a personal key.
MemHub vs. the Memory API
A personal key reads and writes MemHub's own team memory — the brains, facts,
and artifacts you see in the app — over the MCP server or the REST API below. It
can also mint and manage your Memory API keys. But it is not itself a
credential for the Memory API's data: reading that product's stored memories
uses an xtk_ API key, not your mhk_ key. Pointing a control-plane token at the
data plane would blur the line between the two products, so that door is closed on
purpose.
Create a key
Mint a key with one API call, authenticated with your MemHub login
($MEMHUB_JWT — the bearer token from your signed-in session):
curl -X POST https://api.memhub.xtrace.ai/v1/developer/access-tokens \
-H "Authorization: Bearer $MEMHUB_JWT" \
-H "Content-Type: application/json" \
-d '{"label": "research-agent", "scopes": ["memory:read", "memory:write"]}'
# → { "secret": "mhk_…" } — shown once; copy it now
-
Label each key (
laptop,ci,research-agent) so you can tell them apart. -
Pass
"scopes": ["memory:read"]for a read-only key (see Scopes),"default_org_id"to pin it to one org, or"expires_at"to set an expiry. -
The secret is returned once — store it in a secret manager or an env var:
export MEMHUB_API_KEY="mhk_…"
You can hold up to 5 keys at a time. Minting requires a real login — a key can't mint another key.
Use a key
Full endpoint list: the PAK API reference documents every MCP tool and REST endpoint a key can call, with request/response shapes.
With an MCP client (recommended)
Point any MCP client — Claude Code, Cursor, the Claude Agent SDK, LangChain, etc. — at MemHub with the key as a bearer header:
{
"mcpServers": {
"memhub": {
"url": "https://api.memhub.xtrace.ai/mcp-server/mcp",
"headers": { "Authorization": "Bearer ${MEMHUB_API_KEY}" }
}
}
}
If your tool can only launch a local (stdio) MCP process, bridge to the hosted endpoint:
npx mcp-remote https://api.memhub.xtrace.ai/mcp-server/mcp \
--header "Authorization: Bearer $MEMHUB_API_KEY"
From plain HTTP
The MCP endpoint is JSON-RPC over HTTP, so any language can call it. Two things to
get right: send both Accept media types, and put the tool name/args under
params.
curl -sX POST https://api.memhub.xtrace.ai/mcp-server/mcp \
-H "Authorization: Bearer $MEMHUB_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call",
"params":{"name":"search_memory","arguments":{"query":"onboarding decisions"}}}'
Over the REST API
Prefer plain REST to the MCP protocol? The same key works directly against MemHub's team-memory API — search, read, and write your team's facts, artifacts, and brains:
# search your team's facts
curl -sX POST https://api.memhub.xtrace.ai/v1/team/facts/search \
-H "Authorization: Bearer $MEMHUB_API_KEY" \
-H "X-Org-Id: <your-org-id>" \
-H "Content-Type: application/json" \
-d '{"query": "onboarding decisions"}'
Available today: /v1/team/facts, /v1/team/artifacts, and /v1/team/cbs
(brains) — GET to list, POST …/search to search (both need memory:read);
create / update / delete need memory:write. Same seat throughput and scopes as
the MCP tools. Pass X-Org-Id to choose an org, or pin the key to one when you
mint it.
In an agent loop
The payoff is the loop: search shared memory before answering, write new memory after. With the Anthropic SDK, hand the model the MCP server and it calls the tools itself:
import os
from anthropic import Anthropic
client = Anthropic()
resp = client.beta.messages.create(
model="claude-opus-4-8",
max_tokens=1024,
messages=[{"role": "user", "content": "What did we decide about billing?"}],
mcp_servers=[{
"type": "url",
"url": "https://api.memhub.xtrace.ai/mcp-server/mcp",
"name": "memhub",
"authorization_token": os.environ["MEMHUB_API_KEY"],
}],
betas=["mcp-client-2025-04-04"],
)
print(resp.content)
Scopes
Keys carry a coarse scope so you can limit a key's blast radius:
| Scope | Can |
|---|---|
memory:read | search memory (read-only) |
memory:write | read and write memory, and manage developer API keys |
A new key gets both by default. Choose read-only when a key only needs to
search: the write gate is enforced everywhere — the MCP write tools and the
REST write endpoints both reject a memory:read-only key — so a leaked read-only
key can search but can't change anything or touch your API keys.
Rate limits
A key runs at one seat's throughput, and your whole org is capped at your
purchased seats' worth. If you go too fast you'll get 429 Too Many Requests
with a Retry-After header — back off for that many seconds and retry. This is a
product boundary, not a performance limit: a single agent working at human pace
won't hit it.
Rotate a key
To rotate without downtime: create a new key, deploy it, then revoke the old one. Because you can hold several keys at once, the old one keeps working until you remove it — no gap.
Revoke a key
List your keys with GET /v1/developer/access-tokens, then revoke one by id:
curl -X DELETE https://api.memhub.xtrace.ai/v1/developer/access-tokens/<token-id> \
-H "Authorization: Bearer $MEMHUB_JWT"
Revocation takes effect within about a minute across the MCP server and the API. Revoke a key the moment a laptop or environment it lived on is gone. (A Settings page for this is on the way.)
Good to know
- A key is tied to you. If you leave the org, your keys stop working — so shared automation should run on a dedicated account, not a personal key.
- A key can't create another key — minting keys always requires a real login. It also can't touch org settings, billing, or other people's data.
- Keys are stored hashed; MemHub never sees your secret again after you copy it, which is why a lost secret means minting a new key, not recovering the old.