@datafrog-io/n2n-memory 1.0.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/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ ISC License
2
+
3
+ Copyright (c) 2025, James
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,60 @@
1
+ # N2N 记忆 (N2N Memory) MCP 服务
2
+
3
+ 这是一个专为解决 AI 跨项目开发时“记忆污染”而设计的 MCP 服务。它将 AI 的认知碎片持久化在每个项目自己的目录下。
4
+
5
+ ## 核心亮点
6
+ - **项目级物理隔离**: 记忆文件存储在 `[项目根目录]/.mcp/memory.json`。
7
+ - **Git 版本可控**: 自动对 JSON 数据进行字典序排序,生成清晰的 `git diff`。
8
+ - **工具中立**: 使用 `.mcp` 命名,不绑定任何特定 AI 品牌或 IDE 插件。
9
+ - **资产化**: 记忆随代码走,团队成员拉取仓库即可共享 AI 对架构的理解。
10
+
11
+ ## 快速配置
12
+
13
+ ### 1. JSON 配置 (IDE / Claude Desktop)
14
+
15
+ 根据您使用的客户端,在相应的 MCP 配置文件中添加以下内容:
16
+
17
+ #### Claude Desktop
18
+ 配置文件路径: `%APPDATA%\Claude\claude_desktop_config.json`
19
+
20
+ ```json
21
+ {
22
+ "mcpServers": {
23
+ "n2n-memory": {
24
+ "command": "node",
25
+ "args": ["D:/DevSpace/MCP_N2N_Memory/build/index.js"]
26
+ }
27
+ }
28
+ }
29
+ ```
30
+
31
+ #### Cursor / VSCode (MCP 插件)
32
+ 在 MCP 设置面板中添加:
33
+ - **Name**: `n2n-memory`
34
+ - **Type**: `command`
35
+ - **Command**: `node D:/DevSpace/MCP_N2N_Memory/build/index.js`
36
+
37
+ ### 2. 使用指南 (Usage Guide)
38
+
39
+ 本服务完全由路径驱动,AI 助手在调用工具时需要关注以下几点:
40
+
41
+ 1. **绝对路径**: 调用任何 `n2n_*` 工具时,必须传入当前项目根目录的**绝对路径**(`projectPath`)。
42
+ 2. **自动存储**: 记忆将自动保存在 `[项目路径]/.mcp/memory.json`。
43
+ 3. **协作共享**: 建议将 `.mcp/memory.json` 提交至 Git 仓库,以便团队成员共享 AI 对代码架构的理解。
44
+
45
+ #### 常用场景指令示例:
46
+ - `n2n_add_entities`: 创建新实体。
47
+ - `n2n_add_observations`: 追加观测事实。
48
+ - `n2n_create_relations`: 建立实体间联系。
49
+ - `n2n_read_graph`: 读取完整图谱。
50
+ - `n2n_search`: 关键词搜索图谱(支持实体名、类型、观测事实)。
51
+ - *"将这个新发现的 Bug 记录到内存中"* -> AI 将调用 `n2n_add_observations`。
52
+
53
+ ## 文档指引 (Docs)
54
+
55
+ - **[设计方案](./docs/DESIGN.md)**: 了解为什么要进行物理隔离以及核心架构设计。
56
+ - **[API 参考手册](./docs/API_REFERENCE.md)**: 详细描述了可用的 Tool 及其参数结构。
57
+ - **[开发与维护](./docs/DEVELOPMENT.md)**: 指导如何构建、测试和扩展本项目。
58
+
59
+ ## 许可证
60
+ 本项目采用 [ISC 许可证](./LICENSE)。
package/build/index.js ADDED
@@ -0,0 +1,248 @@
1
+ #!/usr/bin/env node
2
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, ErrorCode, McpError, } from "@modelcontextprotocol/sdk/types.js";
5
+ import { z } from "zod";
6
+ import { MemoryManager } from "./memory-manager.js";
7
+ import { EntitySchema, RelationSchema } from "./types.js";
8
+ // Input Schemas for validation
9
+ const AddEntitiesSchema = z.object({
10
+ projectPath: z.string(),
11
+ entities: z.array(EntitySchema),
12
+ });
13
+ const AddObservationsSchema = z.object({
14
+ projectPath: z.string(),
15
+ observations: z.array(z.object({
16
+ entityName: z.string(),
17
+ contents: z.array(z.string()),
18
+ })),
19
+ });
20
+ const CreateRelationsSchema = z.object({
21
+ projectPath: z.string(),
22
+ relations: z.array(RelationSchema),
23
+ });
24
+ const ReadGraphSchema = z.object({
25
+ projectPath: z.string(),
26
+ });
27
+ const SearchSchema = z.object({
28
+ projectPath: z.string(),
29
+ query: z.string().describe("Search keywords for entities, types, or observations"),
30
+ });
31
+ export const server = new Server({
32
+ name: "n2n-memory",
33
+ version: "1.0.0",
34
+ }, {
35
+ capabilities: {
36
+ tools: {},
37
+ resources: {},
38
+ },
39
+ });
40
+ // --- Handler Logic Extensions (Exported for Testing) ---
41
+ export const Handlers = {
42
+ async listTools() {
43
+ return {
44
+ tools: [
45
+ {
46
+ name: "n2n_add_entities",
47
+ description: "Add new entities (concepts, components, nodes) to the project-local knowledge graph. Use this when you discover a new significant part of the project architecture or a core concept.",
48
+ inputSchema: {
49
+ type: "object",
50
+ properties: {
51
+ projectPath: { type: "string", description: "Absolute path to the project root" },
52
+ entities: {
53
+ type: "array",
54
+ items: {
55
+ type: "object",
56
+ properties: {
57
+ name: { type: "string", description: "Unique name of the entity" },
58
+ entityType: { type: "string", description: "Category of the entity (e.g., CLASS, FUNCTION, MODULE, UI_COMPONENT)" },
59
+ observations: { type: "array", items: { type: "string" }, description: "Initial facts or documentation fragments about this entity" },
60
+ },
61
+ required: ["name", "entityType", "observations"],
62
+ },
63
+ },
64
+ },
65
+ required: ["projectPath", "entities"],
66
+ },
67
+ },
68
+ {
69
+ name: "n2n_add_observations",
70
+ description: "Append new facts or discovery details to existing entities. Use this as you explore the code and learn more about how specific parts work.",
71
+ inputSchema: {
72
+ type: "object",
73
+ properties: {
74
+ projectPath: { type: "string", description: "Absolute path to the project root" },
75
+ observations: {
76
+ type: "array",
77
+ items: {
78
+ type: "object",
79
+ properties: {
80
+ entityName: { type: "string", description: "The name of the existing entity to update" },
81
+ contents: { type: "array", items: { type: "string" }, description: "New specific facts or insights to add" },
82
+ },
83
+ required: ["entityName", "contents"],
84
+ },
85
+ },
86
+ },
87
+ required: ["projectPath", "observations"],
88
+ },
89
+ },
90
+ {
91
+ name: "n2n_create_relations",
92
+ description: "Define relationships between existing entities. Use this to map out dependencies, implementation details, or data flows (e.g., 'AuthService' IMPLEMENTS 'IAuth').",
93
+ inputSchema: {
94
+ type: "object",
95
+ properties: {
96
+ projectPath: { type: "string", description: "Absolute path to the project root" },
97
+ relations: {
98
+ type: "array",
99
+ items: {
100
+ type: "object",
101
+ properties: {
102
+ from: { type: "string", description: "Source entity name" },
103
+ to: { type: "string", description: "Target entity name" },
104
+ relationType: { type: "string", description: "The nature of the link (e.g., CALLS, EXTENDS, USES, CONTAINS)" },
105
+ },
106
+ required: ["from", "to", "relationType"],
107
+ },
108
+ },
109
+ },
110
+ required: ["projectPath", "relations"],
111
+ },
112
+ },
113
+ {
114
+ name: "n2n_read_graph",
115
+ description: "Fetch the entire knowledge graph for the current project. Use this to get an overview of the system architecture and previously stored context.",
116
+ inputSchema: {
117
+ type: "object",
118
+ properties: {
119
+ projectPath: { type: "string", description: "Absolute path to the project root" },
120
+ },
121
+ required: ["projectPath"],
122
+ },
123
+ },
124
+ {
125
+ name: "n2n_search",
126
+ description: "Search for specific entities, relations, or observations within the project knowledge graph using keywords. Useful for large projects where the full graph is too big to browse.",
127
+ inputSchema: {
128
+ type: "object",
129
+ properties: {
130
+ projectPath: { type: "string", description: "Absolute path to the project root" },
131
+ query: { type: "string", description: "Keywords to search for in names, types, and observations" },
132
+ },
133
+ required: ["projectPath", "query"],
134
+ },
135
+ },
136
+ ],
137
+ };
138
+ },
139
+ async callTool(name, args) {
140
+ try {
141
+ switch (name) {
142
+ case "n2n_add_entities": {
143
+ const parsed = AddEntitiesSchema.parse(args);
144
+ await MemoryManager.addEntities(parsed.projectPath, parsed.entities);
145
+ return { content: [{ type: "text", text: `Success: Added ${parsed.entities.length} entities.` }] };
146
+ }
147
+ case "n2n_add_observations": {
148
+ const parsed = AddObservationsSchema.parse(args);
149
+ const addedCount = await MemoryManager.addObservations(parsed.projectPath, parsed.observations);
150
+ return { content: [{ type: "text", text: `Success: Added ${addedCount} observation fragments.` }] };
151
+ }
152
+ case "n2n_create_relations": {
153
+ const parsed = CreateRelationsSchema.parse(args);
154
+ await MemoryManager.createRelations(parsed.projectPath, parsed.relations);
155
+ return { content: [{ type: "text", text: `Success: Created ${parsed.relations.length} relations.` }] };
156
+ }
157
+ case "n2n_read_graph": {
158
+ const parsed = ReadGraphSchema.parse(args);
159
+ const graph = await MemoryManager.readGraph(parsed.projectPath);
160
+ return { content: [{ type: "text", text: JSON.stringify(graph, null, 2) }] };
161
+ }
162
+ case "n2n_search": {
163
+ const parsed = SearchSchema.parse(args);
164
+ const result = await MemoryManager.search(parsed.projectPath, parsed.query);
165
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
166
+ }
167
+ default:
168
+ throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
169
+ }
170
+ }
171
+ catch (error) {
172
+ if (error instanceof z.ZodError) {
173
+ return {
174
+ content: [{
175
+ type: "text",
176
+ text: `Validation Error: ${error.issues.map((i) => `${i.path.join('.')}: ${i.message}`).join(', ')}`
177
+ }],
178
+ isError: true,
179
+ };
180
+ }
181
+ return {
182
+ content: [{ type: "text", text: `Execution Error: ${error instanceof Error ? error.message : String(error)}` }],
183
+ isError: true,
184
+ };
185
+ }
186
+ },
187
+ async listResources() {
188
+ return {
189
+ resources: [
190
+ {
191
+ uri: "mcp://memory/graph",
192
+ name: "Project Knowledge Graph",
193
+ description: "The complete knowledge graph stored in .mcp/memory.json",
194
+ mimeType: "application/json",
195
+ }
196
+ ]
197
+ };
198
+ },
199
+ async readResource(uriString) {
200
+ const uri = new URL(uriString);
201
+ if (uri.protocol !== "mcp:" || uri.host !== "memory") {
202
+ throw new McpError(ErrorCode.InvalidRequest, `Unknown resource URI: ${uriString}`);
203
+ }
204
+ const projectPath = uri.searchParams.get("path");
205
+ if (!projectPath) {
206
+ throw new McpError(ErrorCode.InvalidParams, "projectPath query parameter 'path' is required");
207
+ }
208
+ try {
209
+ const graph = await MemoryManager.readGraph(projectPath);
210
+ return {
211
+ contents: [
212
+ {
213
+ uri: uriString,
214
+ mimeType: "application/json",
215
+ text: JSON.stringify(graph, null, 2),
216
+ }
217
+ ]
218
+ };
219
+ }
220
+ catch (error) {
221
+ throw new McpError(ErrorCode.InternalError, `Failed to read memory: ${error instanceof Error ? error.message : String(error)}`);
222
+ }
223
+ }
224
+ };
225
+ // --- Resources ---
226
+ server.setRequestHandler(ListResourcesRequestSchema, async () => {
227
+ return Handlers.listResources();
228
+ });
229
+ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
230
+ return Handlers.readResource(request.params.uri);
231
+ });
232
+ // --- Tools ---
233
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
234
+ return Handlers.listTools();
235
+ });
236
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
237
+ return Handlers.callTool(request.params.name, request.params.arguments);
238
+ });
239
+ async function main() {
240
+ const transport = new StdioServerTransport();
241
+ await server.connect(transport);
242
+ console.error("N2N Memory MCP server running on stdio");
243
+ }
244
+ main().catch((error) => {
245
+ console.error("Fatal Server Error:", error);
246
+ process.exit(1);
247
+ });
248
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EACH,qBAAqB,EACrB,sBAAsB,EACtB,0BAA0B,EAC1B,yBAAyB,EACzB,SAAS,EACT,QAAQ,GACX,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE1D,+BAA+B;AAC/B,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC/B,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;IACvB,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC;CAClC,CAAC,CAAC;AAEH,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IACnC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;IACvB,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;QAC3B,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE;QACtB,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;KAChC,CAAC,CAAC;CACN,CAAC,CAAC;AAEH,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IACnC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;IACvB,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC;CACrC,CAAC,CAAC;AAEH,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IAC7B,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;CAC1B,CAAC,CAAC;AAEH,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1B,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;IACvB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sDAAsD,CAAC;CACrF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,MAAM,GAAG,IAAI,MAAM,CAC5B;IACI,IAAI,EAAE,YAAY;IAClB,OAAO,EAAE,OAAO;CACnB,EACD;IACI,YAAY,EAAE;QACV,KAAK,EAAE,EAAE;QACT,SAAS,EAAE,EAAE;KAChB;CACJ,CACJ,CAAC;AAEF,0DAA0D;AAC1D,MAAM,CAAC,MAAM,QAAQ,GAAG;IACpB,KAAK,CAAC,SAAS;QACX,OAAO;YACH,KAAK,EAAE;gBACH;oBACI,IAAI,EAAE,kBAAkB;oBACxB,WAAW,EAAE,uLAAuL;oBACpM,WAAW,EAAE;wBACT,IAAI,EAAE,QAAQ;wBACd,UAAU,EAAE;4BACR,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,mCAAmC,EAAE;4BACjF,QAAQ,EAAE;gCACN,IAAI,EAAE,OAAO;gCACb,KAAK,EAAE;oCACH,IAAI,EAAE,QAAQ;oCACd,UAAU,EAAE;wCACR,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,2BAA2B,EAAE;wCAClE,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,sEAAsE,EAAE;wCACnH,YAAY,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,WAAW,EAAE,4DAA4D,EAAE;qCACxI;oCACD,QAAQ,EAAE,CAAC,MAAM,EAAE,YAAY,EAAE,cAAc,CAAC;iCACnD;6BACJ;yBACJ;wBACD,QAAQ,EAAE,CAAC,aAAa,EAAE,UAAU,CAAC;qBACxC;iBACJ;gBACD;oBACI,IAAI,EAAE,sBAAsB;oBAC5B,WAAW,EAAE,4IAA4I;oBACzJ,WAAW,EAAE;wBACT,IAAI,EAAE,QAAQ;wBACd,UAAU,EAAE;4BACR,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,mCAAmC,EAAE;4BACjF,YAAY,EAAE;gCACV,IAAI,EAAE,OAAO;gCACb,KAAK,EAAE;oCACH,IAAI,EAAE,QAAQ;oCACd,UAAU,EAAE;wCACR,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,2CAA2C,EAAE;wCACxF,QAAQ,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,WAAW,EAAE,uCAAuC,EAAE;qCAC/G;oCACD,QAAQ,EAAE,CAAC,YAAY,EAAE,UAAU,CAAC;iCACvC;6BACJ;yBACJ;wBACD,QAAQ,EAAE,CAAC,aAAa,EAAE,cAAc,CAAC;qBAC5C;iBACJ;gBACD;oBACI,IAAI,EAAE,sBAAsB;oBAC5B,WAAW,EAAE,mKAAmK;oBAChL,WAAW,EAAE;wBACT,IAAI,EAAE,QAAQ;wBACd,UAAU,EAAE;4BACR,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,mCAAmC,EAAE;4BACjF,SAAS,EAAE;gCACP,IAAI,EAAE,OAAO;gCACb,KAAK,EAAE;oCACH,IAAI,EAAE,QAAQ;oCACd,UAAU,EAAE;wCACR,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,oBAAoB,EAAE;wCAC3D,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,oBAAoB,EAAE;wCACzD,YAAY,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,+DAA+D,EAAE;qCACjH;oCACD,QAAQ,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,cAAc,CAAC;iCAC3C;6BACJ;yBACJ;wBACD,QAAQ,EAAE,CAAC,aAAa,EAAE,WAAW,CAAC;qBACzC;iBACJ;gBACD;oBACI,IAAI,EAAE,gBAAgB;oBACtB,WAAW,EAAE,iJAAiJ;oBAC9J,WAAW,EAAE;wBACT,IAAI,EAAE,QAAQ;wBACd,UAAU,EAAE;4BACR,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,mCAAmC,EAAE;yBACpF;wBACD,QAAQ,EAAE,CAAC,aAAa,CAAC;qBAC5B;iBACJ;gBACD;oBACI,IAAI,EAAE,YAAY;oBAClB,WAAW,EAAE,kLAAkL;oBAC/L,WAAW,EAAE;wBACT,IAAI,EAAE,QAAQ;wBACd,UAAU,EAAE;4BACR,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,mCAAmC,EAAE;4BACjF,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,0DAA0D,EAAE;yBACrG;wBACD,QAAQ,EAAE,CAAC,aAAa,EAAE,OAAO,CAAC;qBACrC;iBACJ;aACJ;SACJ,CAAC;IACN,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,IAAY,EAAE,IAAS;QAClC,IAAI,CAAC;YACD,QAAQ,IAAI,EAAE,CAAC;gBACX,KAAK,kBAAkB,CAAC,CAAC,CAAC;oBACtB,MAAM,MAAM,GAAG,iBAAiB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;oBAC7C,MAAM,aAAa,CAAC,WAAW,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;oBACrE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,kBAAkB,MAAM,CAAC,QAAQ,CAAC,MAAM,YAAY,EAAE,CAAC,EAAE,CAAC;gBACvG,CAAC;gBAED,KAAK,sBAAsB,CAAC,CAAC,CAAC;oBAC1B,MAAM,MAAM,GAAG,qBAAqB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;oBACjD,MAAM,UAAU,GAAG,MAAM,aAAa,CAAC,eAAe,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC;oBAChG,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,kBAAkB,UAAU,yBAAyB,EAAE,CAAC,EAAE,CAAC;gBACxG,CAAC;gBAED,KAAK,sBAAsB,CAAC,CAAC,CAAC;oBAC1B,MAAM,MAAM,GAAG,qBAAqB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;oBACjD,MAAM,aAAa,CAAC,eAAe,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;oBAC1E,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,oBAAoB,MAAM,CAAC,SAAS,CAAC,MAAM,aAAa,EAAE,CAAC,EAAE,CAAC;gBAC3G,CAAC;gBAED,KAAK,gBAAgB,CAAC,CAAC,CAAC;oBACpB,MAAM,MAAM,GAAG,eAAe,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;oBAC3C,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,SAAS,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;oBAChE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;gBACjF,CAAC;gBAED,KAAK,YAAY,CAAC,CAAC,CAAC;oBAChB,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;oBACxC,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;oBAC5E,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;gBAClF,CAAC;gBAED;oBACI,MAAM,IAAI,QAAQ,CAAC,SAAS,CAAC,cAAc,EAAE,iBAAiB,IAAI,EAAE,CAAC,CAAC;YAC9E,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,IAAI,KAAK,YAAY,CAAC,CAAC,QAAQ,EAAE,CAAC;gBAC9B,OAAO;oBACH,OAAO,EAAE,CAAC;4BACN,IAAI,EAAE,MAAM;4BACZ,IAAI,EAAE,qBAAqB,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAa,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;yBACnH,CAAC;oBACF,OAAO,EAAE,IAAI;iBAChB,CAAC;YACN,CAAC;YACD,OAAO;gBACH,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,oBAAoB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;gBAC/G,OAAO,EAAE,IAAI;aAChB,CAAC;QACN,CAAC;IACL,CAAC;IAED,KAAK,CAAC,aAAa;QACf,OAAO;YACH,SAAS,EAAE;gBACP;oBACI,GAAG,EAAE,oBAAoB;oBACzB,IAAI,EAAE,yBAAyB;oBAC/B,WAAW,EAAE,yDAAyD;oBACtE,QAAQ,EAAE,kBAAkB;iBAC/B;aACJ;SACJ,CAAC;IACN,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,SAAiB;QAChC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC;QAC/B,IAAI,GAAG,CAAC,QAAQ,KAAK,MAAM,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACnD,MAAM,IAAI,QAAQ,CAAC,SAAS,CAAC,cAAc,EAAE,yBAAyB,SAAS,EAAE,CAAC,CAAC;QACvF,CAAC;QAED,MAAM,WAAW,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACjD,IAAI,CAAC,WAAW,EAAE,CAAC;YACf,MAAM,IAAI,QAAQ,CAAC,SAAS,CAAC,aAAa,EAAE,gDAAgD,CAAC,CAAC;QAClG,CAAC;QAED,IAAI,CAAC;YACD,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;YACzD,OAAO;gBACH,QAAQ,EAAE;oBACN;wBACI,GAAG,EAAE,SAAS;wBACd,QAAQ,EAAE,kBAAkB;wBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;qBACvC;iBACJ;aACJ,CAAC;QACN,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,MAAM,IAAI,QAAQ,CACd,SAAS,CAAC,aAAa,EACvB,0BAA0B,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CACrF,CAAC;QACN,CAAC;IACL,CAAC;CACJ,CAAC;AAEF,oBAAoB;AACpB,MAAM,CAAC,iBAAiB,CAAC,0BAA0B,EAAE,KAAK,IAAI,EAAE;IAC5D,OAAO,QAAQ,CAAC,aAAa,EAAE,CAAC;AACpC,CAAC,CAAC,CAAC;AAEH,MAAM,CAAC,iBAAiB,CAAC,yBAAyB,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;IAClE,OAAO,QAAQ,CAAC,YAAY,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AACrD,CAAC,CAAC,CAAC;AAEH,gBAAgB;AAChB,MAAM,CAAC,iBAAiB,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE;IACxD,OAAO,QAAQ,CAAC,SAAS,EAAE,CAAC;AAChC,CAAC,CAAC,CAAC;AAEH,MAAM,CAAC,iBAAiB,CAAC,qBAAqB,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;IAC9D,OAAO,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;AAC5E,CAAC,CAAC,CAAC;AAEH,KAAK,UAAU,IAAI;IACf,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAC;AAC5D,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,qBAAqB,EAAE,KAAK,CAAC,CAAC;IAC5C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACpB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,102 @@
1
+ import fs from "fs-extra";
2
+ import path from "path";
3
+ import { KnowledgeGraphSchema } from "./types.js";
4
+ export const MEMORY_FILE_PATH = ".mcp/memory.json";
5
+ export class MemoryManager {
6
+ static async readGraph(projectPath) {
7
+ const filePath = path.resolve(projectPath, MEMORY_FILE_PATH);
8
+ try {
9
+ if (await fs.pathExists(filePath)) {
10
+ const data = await fs.readJson(filePath);
11
+ return KnowledgeGraphSchema.parse(data);
12
+ }
13
+ }
14
+ catch (error) {
15
+ throw new Error(`Failed to read memory file at ${filePath}: ${error instanceof Error ? error.message : String(error)}`);
16
+ }
17
+ return { entities: [], relations: [] };
18
+ }
19
+ static async writeGraph(projectPath, graph) {
20
+ const filePath = path.resolve(projectPath, MEMORY_FILE_PATH);
21
+ const dirPath = path.dirname(filePath);
22
+ try {
23
+ // Git-friendly sorting
24
+ graph.entities.sort((a, b) => a.name.localeCompare(b.name));
25
+ graph.entities.forEach(entity => {
26
+ if (entity.observations) {
27
+ entity.observations.sort();
28
+ }
29
+ else {
30
+ entity.observations = [];
31
+ }
32
+ });
33
+ graph.relations.sort((a, b) => {
34
+ const fromComp = a.from.localeCompare(b.from);
35
+ if (fromComp !== 0)
36
+ return fromComp;
37
+ const toComp = a.to.localeCompare(b.to);
38
+ if (toComp !== 0)
39
+ return toComp;
40
+ return a.relationType.localeCompare(b.relationType);
41
+ });
42
+ await fs.ensureDir(dirPath);
43
+ await fs.writeJson(filePath, graph, { spaces: 2 });
44
+ }
45
+ catch (error) {
46
+ throw new Error(`Failed to write memory file at ${filePath}: ${error instanceof Error ? error.message : String(error)}`);
47
+ }
48
+ }
49
+ static async addEntities(projectPath, newEntities) {
50
+ const graph = await this.readGraph(projectPath);
51
+ newEntities.forEach(newEntity => {
52
+ const existing = graph.entities.find(e => e.name === newEntity.name);
53
+ if (existing) {
54
+ existing.observations = Array.from(new Set([...existing.observations, ...newEntity.observations]));
55
+ }
56
+ else {
57
+ graph.entities.push(newEntity);
58
+ }
59
+ });
60
+ await this.writeGraph(projectPath, graph);
61
+ }
62
+ static async addObservations(projectPath, observations) {
63
+ const graph = await this.readGraph(projectPath);
64
+ let addedCount = 0;
65
+ observations.forEach(obs => {
66
+ const entity = graph.entities.find(e => e.name === obs.entityName);
67
+ if (entity) {
68
+ entity.observations = Array.from(new Set([...entity.observations, ...obs.contents]));
69
+ addedCount += obs.contents.length;
70
+ }
71
+ });
72
+ await this.writeGraph(projectPath, graph);
73
+ return addedCount;
74
+ }
75
+ static async createRelations(projectPath, newRelations) {
76
+ const graph = await this.readGraph(projectPath);
77
+ newRelations.forEach(newRel => {
78
+ const exists = graph.relations.some(r => r.from === newRel.from && r.to === newRel.to && r.relationType === newRel.relationType);
79
+ if (!exists) {
80
+ graph.relations.push(newRel);
81
+ }
82
+ });
83
+ await this.writeGraph(projectPath, graph);
84
+ }
85
+ static async search(projectPath, query) {
86
+ const graph = await this.readGraph(projectPath);
87
+ const lowerQuery = query.toLowerCase();
88
+ const filteredEntities = graph.entities.filter(e => e.name.toLowerCase().includes(lowerQuery) ||
89
+ e.entityType.toLowerCase().includes(lowerQuery) ||
90
+ e.observations.some(o => o.toLowerCase().includes(lowerQuery)));
91
+ const entityNames = new Set(filteredEntities.map(e => e.name));
92
+ const filteredRelations = graph.relations.filter(r => r.from.toLowerCase().includes(lowerQuery) ||
93
+ r.to.toLowerCase().includes(lowerQuery) ||
94
+ r.relationType.toLowerCase().includes(lowerQuery) ||
95
+ (entityNames.has(r.from) || entityNames.has(r.to)));
96
+ return {
97
+ entities: filteredEntities,
98
+ relations: filteredRelations
99
+ };
100
+ }
101
+ }
102
+ //# sourceMappingURL=memory-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-manager.js","sourceRoot":"","sources":["../src/memory-manager.ts"],"names":[],"mappings":"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"}
package/build/types.js ADDED
@@ -0,0 +1,16 @@
1
+ import { z } from "zod";
2
+ export const EntitySchema = z.object({
3
+ name: z.string().describe("Unique name of the entity"),
4
+ entityType: z.string().describe("Type of entity (e.g. COMPONENT, CONCEPT, BUG)"),
5
+ observations: z.array(z.string()).describe("A list of observations or facts about the entity"),
6
+ });
7
+ export const RelationSchema = z.object({
8
+ from: z.string().describe("Name of the source entity"),
9
+ to: z.string().describe("Name of the target entity"),
10
+ relationType: z.string().describe("The type of relationship (e.g. DEPENDS_ON, IMPLEMENTS)"),
11
+ });
12
+ export const KnowledgeGraphSchema = z.object({
13
+ entities: z.array(EntitySchema).default([]),
14
+ relations: z.array(RelationSchema).default([]),
15
+ });
16
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IACjC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,2BAA2B,CAAC;IACtD,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,+CAA+C,CAAC;IAChF,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,CAAC,kDAAkD,CAAC;CACjG,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC;IACnC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,2BAA2B,CAAC;IACtD,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,2BAA2B,CAAC;IACpD,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,wDAAwD,CAAC;CAC9F,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IAC3C,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;CACjD,CAAC,CAAC"}
@@ -0,0 +1,70 @@
1
+ # N2N Memory API 参数参考手册
2
+
3
+ 本项目提供了一套基于项目本地路径的知识图谱管理工具。所有工具均要求传入 `projectPath` 以确保记忆的物理隔离。
4
+
5
+ ## 核心工具集
6
+
7
+ ### 1. `project_add_entities`
8
+ 向项目的知识图谱中添加新的实体(名词/概念)。
9
+
10
+ **输入参数:**
11
+ - `projectPath` (string): 项目根目录的绝对路径。
12
+ - `entities` (Array): 实体对象列表。
13
+ - `name` (string): 实体名称(唯一标识)。
14
+ - `entityType` (string): 实体类型(如:CONCEPT, COMPONENT, BUG)。
15
+ - `observations` (string[]): 关于该实体的观测事实。
16
+
17
+ **逻辑描述:**
18
+ - 如果实体名称已存在,将合并 `observations` 并自动去重。
19
+ - 写入前会对实体名称进行字典序排序。
20
+
21
+ ---
22
+
23
+ ### 2. `project_add_observations`
24
+ 为已存在的实体追加新的发现或事实。
25
+
26
+ **输入参数:**
27
+ - `projectPath` (string): 项目根目录的绝对路径。
28
+ - `observations` (Array):
29
+ - `entityName` (string): 目标实体名称。
30
+ - `contents` (string[]): 要追加的事实列表。
31
+
32
+ **逻辑描述:**
33
+ - 仅当实体存在时才会添加。
34
+ - 自动对 observation 内容执行字典序排序及去重。
35
+
36
+ ---
37
+
38
+ ### 3. `project_create_relations`
39
+ 在实体之间建立逻辑关系(谓词)。
40
+
41
+ **输入参数:**
42
+ - `projectPath` (string): 项目根目录的绝对路径。
43
+ - `relations` (Array):
44
+ - `from` (string): 源实体名称。
45
+ - `to` (string): 目标实体名称。
46
+ - `relationType` (string): 关系类型(如:DEPENDS_ON, IMPLEMENTS)。
47
+
48
+ **逻辑描述:**
49
+ - 自动过滤完全重复的关系定义,防止数据冗余。
50
+
51
+ ---
52
+
53
+ ### 4. `project_read_graph`
54
+ 读取指定项目的完整知识图谱。
55
+
56
+ **输入参数:**
57
+ - `projectPath` (string): 项目根目录的绝对路径。
58
+
59
+ **返回:**
60
+ - 包含 `entities` 和 `relations` 的标准 JSON 对象。
61
+
62
+ ---
63
+
64
+ ## 数据存储规范
65
+ - **路径**: `.mcp/memory.json`
66
+ - **格式**: 2 空格缩进的 JSON。
67
+ - **排序策略**:
68
+ - 实体:按 `name` 排序。
69
+ - 关系:按 `from` -> `to` -> `type` 排序。
70
+ - 观测:按字母序排序。
package/docs/DESIGN.md ADDED
@@ -0,0 +1,52 @@
1
+ # N2N Memory (N2N 记忆) 开发方案
2
+
3
+ ## 1. 背景与目标
4
+ 解决全局 MCP Memory Server 导致的跨项目“记忆污染”与幻觉问题。通过将 AI 的认知碎片直接持久化在项目源码目录下,实现项目级的物理隔离与知识共享。
5
+
6
+ 本项目旨在开发一个高度简约、工具中立、且对版本管理友好的 N2N 记忆服务。
7
+
8
+ ## 2. 核心架构设计
9
+
10
+ ### 2.1 存储逻辑
11
+ - **存储位置**: `[项目根目录]/.mcp/memory.json`
12
+ - **中立性**: 采用 `.mcp` 命名以脱离特定 AI 助手或 IDE 插件的品牌绑定。
13
+ - **物理隔离**: 一个项目一个文件,互不干扰,完全随项目代码同步。
14
+
15
+ ### 2.2 交互规范
16
+ - **寻址方式**: AI 助理在调用工具时,必须传递当前工作区的**绝对路径 (Absolute Path)**。
17
+ - **无状态设计**: MCP Server 进程本身不维护任何路径状态,仅作为由路径驱动的存取器。
18
+ - **自动初始化**: 若目标路径下的 `.mcp/memory.json` 不存在,Server 应自动创建标准的空图谱结构。
19
+
20
+ ## 3. 数据结构与检索
21
+
22
+ ### 3.1 极简数据格式
23
+ JSON 内部**不包含**版本号、元数据、作者信息或时间戳。仅保留核心知识图谱数据(Entities & Relations),通过 Git 记录实现版本审计。
24
+
25
+ ### 3.2 Git 友好型保存策略
26
+ 为确保 `git diff` 可读:
27
+ 1. **强制排序**: 对 `entities` 和 `relations` 执行字典序排序。
28
+ 2. **规范缩进**: 统一使用 2 空格缩进。
29
+
30
+ ### 3.3 分级检索机制 (Tiered Retrieval)
31
+ - **一级:精准检索**: 基于实体 ID 的 O(1) 匹配,保证逻辑严密性。
32
+ - **二级:语义理解**: AI 助手加载全量 JSON 后,利用模型自身的长上下文理解力处理模糊匹配,无需引入向量数据库。
33
+
34
+ ## 4. 开发语言效率分析 (Go vs. Node.js vs. Python)
35
+
36
+ ### 4.1 Node.js (TypeScript) - [默认推荐]
37
+ - **效率**: 开发效率极高,官方 SDK 最成熟。
38
+ - **性能**: 处理单个项目的 JSON(通常 < 10MB)绰绰有余。
39
+ - **分发**: 通过 `npx` 可实现免安装运行。
40
+
41
+ ### 4.2 Go - [极致性能选型]
42
+ - **效率**: 运行效率最高,内存占用极低(仅需几 MB)。
43
+ - **分发**: 编译为单一二进制文件(Single Binary),部署最干净,适合对 IDE 性能有极致要求的用户。
44
+ - **场景**: 若未来需要处理拥有数万个节点的超大型知识图谱,Go 是唯一选择。
45
+
46
+ ### 4.3 Python - [不推荐]
47
+ - **缺点**: 环境依赖重,分发困难,对于简单的、非 AI 计算密集的 I/O 任务显得过于沉重。
48
+
49
+ ## 5. 优势总结
50
+ - **资产化**: 记忆即源码,可审计、可共享。
51
+ - **零漂移**: 物理隔离,杜绝跨项目污染。
52
+ - **确定性**: 结构化数据比高性能向量数据库更适合高精度的编码决策场景。
@@ -0,0 +1,54 @@
1
+ # 开发与维护手册
2
+
3
+ 本手册记录了 N2N Memory MCP Server 的日常开发、测试及构建流程。
4
+
5
+ ## 开发环境
6
+ - **Runtime**: Node.js v22.x+
7
+ - **Language**: TypeScript
8
+ - **Package Manager**: npm
9
+
10
+ ## 常用指令
11
+
12
+ ### 1. 安装依赖
13
+ ```bash
14
+ npm install
15
+ ```
16
+
17
+ ### 2. 运行测试
18
+ 本项目使用 `mocha` + `sinon` 执行单元测试。
19
+ ```bash
20
+ npm test
21
+ ```
22
+ > **注意**: 在 Windows 环境下,测试脚本已配置为使用 `tsx --import` 以正确处理 ESM 路径兼容性。
23
+
24
+ ### 3. 开发模式 (热更新)
25
+ ```bash
26
+ npm run dev
27
+ ```
28
+
29
+ ### 4. 生产构建
30
+ 将 TypeScript 编译为原生 JavaScript(输出到 `build/` 目录)。
31
+ ```bash
32
+ npm run build
33
+ ```
34
+
35
+ ### 5. 启动服务
36
+ ```bash
37
+ npm start
38
+ ```
39
+
40
+ ## 核心架构说明
41
+
42
+ ### 逻辑分层
43
+ 1. **`index.ts`**: MCP 协议层。负责处理 JSON-RPC、Resources 接口,并使用 **Zod** 进行输入校验。
44
+ 2. **`memory-manager.ts`**: 业务逻辑层。负责文件 I/O、数据排序、实体合并等核心算法。
45
+ 3. **`types.ts`**: 类型与 Schema 定义。包含 Zod 校验规则,是整个项目的类型基准。
46
+
47
+ ### 关键算法:Git 友好排序
48
+ 每当执行写操作(Update/Create)时,`MemoryManager.writeGraph` 会被触发:
49
+ - 它会递归地对数组进行 `localeCompare` 排序。
50
+ - 这样做的目的是保证即使 AI 乱序生成了记忆片段,存入 Git 的文件 diff 依然是稳定且可读的。
51
+
52
+ ## 贡献指南
53
+ - 所有的逻辑变更必须附带相应的单元测试。
54
+ - 修改存储结构前,请先更新 `docs/DESIGN.md`。
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@datafrog-io/n2n-memory",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "main": "build/index.js",
6
+ "bin": {
7
+ "n2n-memory": "build/index.js"
8
+ },
9
+ "type": "module",
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "start": "node build/index.js",
13
+ "dev": "tsx src/index.ts",
14
+ "test": "mocha --node-option import=tsx src/test/**/*.test.ts",
15
+ "lint": "eslint src/**/*.ts"
16
+ },
17
+ "keywords": [],
18
+ "author": "",
19
+ "license": "ISC",
20
+ "dependencies": {
21
+ "@modelcontextprotocol/sdk": "^1.25.1",
22
+ "fs-extra": "^11.3.3",
23
+ "zod": "^4.2.1"
24
+ },
25
+ "devDependencies": {
26
+ "@types/chai": "^5.2.3",
27
+ "@types/fs-extra": "^11.0.4",
28
+ "@types/mocha": "^10.0.10",
29
+ "@types/node": "^25.0.3",
30
+ "@types/sinon": "^21.0.0",
31
+ "@typescript-eslint/eslint-plugin": "^8.50.0",
32
+ "@typescript-eslint/parser": "^8.50.0",
33
+ "chai": "^6.2.1",
34
+ "eslint": "^9.39.2",
35
+ "mocha": "^11.7.5",
36
+ "sinon": "^21.0.0",
37
+ "ts-node": "^10.9.2",
38
+ "tsx": "^4.21.0",
39
+ "typescript": "^5.9.3",
40
+ "typescript-eslint": "^8.50.0"
41
+ }
42
+ }