Personalized Memory API Reference
This document is the API contract for FoundationaLLM personalized agent memory. It is intended for developers implementing the Memory MCP server and for anyone calling CoreAPI memory endpoints directly.
Audience: Memory MCP server developers, CoreAPI integrators
Controller: src/dotnet/CoreAPI/Controllers/MemoryController.cs
Models: src/dotnet/Common/Models/Memory/
Design plan: personalized-agent-memory-plan.md
Overview
Personalized memory stores durable markdown facts about a user (and optionally per agent). Memory is:
- Owned by the authenticated user's UPN
- Stored by FoundationaLLM (Cosmos /
FoundationaLLM.Contextresource provider,memoriesresource type) - Exposed only through CoreAPI convenience endpoints
- Consumed by agents through an out-of-process Memory MCP server that forwards to CoreAPI
The Memory MCP server must not access Cosmos or enforce ownership itself. It validates MCP request shape, authenticates to CoreAPI, forwards identity, and maps MCP tools to the HTTP API below.
Agent (FoundationaLLMMCPClientTool)
│ MCP tools: get_memory / append_memory / clear_memory
│ HTTP headers include X-USER-IDENTITY = resolved user identity JSON
▼
Memory MCP server (separate repo)
│ HTTP to CoreAPI
▼
CoreAPI /instances/{instanceId}/memory/*
│
▼
FoundationaLLM.Context resource provider → Cosmos `Memories`
Base URL
https://{core-api-url}/instances/{instanceId}/memory
| Variable | Description | Where to find |
|---|---|---|
{core-api-url} |
Core API base URL | App Config: FoundationaLLM:APIs:CoreAPI:APIUrl |
{instanceId} |
FoundationaLLM instance GUID | App Config: FoundationaLLM:Instance:Id |
Authentication and identity
Memory endpoints accept the same dual auth model as other CoreAPI controllers:
| Scheme | How to send | Notes |
|---|---|---|
| Microsoft Entra ID (JWT) | Authorization: Bearer <token> |
Policy: Microsoft Entra ID standard |
| Agent access token | Platform agent-access-token auth scheme | Policy: FoundationaLLM agent access token |
User identity for Memory MCP
When the agent invokes the Memory MCP server through FoundationaLLMMCPClientTool, the Management Portal tool configuration should include:
| Header key | Source | Value |
|---|---|---|
X-USER-IDENTITY |
New Value (or system context token) | context://user_identity |
At runtime the MCP client resolves context://user_identity to the signed-in user's identity JSON and sends it as X-USER-IDENTITY.
The Memory MCP server should:
- Accept
X-USER-IDENTITYfrom the inbound MCP/HTTP request. - Authenticate to CoreAPI with its configured service credential (Entra / managed identity / other deployment-approved pattern).
- Propagate the user identity into the CoreAPI call using the platform's trusted service-to-service identity pattern for the deployment.
Full on-behalf-of (OBO) token exchange across Orchestration → LangChain → MCP → CoreAPI is a later workstream. Until then, use the controlled trusted-forwarding pattern described in the memory plan.
Ownership is enforced in CoreAPI / the Memory resource provider against UnifiedUserIdentity.UPN. The MCP server must not invent or substitute a different user UPN.
Scopes
| Scope | Meaning | Stored? | agent_object_id / agentObjectId |
|---|---|---|---|
user |
Cross-agent memory for the user | Yes | Not used |
agent |
Memory for one agent + user | Yes | Required |
combined |
User + current-agent memory assembled at read time | No (read-only composition) | Required for meaningful agent portion |
Agent object IDs are FoundationaLLM resource paths, for example:
/instances/{instanceId}/providers/FoundationaLLM.Agent/agents/{agentName}
Endpoint summary
| Method | Path | Purpose |
|---|---|---|
GET |
/instances/{instanceId}/memory |
Read memory markdown JSON |
POST |
/instances/{instanceId}/memory/append |
Append markdown to user or agent memory |
POST |
/instances/{instanceId}/memory/clear |
Clear user or agent memory (confirm=true) |
GET |
/instances/{instanceId}/memory/export |
Export raw markdown (text/markdown) |
POST |
/instances/{instanceId}/memory/import |
Import markdown (append or replace) |
Shared response model
Most JSON endpoints return MemoryResponse:
{
"scope": "user",
"upn": "user@contoso.com",
"user_name": "user@contoso.com",
"name": "Example User",
"agent_object_id": null,
"agent_name": null,
"content_markdown": "# User memory\n\n- Prefers concise answers\n",
"created_on": "2026-07-19T12:00:00+00:00",
"updated_on": "2026-07-19T12:05:00+00:00"
}
| Field | Type | Description |
|---|---|---|
scope |
string | user, agent, or combined |
upn |
string | Owning user principal name |
user_name |
string? | Username (often email) |
name |
string? | Display name |
agent_object_id |
string? | Set for agent-scoped documents |
agent_name |
string? | Agent display/name when known |
content_markdown |
string | Memory body (empty string when none) |
created_on |
datetime? | Profile created time |
updated_on |
datetime? | Profile last update time |
Empty memory: GET returns 200 OK with content_markdown empty (or containing only content created by prior test/setup). Missing profiles are treated as empty, not 404.
GET /memory — read memory
GET /instances/{instanceId}/memory?scope={scope}&agentObjectId={agentObjectId}
Authorization: Bearer {token}
Accept: application/json
Query parameters
| Name | Required | Description |
|---|---|---|
scope |
No (default combined) |
user, agent, or combined |
agentObjectId |
Required when scope is agent or when agent portion of combined is needed |
Agent resource object ID |
ASP.NET query binding uses camelCase
agentObjectId. JSON request bodies use snake_caseagent_object_id.
Examples
User memory
curl -sS -X GET \
"$CORE_API/instances/$INSTANCE_ID/memory?scope=user" \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/json"
Agent memory
curl -sS -X GET \
"$CORE_API/instances/$INSTANCE_ID/memory?scope=agent&agentObjectId=$AGENT_OBJECT_ID" \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/json"
Combined memory
curl -sS -X GET \
"$CORE_API/instances/$INSTANCE_ID/memory?scope=combined&agentObjectId=$AGENT_OBJECT_ID" \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/json"
combined concatenates non-empty user and agent markdown with blank lines between them. Response scope is combined.
POST /memory/append — append memory
POST /instances/{instanceId}/memory/append
Authorization: Bearer {token}
Content-Type: application/json
Request body (AppendMemoryRequest)
| Field | Type | Required | Description |
|---|---|---|---|
scope |
string | Yes | user or agent (combined is invalid) |
agent_object_id |
string | Required for agent |
Agent object ID |
agent_name |
string | No | Optional; CoreAPI can resolve from the agent resource |
content_markdown |
string | Yes | Markdown to append (must be non-whitespace) |
reason |
string | No | Provenance note included in the append heading |
operation_id |
string | No | Associated completion/operation id |
session_id |
string | No | Associated conversation/session id |
Example
curl -sS -X POST \
"$CORE_API/instances/$INSTANCE_ID/memory/append" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"scope": "user",
"content_markdown": "- Prefers concise answers.",
"reason": "User stated preference"
}'
Behavior
- Appends to the existing markdown document for the scope.
- CoreAPI wraps the append with an automatic heading / provenance block (timestamp; optional reason).
- Returns updated
MemoryResponse.
POST /memory/clear — clear memory
POST /instances/{instanceId}/memory/clear
Authorization: Bearer {token}
Content-Type: application/json
Request body (ClearMemoryRequest)
| Field | Type | Required | Description |
|---|---|---|---|
scope |
string | Yes | user or agent |
agent_object_id |
string | Required for agent |
Agent object ID |
confirm |
boolean | Yes | Must be true or the API returns 400 |
Example
curl -sS -X POST \
"$CORE_API/instances/$INSTANCE_ID/memory/clear" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"scope": "agent",
"agent_object_id": "/instances/00000000-0000-0000-0000-000000000000/providers/FoundationaLLM.Agent/agents/benefits-assistant",
"confirm": true
}'
Behavior
- Sets
content_markdownto empty while retaining the memory profile metadata. confirm: false(or omitted/false) →400 Bad Request.
GET /memory/export — export markdown
GET /instances/{instanceId}/memory/export?scope={scope}&agentObjectId={agentObjectId}
Authorization: Bearer {token}
Accept: text/markdown
| Name | Required | Description |
|---|---|---|
scope |
Yes | user, agent, or combined |
agentObjectId |
Required for agent / agent portion of combined |
Agent object ID |
Response: 200 OK with Content-Type: text/markdown and the markdown body (not wrapped in JSON).
curl -sS -X GET \
"$CORE_API/instances/$INSTANCE_ID/memory/export?scope=user" \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: text/markdown"
POST /memory/import — import markdown
POST /instances/{instanceId}/memory/import
Authorization: Bearer {token}
Content-Type: application/json
Request body (ImportMemoryRequest)
| Field | Type | Required | Description |
|---|---|---|---|
scope |
string | Yes | user or agent |
agent_object_id |
string | Required for agent |
Agent object ID |
content_markdown |
string | Yes | Markdown to import |
mode |
string | No (default append) |
append or replace |
Example
curl -sS -X POST \
"$CORE_API/instances/$INSTANCE_ID/memory/import" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"scope": "user",
"mode": "replace",
"content_markdown": "# User memory\n\n- Imported preference\n"
}'
Behavior
mode |
Result |
|---|---|
append |
Appends imported content under an import heading |
replace |
Replaces the entire content_markdown with the provided body |
| anything else | 400 Bad Request |
Import/export are CoreAPI (and future Agent Portal) features. The agent-facing Memory MCP tools in v1 are get / append / clear only; MCP servers may optionally expose import later but are not required to.
Validation and error responses
| Condition | HTTP status |
|---|---|
Missing agent_object_id / agentObjectId for scope=agent |
400 |
clear with confirm not true |
400 |
Invalid scope |
400 |
Invalid import mode |
400 |
Empty content_markdown on append/import |
400 / argument exception |
| Caller cannot access the agent resource | Agent RP error (typically 403/404) |
| Unauthenticated / unauthorized | 401 / 403 |
Successful reads of empty memory return 200, not 404.
Memory MCP tool mapping
Implement these MCP tools in the Memory MCP server. Do not create separate tools for user vs agent memory — use a scope argument.
get_memory
| MCP argument | Type | Required | Default | Maps to CoreAPI |
|---|---|---|---|---|
scope |
string (user | agent | combined) |
Yes | Often combined in tool config |
GET .../memory?scope= |
CoreAPI call:
GET /instances/{instanceId}/memory?scope={scope}&agentObjectId={currentAgentObjectId}
Return to the agent: markdown text (from content_markdown, or the export body if you prefer).
append_memory
| MCP argument | Type | Required | Maps to CoreAPI |
|---|---|---|---|
scope |
string (user | agent) |
Yes | AppendMemoryRequest.scope |
memory |
string (markdown) | Yes | AppendMemoryRequest.content_markdown |
reason |
string | No | AppendMemoryRequest.reason |
CoreAPI call:
POST /instances/{instanceId}/memory/append
Content-Type: application/json
{
"scope": "{scope}",
"agent_object_id": "{currentAgentObjectId}", // when scope=agent
"content_markdown": "{memory}",
"reason": "{reason}"
}
clear_memory
| MCP argument | Type | Required | Default | Maps to CoreAPI |
|---|---|---|---|---|
scope |
string (user | agent) |
Yes | — | ClearMemoryRequest.scope |
confirm |
boolean | Yes | false in tool config |
ClearMemoryRequest.confirm |
CoreAPI call:
POST /instances/{instanceId}/memory/clear
Content-Type: application/json
{
"scope": "{scope}",
"agent_object_id": "{currentAgentObjectId}", // when scope=agent
"confirm": true
}
Only call CoreAPI when confirm is true. Otherwise return a clear MCP-level validation error to the agent.
Supplying agent_object_id
Agent-facing MCP tool schemas expose scope (and content/confirm), not agent_object_id, to the LLM. For scope=agent or scope=combined, the Memory MCP server must supply the current agent object ID when calling CoreAPI.
Recommended approaches (pick one and document it in the MCP server repo):
- Server configuration — bind each MCP deployment/route to a known agent object ID, or
- Invocation context — accept agent object ID from a trusted inbound header / metadata established by the platform when the tool is invoked, or
- Explicit MCP argument — optionally accept
agent_object_idfor advanced clients (not required for the default FoundationaLLM Tools Experience wrappers).
Never invent an agent object ID from the user prompt.
MCP server responsibilities (checklist)
Do
- [ ] Expose MCP tools
get_memory,append_memory,clear_memory - [ ] Validate MCP argument shapes before calling CoreAPI
- [ ] Call CoreAPI paths documented above
- [ ] Forward / honor
X-USER-IDENTITYfor the signed-in user - [ ] Authenticate to CoreAPI with the deployment's service credential
- [ ] Return markdown (or structured tool results containing markdown) to the agent
- [ ] Require
confirm=truebefore calling clear
Do not
- [ ] Store memory in the MCP server
- [ ] Access Cosmos DB directly
- [ ] Implement vector search or semantic deduplication
- [ ] Implement ChatGPT/Claude/Gemini-specific import parsers
- [ ] Bypass UPN ownership (always use the authenticated / forwarded user identity)
Management Portal configuration (FoundationaLLM side)
In Management Portal Tools Experience, configure three MCP Client tools against the Memory MCP server URL:
- Add header: Key
X-USER-IDENTITY, Source New Value, Valuecontext://user_identity - Leave Intelligent Execute unchecked
- Use List Tools → select the memory tool → Configure
- Save the tool, then save the agent
See verification plan: V018-management-portal-memory-mcp-config.md
MCP client header docs: mcp-client.md
Functional verification
CoreAPI behavior is covered by:
Run V017 against a deployed or local CoreAPI with Entra auth before integrating the MCP server end-to-end.
Related documents
| Document | Purpose |
|---|---|
| personalized-agent-memory-plan.md | Full design, storage model, phases |
| Core API reference (SDKs) | General CoreAPI auth and patterns |
| mcp-client.md | context:// header tokens |
| Agent access tokens | Alternate CoreAPI auth |