@yottameta/yotta-memory 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ ## v0.11.0 (2026-09-06)
2
+
3
+ **MCP 协议对齐最新版 2026-07-28(无状态时代)**:yotta-memory MCP(stdio + serve streamable HTTP)升级 dual-era——modern 直连(server/discover 免握手、逐请求 _meta 版本声明、resultType、-32022 版本错误、HTTP header 校验 HeaderMismatch -32020)服务新客户端;legacy(initialize 握手,protocolVersion 2025-11-25)兼容旧客户端,旧形状响应零惊扰;HTTP+SSE GET 保留为 deprecated 兼容入口。SKILL 标注「基于 MCP 最新协议 2026-07-28(向后兼容 2025-11-25 及更早握手)」。新增 test/mcp-dualera.test.js(26/26:A 层 + HTTP 层),存量测试全绿。
4
+
5
+ ## v0.10.1 (2026-09-05)
6
+
7
+ 发布件修复:SKILL.md frontmatter `description` 曾以 ASCII 双引号开头但未闭合
8
+ (v0.10.0 引入),严格 YAML 解析器会报 MISSING_CHAR,导致技能在 ClawHub/OpenClaw 等
9
+ 平台注册被跳过。已改为无引号裸标量(内容不变);validate-skill 新增 frontmatter 引号
10
+ 闭合检查(防再犯)。版本 0.10.0 → 0.10.1。
11
+
1
12
  ## v0.10.0 (2026-09-02)
2
13
 
3
14
  压缩遗忘(S1)——consolidate 周期摘要 + 近重复自动合并 + 分类型衰减 + 批次回滚。
package/SKILL.md CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: yotta-memory
3
- description: "元忆 —— 有权限边界的文件式智能体记忆。文件式、零依赖、可 diff/可回滚:让任何 AI 智能体活过会话,开工 recall 恢复上下文、重要信息 remember 落盘、收工归档。类型体系 FACT(公共共享)/ PREF / BOUND / COMMIT(私密隔离)。触发:记住、别忘了、记一笔、记忆、remember、recall、跨会话、上次说到、续测、交接、归档、记忆盘、共享记忆、局域网记忆、画像、开工上下文、记忆守则、profile、context、越用越懂、语义检索、反馈、维护、蒸馏、feedback、maintain、distill、explain、自我学习、自我进化、自我提升、查看平台分页、recall 候选预过滤、任务相关记忆、--focus、--embedding、压缩遗忘、consolidate、周期摘要、自动合并、分类型衰减、回滚
4
- version: 0.10.0
3
+ description: 元忆 —— 有权限边界的文件式智能体记忆。文件式、零依赖、可 diff/可回滚:让任何 AI 智能体活过会话,开工 recall 恢复上下文、重要信息 remember 落盘、收工归档。类型体系 FACT(公共共享)/ PREF / BOUND / COMMIT(私密隔离)。触发:记住、别忘了、记一笔、记忆、remember、recall、跨会话、上次说到、续测、交接、归档、记忆盘、共享记忆、局域网记忆、画像、开工上下文、记忆守则、profile、context、越用越懂、语义检索、反馈、维护、蒸馏、feedback、maintain、distill、explain、自我学习、自我进化、自我提升、查看平台分页、recall 候选预过滤、任务相关记忆、--focus、--embedding、压缩遗忘、consolidate、周期摘要、自动合并、分类型衰减、回滚
4
+ version: 0.11.0
5
5
  license: MIT
6
6
  ---
7
7
 
@@ -304,6 +304,8 @@ license: MIT
304
304
  | 其它(Trae / Qwen / Comate / Kimi 等) | 各自 MCP 配置 |
305
305
 
306
306
  ### 4.8 通用 MCP server 配置片段
