MCP server
Tools
Four tools. None of them takes an identity: who you are comes from the token, and the server refuses at startup to register any tool whose schema says otherwise.
Which tools a connection sees depends on its scopes, its kind and its endpoint. A tool the token lacks the scope for is still listed, so the client can ask for it; calling it returns a scope challenge (see Authentication). On /mcp/readonly the write tool is not listed at all. Agents do not see memory_receipt.
memory_search
Search the memory this caller is allowed to see and return the matching fragments with their provenance and a receipt id. Needs memory.read.
| Field | Type | Meaning |
|---|---|---|
| query* | string | What to look for, in natural language. 1–2000 characters. |
| limit | integer | Maximum fragments to return, 1–50. Default 10. |
| as_of | date-time | Read the memory as it stood at this instant. |
| created_after | date-time | Only fragments whose source was created after this instant. |
| created_before | date-time | Only fragments whose source was created before this instant. |
| resource_ids | string[] | Only fragments about these documents. Up to 32. |
| agents | string[] | Narrow to fragments contributed by these agents. Never widens visibility. Up to 16. A caller that is itself an agent must name its sources here to read memory that came from a connected source. |
| task | string | What the caller is doing, e.g. "incident response". The result is arranged for this task when the judgment plane is on; ignored otherwise. Up to 200 characters. |
| task_tags | string[] | Extra hints about the task. Arranges the result; never widens visibility. Up to 8. |
| Field | Type | Meaning |
|---|---|---|
| fragments | Fragment[] | Matches in rank order. Each carries id, value, confidence, grounding_status, created_at, agents, resources, an optional score, and value_truncated when the text was clipped to the 4 KiB per-fragment budget. |
| receipt_id | string | The serving receipt for this read. Pass it to memory_receipt later. |
| as_of | date-time | The instant the read was evaluated at. |
| abstained | boolean | True when memory declined to answer rather than guess; abstain_reason says why. |
| truncated | boolean | True when trailing fragments were dropped to keep the whole result inside 128 KiB. |
| notice | string | A plain-language note when there is one: nothing matched, or no memory is visible to this caller yet. |
An empty result is a successful result, not an error; the notice tells the two cases apart.
memory_write
Store a fact from this conversation as the caller’s private memory, and report what the memory layer did with it. Needs memory.write. Not on the read-only endpoint.
| Field | Type | Meaning |
|---|---|---|
| content* | string | The fact to remember, in plain language. Up to 32 KiB. |
| session_id | string | Conversation this fact came from. Up to 128 characters. |
| resource | string | Source document behind the fact, if any. Up to 512 characters. |
| idempotency_key | string | Supply to make retries safe. Derived automatically from the whole payload when absent; reusing a key with a different payload is refused for 24 hours. |
| Field | Type | Meaning |
|---|---|---|
| outcome | string | One line saying what happened: stored, merged into an existing fragment, superseded one, or dropped. |
| results | Result[] | One entry per candidate fact: operation, fragment_id, superseded_fragment_id, and a reason with its explanation when it was not stored (for example privacy_drop or policy_drop). |
| review_state | string | For agent callers: the write was parked as a proposal awaiting a person's approval. |
| dropped | integer | How many candidates were not stored, with drop_reasons alongside. |
A dropped write is reported as a result the assistant can read and act on, not as a protocol error. Writes are always private to the caller; nothing written here becomes visible to anyone else.
memory_receipt
Reopen one of the caller’s own read receipts and show what it served then, what the same read serves now, and the difference. Needs memory.audit. People only.
| Field | Type | Meaning |
|---|---|---|
| receipt_id* | string | A receipt id returned by memory_search. |
| Field | Type | Meaning |
|---|---|---|
| query · as_of · agents · roles · reader | … | What the original read asked, when, under which agents and role audience, and for whom. |
| served_then | string[] | Fragment ids served by the original read. |
| served_now | string[] | What the identical read serves at replay time. |
| missing_now · extra_now | string[] | The difference, both ways. |
| replayed | boolean | False when the receipt could not be re-executed; note says why. |
You can replay only your own receipts. Somebody else’s id returns an access error.
whoami
Report the tenant, subject, principal kind, granted scopes, available tools and read-pool readiness for the credential on this request. No input. Always available.
{
"tenant": "c40d9736-7165-4478-8d66-5c4550687eb8",
"subject": "okta|00u1abc…",
"principal_kind": "user",
"scopes": ["memory.read", "memory.write"],
"tools_available": ["memory_receipt", "memory_search", "memory_write", "whoami"],
"read_pool_ready": "ready"
}Every field but the last two is read straight from the verified token, which makes the identity guarantee observable: you can see exactly which subject the server believes you are, and that no argument influenced it. read_pool_ready comes from a probe read under the same credential, so it reports what a real search would experience.
Prompt injection