fix(examples): keep memory configs provider-owned

This commit is contained in:
ZiyaZhang
2026-07-31 02:34:52 -07:00
parent 07f51593a0
commit dc7f3253f6
12 changed files with 30 additions and 38 deletions
@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write .agents/notes/implemented/feature/2026-07-31-third-party-memory-mcp-examples.md
2026-07-31-third-party-memory-mcp-examples.md: 512a222d1f8406d11ef5c58c5f2749c9b571d846
2026-07-31-third-party-memory-mcp-examples.zh.md: 8bdc4ae371b7b3c4a8e78eeceed1f965e515a475
2026-07-31-third-party-memory-mcp-examples.md: e82d65a3a5a60cafcc47df5a6873cf5768cd8b8f
2026-07-31-third-party-memory-mcp-examples.zh.md: ee0e9f2e1378f9787e09e32cc05dd13a3648254c
@@ -27,9 +27,9 @@ These third-party configurations are provided as interoperability examples only.
| Account, auth, model, embedding, storage initialization | No | Yes |
| Vendor data migration, retry, crash recovery | No | Yes |
The generic stdio transport scrubs ambient credential-shaped and `DSH_*` variables. Baseline examples explicitly map only the variables they require; optional provider secrets must be added to `config.env` or configured in the provider's own files.
The generic stdio transport scrubs ambient credential-shaped and `DSH_*` variables while inheriting other ambient variables. Baseline examples add only required overrides; optional provider secrets must be added to `config.env` or configured in the provider's own files.
## Pins and identity
## Pins, storage, and identity
| Provider | Tested contract |
|---|---|
@@ -37,7 +37,7 @@ The generic stdio transport scrubs ambient credential-shaped and `DSH_*` variabl
| MCP Reference Memory | npm `2026.7.4`, package commit `6dd0a683e198783e30feabf7abaf42f925bd18b1` |
| Engram | tag `v1.20.0`, commit `ba9e46ced152c37a7cb9e576153c41995873e2fc` |
`DSH_MEMORY_USER_ID` is a stable user partition, not a DSH session id. Each example maps it to a separate provider data path under `$DSH_HOME`.
Storage remains provider-owned. Memorix uses `~/.memorix/data` and Engram uses `~/.engram` by default. The Reference Memory example sets a stable `$HOME/.dsh-mcp-reference-memory.jsonl` path instead of writing into the installed npm package directory. Each provider's own environment variable can override these locations before DSH starts.
Project identity remains provider-owned: Memorix and Engram use the DSH working directory's Git project, with Engram optionally accepting `ENGRAM_PROJECT`.
@@ -56,7 +56,7 @@ Remote CI never contacts third-party services or consumes secrets. The keyless s
Before merge, manual evidence for every pinned provider must separately show:
1. DSH session A calls a write tool and receives success for a unique value.
2. Fresh DSH session B, under the same provider/user scope, calls search or recall and returns that value without session A's transcript.
2. Fresh DSH session B, under the same provider storage scope, calls search or recall and returns that value without session A's transcript.
3. Session B uses the recalled value in a subsequent answer.
"Fresh session" means a new DSH session in the same Host. No Host restart is required. The generic MCP client discovers asynchronously and has no automatic reconnect after a child or HTTP transport closes; validation waits for tools before the first turn and uses HMR or a Host restart only after a crash.
@@ -27,9 +27,9 @@ Status: implemented
| 账户、认证、模型、embedding、存储初始化 | 否 | 是 |
| 提供方数据迁移、重试、崩溃恢复 | 否 | 是 |
通用 stdio 传输会清除环境中名称类似凭据的变量和 `DSH_*` 变量。基线示例仅显式映射自己需要的变量;可选的提供方密钥必须添加到 `config.env`,或配置在提供方自己的文件中。
通用 stdio 传输会清除环境中名称类似凭据的变量和 `DSH_*` 变量,同时继承其他环境变量。基线示例仅添加必需的覆盖项;可选的提供方密钥必须添加到 `config.env`,或配置在提供方自己的文件中。
## 版本固定与身份
## 版本固定、存储与身份
| 提供方 | 已测试契约 |
|---|---|
@@ -37,7 +37,7 @@ Status: implemented
| MCP Reference Memory | npm `2026.7.4`package commit `6dd0a683e198783e30feabf7abaf42f925bd18b1` |
| Engram | tag `v1.20.0`commit `ba9e46ced152c37a7cb9e576153c41995873e2fc` |
`DSH_MEMORY_USER_ID` 是稳定的用户分区,不是 DSH 会话 id。每份示例都将其映射到 `$DSH_HOME` 下相互独立的提供方数据路径
存储仍由提供方负责。Memorix 默认使用 `~/.memorix/data`Engram 默认使用 `~/.engram`。Reference Memory 示例设置稳定的 `$HOME/.dsh-mcp-reference-memory.jsonl` 路径,而不是写入已安装的 npm 包(package)目录。每个提供方自己的环境变量都可以在 DSH 启动前覆盖这些位置
项目身份仍由提供方负责:Memorix 和 Engram 使用 DSH 工作目录中的 Git 项目,其中 Engram 还可以选择接受 `ENGRAM_PROJECT`
@@ -56,7 +56,7 @@ Status: implemented
合并前,每个固定版本的提供方都必须分别提供以下人工证据:
1. DSH 会话 A 调用写入工具,为一个唯一值写入记忆,并收到成功结果。
2. 新的 DSH 会话 B 在相同提供方/用户范围下调用搜索或召回,不借助会话 A 的 transcript(文本记录)便可返回该值。
2. 新的 DSH 会话 B 在相同提供方存储范围下调用搜索或召回,不借助会话 A 的 transcript(文本记录)便可返回该值。
3. 会话 B 在后续回答中使用该召回值。
「新会话」是指同一个 Host 中新建的 DSH 会话,不需要重启 Host。通用 MCP 客户端以异步方式发现工具,子进程或 HTTP 传输关闭后不会自动重连;验证会在第一轮之前等待工具出现,并且只在崩溃后使用 HMR 或重启 Host。
+2 -2
View File
@@ -90,7 +90,7 @@ describe('third-party memory MCP example overlays', () => {
expect(row.name).toBe('@deepseek-ai/dsh-mcp-client')
expect(row.config?.serverName).toBe(contract.serverName)
expect(row.config?.transport).toBe(contract.transport)
expect(source).toContain(contract.pin)
expect(source.split('\n', 1)[0]).toContain(contract.pin)
expect(source).not.toMatch(/\bsk-[A-Za-z0-9_-]{8,}\b/)
expect(source).not.toContain('DEEPSEEK_API_KEY')
})
@@ -121,12 +121,12 @@ describe('third-party memory MCP example overlays', () => {
baseConfig,
[...patches, fixturePatch],
(ctx) => {
liveContexts.add(ctx)
ctx.loader.builtins['memory-test-system-prompt'] = SystemPrompt
ctx.loader.builtins['memory-test-tools'] = ToolRegistry
ctx.loader.builtins['memory-test-mcp-client'] = McpClient
},
)
liveContexts.add(ctx)
await waitForTool(ctx, `mcp__${contract.serverName}__greet`)
}, 15_000)
})
+2 -2
View File
@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write examples/mcp-memory/README.md
README.md: 97d7da66bad3b7b4a14d54a94788108b3831ccc4
README.zh.md: 5d7c19ae76f10b795dc8e1b39c768851921b0703
README.md: b5dd7ffc4ad248d38e108d9aa28c7c26e0c76913
README.zh.md: 1249ae40bb344fc81836cb49d71dd5656457b1b3
+5 -7
View File
@@ -10,7 +10,7 @@ These third-party configurations are provided as interoperability examples only.
DSH parses the selected Cordis overlay, starts a configured stdio command or connects to a configured Streamable HTTP URL, discovers MCP tools, and exposes them as `mcp__<serverName>__<tool>`. DSH does **not** download the server, initialize its database, choose its model or embedding provider, create a cloud account, migrate vendor data, or supervise a separate HTTP service. For stdio, the generic client launches and stops the child with the DSH plugin lifecycle; for HTTP, the upstream service must already be running.
The stdio bridge deliberately removes ambient credential-shaped and `DSH_*` variables before launching a child. Each example explicitly forwards only the variables needed for its baseline. If an optional upstream feature needs another secret, add that variable to the row's `config.env` instead of putting the secret directly in YAML.
The stdio bridge deliberately removes ambient credential-shaped and `DSH_*` variables before launching a child; other ambient variables remain inherited. Each example adds only the baseline override it needs. If an optional upstream feature needs another secret, add that variable to the row's `config.env` instead of putting the secret directly in YAML.
## Choose one
@@ -28,7 +28,7 @@ Pass one overlay to DSH:
dsh --config "$PWD/examples/mcp-memory/memorix.cordis.yml"
```
Replace the filename with `mcp-reference-memory.cordis.yml` or `engram.cordis.yml`. Those two examples also accept `DSH_MEMORY_USER_ID` for stable per-user storage. The path may point to a copied file anywhere on disk. No memory server is present in the shipped composition, so omitting `--config` keeps all three disabled.
Replace the filename with `mcp-reference-memory.cordis.yml` or `engram.cordis.yml`. The path may point to a copied file anywhere on disk. No memory server is present in the shipped composition, so omitting `--config` keeps all three disabled.
Without a repository checkout, download the selected overlay directly:
@@ -59,11 +59,10 @@ Memorix works in local heuristic mode without an LLM or embedding service. Confi
```sh
npm install --global @modelcontextprotocol/server-memory@2026.7.4
export DSH_MEMORY_USER_ID=alice
dsh --config "$PWD/examples/mcp-memory/mcp-reference-memory.cordis.yml"
```
This reference server stores a local knowledge graph and exposes entity, relation, observation, read, search, and open tools. It needs no model or embedding service. The example maps `DSH_MEMORY_USER_ID` to an isolated `MEMORY_FILE_PATH`.
This reference server stores a local knowledge graph and exposes entity, relation, observation, read, search, and open tools. It needs no model or embedding service. The example stores its JSONL at `$HOME/.dsh-mcp-reference-memory.jsonl` instead of the installed npm package directory. Set `MEMORY_FILE_PATH` before starting DSH to override it.
Search is case-insensitive substring matching over entity names, types, and observations, not semantic retrieval. The server does not add embeddings, automatic summarization, conflict resolution, or a forgetting policy.
@@ -71,11 +70,10 @@ Search is case-insensitive substring matching over entity names, types, and obse
```sh
go install github.com/Gentleman-Programming/engram/cmd/engram@v1.20.0
export DSH_MEMORY_USER_ID=alice
dsh --config "$PWD/examples/mcp-memory/engram.cordis.yml"
```
The example maps the user id to an isolated `ENGRAM_DATA_DIR`. Engram still owns project selection: it detects the Git project from the DSH working directory, or accepts `ENGRAM_PROJECT` as an explicit override.
Engram owns storage and project selection: it uses `~/.engram` by default, detects the Git project from the DSH working directory, and accepts `ENGRAM_DATA_DIR` or `ENGRAM_PROJECT` as ambient overrides.
## Optional shared model instruction
@@ -93,7 +91,7 @@ Use one unique value and keep the provider's storage scope unchanged throughout:
2. Create DSH session B in the same running Host. Do not copy session A's conversation. Ask: `What is my validation drink? Check memory.` Confirm the model called the provider's search or recall tool and returned the value.
3. Still in session B, ask: `Use that preference to suggest one drink for the meeting.` Confirm the answer uses the recalled value.
A new DSH session is required; a Host restart is not. Restart or HMR is needed only after an MCP child crashes because the current generic client unregisters tools on disconnect and does not auto-reconnect. Initial discovery is asynchronous, so wait for the provider's `mcp__...` tools before sending the first validation prompt.
A new DSH session is required; a Host restart is not. Restart or HMR is needed only after an MCP child crashes because the current generic client does not auto-reconnect; its tool registrations remain until plugin disposal or a successful re-sync, and calls can fail against the closed transport. Initial discovery is asynchronous, so wait for the provider's `mcp__...` tools before sending the first validation prompt.
## Bring another MCP server
+5 -7
View File
@@ -10,7 +10,7 @@
DSH 解析选中的 Cordis overlay,启动已配置的 stdio 命令或连接已配置的 Streamable HTTP URL,发现 MCP 工具,并以 `mcp__<serverName>__<tool>` 的形式公开这些工具。DSH **不负责** 下载服务器、初始化其数据库、选择模型或 embedding 提供方、创建云端账户、迁移提供方数据,也不监管独立的 HTTP 服务。对于 stdio,通用客户端会随 DSH 插件生命周期启动和停止子进程;对于 HTTP,上游服务必须已经运行。
stdio 桥接器在启动子进程前会主动移除环境中名称类似凭据的变量和 `DSH_*` 变量。每份示例仅显式转发其基线运行所需的变量。如果某个可选的上游功能还需要其他密钥,请将该变量添加到配置项的 `config.env`,不要把密钥直接写进 YAML。
stdio 桥接器在启动子进程前会主动移除环境中名称类似凭据的变量和 `DSH_*` 变量;其余环境变量仍会继承。每份示例仅添加其基线所需的覆盖项。如果某个可选的上游功能还需要其他密钥,请将该变量添加到配置项的 `config.env`,不要把密钥直接写进 YAML。
## 选择一个
@@ -28,7 +28,7 @@ stdio 桥接器在启动子进程前会主动移除环境中名称类似凭据
dsh --config "$PWD/examples/mcp-memory/memorix.cordis.yml"
```
请将文件名替换为 `mcp-reference-memory.cordis.yml``engram.cordis.yml`另外两份示例也接受 `DSH_MEMORY_USER_ID`,用于稳定的逐用户存储。该路径可以指向磁盘任意位置的一份复制文件。交付组合不包含任何记忆服务器,因此不传 `--config` 就会让这三项全部保持关闭。
请将文件名替换为 `mcp-reference-memory.cordis.yml``engram.cordis.yml`。该路径可以指向磁盘任意位置的一份复制文件。交付组合不包含任何记忆服务器,因此不传 `--config` 就会让这三项全部保持关闭。
如果本地没有仓库 checkout,可直接下载所选 overlay
@@ -59,11 +59,10 @@ Memorix 无需 LLM(大语言模型)或 embedding 服务,即可在本地启
```sh
npm install --global @modelcontextprotocol/server-memory@2026.7.4
export DSH_MEMORY_USER_ID=alice
dsh --config "$PWD/examples/mcp-memory/mcp-reference-memory.cordis.yml"
```
该参考服务器存储本地知识图谱,并公开实体、关系、观察、读取、搜索和打开工具。它不需要模型或 embedding 服务。该示例将 `DSH_MEMORY_USER_ID` 映射到隔离的 `MEMORY_FILE_PATH`
该参考服务器存储本地知识图谱,并公开实体、关系、观察、读取、搜索和打开工具。它不需要模型或 embedding 服务。该示例将 JSONL 存储在 `$HOME/.dsh-mcp-reference-memory.jsonl`,而不是已安装的 npm 包(package)目录中。若要覆盖该路径,请在启动 DSH 前设置 `MEMORY_FILE_PATH`
搜索只对实体名称、类型和 observation 进行不区分大小写的子字符串匹配,不是语义检索。该服务器不提供 embedding、自动摘要、冲突消解或遗忘策略。
@@ -71,11 +70,10 @@ dsh --config "$PWD/examples/mcp-memory/mcp-reference-memory.cordis.yml"
```sh
go install github.com/Gentleman-Programming/engram/cmd/engram@v1.20.0
export DSH_MEMORY_USER_ID=alice
dsh --config "$PWD/examples/mcp-memory/engram.cordis.yml"
```
该示例将用户 id 映射到隔离的 `ENGRAM_DATA_DIR`Engram 负责选择项目:它从 DSH 工作目录检测 Git 项目,接受 `ENGRAM_PROJECT` 作为显式覆盖。
Engram 负责存储和项目选择:它默认使用 `~/.engram`从 DSH 工作目录检测 Git 项目,接受 `ENGRAM_DATA_DIR``ENGRAM_PROJECT` 作为环境覆盖
## 可选的共用模型指令
@@ -93,7 +91,7 @@ dsh --config "$PWD/examples/mcp-memory/engram.cordis.yml"
2. 在同一个仍在运行的 Host 中创建 DSH 会话 B。不要复制会话 A 的对话。提出:`What is my validation drink? Check memory.`。确认模型调用了提供方的搜索或召回工具,并返回该值。
3. 继续在会话 B 中提出:`Use that preference to suggest one drink for the meeting.`。确认回答使用了召回的值。
必须新建 DSH 会话,但不需要重启 Host。只有 MCP 子进程崩溃后才需要重启或执行 HMR(热模块替换),因为当前的通用客户端会在连接断开时注销工具,且不会自动重连。初始发现过程是异步的,因此发送第一条验证提示词前,请等待提供方的 `mcp__...` 工具出现。
必须新建 DSH 会话,但不需要重启 Host。只有 MCP 子进程崩溃后才需要重启或执行 HMR(热模块替换),因为当前的通用客户端不会自动重连;其工具注册会一直保留到插件完成资源释放或成功重新同步,针对已关闭传输的调用可能失败。初始发现过程是异步的,因此发送第一条验证提示词前,请等待提供方的 `mcp__...` 工具出现。
## 接入其他 MCP 服务器
+1 -5
View File
@@ -1,5 +1,5 @@
# Opt-in reference for Engram 1.20.0. Install the pinned `engram` executable
# first; project selection remains Engram's cwd/ENGRAM_PROJECT contract.
# first; storage and project selection remain Engram-owned.
- insert:
- id: memory-engram
name: '@deepseek-ai/dsh-mcp-client'
@@ -9,7 +9,3 @@
command: engram
args: [mcp]
cwd: !!js process.cwd()
env:
ENGRAM_PROJECT: !!js process.env.ENGRAM_PROJECT ?? ''
ENGRAM_DATA_DIR: !!js >-
process.env.ENGRAM_DATA_DIR ?? (() => { const path = process.getBuiltinModule('node:path'); const os = process.getBuiltinModule('node:os'); const crypto = process.getBuiltinModule('node:crypto'); const configured = process.env.DSH_HOME; const root = configured !== undefined && configured.trim().length > 0 ? configured : path.join(os.homedir(), '.dsh'); const user = process.env.DSH_MEMORY_USER_ID?.trim() || 'default'; const scope = crypto.createHash('sha256').update(user).digest('hex').slice(0, 16); return path.join(path.resolve(root), 'mcp-memory', 'engram', scope) })()
@@ -10,4 +10,4 @@
cwd: !!js process.cwd()
env:
MEMORY_FILE_PATH: !!js >-
(() => { const path = process.getBuiltinModule('node:path'); const os = process.getBuiltinModule('node:os'); const crypto = process.getBuiltinModule('node:crypto'); const configured = process.env.DSH_HOME; const root = configured !== undefined && configured.trim().length > 0 ? configured : path.join(os.homedir(), '.dsh'); const user = process.env.DSH_MEMORY_USER_ID?.trim() || 'default'; const scope = crypto.createHash('sha256').update(user).digest('hex').slice(0, 16); return path.join(path.resolve(root), `mcp-reference-memory-${scope}.jsonl`) })()
process.env.MEMORY_FILE_PATH?.trim() || process.getBuiltinModule('node:path').join(process.getBuiltinModule('node:os').homedir(), '.dsh-mcp-reference-memory.jsonl')
+2 -2
View File
@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write packages/mcp/mcp-client/README.md
README.md: 82d974635cb35878d6f0365b1aa7a9745436240e
README.zh.md: e687c620158955f954dcfebf682503225ee710de
README.md: fe6531054b00a72050b989013297bf14db85ac66
README.zh.md: 61a1f555e2355a9761f76ac079e90dad675d6914
+1 -1
View File
@@ -61,7 +61,7 @@ Every MCP tool has two names: the raw MCP name (sent on the wire in `tools/call`
- Tool execute: `client.callTool({ name: rawName, arguments }, { signal })` with timeout + abort support—the public name is never sent to the server.
- Canonical success is `{ content: JsonValue[], structuredContent? }`; complete JSON MCP blocks survive for programmatic callers. A supported advertised `outputSchema` validates `structuredContent`; unsupported schema vocabulary falls back to unconstrained `JsonValue`.
- Native/model rendering keeps the existing text projection: text blocks join with newlines while image, audio, resource, and unsupported blocks become placeholders.
- On disconnect/crash: all tools are unregistered; no auto-reconnect.
- On disconnect/crash: no auto-reconnect. Registered tools remain until plugin disposal or a successful re-sync, and calls can fail against the closed transport; reload with HMR or restart the Host to reconnect.
## Services consumed
+1 -1
View File
@@ -61,7 +61,7 @@ MCP 客户端桥接插件:连接外部 [Model Context Protocol](https://modelc
- 工具执行:`client.callTool({ name: rawName, arguments }, { signal })`,支持超时 + 中止;公开名称绝不会发给服务器。
- 规范成功值是 `{ content: JsonValue[], structuredContent? }`;完整的 JSON MCP 块会保留给编程调用方。受支持且已声明的 `outputSchema` 会验证 `structuredContent`;不受支持的 schema 词汇会回退为不受约束的 `JsonValue`
- Native/模型渲染保留现有文本投影:文本块以换行连接,图片、音频、资源和不受支持的块会变成占位符。
- 断开/崩溃时:注销所有工具;不自动重新连接。
- 断开/崩溃时:不自动重新连接。已注册工具会一直保留到插件完成资源释放或成功重新同步,针对已关闭传输的调用可能失败;请通过 HMR 重新加载或重启 Host 来重新连接。
## 消费的服务