307
+
308
+ > 基于 MCP 最新协议 2026-07-28(无状态时代;向后兼容 2025-11-25 及更早握手客户端)。
307
309
  ```json
308
310
  {
309
311
  "mcpServers": {
@@ -22,7 +22,10 @@ const crypto = require('crypto');
22
22
  const http = require('http');
23
23
  const child_process = require('child_process');
24
24
 
25
- const VERSION = '0.10.0';
25
+ const VERSION = '0.11.0';
26
+ // MCP 协议(2026-07-28 无状态 + 2025-11-25 legacy 握手,dual-era)
27
+ const MCP_PROTOCOL_MODERN = '2026-07-28';
28
+ const MCP_PROTOCOL_LEGACY = '2025-11-25';
26
29
  const TYPES = ['FACT', 'PREF', 'BOUND', 'COMMIT'];
27
30
  const TYPE_DIRS = { FACT: 'facts', PREF: 'prefs', BOUND: 'bounds', COMMIT: 'commits' };
28
31
  const PUBLIC_DIR = 'facts';
@@ -2952,14 +2955,50 @@ function callTool(name, args, ctx) {
2952
2955
  return { text: '错误: ' + (e && e.message ? e.message : String(e)), error: true };
2953
2956
  }
2954
2957
  }
2958
+ function reqVersion(params) {
2959
+ const meta = (params && params._meta) || {};
2960
+ return meta['io.modelcontextprotocol/protocolVersion'] || null;
2961
+ }
2962
+ function modernOk(payload, ttl) {
2963
+ const out = { resultType: 'complete' };
2964
+ Object.assign(out, payload);
2965
+ if (ttl) { out.ttlMs = ttl[0]; out.cacheScope = ttl[1]; }
2966
+ out._meta = { 'io.modelcontextprotocol/serverInfo': { name: 'yotta-memory', version: VERSION } };
2967
+ return out;
2968
+ }
2969
+ function unsupportedVersion(id, pv) {
2970
+ return { jsonrpc: '2.0', id: id, error: { code: -32022, message: 'Unsupported protocol version', data: { supported: [MCP_PROTOCOL_MODERN], requested: pv } } };
2971
+ }
2955
2972
  function handleMessage(msg, ctx) {
2956
2973
  if (!msg || msg.jsonrpc !== '2.0') return { jsonrpc: '2.0', id: msg && msg.id, error: { code: -32600, message: 'invalid request' } };
2957
2974
  const id = msg.id;
2958
2975
  if (id === undefined || id === null) return null;
2959
2976
  const method = msg.method || '';
2960
2977
  const params = msg.params || {};
2978
+ const pv = reqVersion(params);
2979
+ if (pv !== null) {
2980
+ // ---- modern(2026-07-28 无状态)----
2981
+ if (pv !== MCP_PROTOCOL_MODERN) return unsupportedVersion(id, pv);
2982
+ if (method === 'server/discover') {
2983
+ return { jsonrpc: '2.0', id: id, result: modernOk({
2984
+ supportedVersions: [MCP_PROTOCOL_MODERN],
2985
+ capabilities: { tools: {} },
2986
+ instructions: '元忆 MCP(基于 MCP 最新协议 2026-07-28,向后兼容 2025-11-25 及更早握手):文件式智能体记忆 remember/recall/search/context/forget/archive/maintain 等读写检索与维护;私密按 owner 物理隔离,数据不出本机。'
2987
+ }, [3600000, 'public']) };
2988
+ }
2989
+ if (method === 'tools/list') return { jsonrpc: '2.0', id: id, result: modernOk({ tools: mcpTools() }, [300000, 'public']) };
2990
+ if (method === 'tools/call') {
2991
+ const out = callTool(params.name || '', params.arguments || {}, ctx);
2992
+ return { jsonrpc: '2.0', id: id, result: modernOk({ content: [{ type: 'text', text: out.text }], isError: !!out.error }) };
2993
+ }
2994
+ if (method === 'initialize') {
2995
+ return { jsonrpc: '2.0', id: id, error: { code: -32601, message: "initialize removed in MCP 2026-07-28; use server/discover. supported: ['2026-07-28']" } };
2996
+ }
2997
+ return { jsonrpc: '2.0', id: id, error: { code: -32601, message: 'Method not found: ' + method } };
2998
+ }
2999
+ // ---- legacy(<=2025-11-25,initialize 握手;响应保持旧形状)----
2961
3000
  if (method === 'initialize') {
2962
- return { jsonrpc: '2.0', id: id, result: { protocolVersion: '2025-03-26', capabilities: { tools: {} }, serverInfo: { name: 'yotta-memory', version: VERSION } } };
3001
+ return { jsonrpc: '2.0', id: id, result: { protocolVersion: MCP_PROTOCOL_LEGACY, capabilities: { tools: {} }, serverInfo: { name: 'yotta-memory', version: VERSION } } };
2963
3002
  }
2964
3003
  if (method === 'ping') return { jsonrpc: '2.0', id: id, result: {} };
2965
3004
  if (method === 'tools/list') return { jsonrpc: '2.0', id: id, result: { tools: mcpTools() } };
@@ -2987,17 +3026,34 @@ function cmdServe(opts) {
2987
3026
  if (tokenMap[agent] && tokenMap[agent].token === token) return { agent: agent };
2988
3027
  return null;
2989
3028
  }
3029
+ function originAllowed(req) {
3030
+ const origin = req.headers['origin'];
3031
+ if (!origin) return true;
3032
+ let oHost = '';
3033
+ try { oHost = new URL(origin).host; } catch (e) { return false; }
3034
+ const hHost = req.headers['host'] || '';
3035
+ const allowed = [hHost, 'localhost', 'localhost:' + port, '127.0.0.1', '127.0.0.1:' + port, '[::1]', '[::1]:' + port];
3036
+ return oHost === hHost || allowed.indexOf(oHost) !== -1;
3037
+ }
3038
+ function sendJson(res, code, obj) {
3039
+ res.writeHead(code, { 'Content-Type': 'application/json' });
3040
+ res.end(JSON.stringify(obj));
3041
+ }
2990
3042
  const server = http.createServer(function (req, res) {
2991
3043
  let pathname = '/';
2992
3044
  try { pathname = new URL(req.url, 'http://' + (req.headers.host || 'localhost')).pathname; } catch (e) {}
2993
3045
  if (pathname !== '/mcp') { res.writeHead(404, { 'Content-Type': 'text/plain' }); res.end('not found'); return; }
3046
+ if (!originAllowed(req)) {
3047
+ sendJson(res, 403, { jsonrpc: '2.0', error: { code: -32000, message: 'origin not allowed' } });
3048
+ return;
3049
+ }
2994
3050
  const auth = authorize(req);
2995
3051
  if (!auth) {
2996
- res.writeHead(401, { 'Content-Type': 'application/json' });
2997
- res.end(JSON.stringify({ jsonrpc: '2.0', error: { code: -32001, message: 'unauthorized: 需要有效 Bearer token 与 X-Agent-Id' } }));
3052
+ sendJson(res, 401, { jsonrpc: '2.0', error: { code: -32001, message: 'unauthorized: 需要有效 Bearer token 与 X-Agent-Id' } });
2998
3053
  return;
2999
3054
  }
3000
3055
  if (req.method === 'GET') {
3056
+ // deprecated 兼容:HTTP+SSE 端点(MCP 2026-07-28 起正式 Deprecated,12 个月窗口内保留给老客户端;新客户端走 POST)
3001
3057
  res.writeHead(200, { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive' });
3002
3058
  res.write('event: endpoint\ndata: /mcp\n\n');
3003
3059
  const iv = setInterval(function () { res.write(': keep-alive\n\n'); }, 15000);
@@ -3010,14 +3066,23 @@ function cmdServe(opts) {
3010
3066
  req.on('end', function () {
3011
3067
  let msg;
3012
3068
  try { msg = JSON.parse(body); } catch (e) {
3013
- res.writeHead(400, { 'Content-Type': 'application/json' });
3014
- res.end(JSON.stringify({ jsonrpc: '2.0', error: { code: -32700, message: 'parse error' } }));
3069
+ sendJson(res, 400, { jsonrpc: '2.0', error: { code: -32700, message: 'parse error' } });
3070
+ return;
3071
+ }
3072
+ const metaPv = reqVersion(msg.params) || null;
3073
+ const hdrPv = req.headers['mcp-protocol-version'] || null;
3074
+ if (hdrPv && metaPv && hdrPv !== metaPv) {
3075
+ sendJson(res, 400, { jsonrpc: '2.0', id: msg.id, error: { code: -32020, message: 'HeaderMismatch: MCP-Protocol-Version header/body 不一致', data: { header: hdrPv, body: metaPv } } });
3076
+ return;
3077
+ }
3078
+ const mcpMethod = req.headers['mcp-method'];
3079
+ if (mcpMethod && metaPv === MCP_PROTOCOL_MODERN && mcpMethod !== msg.method) {
3080
+ sendJson(res, 400, { jsonrpc: '2.0', id: msg.id, error: { code: -32020, message: 'HeaderMismatch: Mcp-Method header/body 不一致', data: { header: mcpMethod, body: msg.method } } });
3015
3081
  return;
3016
3082
  }
3017
3083
  const resp = handleMessage(msg, auth);
3018
3084
  if (resp === null) { res.writeHead(204); res.end(); return; }
3019
- res.writeHead(200, { 'Content-Type': 'application/json' });
3020
- res.end(JSON.stringify(resp));
3085
+ sendJson(res, 200, resp);
3021
3086
  });
3022
3087
  return;
3023
3088
  }
@@ -3027,12 +3092,12 @@ function cmdServe(opts) {
3027
3092
  console.log('yotta-memory 记忆引擎已启动(v' + VERSION + ')');
3028
3093
  console.log('URL: http://' + host + ':' + port + '/mcp');
3029
3094
  console.log('记忆库: ' + root);
3095
+ console.log('MCP 协议: 2026-07-28(modern,server/discover)/ 2025-11-25(legacy 握手兼容)');
3030
3096
  if (noAuth) console.log('鉴权: 已关闭(--no-auth,仅限可信内网)');
3031
3097
  else console.log('鉴权: Bearer token + X-Agent-Id(yotta-memory token new --agent <id> 生成)');
3032
3098
  console.log('按 Ctrl+C 停止');
3033
3099
  });
3034
3100
  }
3035
-
3036
3101
  // ---- stdio 本地零进程模式(客户端按需拉起 CLI)----
3037
3102
  function cmdServeStdio() {
3038
3103
  const root = userRoot();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yottameta/yotta-memory",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "description": "Yuanyi (元忆) — boundary-aware, file-based memory for AI agents. File-based, zero-dependency, diff/rollback-able; FACT/PREF/BOUND/COMMIT types (public shared / private isolated), user-level + project-level storage; v0.10 consolidation (periodic summaries with provenance, near-duplicate auto-merge, per-type decay, batch audit + rollback), v0.9 recall quality + context focus + optional local embedding plugin, plus v0.8 semantic search, feedback loop, self-organization and distillation.",
5
5
  "license": "MIT",
6
6
  "keywords": [