OpenCode's MCP configuration shape differs enough from Claude Code and Cursor that copy-pasting a mcpServers block from one of those tools straight into opencode.json will fail silently or throw a schema error, depending on version. This topic covers the OpenCode-specific config, a realistic session pattern, and the rough edges you'll hit that the other clients don't have.
Installing and Connecting Memory MCP to OpenCode
OpenCode reads MCP server definitions from opencode.json (project-level) or ~/.config/opencode/opencode.json (global), under an mcp key — not mcpServers. Each entry needs an explicit type ("local" for a subprocess server, "remote" for an HTTP/SSE endpoint) and the command as an array rather than separate command/args fields:
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"memory": {
"type": "local",
"command": ["npx", "-y", "@modelcontextprotocol/server-memory"],
"environment": {
"MEMORY_FILE_PATH": "/Users/dat/agent-memory/english-grammar-platform.json"
},
"enabled": true
}
}
}
Put this at the project root as opencode.json if you want it scoped to one repo, or in the global config if you want the same memory server available everywhere (with the caveats about cross-project pollution covered in this module's first topic — a global mcp entry doesn't give you a global memory file unless you also point every project at the same MEMORY_FILE_PATH, which you generally shouldn't).
Start OpenCode and confirm the server loaded:
opencode
/mcp
If it shows disconnected, the most common cause isn't a config typo — it's npx failing to resolve the package because OpenCode launched from a shell without your usual PATH (common when OpenCode is launched from a GUI app launcher rather than a terminal). Confirm by running the exact command array manually:
npx -y @modelcontextprotocol/server-memory
If that hangs correctly but OpenCode still reports disconnected, check enabled: true is actually present — omitting it defaults to disabled in some OpenCode config schema versions, which is an easy miss when copying a snippet from documentation that assumes the field is optional.
Tips
- OpenCode's config key ismcp, notmcpServers, andcommandis an array — porting a Claude Code or Cursor config verbatim will not work.
- Testnpx -y @modelcontextprotocol/server-memorymanually in the same shell context OpenCode launches from if the server shows disconnected.
- Explicitly set"enabled": true— don't rely on it defaulting the way you'd expect from other MCP clients.
Storing and Retrieving Session Context in OpenCode
Once connected, the interaction pattern is identical in substance to any other MCP client — the tool names and JSON shapes are server-defined, not client-defined, so create_entities, search_nodes, and the rest behave the same everywhere. What differs is how naturally OpenCode's session model nudges you toward using them.
OpenCode sessions are more explicitly file-and-directory scoped than Claude Code's — each session tracks a working directory, and it's common to run several concurrent OpenCode sessions across different branches or worktrees of the same repo. That makes memory even more valuable here than in a single-session tool: two OpenCode sessions on different feature branches, both pointed at the same MEMORY_FILE_PATH, share facts about the codebase in real time.
Session A (working on feature/rate-limit-v2):
Prompt: Store a memory entity for the new rate limiter design —
entityType "decision", name "rate-limit-v2", noting we're moving
to a sliding-window-log algorithm this time, with a fix for the
burst-rejection issue via a grace-window parameter.
Session B (working on feature/billing-refactor, separate worktree):
Prompt: Before I touch anything calling the rate limiter's
public interface, check memory for related changes in flight.
→ search_nodes("rate limit")
→ finds "rate-limit-v2" decision entity from Session A, created
20 minutes ago
That cross-session, near-real-time visibility is the concrete payoff of a shared JSON file over per-session in-memory state — Session B finds out about an in-progress interface change on another branch without anyone sending a Slack message. The risk is the mirror image of the benefit: two sessions writing observations to the same file concurrently can race. The server re-reads and rewrites the whole file per call, so a genuinely simultaneous write from two sessions can lose one of the two updates. In practice this only bites during rapid parallel work; stagger memory writes when you know two sessions are active at once, or dedicate specific entities to specific work streams.
{
"type": "entity",
"name": "rate-limit-v2",
"entityType": "decision",
"observations": [
"Moving to sliding-window-log algorithm",
"Adds a grace-window parameter to fix the 2026 burst-rejection issue",
"In progress on feature/rate-limit-v2 as of 2026-08-21"
]
}
Tips
- Point every concurrent OpenCode worktree/session at the sameMEMORY_FILE_PATHwhen they're working on the same repo — this is where shared memory pays off fastest.
- Be aware of the read-modify-write race on the JSON file under truly simultaneous writes from two sessions; it's rare but not impossible.
- Tag time-sensitive observations with a date and status ("in progress as of...") since the graph has no built-in staleness tracking.
Practical Example: Resuming a Multi-Day Refactor Without Re-Briefing the Agent
Take a realistic case: migrating the platform's topic-fixture pipeline from synchronous markdown conversion to an async job queue, spread across three days of OpenCode sessions with gaps in between.
Day 1, end of session:
Prompt: Summarize today's refactor progress and store it as memory.
Entity: entityType "decision", name "fixture-pipeline-async-migration".
Include: what's done, what's not, and the one design question still open.
{
"type": "entity",
"name": "fixture-pipeline-async-migration",
"entityType": "decision",
"observations": [
"Goal: move convert_topic_bodies.py from sync CLI script to a queued job",
"Day 1: extracted the markdown->HTML conversion logic into content/fixtures/converter.py, unit tested in isolation",
"Not yet done: the queue backend choice — evaluating RQ vs a simple DB-polled table, leaning DB-polled to avoid a new infra dependency",
"Open question: does the queue need to survive a Django app restart mid-conversion, or is at-most-once fine for this workload?"
]
}
Day 3, new OpenCode session, no manual briefing:
Prompt: Resume the fixture pipeline async migration. Check memory
first for where we left off.
→ open_nodes(["fixture-pipeline-async-migration"])
→ returns the full entity above
Agent: Picking up from Day 1 — converter.py extraction is done and
tested. The open question was queue backend choice. Since you leaned
toward DB-polled to avoid new infra, I'll scaffold that unless you've
decided otherwise since then.
The agent restated the open decision instead of silently picking one, which is exactly the behavior you want — memory should surface unresolved questions, not paper over them with a confident-sounding guess. Compare this to the no-memory alternative: either you re-type the Day 1 summary by hand on Day 3, or you skip it and the agent starts proposing a Redis-backed queue because that's the generically "correct" answer, ignoring the infra constraint you'd already ruled it out for.
Tips
- Explicitly store open questions and undecided trade-offs, not just completed work — that's what prevents an agent from silently re-deciding something you'd already ruled on.
- Useopen_nodeswith the exact entity name when resuming known work — it's a direct fetch, cheaper than asearch_nodesguess.
- End every multi-day task's session with an explicit "what's done / what's not / what's open" memory write — this is the single habit with the highest payoff for resumability.
Known Limitations for Memory MCP in OpenCode
Be upfront about where this breaks down in OpenCode specifically, beyond the generic limitations of the memory server itself (no semantic search, no encryption, unbounded read_graph growth — covered in this module's first topic):
- No first-class memory UI. OpenCode's TUI shows connected MCP servers and lets you inspect tool calls in the session log, but there's no dedicated pane to browse the knowledge graph the way you might browse files in the file tree. Inspecting the graph directly means reading the JSON file yourself or asking the agent to
read_graphand summarize. - Config schema volatility. OpenCode's
opencode.jsonschema has changed shape across versions (themcpkey structure, theenvironmentvsenvfield naming) more than Claude Code's or Cursor's have. Pin your OpenCode version or double-check the$schemaURL's current shape before assuming a config snippet from six months ago still validates. - Concurrent-session write races, covered above — sharper here than in single-session tools because running multiple OpenCode sessions in parallel worktrees is a normal, encouraged workflow, not an edge case.
- No automatic project-vs-global scoping enforcement. Nothing stops a global
opencode.jsonmemory config from silently shadowing a project-level one, or vice versa, depending on which config OpenCode resolves first for a given launch directory — verify with/mcpin-session rather than assuming your project config took effect.
None of these are severe enough to avoid the integration — they're the kind of thing you learn once and route around, not blockers.
Tips
- Don't expect a graph browser UI in OpenCode — plan onread_graph+ agent summary, or a small external script, if you need to eyeball the whole memory file.
- Re-check youropencode.jsonagainst the current$schemaafter any OpenCode upgrade — themcpblock's shape isn't guaranteed stable across versions.
- Confirm which config (project or global) actually took effect via/mcprather than assuming — scoping precedence isn't always obvious from the files alone.
Tips
Tips
- OpenCode'smcpconfig key, array-formcommand, andenvironmentfield are meaningfully different from Claude Code/Cursor'smcpServersshape — don't copy-paste configs across tools.
- Shared memory across concurrent OpenCode worktree sessions is this client's strongest use case for memory MCP — lean into it deliberately.
- Store open questions and unresolved trade-offs explicitly, not just completed work, so resumed sessions don't silently re-decide settled matters.
- Watch for config schema drift across OpenCode versions and re-validate after upgrades.