Build
Any agent framework
Your agent framework can start oort mcp through its MCP client, like any other MCP server. Or call the oort CLI from your own code.
Every example below needs the CLI on your PATH (npm i -g oortmem). Each one passes --project so the agent sees one project's memories, plus global ones. Recall works without keys. Saving new memories needs Oort Pro or your own keys.
Vercel AI SDK
npm i ai @ai-sdk/mcpimport { createMCPClient } from '@ai-sdk/mcp';
import { Experimental_StdioMCPTransport } from '@ai-sdk/mcp/mcp-stdio';
import { generateText, isStepCount } from 'ai';
let client;
try {
client = await createMCPClient({
transport: new Experimental_StdioMCPTransport({
command: 'oort',
args: ['mcp', '--project', process.cwd()],
}),
});
const tools = await client.tools();
const { text } = await generateText({
model: 'anthropic/claude-sonnet-5.5',
tools,
stopWhen: isStepCount(5),
messages: [{ role: 'user', content: 'What did we decide about the deploy?' }],
});
console.log(text);
} finally {
if (client) {
await client.close();
}
}client.tools() turns Oort's MCP tools into AI SDK tools. stopWhen lets the model call recall and then answer. Close the client when you are done, so the oort mcp process ends.
LangGraph
pip install langchain-mcp-adapters langchain langchain-openaiimport asyncio
from langchain.agents import create_agent
from langchain_mcp_adapters.client import MultiServerMCPClient
async def main():
client = MultiServerMCPClient(
{
"oort": {
"command": "oort",
"args": ["mcp", "--project", "/path/to/repo"],
"transport": "stdio",
}
}
)
tools = await client.get_tools()
agent = create_agent("openai:gpt-4.1", tools)
result = await agent.ainvoke({"messages": "What did we decide about the deploy?"})
print(result["messages"][-1].content)
asyncio.run(main())MultiServerMCPClient loads Oort's tools as LangChain tools, and create_agent runs them in a LangGraph agent. Without a long-lived session, the adapter starts a new oort mcp for each tool call.
OpenAI Agents SDK
pip install openai-agentsimport asyncio
from agents import Agent, Runner
from agents.mcp import MCPServerStdio
async def main():
async with MCPServerStdio(
name="Oort",
params={
"command": "oort",
"args": ["mcp", "--project", "/path/to/repo"],
},
) as oort:
agent = Agent(
name="Assistant",
instructions="Use Oort to recall what the user told you before.",
mcp_servers=[oort],
)
result = await Runner.run(agent, "What did we decide about the deploy?")
print(result.final_output)
asyncio.run(main())MCPServerStdio starts oort mcp and stops it when the async with block ends.
Mastra
npm i @mastra/core @mastra/mcpimport { Agent } from '@mastra/core/agent';
import { MCPClient } from '@mastra/mcp';
const mcp = new MCPClient({
servers: {
oort: {
command: 'oort',
args: ['mcp', '--project', process.cwd()],
},
},
});
const agent = new Agent({
id: 'assistant',
name: 'Assistant',
instructions: 'Use Oort to recall what the user told you before.',
model: 'openai/gpt-4.1',
tools: await mcp.listTools(),
});
const response = await agent.generate('What did we decide about the deploy?');
console.log(response.text);listTools() names each tool after its server, so the agent sees oort_recall, oort_remember and so on.
Your own code
No framework? Run the CLI. Recall before the model call, and observe after it.
# memories for a question, as JSON
oort recall --json "how do we deploy?"
# run one finished turn through the write path
oort observe --user "We deploy from main with wrangler." --assistant "Noted."Without --json, oort recall prints an <oort-memory> block you can put straight into a prompt. oort observe also reads one turn as JSON on stdin:
echo '{"userText": "We deploy from main with wrangler.", "assistantText": "Noted."}' | oort observeThe same two calls from Node.js:
import { execFileSync } from 'node:child_process';
const repo = '/path/to/repo'; // the project comes from the folder
// Before the model call: recall what matters for this message.
const recalled = JSON.parse(
execFileSync('oort', ['recall', '--json', userText], { cwd: repo, encoding: 'utf8' }),
);
const context = recalled.memories.map((m) => `- ${m.text}`).join('\n');
// After the reply: send the finished turn through the write path.
execFileSync('oort', ['observe'], {
cwd: repo,
input: JSON.stringify({ userText, assistantText }),
});| Command | Prints |
|---|---|
oort recall --json | memories, each with id, text, type, tier and an explanation of its ranks. |
oort observe | The outcome (added, reinforced, updated, superseded or skipped), the memory id and the decisions behind it. |
oort observe --dry-run | What the scrubber would redact. It saves nothing and calls no provider. |