opencode-mmcp-1file
v0.4.0
Published
OpenCode plugin that automatically reads/writes project-memory MCP for agents
Maintainers
Readme
opencode-mmcp-1file
Persistent memory for OpenCode agents via memory-mcp-1file.
What it does
This OpenCode plugin gives agents persistent memory across sessions. It connects to a memory-mcp-1file MCP server via stdio and registers 28 plugin tools — consolidating memory search, storage, lifecycle management, code intelligence, project indexing, learning memory management, and shared HTTP server control into an ergonomic interface with automatic routing. The plugin also provides automatic context injection, idle-time capture, optional background code-index refresh, compaction recovery, smart trigger nudges, agent guidance via system prompt, a /init-mcp-memory bootstrap command for deep project onboarding, a /setup-mcp-memory guided configuration wizard, and a /manage-mcp-server command for controlled HTTP lifecycle actions.
The plugin now distinguishes between a physical storage shard and a logical retrieval scope:
mcpServer.tag/dataDirdecide which on-disk memory store you are using.memoryScope.namespacenarrows reads and writes within that shard.- For agentic coding, the default is shared memory across collaborating agents. Agent/run identifiers are treated as provenance unless you explicitly opt into tighter isolation.
Features
Agent-facing (via plugin tool registration)
- Plugin Tools (28 tools) — The plugin consolidates underlying MCP operations into ergonomic tools:
memory_query— Unified search with auto/semantic/keyword/recent modes. Routes to the best search strategy automatically.memory_save— Smart storage with auto-categorization (DECISION, TASK, PATTERN, BUGFIX, etc.) and privacy filtering.memory_manage— Memory lifecycle: get, update, delete, or invalidate by ID.memory_migrate— Copy project memories between physical shards or project IDs with dry-run support.code_search— Unified code intelligence: intent-based search, symbol lookup, and call graph traversal (callers/callees/related).project_index— Minimal project indexing entry point for ordinary agent-triggered indexing. Takes onlypathand optionalforce; use this instead ofproject_statusfor simple fresh index starts.project_ensure_index— Default readiness entry point for agent workflows. Takes onlypath, checks durable status first, resumes safely when possible, returns already-running/already-ready states without extra calls, and otherwise starts a clean fresh index.project_recover_index— Minimal interrupted-index recovery entry point. Takes onlypath, checks durable status, and resumes only when the server provides resume identity.project_projection— Simple project projection/readback entry point. Use this for ordinary projection workflows; it takesproject_id, optionallocator, and optionalrelation_scope/sort_mode, then returns raw JSON from the server or falls back to a fresh projection when locator readback is unavailable.project_status— Project indexing and projections: list indexed projects, index new ones, view code statistics, build short-lived projections, or read them back by ephemeral locator. Also supports durable indexing controls:status(query current indexing state),resume(resume an interrupted job withjob_id+resume_token),cancel(cancel active job), andcleanup(remove abandoned/failed jobs). Useproject_projectionfor ordinary projection/readback workflows.mcp_server_control— Manage shared HTTP MCP server lifecycle withstatus,stop, andrestartactions. HTTP transport only.knowledge_graph— Map and query architectural relationships between codebase components. Use when analyzing system architecture, tracing module dependencies, or recording structural relationships. Actions: create_entity, create_relation, get_related, detect_communities.get_status— Memory system status and startup progress.reload_config— Hot-reload configuration from disk without restart.memory_learning_*/learning_memory_*— Manage typed learning memory records, including list, retrieve, confirm/promote, update, reject, archive, supersede, migrate legacy records, and the deprecated delete compatibility shim.
- System Prompt Guidance — Injects a Memory Protocol into the system prompt via
experimental.chat.system.transform, teaching the agent when and how to use memory tools, prefix conventions, memory lifecycle, action triggers, and anti-patterns. - Tool Description Enhancement — Augments raw MCP tool descriptions via
tool.definitionhook with guidance that points agents back to the unified plugin tools first. - Keyword Detection — Detects phrases like "remember this", "save this", "记住" in user messages and nudges the agent to store explicit user-requested memories with a
USER:prefix. - Smart Triggers — Detects decision points, new task starts, and error/debugging contexts in conversations, nudging the agent to store or recall memories at the right time (with 5-minute cooldown per trigger type).
Plugin-managed (automatic, behind the scenes)
- Memory Injection — Injects query recall, project knowledge, and code-intelligence guidance independently, with per-source injection strategies, score filtering, dedupe, and source-specific budgets before synthetic context is added.
- Auto-Capture — When session goes idle (10s default), extracts the latest exchange, summarizes it via an external LLM, and stores with AGENTS.md-compatible prefixes.
- Code Index Sync — Optional startup/idle refresh computes a lightweight workspace fingerprint for code index freshness detection and refreshes stale code indexes in the background with debounce, cooldown, and single-flight locking when
codeIndexSync.autoRefreshis enabled. Freshness signals include common iOS, Android, and Flutter source/project/dependency metadata changes, while common generated/dependency directories are ignored. This is freshness detection only and does not add mobile semantic indexing, mobile parsers, or mobile LSP support. Sync metadata, cooldown, and lock contention are tracked per workspace inside the current shard. In HTTP mode, only the shared server's primary live holder coordinates freshness checks; follower clients skip redundant coordination work. - Compaction Recovery — After context compaction, injects recovery guidance and relevant memories via
experimental.session.compactinghook. Instructs the agent to usememory_queryto restore in-progress tasks and project context. - Preemptive Compaction — Tracks estimated token usage per session. When approaching model context limit (default 80%), triggers early compaction with memory context preserved.
- Privacy Filtering — Content wrapped in
<private>...</private>is stripped to[REDACTED]before storing. Also intercepts agent's direct raw MCPstore_memory/update_memorycalls viatool.execute.before. - Compaction Summary Capture — After compaction completes, stores the summary as a CONTEXT: memory for future reference.
Install
npm install opencode-mmcp-1fileAdd to your OpenCode configuration (opencode.json or ~/.config/opencode/config.json):
{
"plugin": ["opencode-mmcp-1file"]
}The plugin automatically spawns the @steinx/memory-mcp-1file server package via stdio. No separate MCP server configuration is needed, but first-time installs must allow npm to read the @steinx package from GitHub Packages:
npm login --scope=@steinx --auth-type=legacy --registry=https://npm.pkg.github.comOr configure ~/.npmrc with an equivalent @steinx:registry=https://npm.pkg.github.com entry and GitHub Packages auth token.
Configuration
Create opencode-mmcp-1file.jsonc at your project root or ~/.config/opencode/opencode-mmcp-1file.jsonc:
{
// Memory injection on user messages (READ)
"chatMessage": {
"enabled": true,
"maxMemories": 5,
"maxInjectedMemories": 6, // Max query-recall memories injected after filtering/dedupe
"maxProjectMemories": 30, // Max memories to fetch for tiered allocation (pool size)
"injectOn": "first", // Query recall only: "first" or "always"
"projectKnowledgeInjectOn": "compaction", // "first" | "always" | "compaction" | "never"
"codeIntelInjectOn": "compaction", // "first" | "always" | "compaction" | "never"
"shortQueryMinLength": 3, // Skip query recall for very short queries
"minScore": 0.35, // Query recall score threshold before injection
"projectKnowledgeValidOnly": false, // Use only valid project memories when true
"knowledgeGraphInjectOn": "compaction", // "first" | "always" | "compaction" | "never"
"maxKnowledgeGraphItems": 10, // Max related entities to inject from the graph
"knowledgeGraphRelatedDepth": 1, // Traversal depth for related entity lookup
"knowledgeGraphEntityMatch": true, // Enable automatic entity matching in conversation
"bootstrapLimit": 10, // Server-side memory_bootstrap result limit for normal prompt context
"bootstrapTokenBudget": 4000, // Server-side memory_bootstrap token budget for normal prompt context
// Tiered injection: prioritize explicit user-requested memories first, then project guidance.
// Set to null to disable and use flat recency-based list.
"projectKnowledgeTiers": [
{ "categories": ["USER"], "limit": 5 },
{ "categories": ["DECISION", "PATTERN"], "limit": 5 },
{ "categories": ["CONTEXT"], "limit": 5 }
]
},
// Auto-capture on session idle (WRITE)
"autoCapture": {
"enabled": false,
"debounceMs": 10000,
"language": "en"
},
// Memory recovery after context compaction (READ)
"compaction": {
"enabled": true,
"memoryLimit": 10,
"bootstrapLimit": 5, // Server-side memory_bootstrap result limit for recovery context
"bootstrapTokenBudget": 1500 // Server-side memory_bootstrap token budget for recovery context
},
// Keyword detection for explicit memory requests
// Agent should store these with a USER: prefix when they are direct user instructions to remember something.
"keywordDetection": {
"enabled": true,
"extraPatterns": [] // Additional regex patterns to detect
},
// Preemptive compaction before hitting context limit
"preemptiveCompaction": {
"enabled": true,
"thresholdPercent": 80,
"modelContextLimit": 200000,
"autoContinue": true
},
// Privacy: strip <private> tags before storing
"privacy": {
"enabled": true
},
// Store compaction summaries as memories
"compactionSummaryCapture": {
"enabled": true
},
// Plugin-managed code intelligence refresh
"codeIndexSync": {
"enabled": true,
"autoRefresh": false, // Automatically refresh stale indexes on startup/idle; manual project_index tools still work when false
"debounceMs": 10000, // Wait after detecting staleness before re-indexing
"minReindexIntervalMs": 300000, // Cooldown between successful re-indexes
"resume": {
"enabled": true, // Enable checkpoint resume for interrupted index jobs
"pollIntervalMs": 5000, // How often to poll server status during resume (ms)
"maxPollMs": 300000, // Maximum time to wait for resume completion (ms, 5 min)
"allowFullRestartFallback": false, // Allow full rebuild when resume is not possible (default: false for safety)
"allowDestructiveRecovery": false // Allow destructive recovery for corrupt storage (default: false)
},
// Optional code-index scope filters. Omit both to use MCP server defaults (env vars CODE_INDEX_INCLUDE_PATTERNS / CODE_INDEX_EXCLUDE_PATTERNS).
// Empty array [] is meaningful: it disables that side of filtering entirely.
// Values are project-relative glob patterns using / separators, must not start with /.
// "includePatterns": ["src/**/*", "tests/**/*"], // Include only these paths; omit to use server default
// "excludePatterns": ["**/generated/**", "**/*.min.js"] // Exclude these paths; omit to use server default
},
// Preference learning from conversational signals
// NOTE: "preferenceLearning" is a legacy/compatibility alias. Use "learningMemory" instead for new configurations.
"preferenceLearning": {
"enabled": false,
"learnOnCorrections": true, // Learn when users correct prior assistant output
"learnOnNegations": true, // Learn when users reject/negate suggestions
"learnOnMessageUpdated": true, // Learn from message-updated events when available
"injectOn": "first", // "first" | "always" | "compaction" | "never"
"scope": "project", // "project" or "global"
"minConfidence": 0.7, // Minimum confidence required to persist a learned preference
"candidateConfidence": 0.4, // Lower threshold for candidate preferences pending stronger evidence
"maxPreferences": 5, // Max injected preferences per retrieval
"maxCandidates": 3, // Max candidate preferences tracked per cycle
"debounceMs": 10000, // Debounce learning updates to avoid rapid duplicate writes
"maxInputChars": 4000, // Truncate oversized inputs before preference extraction
"maxStoredPreferences": 50 // Upper bound for stored preference records per scope
},
// Learning memory — typed preference/lesson/rule capture (default: disabled)
// Requires server-side support: metadata.learning.schema_version = 1 must be present on stored records.
// Only confirmed/rule records that are active and injectable_by_default=true are injected into context.
"learningMemory": {
// Master switch — set to true to enable any learning memory features
"enabled": false,
// Preference learning — capture user preferences from chat signals
"preferences": { "enabled": false },
// Lesson learning — extract lessons/patterns/pitfalls from sessions
"lessons": { "enabled": false },
// Rule learning — promote confirmed preferences to hard rules
"rules": { "enabled": false },
// Injection settings — how learning memories appear in context
"injection": {
"mode": "auto", // "auto" | "manual"
"maxPinned": 3, // max hard rules pinned in context
"maxRetrieved": 10, // max retrieved learning memories
"includeEvidence": false // include source evidence snippets
},
// Fallback — read legacy USER — Preference: memories when server unsupported
"fallback": {
"legacyPreferences": true
}
},
// LLM for auto-capture summarization
// When apiKey is set: uses direct HTTP to the specified API (fastest)
// When apiKey is empty: uses OpenCode's session API with your configured providers (zero-config)
"captureModel": {
"provider": "", // OpenCode provider ID (e.g. "openai", "anthropic"); empty = use default
"model": "", // Model ID (e.g. "gpt-4o-mini"); empty = use default
"apiUrl": "", // Only used with direct HTTP mode (when apiKey is set)
"apiKey": "" // Optional; leave empty to use OpenCode session API
},
// Logical memory scope inside the current tag/dataDir shard
"memoryScope": {
"namespace": "", // Optional logical scope for one project/workstream inside the current shard
"shareAcrossAgents": true, // Default for agentic coding: collaborating agents read/write shared memory
"includeAgentMetadata": true, // Record source_agent_id in metadata for observability
"includeRunMetadata": false, // Record source_run_id in metadata when run/session provenance matters
"userId": "", // Optional default user scope applied to reads/writes
"defaultMetadata": {} // Optional metadata merged into every write
},
// MCP server configuration (memory-mcp-1file)
"mcpServer": {
"command": ["npm", "exec", "-y", "@steinx/memory-mcp-1file", "--"],
"tag": "default", // Physical storage shard; derives dataDir as ~/.local/share/opencode-mmcp-1file/{tag}
// "dataDir": "", // Override: explicit data directory (takes precedence over tag)
"model": "qwen3", // Embedding model for vector search
"mcpServerName": "memory-mcp-1file", // Cosmetic name for logging
// "commandPath": "", // Override: path to custom binary (plugin appends flags automatically)
"transport": "stdio", // "stdio" or "http" — HTTP mode shares one server across processes
"port": 23817, // HTTP mode: server listen port
"bind": "127.0.0.1", // HTTP mode: server bind address
"reconnectIntervalMs": 30000, // Background reconnect cadence after failures
"heartbeatIntervalMs": 20000 // HTTP mode: keepalive/liveness check while connected
},
// System prompt injection — guides agent on memory tool usage
"systemPrompt": {
"enabled": true
},
// Performance resilience: per-call timeouts and caching
"performance": {
"recallTimeoutMs": 15000, // Timeout for recall/semantic search MCP calls (ms)
"projectInfoTimeoutMs": 10000, // Timeout for project_info list MCP calls (ms)
"knowledgeGraphTimeoutMs": 10000, // Timeout for knowledge graph entity lookup MCP calls (ms)
"projectKnowledgeTimeoutMs": 15000, // Timeout for project knowledge retrieval MCP calls (ms)
"learningMemoryTimeoutMs": 10000, // Timeout for learning memory retrieval MCP calls (ms)
"bootstrapTimeoutMs": 10000, // Timeout for server-side memory_bootstrap calls (ms)
"observationTimeoutMs": 10000, // Timeout for memory_observation_create hook evidence writes (ms)
"auditTimeoutMs": 10000, // Timeout for memory_audit calls (ms)
"searchTraceTimeoutMs": 10000, // Timeout for memory_search_trace calls (ms)
"projectInfoCacheTtlMs": 300000 // TTL for project_info in-memory cache (ms). Default: 5 minutes.
}
}Configuration Sections
| Section | Purpose |
|---------|---------|
| chatMessage | Controls memory retrieval, server-side bootstrap budgets, and injection into the chat stream |
| autoCapture | Idle-time memory extraction via external LLM |
| compaction | Memory re-injection after context compaction, including bootstrap recovery budgets |
| keywordDetection | Detection of "remember" requests in user messages |
| preemptiveCompaction | Early compaction trigger based on token estimates |
| privacy | Redaction of <private> tagged content |
| compactionSummaryCapture | Saves compaction summaries as memories |
| codeIndexSync | Controls code index readiness and optional automatic refresh. enabled keeps manual code-index tools available; autoRefresh controls startup/idle stale-index refresh. Nested resume policy controls polling, timeouts, and fallback behavior. Optional includePatterns / excludePatterns filter defaults narrow which files the server indexes; omit to use server env-var defaults. |
| preferenceLearning | Legacy/compatibility alias for learningMemory. Controls preference extraction, confidence thresholds, scope, and injection cadence for learned user preferences. Use learningMemory for new configurations. |
| learningMemory | Typed preference/lesson/rule capture from conversational signals. Requires server-side support (metadata.learning.schema_version = 1). Only confirmed/rule records that are active and injectable_by_default=true are injected into context. Sub-sections: preferences, lessons, rules, injection, fallback. |
| captureModel | LLM for auto-capture summarization — uses direct HTTP when apiKey is set, otherwise OpenCode session API |
| memoryScope | Logical scope, agent-sharing defaults, and default metadata layered inside the current shard |
| mcpServer | @steinx/memory-mcp-1file server command, physical data shard, embedding model, transport mode, and HTTP reconnect/heartbeat timing |
| systemPrompt | Agent guidance via Memory Protocol in system prompt |
| performance | Per-call timeouts for recall, bootstrap, observation, audit, trace, project info, knowledge graph, project knowledge, learning memory, and project-info caching. Increase timeout values for large databases (>10k memories). |
By default, USER: memories are prioritized ahead of DECISION:, PATTERN:, and CONTEXT: in Project Knowledge. This keeps explicit user-requested memories more visible during session bootstrap and compaction recovery.
Code Index Filters
The plugin can narrow the files the Memory MCP server indexes to a specific subset of your workspace.
Config defaults (codeIndexSync section, camelCase):
"codeIndexSync": {
"autoRefresh": false, // opt into startup/idle stale-index refresh
"includePatterns": ["src/**/*", "tests/**/*"], // project-relative globs, / separator, no leading /
"excludePatterns": ["**/generated/**"]
}Manual override at call time (project_index for simple starts; project_recover_index for interrupted jobs; project_status for advanced overrides, snake_case):
project_index(path: "/workspace/project")
project_recover_index(path: "/workspace/project")
project_status(action: "index", include_patterns: ["src/**/*"], exclude_patterns: ["**/dist/**"])Use project_index for ordinary agent-triggered indexing so the call stays narrow and avoids optional-parameter pollution. Use project_recover_index when an index was interrupted and you want the plugin to fetch durable status and resume with a clean payload. Reach for project_status only when you need filter overrides, explicit durable status checks, manual resume tokens, cancel, cleanup, stats, or projections.
Semantics:
- Omitting a filter key (not set in config) → uses MCP server env-var default (
CODE_INDEX_INCLUDE_PATTERNS/CODE_INDEX_EXCLUDE_PATTERNS) - Empty array (
[]) → disables that filter side entirely (overrides any server default) excludePatternswins overincludePatternswhen both match the same file- Filters are not accepted on resume operations (
action: "resume"or resume-style index calls) - Server hard invariants (skip dirs, extension whitelist,
.gitignore) are always applied regardless of these filters - A change to configured filter defaults triggers a fresh re-index on the next idle check
Physical Shard vs Logical Scope
Use the two layers for different jobs:
mcpServer.tag/dataDir— physical storage shard. Use this to separate unrelated projects, environments, or trust boundaries.memoryScope.namespace— logical scope within that shard. Use this for sub-workspaces, branches of work, or multi-tenant slices that should still live in the same store.
For agentic coding, the plugin defaults to shared memory across collaborating agents:
shareAcrossAgents: truemeans reads are not filtered byagent_idby default.includeAgentMetadata: truerecords provenance as metadata (source_agent_id) so you can still inspect or filter later.includeRunMetadata: falseavoids overfitting durable project memory to one transient session, but you can enable it when run/session provenance matters.
Examples:
// Project-specific physical shard
{ "mcpServer": { "tag": "my-project" } }
// → stores in ~/.local/share/opencode-mmcp-1file/my-project/
// Shared shard plus logical namespace separation
{
"mcpServer": { "tag": "team-memory" },
"memoryScope": { "namespace": "frontend" }
}
// → stores in ~/.local/share/opencode-mmcp-1file/team-memory/
// → reads/writes are filtered to namespace=frontend inside that shard
// Shared across all projects
{ "mcpServer": { "tag": "global" } }
// → stores in ~/.local/share/opencode-mmcp-1file/global/Set dataDir to override the derived path entirely. If neither tag nor dataDir is set, the plugin is disabled.
Recommended rule of thumb:
- Change
tagwhen you want a different physical store. - Change
memoryScope.namespacewhen you want a different retrieval boundary inside the same store. - Only use
agent_idoverrides for explicit per-agent isolation workflows; do not make that your default collaboration model.
Architecture
Plugin hooks (index.ts)
├── experimental.chat.system.transform → Memory Protocol system prompt
├── chat.message → context injection + keyword nudge
├── tool.definition → raw MCP tool hint enhancement
├── tool.execute.before → privacy filtering on agent store/update calls
├── experimental.session.compacting → compaction recovery context
├── event:session.idle → auto-capture + code-index freshness check
├── event:compacted → inject recovery context
├── event:message.updated → preemptive compaction + summary capture
└── tool → 28 plugin tools
↓
Services layer (src/services/)
├── tool-registry.ts → register 28 plugin tools (unified wrappers plus learning-memory lifecycle tools)
├── mcp-client.ts → stdio/HTTP transport + centralized contract adapters
├── system-prompt.ts → Memory Protocol prompt builder
├── auto-capture.ts → LLM summarization + store
├── code-index-sync.ts → fingerprinting + background re-index
├── context-inject.ts → per-source memory injection assembly
├── compaction.ts → recovery guidance + data
├── preemptive-compaction.ts → token tracking
└── llm-client.ts → OpenAI-compatible API
↓
MCP Server (memory-mcp-1file)
└── stdio or HTTP: plugin proxies tool callsHow It Works
The plugin spawns the @steinx/memory-mcp-1file server package via stdio and registers 28 plugin tools that wrap underlying MCP operations. The agent calls these tools directly; each call is automatically routed to the appropriate MCP operation.
project_projection is the simple projection/readback entry point. It takes only project_id plus optional locator, relation_scope, and sort_mode, returning raw JSON from the server and falling back to a fresh projection when locator readback is unavailable. project_status remains part of that same tool surface for indexing lifecycle control and compatibility projection actions. In addition to list, index, and stats, it still supports projection workflows with action: "projection" and action: "projection_by_locator". Projection requests default to relation_scope: "all" and sort_mode: "canonical", and any locator returned by the server is treated as an opaque, same-process, non-persistable handle.
project_ensure_index is the default readiness path for agents. It takes only path, checks durable status first, returns already-running or already-ready responses without extra work, resumes only when the server provides resume identity, and otherwise starts a clean fresh index.
mcp_server_control is also part of the same tool surface and supports action: "status" | "stop" | "restart" for controlled shared HTTP MCP server lifecycle operations.
Memory context is also handled through synthetic parts — invisible in the OpenCode TUI but received by the LLM as part of the conversation. The agent has full access to past project context without cluttering the user's view.
Project Initialization
The plugin ships with a /init-mcp-memory slash command that bootstraps deep project knowledge in memory. On first load, the command file is automatically installed to ~/.config/opencode/command/init-mcp-memory.md.
Usage
In OpenCode, run:
/init-mcp-memoryThe agent will execute a 3-phase initialization:
- Code Intelligence Readiness — Checks current index state first, only triggers indexing when missing or clearly stale, then verifies readiness with project stats.
- Deep Research — Explores docs, configs, git history, dependencies, and code patterns. Stores findings as categorized memories (CONTEXT:, PATTERN:, DECISION:, etc.).
- Knowledge Graph — Creates entities and relations for key architectural components, then runs community detection.
This typically involves 30–60+ tool calls and takes a few minutes. The result is a rich, queryable memory base the agent can draw on in future sessions.
Manual Installation
If auto-install doesn't work (e.g. permissions), copy the command files manually:
cp node_modules/opencode-mmcp-1file/commands/init-mcp-memory.md ~/.config/opencode/command/
cp node_modules/opencode-mmcp-1file/commands/setup-mcp-memory.md ~/.config/opencode/command/
cp node_modules/opencode-mmcp-1file/commands/manage-mcp-server.md ~/.config/opencode/command/Configuration Setup
The plugin ships with a /setup-mcp-memory slash command that guides you through generating a project-scoped configuration file.
Usage
In OpenCode, run:
/setup-mcp-memoryThe agent will walk you through:
- Memory namespace — choosing a
tagto isolate this project's memories - Logical scope — optionally choosing a
memoryScope.namespaceinside that shard for narrower retrieval - Auto-capture — configuring the LLM provider and model for automatic memory extraction (API key optional)
- Embedding model — selecting the local embedding model for code search
- Optional tuning — memory injection frequency, context limits, privacy settings
After answering, the agent generates opencode-mmcp-1file.jsonc in the project root and calls reload_config() to apply changes immediately — no restart needed.
You can also re-run /setup-mcp-memory anytime to update your configuration.
Learning Memory Commands
The plugin ships with two slash commands for managing learning memories:
/manage-learning-memory
View, confirm, reject, archive, or supersede learning memory records (preferences, lessons, rules). Supports listing pending candidates, promoting confirmed preferences to rules, and reviewing the full learning memory lifecycle.
/manage-learning-memory/migrate-learning-memory
Migrate legacy USER — Preference: memories to the typed learning memory format (metadata.learning.schema_version = 1). Run once after enabling learningMemory to preserve existing preferences.
/migrate-learning-memoryMCP Server Management
The plugin ships with a /manage-mcp-server slash command that controls the current shared HTTP MCP server through the local unified tool mcp_server_control.
Usage
In OpenCode, run:
/manage-mcp-serverChoose one action:
status— returns current transport, running state, and HTTP URL/port when available.stop— performs a controlled shutdown request in HTTP mode. If other live holders remain, it does not force-kill the shared server and reports that it is still running/reused.restart— performs controlled HTTP restart by ensuring a running/healthy shared server and reports final URL/port after health verification.
Behavior by transport:
- HTTP (
"transport": "http") — all three actions are supported with controlled lifecycle behavior. - stdio (
"transport": "stdio") — there is no shared HTTP server to stop or restart; actions return no-op status guidance.
Requirements
- OpenCode v1.2.27+
- Node.js 18+
- For auto-capture: Works out of the box using OpenCode's session API; optionally set an API key for direct HTTP mode
Troubleshooting: legacy access_count warning
If you see a startup warning like:
Failed to deserialize field 'access_count' on type 'Memory': Expected number, got none
this plugin should be treated as a diagnose-only layer. The warning is typically a
memory-mcp-1file storage/model compatibility issue, not a plugin-side schema or mutation path.
Recommended diagnosis path:
- Confirm your
memory-mcp-1fileversion and changelog for storage/model compatibility updates. - If core memory flows still work (
memory_query,memory_save,memory_manage), keep the plugin running and monitor. - If warnings persist or functionality degrades, upgrade the
memory-mcp-1fileserver and validate in a safe/staging environment first.
Safety guardrail:
- Do not manually edit or delete production memory DB records as a normal fix path from this plugin repository.
Limitations
- HTTP transport sharing — In HTTP mode (
"transport": "http"), multiple plugin processes share one MCP server instance via a file-based holder list. The lock file ({dataDir}/.server-lock) records the PID of each live client; on every read, dead PIDs are pruned to maintain an accurate holder count. The server remains resident by default for fast subsequent connections even after the last plugin process disconnects./manage-mcp-serverprovides controlled status/stop/restart operations for this shared server. Controlled stop/restart does not force-kill when other live holders remain; the result reports that the server is still running/reused. Restart success is health-gated and reports the final server URL/port after verification. The first live holder also acts as the code-index sync leader, so follower clients skip redundant fingerprint/debounce/cooldown work and rely on the leader to trigger background re-indexing. Code-index sync state is tracked per workspace so multiple workspaces sharing onetag/dataDirdo not overwrite each other's freshness metadata or cooldown timestamps. The shared server startup is coordinated via a separate.server-startup-lockwhich ensures that even during concurrent plugin launches, only one process attempts to spawn the server while others wait for it to become healthy. This eliminates the narrow race window previously present in rename-based atomic writes. - stdio lifecycle scope — In stdio mode (
"transport": "stdio"), each plugin process manages its own MCP server connection through stdio transport. There is no shared HTTP server for/manage-mcp-serverto stop or restart. - Auto-capture LLM routing — When
captureModel.apiKeyis set, auto-capture uses direct HTTP to the specified API. When empty, it falls back to OpenCode's session API (creates an ephemeral session, prompts, then deletes). The session API approach is zero-config but slightly slower due to session lifecycle overhead. - In-memory session tracking — Duplicate-prevention state (
injectedSessions,capturedSessions) is held in memory and resets on process restart. The first message after a restart may re-inject memories that were already injected in the previous session. - Tag-based privacy only — Content is redacted only when explicitly wrapped in
<private>…</private>tags. There is no automatic PII or secret detection. - Approximate token counting — Preemptive compaction estimates token usage via
chars / 4, not a real tokenizer. Thresholds may not trigger at the exact expected point. - Single default logical scope per config — Each configuration has one default shard (
tag/dataDir) and one default logical scope (memoryScope.namespace). Unified tools can override scope per call, but automatic plugin-managed retrieval uses the configured default scope.
License
MIT
